From 3b681e255cd8577a77983958ef7f566b05806cd0 Mon Sep 17 00:00:00 2001 From: Peter Krefting Date: Thu, 26 Oct 2023 21:47:18 +0100 Subject: gitk: sv.po: Update Swedish translation (323t) Signed-off-by: Peter Krefting --- po/sv.po | 734 ++++++++++++++++++++++++++++++++------------------------------- 1 file changed, 377 insertions(+), 357 deletions(-) diff --git a/po/sv.po b/po/sv.po index 2a06fe5bbc..5afbe6da1d 100644 --- a/po/sv.po +++ b/po/sv.po @@ -3,14 +3,14 @@ # This file is distributed under the same license as the gitk package. # # Mikael Magnusson , 2008. -# Peter Krefting , 2008, 2009, 2010, 2012, 2013, 2015. +# Peter Krefting , 2008-2023. # msgid "" msgstr "" "Project-Id-Version: sv\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-12-09 09:40+0100\n" -"PO-Revision-Date: 2015-12-11 09:46+0100\n" +"POT-Creation-Date: 2023-10-26 21:39+0100\n" +"PO-Revision-Date: 2023-10-26 21:42+0100\n" "Last-Translator: Peter Krefting \n" "Language-Team: Swedish \n" "Language: sv\n" @@ -18,35 +18,35 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Gtranslator 2.91.6\n" +"X-Generator: Gtranslator 3.38.0\n" -#: gitk:140 +#: gitk:139 msgid "Couldn't get list of unmerged files:" msgstr "Kunde inte hämta lista över ej sammanslagna filer:" -#: gitk:212 gitk:2381 +#: gitk:211 gitk:2406 msgid "Color words" msgstr "Färga ord" -#: gitk:217 gitk:2381 gitk:8221 gitk:8254 +#: gitk:216 gitk:2406 gitk:8307 gitk:8340 msgid "Markup words" msgstr "Märk upp ord" -#: gitk:324 +#: gitk:323 msgid "Error parsing revisions:" msgstr "Fel vid tolkning av revisioner:" -#: gitk:380 +#: gitk:379 msgid "Error executing --argscmd command:" msgstr "Fel vid körning av --argscmd-kommando:" -#: gitk:393 +#: gitk:392 msgid "No files selected: --merge specified but no files are unmerged." msgstr "" "Inga filer valdes: --merge angavs men det finns inga filer som inte har " "slagits samman." -#: gitk:396 +#: gitk:395 msgid "" "No files selected: --merge specified but no unmerged files are within file " "limit." @@ -54,322 +54,326 @@ msgstr "" "Inga filer valdes: --merge angavs men det finns inga filer inom " "filbegränsningen." -#: gitk:418 gitk:566 +#: gitk:417 gitk:565 msgid "Error executing git log:" msgstr "Fel vid körning av git log:" -#: gitk:436 gitk:582 +#: gitk:435 gitk:581 msgid "Reading" msgstr "Läser" -#: gitk:496 gitk:4526 +#: gitk:495 gitk:4572 msgid "Reading commits..." msgstr "Läser incheckningar..." -#: gitk:499 gitk:1637 gitk:4529 +#: gitk:498 gitk:1640 gitk:4575 msgid "No commits selected" msgstr "Inga incheckningar markerade" -#: gitk:1445 gitk:4046 gitk:12447 +#: gitk:1448 gitk:4092 gitk:12674 msgid "Command line" msgstr "Kommandorad" -#: gitk:1511 +#: gitk:1514 msgid "Can't parse git log output:" msgstr "Kan inte tolka utdata från git log:" -#: gitk:1740 +#: gitk:1743 msgid "No commit information available" msgstr "Ingen incheckningsinformation är tillgänglig" -#: gitk:1903 gitk:1932 gitk:4316 gitk:9684 gitk:11256 gitk:11536 +#: gitk:1910 gitk:1939 gitk:4362 gitk:9847 gitk:11451 gitk:11751 msgid "OK" msgstr "OK" -#: gitk:1934 gitk:4318 gitk:9197 gitk:9276 gitk:9406 gitk:9455 gitk:9686 -#: gitk:11257 gitk:11537 +#: gitk:1941 gitk:4364 gitk:9283 gitk:9362 gitk:9492 gitk:9578 gitk:9849 +#: gitk:11452 gitk:11752 msgid "Cancel" msgstr "Avbryt" -#: gitk:2069 +#: gitk:2090 msgid "&Update" msgstr "&Uppdatera" -#: gitk:2070 +#: gitk:2091 msgid "&Reload" msgstr "Läs &om" -#: gitk:2071 +#: gitk:2092 msgid "Reread re&ferences" msgstr "Läs om &referenser" -#: gitk:2072 +#: gitk:2093 msgid "&List references" msgstr "&Visa referenser" -#: gitk:2074 +#: gitk:2095 msgid "Start git &gui" msgstr "Starta git &gui" -#: gitk:2076 +#: gitk:2097 msgid "&Quit" msgstr "&Avsluta" -#: gitk:2068 +#: gitk:2089 msgid "&File" msgstr "&Arkiv" -#: gitk:2080 +#: gitk:2101 msgid "&Preferences" msgstr "&Inställningar" -#: gitk:2079 +#: gitk:2100 msgid "&Edit" msgstr "&Redigera" -#: gitk:2084 +#: gitk:2105 msgid "&New view..." msgstr "&Ny vy..." -#: gitk:2085 +#: gitk:2106 msgid "&Edit view..." msgstr "&Ändra vy..." -#: gitk:2086 +#: gitk:2107 msgid "&Delete view" msgstr "&Ta bort vy" -#: gitk:2088 +#: gitk:2109 msgid "&All files" msgstr "&Alla filer" -#: gitk:2083 +#: gitk:2104 msgid "&View" msgstr "&Visa" -#: gitk:2093 gitk:2103 +#: gitk:2114 gitk:2124 msgid "&About gitk" msgstr "&Om gitk" -#: gitk:2094 gitk:2108 +#: gitk:2115 gitk:2129 msgid "&Key bindings" msgstr "&Tangentbordsbindningar" -#: gitk:2092 gitk:2107 +#: gitk:2113 gitk:2128 msgid "&Help" msgstr "&Hjälp" -#: gitk:2185 gitk:8653 +#: gitk:2206 gitk:8739 msgid "SHA1 ID:" msgstr "SHA1-id:" -#: gitk:2229 +#: gitk:2250 msgid "Row" msgstr "Rad" -#: gitk:2267 +#: gitk:2288 msgid "Find" msgstr "Sök" -#: gitk:2295 +#: gitk:2316 msgid "commit" msgstr "incheckning" -#: gitk:2299 gitk:2301 gitk:4688 gitk:4711 gitk:4735 gitk:6756 gitk:6828 -#: gitk:6913 +#: gitk:2320 gitk:2322 gitk:4734 gitk:4757 gitk:4781 gitk:6802 gitk:6874 +#: gitk:6959 msgid "containing:" msgstr "som innehåller:" -#: gitk:2302 gitk:3527 gitk:3532 gitk:4764 +#: gitk:2323 gitk:3573 gitk:3578 gitk:4810 msgid "touching paths:" msgstr "som rör sökväg:" -#: gitk:2303 gitk:4778 +#: gitk:2324 gitk:4824 msgid "adding/removing string:" msgstr "som lägger/till tar bort sträng:" -#: gitk:2304 gitk:4780 +#: gitk:2325 gitk:4826 msgid "changing lines matching:" msgstr "ändrar rader som matchar:" -#: gitk:2313 gitk:2315 gitk:4767 +#: gitk:2334 gitk:2336 gitk:4813 msgid "Exact" msgstr "Exakt" -#: gitk:2315 gitk:4855 gitk:6724 +#: gitk:2336 gitk:4901 gitk:6770 msgid "IgnCase" msgstr "IgnVersaler" -#: gitk:2315 gitk:4737 gitk:4853 gitk:6720 +#: gitk:2336 gitk:4783 gitk:4899 gitk:6766 msgid "Regexp" msgstr "Reg.uttr." -#: gitk:2317 gitk:2318 gitk:4875 gitk:4905 gitk:4912 gitk:6849 gitk:6917 +#: gitk:2338 gitk:2339 gitk:4921 gitk:4951 gitk:4958 gitk:6895 gitk:6963 msgid "All fields" msgstr "Alla fält" -#: gitk:2318 gitk:4872 gitk:4905 gitk:6787 +#: gitk:2339 gitk:4918 gitk:4951 gitk:6833 msgid "Headline" msgstr "Rubrik" -#: gitk:2319 gitk:4872 gitk:6787 gitk:6917 gitk:7390 +#: gitk:2340 gitk:4918 gitk:6833 gitk:6963 gitk:7471 msgid "Comments" msgstr "Kommentarer" -#: gitk:2319 gitk:4872 gitk:4877 gitk:4912 gitk:6787 gitk:7325 gitk:8831 -#: gitk:8846 +#: gitk:2340 gitk:4918 gitk:4923 gitk:4958 gitk:6833 gitk:7406 gitk:8917 +#: gitk:8932 msgid "Author" msgstr "Författare" -#: gitk:2319 gitk:4872 gitk:6787 gitk:7327 +#: gitk:2340 gitk:4918 gitk:6833 gitk:7408 msgid "Committer" msgstr "Incheckare" -#: gitk:2350 +#: gitk:2374 msgid "Search" msgstr "Sök" -#: gitk:2358 +#: gitk:2382 msgid "Diff" msgstr "Diff" -#: gitk:2360 +#: gitk:2384 msgid "Old version" msgstr "Gammal version" -#: gitk:2362 +#: gitk:2386 msgid "New version" msgstr "Ny version" -#: gitk:2364 +#: gitk:2389 msgid "Lines of context" msgstr "Rader sammanhang" -#: gitk:2374 +#: gitk:2399 msgid "Ignore space change" msgstr "Ignorera ändringar i blanksteg" -#: gitk:2378 gitk:2380 gitk:7960 gitk:8207 +#: gitk:2403 gitk:2405 gitk:8041 gitk:8293 msgid "Line diff" msgstr "Rad-diff" -#: gitk:2445 +#: gitk:2478 msgid "Patch" msgstr "Patch" -#: gitk:2447 +#: gitk:2480 msgid "Tree" msgstr "Träd" -#: gitk:2617 gitk:2638 +#: gitk:2650 gitk:2671 msgid "Diff this -> selected" msgstr "Diff denna -> markerad" -#: gitk:2618 gitk:2639 +#: gitk:2651 gitk:2672 msgid "Diff selected -> this" msgstr "Diff markerad -> denna" -#: gitk:2619 gitk:2640 +#: gitk:2652 gitk:2673 msgid "Make patch" msgstr "Skapa patch" -#: gitk:2620 gitk:9255 +#: gitk:2653 gitk:9341 msgid "Create tag" msgstr "Skapa tagg" -#: gitk:2621 -msgid "Copy commit summary" -msgstr "Kopiera incheckningssammanfattning" +#: gitk:2654 +msgid "Copy commit reference" +msgstr "Kopiera incheckningsreferens" -#: gitk:2622 gitk:9386 +#: gitk:2655 gitk:9472 msgid "Write commit to file" msgstr "Skriv incheckning till fil" -#: gitk:2623 gitk:9443 +#: gitk:2656 msgid "Create new branch" msgstr "Skapa ny gren" -#: gitk:2624 +#: gitk:2657 msgid "Cherry-pick this commit" msgstr "Plocka denna incheckning" -#: gitk:2625 +#: gitk:2658 msgid "Reset HEAD branch to here" msgstr "Återställ HEAD-grenen hit" -#: gitk:2626 +#: gitk:2659 msgid "Mark this commit" msgstr "Markera denna incheckning" -#: gitk:2627 +#: gitk:2660 msgid "Return to mark" msgstr "Återgå till markering" -#: gitk:2628 +#: gitk:2661 msgid "Find descendant of this and mark" msgstr "Hitta efterföljare till denna och markera" -#: gitk:2629 +#: gitk:2662 msgid "Compare with marked commit" msgstr "Jämför med markerad incheckning" -#: gitk:2630 gitk:2641 +#: gitk:2663 gitk:2674 msgid "Diff this -> marked commit" msgstr "Diff denna -> markerad incheckning" -#: gitk:2631 gitk:2642 +#: gitk:2664 gitk:2675 msgid "Diff marked commit -> this" msgstr "Diff markerad incheckning -> denna" -#: gitk:2632 +#: gitk:2665 msgid "Revert this commit" msgstr "Ångra denna incheckning" -#: gitk:2648 +#: gitk:2681 msgid "Check out this branch" msgstr "Checka ut denna gren" -#: gitk:2649 +#: gitk:2682 +msgid "Rename this branch" +msgstr "Byt namn på denna gren" + +#: gitk:2683 msgid "Remove this branch" msgstr "Ta bort denna gren" -#: gitk:2650 +#: gitk:2684 msgid "Copy branch name" msgstr "Kopiera namn på gren" -#: gitk:2657 +#: gitk:2691 msgid "Highlight this too" msgstr "Markera även detta" -#: gitk:2658 +#: gitk:2692 msgid "Highlight this only" msgstr "Markera bara detta" -#: gitk:2659 +#: gitk:2693 msgid "External diff" msgstr "Extern diff" -#: gitk:2660 +#: gitk:2694 msgid "Blame parent commit" msgstr "Klandra föräldraincheckning" -#: gitk:2661 +#: gitk:2695 msgid "Copy path" msgstr "Kopiera sökväg" -#: gitk:2668 +#: gitk:2702 msgid "Show origin of this line" msgstr "Visa ursprunget för den här raden" -#: gitk:2669 +#: gitk:2703 msgid "Run git gui blame on this line" msgstr "Kör git gui blame på den här raden" -#: gitk:3013 +#: gitk:3057 msgid "About gitk" msgstr "Om gitk" -#: gitk:3015 +#: gitk:3059 msgid "" "\n" "Gitk - a commit viewer for git\n" @@ -385,525 +389,529 @@ msgstr "" "\n" "Använd och vidareförmedla enligt villkoren i GNU General Public License" -#: gitk:3023 gitk:3090 gitk:9872 +#: gitk:3067 gitk:3134 gitk:10062 msgid "Close" msgstr "Stäng" -#: gitk:3044 +#: gitk:3088 msgid "Gitk key bindings" msgstr "Tangentbordsbindningar för Gitk" -#: gitk:3047 +#: gitk:3091 msgid "Gitk key bindings:" msgstr "Tangentbordsbindningar för Gitk:" -#: gitk:3049 +#: gitk:3093 #, tcl-format msgid "<%s-Q>\t\tQuit" msgstr "<%s-Q>\t\tAvsluta" -#: gitk:3050 +#: gitk:3094 #, tcl-format msgid "<%s-W>\t\tClose window" msgstr "<%s-W>\t\tStäng fönster" -#: gitk:3051 +#: gitk:3095 msgid "\t\tMove to first commit" msgstr "\t\tGå till första incheckning" -#: gitk:3052 +#: gitk:3096 msgid "\t\tMove to last commit" msgstr "\t\tGå till sista incheckning" -#: gitk:3053 +#: gitk:3097 msgid ", p, k\tMove up one commit" msgstr ", p, k\tGå en incheckning upp" -#: gitk:3054 +#: gitk:3098 msgid ", n, j\tMove down one commit" msgstr ", n, j\tGå en incheckning ned" -#: gitk:3055 +#: gitk:3099 msgid ", z, h\tGo back in history list" msgstr ", z, h\tGå bakåt i historiken" -#: gitk:3056 +#: gitk:3100 msgid ", x, l\tGo forward in history list" msgstr ", x, l\tGå framåt i historiken" -#: gitk:3057 +#: gitk:3101 #, tcl-format msgid "<%s-n>\tGo to n-th parent of current commit in history list" msgstr "<%s-n>\tGå till aktuell inchecknings n:te förälder i historielistan" -#: gitk:3058 +#: gitk:3102 msgid "\tMove up one page in commit list" msgstr "\tGå upp en sida i incheckningslistan" -#: gitk:3059 +#: gitk:3103 msgid "\tMove down one page in commit list" msgstr "\tGå ned en sida i incheckningslistan" -#: gitk:3060 +#: gitk:3104 #, tcl-format msgid "<%s-Home>\tScroll to top of commit list" msgstr "<%s-Home>\tRulla till början av incheckningslistan" -#: gitk:3061 +#: gitk:3105 #, tcl-format msgid "<%s-End>\tScroll to bottom of commit list" msgstr "<%s-End>\tRulla till slutet av incheckningslistan" -#: gitk:3062 +#: gitk:3106 #, tcl-format msgid "<%s-Up>\tScroll commit list up one line" msgstr "<%s-Upp>\tRulla incheckningslistan upp ett steg" -#: gitk:3063 +#: gitk:3107 #, tcl-format msgid "<%s-Down>\tScroll commit list down one line" msgstr "<%s-Ned>\tRulla incheckningslistan ned ett steg" -#: gitk:3064 +#: gitk:3108 #, tcl-format msgid "<%s-PageUp>\tScroll commit list up one page" msgstr "<%s-PageUp>\tRulla incheckningslistan upp en sida" -#: gitk:3065 +#: gitk:3109 #, tcl-format msgid "<%s-PageDown>\tScroll commit list down one page" msgstr "<%s-PageDown>\tRulla incheckningslistan ned en sida" -#: gitk:3066 +#: gitk:3110 msgid "\tFind backwards (upwards, later commits)" msgstr "\tSök bakåt (uppåt, senare incheckningar)" -#: gitk:3067 +#: gitk:3111 msgid "\tFind forwards (downwards, earlier commits)" msgstr "\tSök framåt (nedåt, tidigare incheckningar)" -#: gitk:3068 +#: gitk:3112 msgid ", b\tScroll diff view up one page" msgstr ", b\tRulla diffvisningen upp en sida" -#: gitk:3069 +#: gitk:3113 msgid "\tScroll diff view up one page" msgstr "\tRulla diffvisningen upp en sida" -#: gitk:3070 +#: gitk:3114 msgid "\t\tScroll diff view down one page" msgstr "\tRulla diffvisningen ned en sida" -#: gitk:3071 +#: gitk:3115 msgid "u\t\tScroll diff view up 18 lines" msgstr "u\t\tRulla diffvisningen upp 18 rader" -#: gitk:3072 +#: gitk:3116 msgid "d\t\tScroll diff view down 18 lines" msgstr "d\t\tRulla diffvisningen ned 18 rader" -#: gitk:3073 +#: gitk:3117 #, tcl-format msgid "<%s-F>\t\tFind" msgstr "<%s-F>\t\tSök" -#: gitk:3074 +#: gitk:3118 #, tcl-format msgid "<%s-G>\t\tMove to next find hit" msgstr "<%s-G>\t\tGå till nästa sökträff" -#: gitk:3075 +#: gitk:3119 msgid "\tMove to next find hit" msgstr "\t\tGå till nästa sökträff" -#: gitk:3076 +#: gitk:3120 msgid "g\t\tGo to commit" msgstr "g\t\tGå till incheckning" -#: gitk:3077 +#: gitk:3121 msgid "/\t\tFocus the search box" msgstr "/\t\tFokusera sökrutan" -#: gitk:3078 +#: gitk:3122 msgid "?\t\tMove to previous find hit" msgstr "?\t\tGå till föregående sökträff" -#: gitk:3079 +#: gitk:3123 msgid "f\t\tScroll diff view to next file" msgstr "f\t\tRulla diffvisningen till nästa fil" -#: gitk:3080 +#: gitk:3124 #, tcl-format msgid "<%s-S>\t\tSearch for next hit in diff view" msgstr "<%s-S>\t\tGå till nästa sökträff i diffvisningen" -#: gitk:3081 +#: gitk:3125 #, tcl-format msgid "<%s-R>\t\tSearch for previous hit in diff view" msgstr "<%s-R>\t\tGå till föregående sökträff i diffvisningen" -#: gitk:3082 +#: gitk:3126 #, tcl-format msgid "<%s-KP+>\tIncrease font size" msgstr "<%s-Num+>\tÖka teckenstorlek" -#: gitk:3083 +#: gitk:3127 #, tcl-format msgid "<%s-plus>\tIncrease font size" msgstr "<%s-plus>\tÖka teckenstorlek" -#: gitk:3084 +#: gitk:3128 #, tcl-format msgid "<%s-KP->\tDecrease font size" msgstr "<%s-Num->\tMinska teckenstorlek" -#: gitk:3085 +#: gitk:3129 #, tcl-format msgid "<%s-minus>\tDecrease font size" msgstr "<%s-minus>\tMinska teckenstorlek" -#: gitk:3086 +#: gitk:3130 msgid "\t\tUpdate" msgstr "\t\tUppdatera" -#: gitk:3551 gitk:3560 +#: gitk:3597 gitk:3606 #, tcl-format msgid "Error creating temporary directory %s:" msgstr "Fel vid skapande av temporär katalog %s:" -#: gitk:3573 +#: gitk:3619 #, tcl-format msgid "Error getting \"%s\" from %s:" -msgstr "Fel vid hämtning av \"%s\" från %s:" +msgstr "Fel vid hämtning av ”%s” från %s:" -#: gitk:3636 +#: gitk:3682 msgid "command failed:" msgstr "kommando misslyckades:" -#: gitk:3785 +#: gitk:3831 msgid "No such commit" msgstr "Incheckning saknas" -#: gitk:3799 +#: gitk:3845 msgid "git gui blame: command failed:" msgstr "git gui blame: kommando misslyckades:" -#: gitk:3830 +#: gitk:3876 #, tcl-format msgid "Couldn't read merge head: %s" msgstr "Kunde inte läsa sammanslagningshuvud: %s" -#: gitk:3838 +#: gitk:3884 #, tcl-format msgid "Error reading index: %s" msgstr "Fel vid läsning av index: %s" -#: gitk:3863 +#: gitk:3909 #, tcl-format msgid "Couldn't start git blame: %s" msgstr "Kunde inte starta git blame: %s" -#: gitk:3866 gitk:6755 +#: gitk:3912 gitk:6801 msgid "Searching" msgstr "Söker" -#: gitk:3898 +#: gitk:3944 #, tcl-format msgid "Error running git blame: %s" msgstr "Fel vid körning av git blame: %s" -#: gitk:3926 +#: gitk:3972 #, tcl-format msgid "That line comes from commit %s, which is not in this view" msgstr "Raden kommer från incheckningen %s, som inte finns i denna vy" -#: gitk:3940 +#: gitk:3986 msgid "External diff viewer failed:" msgstr "Externt diff-verktyg misslyckades:" -#: gitk:4044 +#: gitk:4090 msgid "All files" msgstr "Alla filer" -#: gitk:4068 +#: gitk:4114 msgid "View" msgstr "Visa" -#: gitk:4071 +#: gitk:4117 msgid "Gitk view definition" msgstr "Definition av Gitk-vy" -#: gitk:4075 +#: gitk:4121 msgid "Remember this view" msgstr "Spara denna vy" -#: gitk:4076 +#: gitk:4122 msgid "References (space separated list):" msgstr "Referenser (blankstegsavdelad lista):" -#: gitk:4077 +#: gitk:4123 msgid "Branches & tags:" msgstr "Grenar & taggar:" -#: gitk:4078 +#: gitk:4124 msgid "All refs" msgstr "Alla referenser" -#: gitk:4079 +#: gitk:4125 msgid "All (local) branches" msgstr "Alla (lokala) grenar" -#: gitk:4080 +#: gitk:4126 msgid "All tags" msgstr "Alla taggar" -#: gitk:4081 +#: gitk:4127 msgid "All remote-tracking branches" msgstr "Alla fjärrspårande grenar" -#: gitk:4082 +#: gitk:4128 msgid "Commit Info (regular expressions):" msgstr "Incheckningsinfo (reguljära uttryck):" -#: gitk:4083 +#: gitk:4129 msgid "Author:" msgstr "Författare:" -#: gitk:4084 +#: gitk:4130 msgid "Committer:" msgstr "Incheckare:" -#: gitk:4085 +#: gitk:4131 msgid "Commit Message:" msgstr "Incheckningsmeddelande:" -#: gitk:4086 +#: gitk:4132 msgid "Matches all Commit Info criteria" msgstr "Motsvarar alla kriterier för incheckningsinfo" -#: gitk:4087 +#: gitk:4133 msgid "Matches no Commit Info criteria" msgstr "Motsvarar inga kriterier för incheckningsinfo" -#: gitk:4088 +#: gitk:4134 msgid "Changes to Files:" msgstr "Ändringar av filer:" -#: gitk:4089 +#: gitk:4135 msgid "Fixed String" msgstr "Fast sträng" -#: gitk:4090 +#: gitk:4136 msgid "Regular Expression" msgstr "Reguljärt uttryck" -#: gitk:4091 +#: gitk:4137 msgid "Search string:" msgstr "Söksträng:" -#: gitk:4092 +#: gitk:4138 msgid "" "Commit Dates (\"2 weeks ago\", \"2009-03-17 15:27:38\", \"March 17, 2009 " "15:27:38\"):" msgstr "" -"Incheckingsdatum (\"2 weeks ago\", \"2009-03-17 15:27:38\", \"March 17, 2009 " -"15:27:38\"):" +"Incheckningsdatum (”2 weeks ago”, ”2009-03-17 15:27:38”, ”March 17, 2009 " +"15:27:38”):" -#: gitk:4093 +#: gitk:4139 msgid "Since:" msgstr "Från:" -#: gitk:4094 +#: gitk:4140 msgid "Until:" msgstr "Till:" -#: gitk:4095 +#: gitk:4141 msgid "Limit and/or skip a number of revisions (positive integer):" msgstr "Begränsa och/eller hoppa över ett antal revisioner (positivt heltal):" -#: gitk:4096 +#: gitk:4142 msgid "Number to show:" msgstr "Antal att visa:" -#: gitk:4097 +#: gitk:4143 msgid "Number to skip:" msgstr "Antal att hoppa över:" -#: gitk:4098 +#: gitk:4144 msgid "Miscellaneous options:" msgstr "Diverse alternativ:" -#: gitk:4099 +#: gitk:4145 msgid "Strictly sort by date" msgstr "Strikt datumsortering" -#: gitk:4100 +#: gitk:4146 msgid "Mark branch sides" msgstr "Markera sidogrenar" -#: gitk:4101 +#: gitk:4147 msgid "Limit to first parent" msgstr "Begränsa till första förälder" -#: gitk:4102 +#: gitk:4148 msgid "Simple history" msgstr "Enkel historik" -#: gitk:4103 +#: gitk:4149 msgid "Additional arguments to git log:" msgstr "Ytterligare argument till git log:" -#: gitk:4104 +#: gitk:4150 msgid "Enter files and directories to include, one per line:" msgstr "Ange filer och kataloger att ta med, en per rad:" -#: gitk:4105 +#: gitk:4151 msgid "Command to generate more commits to include:" msgstr "Kommando för att generera fler incheckningar att ta med:" -#: gitk:4229 +#: gitk:4275 msgid "Gitk: edit view" msgstr "Gitk: redigera vy" -#: gitk:4237 +#: gitk:4283 msgid "-- criteria for selecting revisions" msgstr " - kriterier för val av revisioner" -#: gitk:4242 +#: gitk:4288 msgid "View Name" msgstr "Namn på vy" -#: gitk:4317 +#: gitk:4363 msgid "Apply (F5)" msgstr "Använd (F5)" -#: gitk:4355 +#: gitk:4401 msgid "Error in commit selection arguments:" msgstr "Fel i argument för val av incheckningar:" -#: gitk:4410 gitk:4463 gitk:4925 gitk:4939 gitk:6209 gitk:12388 gitk:12389 +#: gitk:4456 gitk:4509 gitk:4971 gitk:4985 gitk:6255 gitk:12615 gitk:12616 msgid "None" msgstr "Inget" -#: gitk:5022 gitk:5027 +#: gitk:5068 gitk:5073 msgid "Descendant" msgstr "Avkomling" -#: gitk:5023 +#: gitk:5069 msgid "Not descendant" msgstr "Inte avkomling" -#: gitk:5030 gitk:5035 +#: gitk:5076 gitk:5081 msgid "Ancestor" msgstr "Förfader" -#: gitk:5031 +#: gitk:5077 msgid "Not ancestor" msgstr "Inte förfader" -#: gitk:5325 +#: gitk:5371 msgid "Local changes checked in to index but not committed" msgstr "Lokala ändringar sparade i indexet men inte incheckade" -#: gitk:5361 +#: gitk:5407 msgid "Local uncommitted changes, not checked in to index" msgstr "Lokala ändringar, ej sparade i indexet" -#: gitk:7135 +#: gitk:7155 +msgid "Error starting web browser:" +msgstr "Fel när webbläsaren skulle startas:" + +#: gitk:7216 msgid "and many more" msgstr "med många flera" -#: gitk:7138 +#: gitk:7219 msgid "many" msgstr "många" -#: gitk:7329 +#: gitk:7410 msgid "Tags:" msgstr "Taggar:" -#: gitk:7346 gitk:7352 gitk:8826 +#: gitk:7427 gitk:7433 gitk:8912 msgid "Parent" msgstr "Förälder" -#: gitk:7357 +#: gitk:7438 msgid "Child" msgstr "Barn" -#: gitk:7366 +#: gitk:7447 msgid "Branch" msgstr "Gren" -#: gitk:7369 +#: gitk:7450 msgid "Follows" msgstr "Följer" -#: gitk:7372 +#: gitk:7453 msgid "Precedes" msgstr "Föregår" -#: gitk:7967 +#: gitk:8048 #, tcl-format msgid "Error getting diffs: %s" msgstr "Fel vid hämtning av diff: %s" -#: gitk:8651 +#: gitk:8737 msgid "Goto:" msgstr "Gå till:" -#: gitk:8672 +#: gitk:8758 #, tcl-format msgid "Short SHA1 id %s is ambiguous" msgstr "Förkortat SHA1-id %s är tvetydigt" -#: gitk:8679 +#: gitk:8765 #, tcl-format msgid "Revision %s is not known" msgstr "Revisionen %s är inte känd" -#: gitk:8689 +#: gitk:8775 #, tcl-format msgid "SHA1 id %s is not known" msgstr "SHA-id:t %s är inte känt" -#: gitk:8691 +#: gitk:8777 #, tcl-format msgid "Revision %s is not in the current view" msgstr "Revisionen %s finns inte i den nuvarande vyn" -#: gitk:8833 gitk:8848 +#: gitk:8919 gitk:8934 msgid "Date" msgstr "Datum" -#: gitk:8836 +#: gitk:8922 msgid "Children" msgstr "Barn" -#: gitk:8899 +#: gitk:8985 #, tcl-format msgid "Reset %s branch to here" msgstr "Återställ grenen %s hit" -#: gitk:8901 +#: gitk:8987 msgid "Detached head: can't reset" msgstr "Frånkopplad head: kan inte återställa" -#: gitk:9006 gitk:9012 +#: gitk:9092 gitk:9098 msgid "Skipping merge commit " msgstr "Hoppar över sammanslagningsincheckning " -#: gitk:9021 gitk:9026 +#: gitk:9107 gitk:9112 msgid "Error getting patch ID for " msgstr "Fel vid hämtning av patch-id för " -#: gitk:9022 gitk:9027 +#: gitk:9108 gitk:9113 msgid " - stopping\n" msgstr " - stannar\n" -#: gitk:9032 gitk:9035 gitk:9043 gitk:9057 gitk:9066 +#: gitk:9118 gitk:9121 gitk:9129 gitk:9143 gitk:9152 msgid "Commit " msgstr "Incheckning " -#: gitk:9036 +#: gitk:9122 msgid "" " is the same patch as\n" " " @@ -911,7 +919,7 @@ msgstr "" " är samma patch som\n" " " -#: gitk:9044 +#: gitk:9130 msgid "" " differs from\n" " " @@ -919,7 +927,7 @@ msgstr "" " skiljer sig från\n" " " -#: gitk:9046 +#: gitk:9132 msgid "" "Diff of commits:\n" "\n" @@ -927,141 +935,158 @@ msgstr "" "Skillnad mellan incheckningar:\n" "\n" -#: gitk:9058 gitk:9067 +#: gitk:9144 gitk:9153 #, tcl-format msgid " has %s children - stopping\n" msgstr " har %s barn - stannar\n" -#: gitk:9086 +#: gitk:9172 #, tcl-format msgid "Error writing commit to file: %s" msgstr "Fel vid skrivning av incheckning till fil: %s" -#: gitk:9092 +#: gitk:9178 #, tcl-format msgid "Error diffing commits: %s" msgstr "Fel vid jämförelse av incheckningar: %s" -#: gitk:9138 +#: gitk:9224 msgid "Top" msgstr "Topp" -#: gitk:9139 +#: gitk:9225 msgid "From" msgstr "Från" -#: gitk:9144 +#: gitk:9230 msgid "To" msgstr "Till" -#: gitk:9168 +#: gitk:9254 msgid "Generate patch" msgstr "Generera patch" -#: gitk:9170 +#: gitk:9256 msgid "From:" msgstr "Från:" -#: gitk:9179 +#: gitk:9265 msgid "To:" msgstr "Till:" -#: gitk:9188 +#: gitk:9274 msgid "Reverse" msgstr "Vänd" -#: gitk:9190 gitk:9400 +#: gitk:9276 gitk:9486 msgid "Output file:" msgstr "Utdatafil:" -#: gitk:9196 +#: gitk:9282 msgid "Generate" msgstr "Generera" -#: gitk:9234 +#: gitk:9320 msgid "Error creating patch:" msgstr "Fel vid generering av patch:" -#: gitk:9257 gitk:9388 gitk:9445 +#: gitk:9343 gitk:9474 gitk:9562 msgid "ID:" msgstr "Id:" -#: gitk:9266 +#: gitk:9352 msgid "Tag name:" msgstr "Taggnamn:" -#: gitk:9269 +#: gitk:9355 msgid "Tag message is optional" msgstr "Taggmeddelandet är valfritt" -#: gitk:9271 +#: gitk:9357 msgid "Tag message:" msgstr "Taggmeddelande:" -#: gitk:9275 gitk:9454 +#: gitk:9361 gitk:9532 msgid "Create" msgstr "Skapa" -#: gitk:9293 +#: gitk:9379 msgid "No tag name specified" msgstr "Inget taggnamn angavs" -#: gitk:9297 +#: gitk:9383 #, tcl-format msgid "Tag \"%s\" already exists" -msgstr "Taggen \"%s\" finns redan" +msgstr "Taggen ”%s” finns redan" -#: gitk:9307 +#: gitk:9393 msgid "Error creating tag:" msgstr "Fel vid skapande av tagg:" -#: gitk:9397 +#: gitk:9483 msgid "Command:" msgstr "Kommando:" -#: gitk:9405 +#: gitk:9491 msgid "Write" msgstr "Skriv" -#: gitk:9423 +#: gitk:9509 msgid "Error writing commit:" msgstr "Fel vid skrivning av incheckning:" -#: gitk:9450 +#: gitk:9531 +msgid "Create branch" +msgstr "Skapa gren" + +#: gitk:9547 +#, tcl-format +msgid "Rename branch %s" +msgstr "Byt namn på grenen %s" + +#: gitk:9548 +msgid "Rename" +msgstr "Byt namn" + +#: gitk:9572 msgid "Name:" msgstr "Namn:" -#: gitk:9473 +#: gitk:9596 msgid "Please specify a name for the new branch" msgstr "Ange ett namn för den nya grenen" -#: gitk:9478 +#: gitk:9601 #, tcl-format msgid "Branch '%s' already exists. Overwrite?" -msgstr "Grenen \"%s\" finns redan. Skriva över?" +msgstr "Grenen ”%s” finns redan. Skriva över?" + +#: gitk:9645 +msgid "Please specify a new name for the branch" +msgstr "Ange ett nytt namn för grenen" -#: gitk:9545 +#: gitk:9708 #, tcl-format msgid "Commit %s is already included in branch %s -- really re-apply it?" msgstr "" "Incheckningen %s finns redan på grenen %s -- skall den verkligen appliceras " "på nytt?" -#: gitk:9550 +#: gitk:9713 msgid "Cherry-picking" msgstr "Plockar" -#: gitk:9559 +#: gitk:9722 #, tcl-format msgid "" "Cherry-pick failed because of local changes to file '%s'.\n" "Please commit, reset or stash your changes and try again." msgstr "" -"Cherry-pick misslyckades på grund av lokala ändringar i filen \"%s\".\n" +"Cherry-pick misslyckades på grund av lokala ändringar i filen ”%s”.\n" "Checka in, återställ eller spara undan (stash) dina ändringar och försök " "igen." -#: gitk:9565 +#: gitk:9728 msgid "" "Cherry-pick failed because of merge conflict.\n" "Do you wish to run git citool to resolve it?" @@ -1069,20 +1094,20 @@ msgstr "" "Cherry-pick misslyckades på grund av en sammanslagningskonflikt.\n" "Vill du köra git citool för att lösa den?" -#: gitk:9581 gitk:9639 +#: gitk:9744 gitk:9802 msgid "No changes committed" msgstr "Inga ändringar incheckade" -#: gitk:9608 +#: gitk:9771 #, tcl-format msgid "Commit %s is not included in branch %s -- really revert it?" msgstr "Incheckningen %s finns inte på grenen %s -- vill du verkligen ångra?" -#: gitk:9613 +#: gitk:9776 msgid "Reverting" msgstr "Ångrar" -#: gitk:9621 +#: gitk:9784 #, tcl-format msgid "" "Revert failed because of local changes to the following files:%s Please " @@ -1092,7 +1117,7 @@ msgstr "" "Checka in, återställ eller spara undan (stash) dina ändringar och försök " "igen." -#: gitk:9625 +#: gitk:9788 msgid "" "Revert failed because of merge conflict.\n" " Do you wish to run git citool to resolve it?" @@ -1100,28 +1125,28 @@ msgstr "" "Misslyckades med att ångra på grund av en sammanslagningskonflikt.\n" " Vill du köra git citool för att lösa den?" -#: gitk:9668 +#: gitk:9831 msgid "Confirm reset" msgstr "Bekräfta återställning" -#: gitk:9670 +#: gitk:9833 #, tcl-format msgid "Reset branch %s to %s?" msgstr "Återställa grenen %s till %s?" -#: gitk:9672 +#: gitk:9835 msgid "Reset type:" msgstr "Typ av återställning:" -#: gitk:9675 +#: gitk:9838 msgid "Soft: Leave working tree and index untouched" msgstr "Mjuk: Rör inte utcheckning och index" -#: gitk:9678 +#: gitk:9841 msgid "Mixed: Leave working tree untouched, reset index" msgstr "Blandad: Rör inte utcheckning, återställ index" -#: gitk:9681 +#: gitk:9844 msgid "" "Hard: Reset working tree and index\n" "(discard ALL local changes)" @@ -1129,19 +1154,24 @@ msgstr "" "Hård: Återställ utcheckning och index\n" "(förkastar ALLA lokala ändringar)" -#: gitk:9698 +#: gitk:9861 msgid "Resetting" msgstr "Återställer" -#: gitk:9758 +#: gitk:9934 +#, tcl-format +msgid "A local branch named %s exists already" +msgstr "Det finns redan en lokal gren som heter %s" + +#: gitk:9942 msgid "Checking out" msgstr "Checkar ut" -#: gitk:9811 +#: gitk:10001 msgid "Cannot delete the currently checked-out branch" msgstr "Kan inte ta bort den just nu utcheckade grenen" -#: gitk:9817 +#: gitk:10007 #, tcl-format msgid "" "The commits on branch %s aren't on any other branch.\n" @@ -1150,16 +1180,16 @@ msgstr "" "Incheckningarna på grenen %s existerar inte på någon annan gren.\n" "Vill du verkligen ta bort grenen %s?" -#: gitk:9848 +#: gitk:10038 #, tcl-format msgid "Tags and heads: %s" msgstr "Taggar och huvuden: %s" -#: gitk:9865 +#: gitk:10055 msgid "Filter" msgstr "Filter" -#: gitk:10161 +#: gitk:10356 msgid "" "Error reading commit topology information; branch and preceding/following " "tag information will be incomplete." @@ -1167,201 +1197,221 @@ msgstr "" "Fel vid läsning av information om incheckningstopologi; information om " "grenar och föregående/senare taggar kommer inte vara komplett." -#: gitk:11138 +#: gitk:11333 msgid "Tag" msgstr "Tagg" -#: gitk:11142 +#: gitk:11337 msgid "Id" msgstr "Id" -#: gitk:11225 +#: gitk:11420 msgid "Gitk font chooser" msgstr "Teckensnittsväljare för Gitk" -#: gitk:11242 +#: gitk:11437 msgid "B" msgstr "F" -#: gitk:11245 +#: gitk:11440 msgid "I" msgstr "K" -#: gitk:11363 +#: gitk:11558 msgid "Commit list display options" msgstr "Alternativ för incheckningslistvy" -#: gitk:11366 +#: gitk:11561 msgid "Maximum graph width (lines)" msgstr "Maximal grafbredd (rader)" -#: gitk:11370 +#: gitk:11565 #, no-tcl-format msgid "Maximum graph width (% of pane)" msgstr "Maximal grafbredd (% av ruta)" -#: gitk:11373 +#: gitk:11568 msgid "Show local changes" msgstr "Visa lokala ändringar" -#: gitk:11376 +#: gitk:11571 msgid "Auto-select SHA1 (length)" msgstr "Välj SHA1 (längd) automatiskt" -#: gitk:11380 +#: gitk:11575 msgid "Hide remote refs" msgstr "Dölj fjärr-referenser" -#: gitk:11384 +#: gitk:11579 msgid "Diff display options" msgstr "Alternativ för diffvy" -#: gitk:11386 +#: gitk:11581 msgid "Tab spacing" msgstr "Blanksteg för tabulatortecken" -#: gitk:11389 +#: gitk:11584 msgid "Display nearby tags/heads" msgstr "Visa närliggande taggar/huvuden" -#: gitk:11392 +#: gitk:11587 msgid "Maximum # tags/heads to show" msgstr "Maximalt antal taggar/huvuden att visa" -#: gitk:11395 +#: gitk:11590 msgid "Limit diffs to listed paths" msgstr "Begränsa diff till listade sökvägar" -#: gitk:11398 +#: gitk:11593 msgid "Support per-file encodings" msgstr "Stöd för filspecifika teckenkodningar" -#: gitk:11404 gitk:11551 +#: gitk:11599 gitk:11766 msgid "External diff tool" msgstr "Externt diff-verktyg" -#: gitk:11405 +#: gitk:11600 msgid "Choose..." msgstr "Välj..." -#: gitk:11410 +#: gitk:11607 +msgid "Web browser" +msgstr "Webbläsare" + +#: gitk:11612 msgid "General options" msgstr "Allmänna inställningar" -#: gitk:11413 +#: gitk:11615 msgid "Use themed widgets" msgstr "Använd tema på fönsterelement" -#: gitk:11415 +#: gitk:11617 msgid "(change requires restart)" msgstr "(ändringen kräver omstart)" -#: gitk:11417 +#: gitk:11619 msgid "(currently unavailable)" msgstr "(för närvarande inte tillgängligt)" -#: gitk:11428 +#: gitk:11631 msgid "Colors: press to choose" msgstr "Färger: tryck för att välja" -#: gitk:11431 +#: gitk:11634 msgid "Interface" msgstr "Gränssnitt" -#: gitk:11432 +#: gitk:11635 msgid "interface" msgstr "gränssnitt" -#: gitk:11435 +#: gitk:11638 msgid "Background" msgstr "Bakgrund" -#: gitk:11436 gitk:11466 +#: gitk:11639 gitk:11681 msgid "background" msgstr "bakgrund" -#: gitk:11439 +#: gitk:11642 msgid "Foreground" msgstr "Förgrund" -#: gitk:11440 +#: gitk:11643 msgid "foreground" msgstr "förgrund" -#: gitk:11443 +#: gitk:11646 msgid "Diff: old lines" msgstr "Diff: gamla rader" -#: gitk:11444 +#: gitk:11647 msgid "diff old lines" msgstr "diff gamla rader" -#: gitk:11448 +#: gitk:11651 +msgid "Diff: old lines bg" +msgstr "Diff: gamla rader bg" + +#: gitk:11653 +msgid "diff old lines bg" +msgstr "diff gamla rader bg" + +#: gitk:11657 msgid "Diff: new lines" msgstr "Diff: nya rader" -#: gitk:11449 +#: gitk:11658 msgid "diff new lines" msgstr "diff nya rader" -#: gitk:11453 +#: gitk:11662 +msgid "Diff: new lines bg" +msgstr "Diff: nya rader bg" + +#: gitk:11664 +msgid "diff new lines bg" +msgstr "diff nya rader bg" + +#: gitk:11668 msgid "Diff: hunk header" msgstr "Diff: delhuvud" -#: gitk:11455 +#: gitk:11670 msgid "diff hunk header" msgstr "diff delhuvud" -#: gitk:11459 +#: gitk:11674 msgid "Marked line bg" msgstr "Markerad rad bakgrund" -#: gitk:11461 +#: gitk:11676 msgid "marked line background" msgstr "markerad rad bakgrund" -#: gitk:11465 +#: gitk:11680 msgid "Select bg" msgstr "Markerad bakgrund" -#: gitk:11474 +#: gitk:11689 msgid "Fonts: press to choose" msgstr "Teckensnitt: tryck för att välja" -#: gitk:11476 +#: gitk:11691 msgid "Main font" msgstr "Huvudteckensnitt" -#: gitk:11477 +#: gitk:11692 msgid "Diff display font" msgstr "Teckensnitt för diffvisning" -#: gitk:11478 +#: gitk:11693 msgid "User interface font" msgstr "Teckensnitt för användargränssnitt" -#: gitk:11500 +#: gitk:11715 msgid "Gitk preferences" msgstr "Inställningar för Gitk" -#: gitk:11509 +#: gitk:11724 msgid "General" msgstr "Allmänt" -#: gitk:11510 +#: gitk:11725 msgid "Colors" msgstr "Färger" -#: gitk:11511 +#: gitk:11726 msgid "Fonts" msgstr "Teckensnitt" -#: gitk:11561 +#: gitk:11776 #, tcl-format msgid "Gitk: choose color for %s" msgstr "Gitk: välj färg för %s" -#: gitk:12074 +#: gitk:12289 msgid "" "Sorry, gitk cannot run with this version of Tcl/Tk.\n" " Gitk requires at least Tcl/Tk 8.4." @@ -1369,45 +1419,15 @@ msgstr "" "Gitk kan tyvärr inte köra med denna version av Tcl/Tk.\n" " Gitk kräver åtminstone Tcl/Tk 8.4." -#: gitk:12284 +#: gitk:12507 msgid "Cannot find a git repository here." msgstr "Hittar inget git-arkiv här." -#: gitk:12331 +#: gitk:12554 #, tcl-format msgid "Ambiguous argument '%s': both revision and filename" -msgstr "Tvetydigt argument \"%s\": både revision och filnamn" +msgstr "Tvetydigt argument ”%s”: både revision och filnamn" -#: gitk:12343 +#: gitk:12566 msgid "Bad arguments to gitk:" msgstr "Felaktiga argument till gitk:" - -#~ msgid "mc" -#~ msgstr "mc" - -#~ msgid "next" -#~ msgstr "nästa" - -#~ msgid "prev" -#~ msgstr "föreg" - -#~ msgid "CDate" -#~ msgstr "Skapat datum" - -#~ msgid "Cannot find the git directory \"%s\"." -#~ msgstr "Hittar inte git-katalogen \"%s\"." - -#~ msgid "SHA1 ID: " -#~ msgstr "SHA1-id: " - -#~ msgid "- stopping\n" -#~ msgstr "- stannar\n" - -#~ msgid "Tag/Head %s is not known" -#~ msgstr "Tagg/huvud %s är okänt" - -#~ msgid "/\t\tMove to next find hit, or redo find" -#~ msgstr "/\t\tGå till nästa sökträff, eller sök på nytt" - -#~ msgid "Name" -#~ msgstr "Namn" -- cgit v1.2.3 From f823de75a1f4f061c78aa6fff500f35be8d38e69 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 3 Aug 2024 17:22:51 +0200 Subject: git-gui: Remove forced rescan of stat-dirty files. It is possible that stat information of tracked files is modified without actually modifying the content. Plumbing commands would detect such files as modified, so that Git GUI runs `git update-info --refresh` in order to synchronize the cached stat info with the reality. However, this can be an expensive operation in large repositories. As remediation, e534f3a88676 (git-gui: Allow the user to disable update-index --refresh during rescan, 2006-11-07) introduced an option to skip the expensive part. The option was named "trust file modification timestamp". But the catch is that sometimes file timestamps can't be trusted. In this case, a file would remain listed in Unstaged Changes although there are no changes. So 16403d0b1f9d (git-gui: Refresh a file if it has an empty diff, 2006-11-11) introduced a popup message informing the user about the situation and then removed the file from the Unstaged Changes list. Now users had to click away the message box for every file that was stat-dirty. Under the assumption that a file in such a state is not the only one, 124355d32c06 (git-gui: Always start a rescan on an empty diff, 2007-01-22) introduced a forced (potentially expensive) refresh that would de-list all stat-dirty files after the first notification was dismissed. Along came 6c510bee2013 (Lazy man's auto-CRLF, 2007-02-13) in Git. It introduced a new case where a file in the worktree can have no essential differences to the staged version, but still be detected as modified by plumbing commands. This time, however, the index cannot be synchronized fully by `git update-index --refresh`, so that the file remains listed in Unstaged Changes until it is staged manually. Needless to say that the message box now becomes an annoyance, because it must be dismissed every time an affected file is selected, and the file remains listed nevertheless. Remove the message box. Write the notice that no differences were found in the diff panel instead. Also include a link that, when clicked, initiates the rescan. With this scheme, the rescan does not happen automatically anymore, but requires an additional click. (This is now two clicks in total for users who encounter stat-dirty files after enabling the "trust file modification timestamps" option.) However, users whom the rescan does not help (autocrlf-related dirty files) save half the clicks because there is no message box to dismiss. Signed-off-by: Johannes Sixt --- git-gui.sh | 3 ++- lib/diff.tcl | 26 ++++++-------------------- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/git-gui.sh b/git-gui.sh index 8fe7538e72..887d6d596c 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -1357,7 +1357,6 @@ set current_diff_path {} set is_3way_diff 0 set is_submodule_diff 0 set is_conflict_diff 0 -set diff_empty_count 0 set last_revert {} set last_revert_enc {} @@ -3594,6 +3593,8 @@ $ui_diff tag configure clr1 -font font_diffbold $ui_diff tag configure clr4 -underline 1 $ui_diff tag conf d_info -foreground blue -font font_diffbold +$ui_diff tag conf d_rescan -foreground blue -underline 1 -font font_diffbold +$ui_diff tag bind d_rescan { clear_diff; rescan ui_ready 0 } $ui_diff tag conf d_cr -elide true $ui_diff tag conf d_@ -font font_diffbold diff --git a/lib/diff.tcl b/lib/diff.tcl index 871ad488c2..d657bfec05 100644 --- a/lib/diff.tcl +++ b/lib/diff.tcl @@ -63,28 +63,17 @@ proc force_diff_encoding {enc} { } proc handle_empty_diff {} { - global current_diff_path file_states file_lists - global diff_empty_count + global current_diff_path file_states + global ui_diff set path $current_diff_path set s $file_states($path) if {[lindex $s 0] ne {_M} || [has_textconv $path]} return - # Prevent infinite rescan loops - incr diff_empty_count - if {$diff_empty_count > 1} return - - info_popup [mc "No differences detected. - -%s has no changes. - -The modification date of this file was updated by another application, but the content within the file was not changed. - -A rescan will be automatically started to find other files which may have the same state." [short_path $path]] - - clear_diff - display_file $path __ - rescan ui_ready 0 + $ui_diff conf -state normal + $ui_diff insert end [mc "* No differences detected; stage the file to de-list it from Unstaged Changes.\n"] d_info + $ui_diff insert end [mc "* Click to find other files that may have the same state.\n"] d_rescan + $ui_diff conf -state disabled } proc show_diff {path w {lno {}} {scroll_pos {}} {callback {}}} { @@ -387,7 +376,6 @@ proc read_diff {fd conflict_size cont_info} { global ui_diff diff_active is_submodule_diff global is_3way_diff is_conflict_diff current_diff_header global current_diff_queue - global diff_empty_count $ui_diff conf -state normal while {[gets $fd line] >= 0} { @@ -559,8 +547,6 @@ proc read_diff {fd conflict_size cont_info} { if {[$ui_diff index end] eq {2.0}} { handle_empty_diff - } else { - set diff_empty_count 0 } set callback [lindex $cont_info 1] -- cgit v1.2.3 From 966253db757948d4e0738c5c1fac5b694f0d042d Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Mon, 14 Oct 2024 14:04:08 -0700 Subject: fuzz: port fuzz-credential-from-url-gently from OSS-Fuzz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git's fuzz tests are run continuously as part of OSS-Fuzz [1]. Several additional fuzz tests have been contributed directly to OSS-Fuzz; however, these tests are vulnerable to bitrot because they are not built during Git's CI runs, and thus breaking changes are much less likely to be noticed by Git contributors. Port one of these tests back to the Git project: fuzz-credential-from-url-gently This test was originally written by Eric Sesterhenn as part of a security audit of Git [2]. It was then contributed to the OSS-Fuzz repo in commit c58ac4492 (Git fuzzing: uncomment the existing and add new targets. (#11486), 2024-02-21) by Jaroslav Lobačevski. I (Josh Steadmon) have verified with both Eric and Jaroslav that they're OK with moving this test to the Git project. [1] https://github.com/google/oss-fuzz [2] https://ostif.org/wp-content/uploads/2023/01/X41-OSTIF-Gitlab-Git-Security-Audit-20230117-public.pdf Co-authored-by: Jaroslav Lobačevski Co-authored-by: Josh Steadmon Signed-off-by: Josh Steadmon Signed-off-by: Taylor Blau --- Makefile | 1 + ci/run-build-and-minimal-fuzzers.sh | 11 +++++++++- oss-fuzz/.gitignore | 1 + oss-fuzz/fuzz-credential-from-url-gently.c | 32 ++++++++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 oss-fuzz/fuzz-credential-from-url-gently.c diff --git a/Makefile b/Makefile index feeed6f932..22f7585f74 100644 --- a/Makefile +++ b/Makefile @@ -2422,6 +2422,7 @@ endif FUZZ_OBJS += oss-fuzz/dummy-cmd-main.o FUZZ_OBJS += oss-fuzz/fuzz-commit-graph.o FUZZ_OBJS += oss-fuzz/fuzz-config.o +FUZZ_OBJS += oss-fuzz/fuzz-credential-from-url-gently.o FUZZ_OBJS += oss-fuzz/fuzz-date.o FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o diff --git a/ci/run-build-and-minimal-fuzzers.sh b/ci/run-build-and-minimal-fuzzers.sh index af8065f349..631796ab8b 100755 --- a/ci/run-build-and-minimal-fuzzers.sh +++ b/ci/run-build-and-minimal-fuzzers.sh @@ -13,7 +13,16 @@ group "Build fuzzers" make \ LIB_FUZZING_ENGINE="-fsanitize=fuzzer,address" \ fuzz-all -for fuzzer in commit-graph config date pack-headers pack-idx ; do +fuzzers=" +commit-graph +config +credential-from-url-gently +date +pack-headers +pack-idx +" + +for fuzzer in $fuzzers; do begin_group "fuzz-$fuzzer" ./oss-fuzz/fuzz-$fuzzer -verbosity=0 -runs=1 || exit 1 end_group "fuzz-$fuzzer" diff --git a/oss-fuzz/.gitignore b/oss-fuzz/.gitignore index a877c11f42..2cfc845b20 100644 --- a/oss-fuzz/.gitignore +++ b/oss-fuzz/.gitignore @@ -1,5 +1,6 @@ fuzz-commit-graph fuzz-config +fuzz-credential-from-url-gently fuzz-date fuzz-pack-headers fuzz-pack-idx diff --git a/oss-fuzz/fuzz-credential-from-url-gently.c b/oss-fuzz/fuzz-credential-from-url-gently.c new file mode 100644 index 0000000000..c872f9ad2d --- /dev/null +++ b/oss-fuzz/fuzz-credential-from-url-gently.c @@ -0,0 +1,32 @@ +#include "git-compat-util.h" +#include +#include +#include +#include +#include +#include "credential.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + struct credential c; + char *buf; + + buf = malloc(size + 1); + if (!buf) + return 0; + + memcpy(buf, data, size); + buf[size] = 0; + + // start fuzzing + credential_init(&c); + credential_from_url_gently(&c, buf, 1); + + // cleanup + credential_clear(&c); + free(buf); + + return 0; +} -- cgit v1.2.3 From 72686d4e5e9a7236b9716368d86fae5bf1ae6156 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Mon, 14 Oct 2024 14:04:09 -0700 Subject: fuzz: port fuzz-parse-attr-line from OSS-Fuzz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git's fuzz tests are run continuously as part of OSS-Fuzz [1]. Several additional fuzz tests have been contributed directly to OSS-Fuzz; however, these tests are vulnerable to bitrot because they are not built during Git's CI runs, and thus breaking changes are much less likely to be noticed by Git contributors. Port one of these tests back to the Git project: fuzz-parse-attr-line This test was originally written by Eric Sesterhenn as part of a security audit of Git [2]. It was then contributed to the OSS-Fuzz repo in commit c58ac4492 (Git fuzzing: uncomment the existing and add new targets. (#11486), 2024-02-21) by Jaroslav Lobačevski. I (Josh Steadmon) have verified with both Eric and Jaroslav that they're OK with moving this test to the Git project. [1] https://github.com/google/oss-fuzz [2] https://ostif.org/wp-content/uploads/2023/01/X41-OSTIF-Gitlab-Git-Security-Audit-20230117-public.pdf Co-authored-by: Jaroslav Lobačevski Co-authored-by: Josh Steadmon Signed-off-by: Josh Steadmon Signed-off-by: Taylor Blau --- Makefile | 1 + attr.c | 40 ++-------------------------------- attr.h | 43 +++++++++++++++++++++++++++++++++++++ ci/run-build-and-minimal-fuzzers.sh | 1 + oss-fuzz/.gitignore | 1 + oss-fuzz/fuzz-parse-attr-line.c | 39 +++++++++++++++++++++++++++++++++ 6 files changed, 87 insertions(+), 38 deletions(-) create mode 100644 oss-fuzz/fuzz-parse-attr-line.c diff --git a/Makefile b/Makefile index 22f7585f74..cfbbd70fdc 100644 --- a/Makefile +++ b/Makefile @@ -2426,6 +2426,7 @@ FUZZ_OBJS += oss-fuzz/fuzz-credential-from-url-gently.o FUZZ_OBJS += oss-fuzz/fuzz-date.o FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o +FUZZ_OBJS += oss-fuzz/fuzz-parse-attr-line.o .PHONY: fuzz-objs fuzz-objs: $(FUZZ_OBJS) diff --git a/attr.c b/attr.c index c605d2c170..192936c4bc 100644 --- a/attr.c +++ b/attr.c @@ -259,42 +259,6 @@ const struct git_attr *git_attr(const char *name) return git_attr_internal(name, strlen(name)); } -/* What does a matched pattern decide? */ -struct attr_state { - const struct git_attr *attr; - const char *setto; -}; - -struct pattern { - const char *pattern; - int patternlen; - int nowildcardlen; - unsigned flags; /* PATTERN_FLAG_* */ -}; - -/* - * One rule, as from a .gitattributes file. - * - * If is_macro is true, then u.attr is a pointer to the git_attr being - * defined. - * - * If is_macro is false, then u.pat is the filename pattern to which the - * rule applies. - * - * In either case, num_attr is the number of attributes affected by - * this rule, and state is an array listing them. The attributes are - * listed as they appear in the file (macros unexpanded). - */ -struct match_attr { - union { - struct pattern pat; - const struct git_attr *attr; - } u; - char is_macro; - size_t num_attr; - struct attr_state state[FLEX_ARRAY]; -}; - static const char blank[] = " \t\r\n"; /* Flags usable in read_attr() and parse_attr_line() family of functions. */ @@ -353,8 +317,8 @@ static const char *parse_attr(const char *src, int lineno, const char *cp, return ep + strspn(ep, blank); } -static struct match_attr *parse_attr_line(const char *line, const char *src, - int lineno, unsigned flags) +struct match_attr *parse_attr_line(const char *line, const char *src, + int lineno, unsigned flags) { size_t namelen, num_attr, i; const char *cp, *name, *states; diff --git a/attr.h b/attr.h index bb33b60880..a04a521092 100644 --- a/attr.h +++ b/attr.h @@ -240,4 +240,47 @@ int git_attr_system_is_enabled(void); extern char *git_attr_tree; +/* + * Exposed for fuzz-testing only. + */ + +/* What does a matched pattern decide? */ +struct attr_state { + const struct git_attr *attr; + const char *setto; +}; + +struct pattern { + const char *pattern; + int patternlen; + int nowildcardlen; + unsigned flags; /* PATTERN_FLAG_* */ +}; + +/* + * One rule, as from a .gitattributes file. + * + * If is_macro is true, then u.attr is a pointer to the git_attr being + * defined. + * + * If is_macro is false, then u.pat is the filename pattern to which the + * rule applies. + * + * In either case, num_attr is the number of attributes affected by + * this rule, and state is an array listing them. The attributes are + * listed as they appear in the file (macros unexpanded). + */ +struct match_attr { + union { + struct pattern pat; + const struct git_attr *attr; + } u; + char is_macro; + size_t num_attr; + struct attr_state state[FLEX_ARRAY]; +}; + +struct match_attr *parse_attr_line(const char *line, const char *src, + int lineno, unsigned flags); + #endif /* ATTR_H */ diff --git a/ci/run-build-and-minimal-fuzzers.sh b/ci/run-build-and-minimal-fuzzers.sh index 631796ab8b..13c85320d6 100755 --- a/ci/run-build-and-minimal-fuzzers.sh +++ b/ci/run-build-and-minimal-fuzzers.sh @@ -20,6 +20,7 @@ credential-from-url-gently date pack-headers pack-idx +parse-attr-line " for fuzzer in $fuzzers; do diff --git a/oss-fuzz/.gitignore b/oss-fuzz/.gitignore index 2cfc845b20..ec185f061c 100644 --- a/oss-fuzz/.gitignore +++ b/oss-fuzz/.gitignore @@ -4,3 +4,4 @@ fuzz-credential-from-url-gently fuzz-date fuzz-pack-headers fuzz-pack-idx +fuzz-parse-attr-line diff --git a/oss-fuzz/fuzz-parse-attr-line.c b/oss-fuzz/fuzz-parse-attr-line.c new file mode 100644 index 0000000000..45a4c4e53c --- /dev/null +++ b/oss-fuzz/fuzz-parse-attr-line.c @@ -0,0 +1,39 @@ +#include "git-compat-util.h" +#include +#include +#include +#include +#include "attr.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + struct match_attr *res; + char *buf; + + buf = malloc(size + 1); + if (!buf) + return 0; + + memcpy(buf, data, size); + buf[size] = 0; + + res = parse_attr_line(buf, "dummy", 0, 0); + + if (res) { + int j; + for (j = 0; j < res->num_attr; j++) { + const char *setto = res->state[j].setto; + if (ATTR_TRUE(setto) || ATTR_FALSE(setto) || + ATTR_UNSET(setto)) + ; + else + free((char *)setto); + } + free(res); + } + free(buf); + + return 0; +} -- cgit v1.2.3 From 751d063f27a1d3c77ef092d4737524c55c65d972 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Mon, 14 Oct 2024 14:04:10 -0700 Subject: fuzz: port fuzz-url-decode-mem from OSS-Fuzz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git's fuzz tests are run continuously as part of OSS-Fuzz [1]. Several additional fuzz tests have been contributed directly to OSS-Fuzz; however, these tests are vulnerable to bitrot because they are not built during Git's CI runs, and thus breaking changes are much less likely to be noticed by Git contributors. Port one of these tests back to the Git project: fuzz-url-decode-mem This test was originally written by Eric Sesterhenn as part of a security audit of Git [2]. It was then contributed to the OSS-Fuzz repo in commit c58ac4492 (Git fuzzing: uncomment the existing and add new targets. (#11486), 2024-02-21) by Jaroslav Lobačevski. I (Josh Steadmon) have verified with both Eric and Jaroslav that they're OK with moving this test to the Git project. [1] https://github.com/google/oss-fuzz [2] https://ostif.org/wp-content/uploads/2023/01/X41-OSTIF-Gitlab-Git-Security-Audit-20230117-public.pdf Co-authored-by: Jaroslav Lobačevski Co-authored-by: Josh Steadmon Signed-off-by: Josh Steadmon Signed-off-by: Taylor Blau --- Makefile | 1 + ci/run-build-and-minimal-fuzzers.sh | 1 + oss-fuzz/.gitignore | 1 + oss-fuzz/fuzz-url-decode-mem.c | 43 +++++++++++++++++++++++++++++++++++++ 4 files changed, 46 insertions(+) create mode 100644 oss-fuzz/fuzz-url-decode-mem.c diff --git a/Makefile b/Makefile index cfbbd70fdc..5d630eedaa 100644 --- a/Makefile +++ b/Makefile @@ -2427,6 +2427,7 @@ FUZZ_OBJS += oss-fuzz/fuzz-date.o FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o FUZZ_OBJS += oss-fuzz/fuzz-parse-attr-line.o +FUZZ_OBJS += oss-fuzz/fuzz-url-decode-mem.o .PHONY: fuzz-objs fuzz-objs: $(FUZZ_OBJS) diff --git a/ci/run-build-and-minimal-fuzzers.sh b/ci/run-build-and-minimal-fuzzers.sh index 13c85320d6..e7b97952e7 100755 --- a/ci/run-build-and-minimal-fuzzers.sh +++ b/ci/run-build-and-minimal-fuzzers.sh @@ -21,6 +21,7 @@ date pack-headers pack-idx parse-attr-line +url-decode-mem " for fuzzer in $fuzzers; do diff --git a/oss-fuzz/.gitignore b/oss-fuzz/.gitignore index ec185f061c..f2d74de457 100644 --- a/oss-fuzz/.gitignore +++ b/oss-fuzz/.gitignore @@ -5,3 +5,4 @@ fuzz-date fuzz-pack-headers fuzz-pack-idx fuzz-parse-attr-line +fuzz-url-decode-mem diff --git a/oss-fuzz/fuzz-url-decode-mem.c b/oss-fuzz/fuzz-url-decode-mem.c new file mode 100644 index 0000000000..2342aa993b --- /dev/null +++ b/oss-fuzz/fuzz-url-decode-mem.c @@ -0,0 +1,43 @@ +#include "git-compat-util.h" +#include +#include +#include +#include +#include +#include "url.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + char *buf; + char *r; + const char *pbuf; + + buf = malloc(size + 1); + if (!buf) + return 0; + + memcpy(buf, data, size); + buf[size] = 0; + + // start fuzzing + r = url_decode(buf); + free(r); + + r = url_percent_decode(buf); + free(r); + + pbuf = (const char*) buf; + r = url_decode_parameter_name(&pbuf); + free(r); + + pbuf = (const char*) buf; + r = url_decode_parameter_value(&pbuf); + free(r); + + // cleanup + free(buf); + + return 0; +} -- cgit v1.2.3 From 0d606d8c2a387189bd5cf453e64519c314283a96 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 9 Sep 2024 16:00:20 -0700 Subject: ci: remove 'Upload failed tests' directories' step from linux32 jobs Linux32 jobs seem to be getting: Error: This request has been automatically failed because it uses a deprecated version of `actions/upload-artifact: v1`. Learn more: https://github.blog/changelog/2024-02-13-deprecation-notice-v1-and-v2-of-the-artifact-actions/ before doing anything useful. For now, disable the step. Ever since actions/upload-artifact@v1 got disabled, mentioning the offending version of it seems to stop anything from happening. At least this should run the same build and test. See https://github.com/git/git/actions/runs/10780030750/job/29894867249 for example. [Backported from 90f2c7240cc (ci: remove 'Upload failed tests' directories' step from linux32 jobs, 2024-09-09).] Signed-off-by: Junio C Hamano Signed-off-by: Johannes Schindelin --- .github/workflows/main.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bd390ab587..8eedf35011 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -334,12 +334,6 @@ jobs: with: name: failed-tests-${{matrix.vector.jobname}} path: ${{env.FAILED_TEST_ARTIFACTS}} - - name: Upload failed tests' directories - if: failure() && env.FAILED_TEST_ARTIFACTS != '' && matrix.vector.jobname == 'linux32' - uses: actions/upload-artifact@v1 # cannot be upgraded because Node.js Actions aren't supported in this container - with: - name: failed-tests-${{matrix.vector.jobname}} - path: ${{env.FAILED_TEST_ARTIFACTS}} static-analysis: needs: ci-config if: needs.ci-config.outputs.enabled == 'yes' -- cgit v1.2.3 From 5d828879f320501ba8fa75099ee01dc6f4c3cf77 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Jun 2024 06:09:58 +0000 Subject: mingw: drop bogus (and unneeded) declaration of `_pgmptr` In 08809c09aa13 (mingw: add a helper function to attach GDB to the current process, 2020-02-13), I added a declaration that was not needed. Back then, that did not matter, but now that the declaration of that symbol was changed in mingw-w64's headers, it causes the following compile error: CC compat/mingw.o compat/mingw.c: In function 'open_in_gdb': compat/mingw.c:35:9: error: function declaration isn't a prototype [-Werror=strict-prototypes] 35 | extern char *_pgmptr; | ^~~~~~ In file included from C:/git-sdk-64/usr/src/git/build-installers/mingw64/lib/gcc/x86_64-w64-mingw32/14.1.0/include/mm_malloc.h:27, from C:/git-sdk-64/usr/src/git/build-installers/mingw64/lib/gcc/x86_64-w64-mingw32/14.1.0/include/xmmintrin.h:34, from C:/git-sdk-64/usr/src/git/build-installers/mingw64/lib/gcc/x86_64-w64-mingw32/14.1.0/include/immintrin.h:31, from C:/git-sdk-64/usr/src/git/build-installers/mingw64/lib/gcc/x86_64-w64-mingw32/14.1.0/include/x86intrin.h:32, from C:/git-sdk-64/usr/src/git/build-installers/mingw64/include/winnt.h:1658, from C:/git-sdk-64/usr/src/git/build-installers/mingw64/include/minwindef.h:163, from C:/git-sdk-64/usr/src/git/build-installers/mingw64/include/windef.h:9, from C:/git-sdk-64/usr/src/git/build-installers/mingw64/include/windows.h:69, from C:/git-sdk-64/usr/src/git/build-installers/mingw64/include/winsock2.h:23, from compat/../git-compat-util.h:215, from compat/mingw.c:1: compat/mingw.c:35:22: error: '__p__pgmptr' redeclared without dllimport attribute: previous dllimport ignored [-Werror=attributes] 35 | extern char *_pgmptr; | ^~~~~~~ Let's just drop the declaration and get rid of this compile error. [Backported from 3c295c87c25 (mingw: drop bogus (and unneeded) declaration of `_pgmptr`, 2024-06-19).] Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano Signed-off-by: Johannes Schindelin --- compat/mingw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index e433740381..e08db82635 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -20,7 +20,6 @@ static const int delay[] = { 0, 1, 10, 20, 40 }; void open_in_gdb(void) { static struct child_process cp = CHILD_PROCESS_INIT; - extern char *_pgmptr; strvec_pushl(&cp.args, "mintty", "gdb", NULL); strvec_pushf(&cp.args, "--pid=%d", getpid()); -- cgit v1.2.3 From 7e6073d27083054773f3c3b21a608f400cf7348d Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 11 May 2024 23:25:04 -0700 Subject: compat/regex: fix argument order to calloc(3) Windows compiler suddenly started complaining that calloc(3) takes its arguments in order. Indeed, there are many calls that has their arguments in a _wrong_ order. Fix them all. A sample breakage can be seen at https://github.com/git/git/actions/runs/9046793153/job/24857988702#step:4:272 [Backported from f01301aabe1 (compat/regex: fix argument order to calloc(3), 2024-05-11).] Signed-off-by: Junio C Hamano Signed-off-by: Johannes Schindelin --- compat/regex/regcomp.c | 12 ++++++------ compat/regex/regex_internal.c | 4 ++-- compat/regex/regexec.c | 10 +++++----- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compat/regex/regcomp.c b/compat/regex/regcomp.c index d1bc09e49b..2bc0f1187a 100644 --- a/compat/regex/regcomp.c +++ b/compat/regex/regcomp.c @@ -868,7 +868,7 @@ init_dfa (re_dfa_t *dfa, size_t pat_len) if (table_size > pat_len) break; - dfa->state_table = calloc (sizeof (struct re_state_table_entry), table_size); + dfa->state_table = calloc (table_size, sizeof (struct re_state_table_entry)); dfa->state_hash_mask = table_size - 1; dfa->mb_cur_max = MB_CUR_MAX; @@ -936,7 +936,7 @@ init_dfa (re_dfa_t *dfa, size_t pat_len) { int i, j, ch; - dfa->sb_char = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); + dfa->sb_char = (re_bitset_ptr_t) calloc (1, sizeof (bitset_t)); if (BE (dfa->sb_char == NULL, 0)) return REG_ESPACE; @@ -3079,9 +3079,9 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, _NL_COLLATE_SYMB_EXTRAMB); } #endif - sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); + sbcset = (re_bitset_ptr_t) calloc (1, sizeof (bitset_t)); #ifdef RE_ENABLE_I18N - mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1); + mbcset = (re_charset_t *) calloc (1, sizeof (re_charset_t)); #endif /* RE_ENABLE_I18N */ #ifdef RE_ENABLE_I18N if (BE (sbcset == NULL || mbcset == NULL, 0)) @@ -3626,9 +3626,9 @@ build_charclass_op (re_dfa_t *dfa, RE_TRANSLATE_TYPE trans, re_token_t br_token; bin_tree_t *tree; - sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); + sbcset = (re_bitset_ptr_t) calloc (1, sizeof (bitset_t)); #ifdef RE_ENABLE_I18N - mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1); + mbcset = (re_charset_t *) calloc (1, sizeof (re_charset_t)); #endif /* RE_ENABLE_I18N */ #ifdef RE_ENABLE_I18N diff --git a/compat/regex/regex_internal.c b/compat/regex/regex_internal.c index ec51cf3446..ec5cc5d2dd 100644 --- a/compat/regex/regex_internal.c +++ b/compat/regex/regex_internal.c @@ -1628,7 +1628,7 @@ create_ci_newstate (const re_dfa_t *dfa, const re_node_set *nodes, reg_errcode_t err; re_dfastate_t *newstate; - newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1); + newstate = (re_dfastate_t *) calloc (1, sizeof (re_dfastate_t)); if (BE (newstate == NULL, 0)) return NULL; err = re_node_set_init_copy (&newstate->nodes, nodes); @@ -1678,7 +1678,7 @@ create_cd_newstate (const re_dfa_t *dfa, const re_node_set *nodes, reg_errcode_t err; re_dfastate_t *newstate; - newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1); + newstate = (re_dfastate_t *) calloc (1, sizeof (re_dfastate_t)); if (BE (newstate == NULL, 0)) return NULL; err = re_node_set_init_copy (&newstate->nodes, nodes); diff --git a/compat/regex/regexec.c b/compat/regex/regexec.c index 49358ae475..e92be5741d 100644 --- a/compat/regex/regexec.c +++ b/compat/regex/regexec.c @@ -2796,8 +2796,8 @@ get_subexp (re_match_context_t *mctx, int bkref_node, int bkref_str_idx) continue; /* No. */ if (sub_top->path == NULL) { - sub_top->path = calloc (sizeof (state_array_t), - sl_str - sub_top->str_idx + 1); + sub_top->path = calloc (sl_str - sub_top->str_idx + 1, + sizeof (state_array_t)); if (sub_top->path == NULL) return REG_ESPACE; } @@ -3361,7 +3361,7 @@ build_trtable (const re_dfa_t *dfa, re_dfastate_t *state) if (ndests == 0) { state->trtable = (re_dfastate_t **) - calloc (sizeof (re_dfastate_t *), SBC_MAX); + calloc (SBC_MAX, sizeof (re_dfastate_t *)); return 1; } return 0; @@ -3457,7 +3457,7 @@ out_free: discern by looking at the character code: allocate a 256-entry transition table. */ trtable = state->trtable = - (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX); + (re_dfastate_t **) calloc (SBC_MAX, sizeof (re_dfastate_t *)); if (BE (trtable == NULL, 0)) goto out_free; @@ -3488,7 +3488,7 @@ out_free: transition tables, one starting at trtable[0] and one starting at trtable[SBC_MAX]. */ trtable = state->word_trtable = - (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), 2 * SBC_MAX); + (re_dfastate_t **) calloc (2 * SBC_MAX, sizeof (re_dfastate_t *)); if (BE (trtable == NULL, 0)) goto out_free; -- cgit v1.2.3 From 83b08eb19f05710a92d565124606dcaf68bcc68b Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Wed, 9 Oct 2024 15:25:18 +0200 Subject: t7300: work around platform-specific behaviour with long paths on MinGW Windows by default has a restriction in place to only allow paths up to 260 characters. This restriction can nowadays be lifted by setting a registry key, but is still active by default. In t7300 we have one test that exercises the behaviour of git-clean(1) with such long paths. Interestingly enough, this test fails on my system that uses Windows 10 with mingw-w64 installed via MSYS2: instead of observing ENAMETOOLONG, we observe ENOENT. This behaviour is consistent across multiple different environments I have tried. I cannot say why exactly we observe a different error here, but I would not be surprised if this was either dependent on the Windows version, the version of MinGW, the current working directory of Git or any kind of combination of these. Work around the issue by handling both errors. [Backported from 106834e34a2 (t7300: work around platform-specific behaviour with long paths on MinGW, 2024-10-09).] Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano Signed-off-by: Johannes Schindelin --- t/t7300-clean.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh index c975eb54d2..a831438f74 100755 --- a/t/t7300-clean.sh +++ b/t/t7300-clean.sh @@ -735,7 +735,7 @@ test_expect_success MINGW 'handle clean & core.longpaths = false nicely' ' test_must_fail git clean -xdf 2>.git/err && # grepping for a strerror string is unportable but it is OK here with # MINGW prereq - test_i18ngrep "too long" .git/err + test_i18ngrep -e "too long" -e "No such file or directory" .git/err ' test_expect_success 'clean untracked paths by pathspec' ' -- cgit v1.2.3 From c85bcb5de163a658102bea058a1ea53aea1c5476 Mon Sep 17 00:00:00 2001 From: "brian m. carlson" Date: Thu, 31 Oct 2024 23:49:32 +0000 Subject: gitlab-ci: switch from Ubuntu 16.04 to 20.04 Ubuntu 16.04 is past its normal LTS lifespan, so let's switch to Ubuntu 20.04 instead, which is the latest regular LTS version. Signed-off-by: brian m. carlson Signed-off-by: Taylor Blau --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 526ecfe030..a1bc92893f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -35,7 +35,7 @@ test:linux: parallel: matrix: - jobname: linux-old - image: ubuntu:16.04 + image: ubuntu:20.04 CC: gcc - jobname: linux-sha256 image: ubuntu:latest -- cgit v1.2.3 From ad797eace4209f34aec7fc113ed70887d05c8007 Mon Sep 17 00:00:00 2001 From: "brian m. carlson" Date: Thu, 31 Oct 2024 23:49:33 +0000 Subject: ci: remove clause for Ubuntu 16.04 We're no longer testing this version and it's well beyond regular LTS support now, so remove the stanza for it from the case statement in our CI code. Signed-off-by: brian m. carlson Signed-off-by: Taylor Blau --- ci/install-dependencies.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ci/install-dependencies.sh b/ci/install-dependencies.sh index 126e570eb4..d30ae53a18 100755 --- a/ci/install-dependencies.sh +++ b/ci/install-dependencies.sh @@ -55,11 +55,6 @@ ubuntu-*|ubuntu32-*) ${CC_PACKAGE:-${CC:-gcc}} $PYTHON_PACKAGE case "$distro" in - ubuntu-16.04) - # Does not support JGit, but we also don't really care about - # the others. We rather care whether Git still compiles and - # runs fine overall. - ;; ubuntu-*) mkdir --parents "$CUSTOM_PATH" -- cgit v1.2.3 From ac112fd4f088040787f501b3f4b8279caa394d4e Mon Sep 17 00:00:00 2001 From: "brian m. carlson" Date: Thu, 31 Oct 2024 23:49:34 +0000 Subject: Add additional CI jobs to avoid accidental breakage In general, we'd like to make sure Git works on the LTS versions of major Linux distributions. To do that, let's add CI jobs for the oldest regular (non-extended) LTS versions of the major distributions: Ubuntu 20.04, Debian 11, and RHEL 8. Because RHEL isn't available to the public at no charge, use AlmaLinux, which is binary compatible with it. Note that Debian does not offer the language-pack packages, but suitable locale support can be installed with the locales-all package. Otherwise, use the set of installation instructions which exist and are most similar to the existing supported distros. Signed-off-by: brian m. carlson Signed-off-by: Taylor Blau --- .github/workflows/main.yml | 9 +++++++++ ci/install-dependencies.sh | 14 ++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9301a1edd6..808ddc19b8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -342,12 +342,21 @@ jobs: - jobname: linux-musl image: alpine distro: alpine-latest + # Supported until 2025-04-02. - jobname: linux32 image: i386/ubuntu:focal distro: ubuntu32-20.04 - jobname: pedantic image: fedora distro: fedora-latest + # A RHEL 8 compatible distro. Supported until 2029-05-31. + - jobname: almalinux-8 + image: almalinux:8 + distro: almalinux-8 + # Supported until 2026-08-31. + - jobname: debian-11 + image: debian:11 + distro: debian-11 env: jobname: ${{matrix.vector.jobname}} distro: ${{matrix.vector.distro}} diff --git a/ci/install-dependencies.sh b/ci/install-dependencies.sh index d30ae53a18..d020cb7aa5 100755 --- a/ci/install-dependencies.sh +++ b/ci/install-dependencies.sh @@ -29,26 +29,32 @@ alpine-*) apache2 apache2-http2 apache2-proxy apache2-ssl apache2-webdav apr-util-dbd_sqlite3 \ bash cvs gnupg perl-cgi perl-dbd-sqlite perl-io-tty >/dev/null ;; -fedora-*) +fedora-*|almalinux-*) dnf -yq update >/dev/null && dnf -yq install make gcc findutils diffutils perl python3 gettext zlib-devel expat-devel openssl-devel curl-devel pcre2-devel >/dev/null ;; -ubuntu-*|ubuntu32-*) +ubuntu-*|ubuntu32-*|debian-*) # Required so that apt doesn't wait for user input on certain packages. export DEBIAN_FRONTEND=noninteractive case "$distro" in ubuntu-*) SVN='libsvn-perl subversion' + LANGUAGES='language-pack-is' ;; - *) + ubuntu32-*) SVN= + LANGUAGES='language-pack-is' + ;; + *) + SVN='libsvn-perl subversion' + LANGUAGES='locales-all' ;; esac sudo apt-get -q update sudo apt-get -q -y install \ - language-pack-is apache2 cvs cvsps git gnupg $SVN \ + $LANGUAGES apache2 cvs cvsps git gnupg $SVN \ make libssl-dev libcurl4-openssl-dev libexpat-dev wget sudo default-jre \ tcl tk gettext zlib1g-dev perl-modules liberror-perl libauthen-sasl-perl \ libemail-valid-perl libio-pty-perl libio-socket-ssl-perl libnet-smtp-ssl-perl libdbd-sqlite3-perl libcgi-pm-perl \ -- cgit v1.2.3 From d0e52c1728bdab27f7ca61ee0d4ff91055646bae Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 6 Nov 2024 16:16:58 -0500 Subject: t6120: demonstrate weakness in disjoint-root handling Commit 30b1c7ad9d (describe: don't abort too early when searching tags, 2020-02-26) tried to fix a problem that happens when there are disjoint histories: to accurately compare the counts for different tags, we need to keep walking the history longer in order to find a common base. But its fix misses a case: we may still bail early if we hit the max_candidates limit, producing suboptimal output. You can see this in action by adding "--candidates=2" to the tests; we'll stop traversing as soon as we see the second tag and will produce the wrong answer. I hit this in practice while trying to teach git-describe not to keep looking for candidates after we've seen all tags in the repo (effectively adding --candidates=2, since these toy repos have only two tags each). This is probably fixable by continuing to walk after hitting the max-candidates limit, all the way down to a common ancestor of all candidates. But it's not clear in practice what the preformance implications would be (it would depend on how long the branches that hold the candidates are). So I'm punting on that for now, but I'd like to adjust the tests to be more resilient, and to document the findings. So this patch: 1. Adds an extra tag at the bottom of history. This shouldn't change the output, but does mean we are more resilient to low values of --candidates (e.g., if we start reducing it to the total number of tags). This is arguably closer to the real world anyway, where you're not going to have just 2 tags, but an arbitrarily long history going back in time, possibly with multiple irrelevant tags in it (I called the new tag "H" here for "history"). 2. Run the same tests with --candidates=2, which shows that even with the current code they can fail if we end the traversal early. That leaves a trail for anybody interested in trying to improve the behavior. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t6120-describe.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh index 05ed2510d9..69689d2f36 100755 --- a/t/t6120-describe.sh +++ b/t/t6120-describe.sh @@ -19,6 +19,7 @@ TEST_PASSES_SANITIZE_LEAK=true check_describe () { indir= && + outcome=success && while test $# != 0 do case "$1" in @@ -26,6 +27,9 @@ check_describe () { indir="$2" shift ;; + --expect-failure) + outcome=failure + ;; *) break ;; @@ -36,7 +40,7 @@ check_describe () { expect="$1" shift describe_opts="$@" - test_expect_success "describe $describe_opts" ' + test_expect_${outcome} "describe $describe_opts" ' git ${indir:+ -C "$indir"} describe $describe_opts >raw && sed -e "s/-g[0-9a-f]*\$/-gHASH/" actual && echo "$expect" >expect && @@ -617,7 +621,7 @@ test_expect_success 'name-rev --annotate-stdin works with commitGraph' ' # B # o -# \ +# H \ # o-----o---o----x # A # @@ -627,6 +631,7 @@ test_expect_success 'setup: describe commits with disjoint bases' ' cd disjoint1 && echo o >> file && git add file && git commit -m o && + git tag H -a -m H && echo A >> file && git add file && git commit -m A && git tag A -a -m A && echo o >> file && git add file && git commit -m o && @@ -639,8 +644,9 @@ test_expect_success 'setup: describe commits with disjoint bases' ' ' check_describe -C disjoint1 "A-3-gHASH" HEAD +check_describe -C disjoint1 --expect-failure "A-3-gHASH" --candidates=2 HEAD -# B +# H B # o---o---o------------. # \ # o---o---x @@ -658,6 +664,7 @@ test_expect_success 'setup: describe commits with disjoint bases 2' ' git checkout --orphan branch && echo o >> file2 && git add file2 && GIT_COMMITTER_DATE="2020-01-01 15:00" git commit -m o && echo o >> file2 && git add file2 && GIT_COMMITTER_DATE="2020-01-01 15:01" git commit -m o && + git tag H -a -m H && echo B >> file2 && git add file2 && GIT_COMMITTER_DATE="2020-01-01 15:02" git commit -m B && git tag B -a -m B && git merge --no-ff --allow-unrelated-histories main -m x @@ -665,6 +672,7 @@ test_expect_success 'setup: describe commits with disjoint bases 2' ' ' check_describe -C disjoint2 "B-3-gHASH" HEAD +check_describe -C disjoint2 --expect-failure "B-3-gHASH" --candidates=2 HEAD test_expect_success 'setup misleading taggerdates' ' GIT_COMMITTER_DATE="2006-12-12 12:31" git tag -a -m "another tag" newer-tag-older-commit unique-file~1 -- cgit v1.2.3 From bb0830c6820bf25cdf4722c63a3ff06470e18b0e Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 6 Nov 2024 16:17:08 -0500 Subject: t/perf: add tests for git-describe We don't have a perf script for git-describe, despite it often being accused of slowness. Let's add a few simple tests to start with. Rather than use the existing tags from our test repo, we'll make our own so that we have a known quantity and position. We'll add a "new" tag near the tip of HEAD, and an "old" one that is at the very bottom. And then our tests are: 1. Describing HEAD naively requires walking all the way down to the old tag as we collect candidates. This gives us a baseline for what "slow" looks like. 2. Doing the same with --candidates=1 can potentially be fast, because we can quie after finding "new". But we don't, and it's also slow. 3. Likewise we should be able to quit when there are no more tags to find. This can happen naturally if a repo has few tags, but also if you restrict the set of tags with --match. Here are the results running against linux.git. Note that I have a commit-graph built for the repo, so "slow" here is ~700ms. Without a commit graph it's more like 9s! Test HEAD -------------------------------------------------------------- 6100.2: describe HEAD 0.70(0.66+0.04) 6100.3: describe HEAD with one max candidate 0.70(0.66+0.04) 6100.4: describe HEAD with one tag 0.70(0.64+0.06) Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/perf/p6100-describe.sh | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100755 t/perf/p6100-describe.sh diff --git a/t/perf/p6100-describe.sh b/t/perf/p6100-describe.sh new file mode 100755 index 0000000000..069f91ce49 --- /dev/null +++ b/t/perf/p6100-describe.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +test_description='performance of git-describe' +. ./perf-lib.sh + +test_perf_default_repo + +# clear out old tags and give us a known state +test_expect_success 'set up tags' ' + git for-each-ref --format="delete %(refname)" refs/tags >to-delete && + git update-ref --stdin Date: Wed, 6 Nov 2024 16:17:14 -0500 Subject: describe: stop digging for max_candidates+1 By default, describe considers only 10 candidate matches, and stops traversing when we have enough. This makes things much faster in a large repository, where collecting all candidates requires walking all the way down to the root (or at least to the oldest tag). This goes all the way back to 8713ab3079 (Improve git-describe performance by reducing revision listing., 2007-01-13). However, we don't stop immediately when we have enough candidates. We keep traversing and only bail when we find one more candidate that we're ignoring. Usually this is not too expensive, if the tags are sprinkled evenly throughout history. But if you are unlucky, you might hit the max candidate quickly, and then have a huge swath of history before finding the next one. Our p6100 test has exactly this unlucky case: with a max of "1", we find a recent tag quickly and then have to go all the way to the root to find the old tag that will be discarded. A more interesting real-world case is: git describe --candidates=1 --match=v6.12-rc4 HEAD in the linux.git repo. There we restrict the set of tags to a single one, so there is no older candidate to find at all! But despite --candidates=1, we keep traversing to the root only to find nothing. So why do we keep traversing after hitting thet max? There are two reasons I can see: 1. In theory the extra information that there was another candidate could be useful, and we record it in the gave_up_on variable. But we only show this information with --debug. 2. After finding the candidate, there's more processing we do in our loop. The most important of this is propagating the "within" flags to our parent commits, and putting them in the commit_list we'll use for finish_depth_computation(). That function continues the traversal until we've counted all commits reachable from the starting point but not reachable from our best candidate tag (so essentially counting "$tag..$start", but avoiding re-walking over the bits we've seen). If we break immediately without putting those commits into the list, our depth computation will be wrong (in the worst case we'll count all the way down to the root, not realizing those commits are included in our tag). But we don't need to find a new candidate for (2). As soon as we finish the loop iteration where we hit max_candidates, we can then quit on the next iteration. This should produce the same output as the original code (which could, after all, find a candidate on the very next commit anyway) but ends the traversal with less pointless digging. We still have to set "gave_up_on"; we've popped it off the list and it has to go back. An alternative would be to re-order the loop so that it never gets popped, but it's perhaps still useful to show in the --debug output, so we need to know it anyway. We do have to adjust the --debug output since it's now just a commit where we stopped traversing, and not the max+1th candidate. p6100 shows the speedup using linux.git: Test HEAD^ HEAD --------------------------------------------------------------------------------------- 6100.2: describe HEAD 0.70(0.63+0.06) 0.71(0.66+0.04) +1.4% 6100.3: describe HEAD with one max candidate 0.70(0.64+0.05) 0.01(0.00+0.00) -98.6% 6100.4: describe HEAD with one tag 0.70(0.67+0.03) 0.70(0.63+0.06) +0.0% Reported-by: Josh Poimboeuf Helped-by: Rasmus Villemoes Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin/describe.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/builtin/describe.c b/builtin/describe.c index 7330a77b38..69f2d942be 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -366,6 +366,12 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst) struct commit_name **slot; seen_commits++; + + if (match_cnt == max_candidates) { + gave_up_on = c; + break; + } + slot = commit_names_peek(&commit_names, c); n = slot ? *slot : NULL; if (n) { @@ -381,10 +387,6 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst) if (n->prio == 2) annotated_cnt++; } - else { - gave_up_on = c; - break; - } } for (cur_match = 0; cur_match < match_cnt; cur_match++) { struct possible_tag *t = &all_matches[cur_match]; @@ -470,9 +472,8 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst) fprintf(stderr, _("traversed %lu commits\n"), seen_commits); if (gave_up_on) { fprintf(stderr, - _("more than %i tags found; listed %i most recent\n" - "gave up search at %s\n"), - max_candidates, max_candidates, + _("found %i tags; gave up search at %s\n"), + max_candidates, oid_to_hex(&gave_up_on->object.oid)); } } -- cgit v1.2.3 From b8150bfee1f8d609e3d1f38eaa98cfb64a1c2ca5 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 6 Nov 2024 16:17:17 -0500 Subject: describe: stop traversing when we run out of names When trying to describe a commit, we'll traverse from the commit, collecting candidate tags that point to its ancestors. But once we've seen all of the tags in the repo, there's no point in traversing further. There's nothing left to find! For a default "git describe", this isn't usually a big problem. In a large repo you'll probably have multiple tags, so we'll eventually find 10 candidates (the default for max_candidates) and stop there. And in a small repo, it's quick to traverse to the root. But you can imagine a large repo with few tags. Or, as we saw in a real world case, explicitly limiting the set of matches like this (on linux.git): git describe --match=v6.12-rc4 HEAD which goes all the way to the root before realizing that no, there are no other tags under consideration besides the one we fed via --match. If we add in "--candidates=1" there, it's much faster (at least as of the previous commit). But we should be able to speed this up without the user asking for it. After expanding all matching tags, we know the total number of names. We could just stop the traversal there, but as hinted at above we already have a mechanism for doing that: the max_candidate limit. So we can just reduce that limit to match the number of possible candidates. Our p6100 test shows this off: Test HEAD^ HEAD --------------------------------------------------------------------------------------- 6100.2: describe HEAD 0.71(0.65+0.06) 0.72(0.68+0.04) +1.4% 6100.3: describe HEAD with one max candidate 0.01(0.00+0.00) 0.01(0.00+0.00) +0.0% 6100.4: describe HEAD with one tag 0.72(0.66+0.05) 0.01(0.00+0.00) -98.6% Now we are fast automatically, just as if --candidates=1 were supplied by the user. Reported-by: Josh Poimboeuf Helped-by: Rasmus Villemoes Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin/describe.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/builtin/describe.c b/builtin/describe.c index 69f2d942be..8ec3be87df 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -667,6 +667,8 @@ int cmd_describe(int argc, NULL); if (!hashmap_get_size(&names) && !always) die(_("No names found, cannot describe anything.")); + if (hashmap_get_size(&names) < max_candidates) + max_candidates = hashmap_get_size(&names); if (argc == 0) { if (broken) { -- cgit v1.2.3 From 4da8d90fdda420e981b49452719fc4aea322e815 Mon Sep 17 00:00:00 2001 From: Abhijeet Sonar Date: Sat, 9 Nov 2024 14:57:38 +0530 Subject: show-index: fix uninitialized hash function In c8aed5e8da (repository: stop setting SHA1 as the default object hash), we got rid of the default hash algorithm for the_repository. Due to this change, it is now the responsibility of the callers to set their own default when this is not present. As stated in the docs, show-index should use SHA1 as the default hash algorithm when run outside a repository. Make sure this promise is met by falling back to SHA1 when the_hash_algo is not present (i.e. when the command is run outside a repository). Also add a test that verifies this behavior. Signed-off-by: Abhijeet Sonar Signed-off-by: Junio C Hamano --- builtin/show-index.c | 9 +++++++++ t/t5300-pack-object.sh | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/builtin/show-index.c b/builtin/show-index.c index f164c01bbe..b5e337869d 100644 --- a/builtin/show-index.c +++ b/builtin/show-index.c @@ -38,6 +38,15 @@ int cmd_show_index(int argc, repo_set_hash_algo(the_repository, hash_algo); } + /* + * Fallback to SHA1 if we are running outside of a repository. + * + * TODO: Figure out and implement a way to detect the hash algorithm in use by the + * the index file passed in and use that instead. + */ + if (!the_hash_algo) + repo_set_hash_algo(the_repository, GIT_HASH_SHA1); + hashsz = the_hash_algo->rawsz; if (fread(top_index, 2 * 4, 1, stdin) != 1) diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index 3b9dae331a..51fed26cc4 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -523,6 +523,10 @@ test_expect_success 'index-pack --strict works in non-repo' ' test_path_is_file foo.idx ' +test_expect_success SHA1 'show-index works OK outside a repository' ' + nongit git show-index err && -- cgit v1.2.3 From 34d3f2a984eed5c31384e384f391293d38478036 Mon Sep 17 00:00:00 2001 From: Abhijeet Sonar Date: Sat, 9 Nov 2024 14:57:39 +0530 Subject: t5300: add test for 'show-index --object-format' In 88a09a557c (builtin/show-index: provide options to determine hash algo), the flag --object-format was added to show-index builtin as a way to provide a hash algorithm explicitly. However, we do not have tests in place for that functionality. Add them. Signed-off-by: Abhijeet Sonar Signed-off-by: Junio C Hamano --- t/t5300-pack-object.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index 51fed26cc4..bb6a22b438 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -527,6 +527,20 @@ test_expect_success SHA1 'show-index works OK outside a repository' ' nongit git show-index in && + git -C explicit-hash-$hash pack-objects explicit-hash-$hash actual && + test_line_count = 1 actual + ' +done + test_expect_success !PTHREADS,!FAIL_PREREQS \ 'index-pack --threads=N or pack.threads=N warns when no pthreads' ' test_must_fail git index-pack --threads=2 2>err && -- cgit v1.2.3 From 0ffb5a6bf1b0fd9ce0c0b1fd9ce9fd30b89a2563 Mon Sep 17 00:00:00 2001 From: "brian m. carlson" Date: Fri, 15 Nov 2024 00:54:04 +0000 Subject: Allow cloning from repositories owned by another user Historically, Git has allowed users to clone from an untrusted repository, and we have documented that this is safe to do so: `upload-pack` tries to avoid any dangerous configuration options or hooks from the repository it's serving, making it safe to clone an untrusted directory and run commands on the resulting clone. However, this was broken by f4aa8c8bb1 ("fetch/clone: detect dubious ownership of local repositories", 2024-04-10) in an attempt to make things more secure. That change resulted in a variety of problems when cloning locally and over SSH, but it did not change the stated security boundary. Because the security boundary has not changed, it is safe to adjust part of the code that patch introduced. To do that and restore the previous functionality, adjust enter_repo to take two flags instead of one. The two bits are - ENTER_REPO_STRICT: callers that require exact paths (as opposed to allowing known suffixes like ".git", ".git/.git" to be omitted) can set this bit. Corresponds to the "strict" parameter that the flags word replaces. - ENTER_REPO_ANY_OWNER_OK: callers that are willing to run without ownership check can set this bit. The former is --strict-paths option of "git daemon". The latter is set only by upload-pack, which honors the claimed security boundary. Note that local clones across ownership boundaries require --no-local so that upload-pack is used. Document this fact in the manual page and provide an example. This patch was based on one written by Junio C Hamano. Signed-off-by: Junio C Hamano --- Documentation/git-clone.txt | 9 +++++++++ builtin/upload-pack.c | 5 ++++- daemon.c | 6 ++++-- path.c | 10 ++++++---- path.h | 17 ++++++++++++++++- t/t0411-clone-from-partial.sh | 3 --- t/t5605-clone-local.sh | 10 ++++++++++ 7 files changed, 49 insertions(+), 11 deletions(-) diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index 6e43eb9c20..5347cc5255 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -63,6 +63,9 @@ symbolic link, the clone will fail. This is a security measure to prevent the unintentional copying of files by dereferencing the symbolic links. + +This option does not work with repositories owned by other users for security +reasons, and `--no-local` must be specified for the clone to succeed. ++ *NOTE*: this operation can race with concurrent modification to the source repository, similar to running `cp -r src dst` while modifying `src`. @@ -381,6 +384,12 @@ $ cd my-linux $ git clone --bare -l /home/proj/.git /pub/scm/proj.git ------------ +* Clone a local repository from a different user: ++ +------------ +$ git clone --no-local /home/otheruser/proj.git /pub/scm/proj.git +------------ + CONFIGURATION ------------- diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c index 272cddaafd..72af0094e4 100644 --- a/builtin/upload-pack.c +++ b/builtin/upload-pack.c @@ -34,6 +34,7 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix) N_("interrupt transfer after seconds of inactivity")), OPT_END() }; + unsigned enter_repo_flags = ENTER_REPO_ANY_OWNER_OK; packet_trace_identity("upload-pack"); disable_replace_refs(); @@ -49,7 +50,9 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix) dir = argv[0]; - if (!enter_repo(dir, strict)) + if (strict) + enter_repo_flags |= ENTER_REPO_STRICT; + if (!enter_repo(dir, enter_repo_flags)) die("'%s' does not appear to be a git repository", dir); switch (determine_protocol_version_server()) { diff --git a/daemon.c b/daemon.c index 17d331b2f3..fb37135521 100644 --- a/daemon.c +++ b/daemon.c @@ -149,6 +149,7 @@ static const char *path_ok(const char *directory, struct hostinfo *hi) size_t rlen; const char *path; const char *dir; + unsigned enter_repo_flags; dir = directory; @@ -239,14 +240,15 @@ static const char *path_ok(const char *directory, struct hostinfo *hi) dir = rpath; } - path = enter_repo(dir, strict_paths); + enter_repo_flags = strict_paths ? ENTER_REPO_STRICT : 0; + path = enter_repo(dir, enter_repo_flags); if (!path && base_path && base_path_relaxed) { /* * if we fail and base_path_relaxed is enabled, try without * prefixing the base path */ dir = directory; - path = enter_repo(dir, strict_paths); + path = enter_repo(dir, enter_repo_flags); } if (!path) { diff --git a/path.c b/path.c index 1d3e67936b..11177b46f4 100644 --- a/path.c +++ b/path.c @@ -794,7 +794,7 @@ return_null: * links. User relative paths are also returned as they are given, * except DWIM suffixing. */ -const char *enter_repo(const char *path, int strict) +const char *enter_repo(const char *path, unsigned flags) { static struct strbuf validated_path = STRBUF_INIT; static struct strbuf used_path = STRBUF_INIT; @@ -802,7 +802,7 @@ const char *enter_repo(const char *path, int strict) if (!path) return NULL; - if (!strict) { + if (!(flags & ENTER_REPO_STRICT)) { static const char *suffix[] = { "/.git", "", ".git/.git", ".git", NULL, }; @@ -846,7 +846,8 @@ const char *enter_repo(const char *path, int strict) if (!suffix[i]) return NULL; gitfile = read_gitfile(used_path.buf); - die_upon_dubious_ownership(gitfile, NULL, used_path.buf); + if (!(flags & ENTER_REPO_ANY_OWNER_OK)) + die_upon_dubious_ownership(gitfile, NULL, used_path.buf); if (gitfile) { strbuf_reset(&used_path); strbuf_addstr(&used_path, gitfile); @@ -857,7 +858,8 @@ const char *enter_repo(const char *path, int strict) } else { const char *gitfile = read_gitfile(path); - die_upon_dubious_ownership(gitfile, NULL, path); + if (!(flags & ENTER_REPO_ANY_OWNER_OK)) + die_upon_dubious_ownership(gitfile, NULL, path); if (gitfile) path = gitfile; if (chdir(path)) diff --git a/path.h b/path.h index b3233c51fa..39673094f7 100644 --- a/path.h +++ b/path.h @@ -184,7 +184,22 @@ int validate_headref(const char *ref); int adjust_shared_perm(const char *path); char *interpolate_path(const char *path, int real_home); -const char *enter_repo(const char *path, int strict); + +/* The bits are as follows: + * + * - ENTER_REPO_STRICT: callers that require exact paths (as opposed + * to allowing known suffixes like ".git", ".git/.git" to be + * omitted) can set this bit. + * + * - ENTER_REPO_ANY_OWNER_OK: callers that are willing to run without + * ownership check can set this bit. + */ +enum { + ENTER_REPO_STRICT = (1<<0), + ENTER_REPO_ANY_OWNER_OK = (1<<1), +}; + +const char *enter_repo(const char *path, unsigned flags); const char *remove_leading_path(const char *in, const char *prefix); const char *relative_path(const char *in, const char *prefix, struct strbuf *sb); int normalize_path_copy_len(char *dst, const char *src, int *prefix_len); diff --git a/t/t0411-clone-from-partial.sh b/t/t0411-clone-from-partial.sh index c98d501869..196fc61784 100755 --- a/t/t0411-clone-from-partial.sh +++ b/t/t0411-clone-from-partial.sh @@ -28,7 +28,6 @@ test_expect_success 'local clone must not fetch from promisor remote and execute test_must_fail git clone \ --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \ evil clone1 2>err && - test_grep "detected dubious ownership" err && test_grep ! "fake-upload-pack running" err && test_path_is_missing script-executed ' @@ -38,7 +37,6 @@ test_expect_success 'clone from file://... must not fetch from promisor remote a test_must_fail git clone \ --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \ "file://$(pwd)/evil" clone2 2>err && - test_grep "detected dubious ownership" err && test_grep ! "fake-upload-pack running" err && test_path_is_missing script-executed ' @@ -48,7 +46,6 @@ test_expect_success 'fetch from file://... must not fetch from promisor remote a test_must_fail git fetch \ --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \ "file://$(pwd)/evil" 2>err && - test_grep "detected dubious ownership" err && test_grep ! "fake-upload-pack running" err && test_path_is_missing script-executed ' diff --git a/t/t5605-clone-local.sh b/t/t5605-clone-local.sh index a3055869bc..31f6249ac9 100755 --- a/t/t5605-clone-local.sh +++ b/t/t5605-clone-local.sh @@ -153,6 +153,16 @@ test_expect_success 'cloning a local path with --no-local does not hardlink' ' ! repo_is_hardlinked force-nonlocal ' +test_expect_success 'cloning a local path with --no-local from a different user succeeds' ' + git clone --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \ + --no-local a nonlocal-otheruser 2>err && + ! repo_is_hardlinked nonlocal-otheruser && + # Verify that this is a git repository. + git -C nonlocal-otheruser rev-parse --show-toplevel && + ! test_grep "detected dubious ownership" err + +' + test_expect_success 'cloning locally respects "-u" for fetching refs' ' test_must_fail git clone --bare -u false a should_not_work.git ' -- cgit v1.2.3 From 17e80398782b4e8746a389604aaaf9744fd6900a Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 18 Nov 2024 16:33:52 +0100 Subject: reftable/system: move "dir.h" to its only user We still include "dir.h" in "reftable/system.h" even though it is not used by anything but by a single unit test. Move it over into that unit test so that we don't accidentally use any functionality provided by it in the reftable codebase. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- reftable/system.h | 1 - t/unit-tests/t-reftable-stack.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/reftable/system.h b/reftable/system.h index 5ec8583343..8564213475 100644 --- a/reftable/system.h +++ b/reftable/system.h @@ -15,7 +15,6 @@ https://developers.google.com/open-source/licenses/bsd #include "lockfile.h" #include "tempfile.h" #include "hash.h" /* hash ID, sizes.*/ -#include "dir.h" /* remove_dir_recursively, for tests.*/ int hash_size(uint32_t id); diff --git a/t/unit-tests/t-reftable-stack.c b/t/unit-tests/t-reftable-stack.c index 72f6747064..1b4363a58f 100644 --- a/t/unit-tests/t-reftable-stack.c +++ b/t/unit-tests/t-reftable-stack.c @@ -8,6 +8,7 @@ https://developers.google.com/open-source/licenses/bsd #include "test-lib.h" #include "lib-reftable.h" +#include "dir.h" #include "reftable/merged.h" #include "reftable/reader.h" #include "reftable/reftable-error.h" -- cgit v1.2.3 From 88e297275b94f2fbbc60b770f37654796799b907 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 18 Nov 2024 16:33:55 +0100 Subject: reftable: explicitly handle hash format IDs The hash format IDs are used for two different things across the reftable codebase: - They are used as a 32 bit unsigned integer when reading and writing the header in order to identify the hash function. - They are used internally to identify which hash function is in use. When one only considers the second usecase one might think that one can easily change the representation of those hash IDs. But because those IDs end up in the reftable header and footer on disk it is important that those never change. Create separate constants `REFTABLE_FORMAT_ID_*` and use them in contexts where we read or write reftable headers. This serves multiple purposes: - It allows us to more easily discern cases where we actually use those constants for the on-disk format. - It detangles us from the same constants that are defined in libgit.a, which is another required step to convert the reftable library to become standalone. - It makes the next step easier where we stop using `GIT_*_FORMAT_ID` constants in favor of a custom enum. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- reftable/basics.h | 8 ++++++++ reftable/reader.c | 10 ++++++---- reftable/writer.c | 16 +++++++++++++++- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/reftable/basics.h b/reftable/basics.h index 7aa46d7c30..bcab0b529b 100644 --- a/reftable/basics.h +++ b/reftable/basics.h @@ -150,4 +150,12 @@ int common_prefix_size(struct reftable_buf *a, struct reftable_buf *b); int hash_size(uint32_t id); +/* + * Format IDs that identify the hash function used by a reftable. Note that + * these constants end up on disk and thus mustn't change. The format IDs are + * "sha1" and "s256" in big endian, respectively. + */ +#define REFTABLE_FORMAT_ID_SHA1 ((uint32_t) 0x73686131) +#define REFTABLE_FORMAT_ID_SHA256 ((uint32_t) 0x73323536) + #endif diff --git a/reftable/reader.c b/reftable/reader.c index 90dc950b57..64eb6938ef 100644 --- a/reftable/reader.c +++ b/reftable/reader.c @@ -109,16 +109,18 @@ static int parse_footer(struct reftable_reader *r, uint8_t *footer, if (r->version == 1) { r->hash_id = GIT_SHA1_FORMAT_ID; } else { - r->hash_id = get_be32(f); - switch (r->hash_id) { - case GIT_SHA1_FORMAT_ID: + switch (get_be32(f)) { + case REFTABLE_FORMAT_ID_SHA1: + r->hash_id = GIT_SHA1_FORMAT_ID; break; - case GIT_SHA256_FORMAT_ID: + case REFTABLE_FORMAT_ID_SHA256: + r->hash_id = GIT_SHA256_FORMAT_ID; break; default: err = REFTABLE_FORMAT_ERROR; goto done; } + f += 4; } diff --git a/reftable/writer.c b/reftable/writer.c index fd136794d5..9aa45de634 100644 --- a/reftable/writer.c +++ b/reftable/writer.c @@ -103,8 +103,22 @@ static int writer_write_header(struct reftable_writer *w, uint8_t *dest) put_be64(dest + 8, w->min_update_index); put_be64(dest + 16, w->max_update_index); if (writer_version(w) == 2) { - put_be32(dest + 24, w->opts.hash_id); + uint32_t hash_id; + + switch (w->opts.hash_id) { + case GIT_SHA1_FORMAT_ID: + hash_id = REFTABLE_FORMAT_ID_SHA1; + break; + case GIT_SHA256_FORMAT_ID: + hash_id = REFTABLE_FORMAT_ID_SHA256; + break; + default: + return -1; + } + + put_be32(dest + 24, hash_id); } + return header_size(writer_version(w)); } -- cgit v1.2.3 From c2f08236ed786a48e50af33ecc5c0f951c14761b Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 18 Nov 2024 16:33:57 +0100 Subject: reftable/system: stop depending on "hash.h" We include "hash.h" in "reftable/system.h" such that we can use hash format IDs as well as the raw size of SHA1 and SHA256. As we are in the process of converting the reftable library to become standalone we of course cannot rely on those constants anymore. Introduce a new `enum reftable_hash` to replace internal uses of the hash format IDs and new constants that replace internal uses of the hash size. Adapt the reftable backend to set up the correct hash function. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- refs/reftable-backend.c | 12 +++++++- reftable/basics.c | 13 ++++---- reftable/basics.h | 2 +- reftable/merged.c | 4 +-- reftable/merged.h | 3 +- reftable/reader.c | 8 ++--- reftable/reader.h | 4 +-- reftable/reftable-basics.h | 13 ++++++++ reftable/reftable-merged.h | 4 +-- reftable/reftable-reader.h | 2 +- reftable/reftable-record.h | 12 ++++---- reftable/reftable-writer.h | 2 +- reftable/stack.c | 4 +-- reftable/system.h | 3 -- reftable/writer.c | 8 ++--- t/helper/test-reftable.c | 4 +-- t/unit-tests/lib-reftable.c | 4 +-- t/unit-tests/lib-reftable.h | 2 +- t/unit-tests/t-reftable-block.c | 40 ++++++++++++------------- t/unit-tests/t-reftable-merged.c | 26 ++++++++-------- t/unit-tests/t-reftable-pq.c | 2 +- t/unit-tests/t-reftable-reader.c | 4 +-- t/unit-tests/t-reftable-readwrite.c | 40 ++++++++++++------------- t/unit-tests/t-reftable-record.c | 59 +++++++++++++++++++------------------ t/unit-tests/t-reftable-stack.c | 34 ++++++++++----------- 25 files changed, 166 insertions(+), 143 deletions(-) diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c index 3c6107c7ce..7d86d92097 100644 --- a/refs/reftable-backend.c +++ b/refs/reftable-backend.c @@ -15,6 +15,7 @@ #include "../object.h" #include "../path.h" #include "../refs.h" +#include "../reftable/reftable-basics.h" #include "../reftable/reftable-stack.h" #include "../reftable/reftable-record.h" #include "../reftable/reftable-error.h" @@ -289,7 +290,16 @@ static struct ref_store *reftable_be_init(struct repository *repo, refs->store_flags = store_flags; refs->log_all_ref_updates = repo_settings_get_log_all_ref_updates(repo); - refs->write_options.hash_id = repo->hash_algo->format_id; + switch (repo->hash_algo->format_id) { + case GIT_SHA1_FORMAT_ID: + refs->write_options.hash_id = REFTABLE_HASH_SHA1; + break; + case GIT_SHA256_FORMAT_ID: + refs->write_options.hash_id = REFTABLE_HASH_SHA256; + break; + default: + BUG("unknown hash algorithm %d", repo->hash_algo->format_id); + } refs->write_options.default_permissions = calc_shared_perm(0666 & ~mask); refs->write_options.disable_auto_compact = !git_env_bool("GIT_TEST_REFTABLE_AUTOCOMPACTION", 1); diff --git a/reftable/basics.c b/reftable/basics.c index bc4fcc9144..7d84a5d62d 100644 --- a/reftable/basics.c +++ b/reftable/basics.c @@ -271,14 +271,15 @@ int common_prefix_size(struct reftable_buf *a, struct reftable_buf *b) return p; } -int hash_size(uint32_t id) +int hash_size(enum reftable_hash id) { + if (!id) + return REFTABLE_HASH_SIZE_SHA1; switch (id) { - case 0: - case GIT_SHA1_FORMAT_ID: - return GIT_SHA1_RAWSZ; - case GIT_SHA256_FORMAT_ID: - return GIT_SHA256_RAWSZ; + case REFTABLE_HASH_SHA1: + return REFTABLE_HASH_SIZE_SHA1; + case REFTABLE_HASH_SHA256: + return REFTABLE_HASH_SIZE_SHA256; } abort(); } diff --git a/reftable/basics.h b/reftable/basics.h index bcab0b529b..36beda2c25 100644 --- a/reftable/basics.h +++ b/reftable/basics.h @@ -148,7 +148,7 @@ char *reftable_strdup(const char *str); /* Find the longest shared prefix size of `a` and `b` */ int common_prefix_size(struct reftable_buf *a, struct reftable_buf *b); -int hash_size(uint32_t id); +int hash_size(enum reftable_hash id); /* * Format IDs that identify the hash function used by a reftable. Note that diff --git a/reftable/merged.c b/reftable/merged.c index 514d6facf4..5b93e20f42 100644 --- a/reftable/merged.c +++ b/reftable/merged.c @@ -181,7 +181,7 @@ static void iterator_from_merged_iter(struct reftable_iterator *it, int reftable_merged_table_new(struct reftable_merged_table **dest, struct reftable_reader **readers, size_t n, - uint32_t hash_id) + enum reftable_hash hash_id) { struct reftable_merged_table *m = NULL; uint64_t last_max = 0; @@ -293,7 +293,7 @@ int reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt, return merged_table_init_iter(mt, it, BLOCK_TYPE_LOG); } -uint32_t reftable_merged_table_hash_id(struct reftable_merged_table *mt) +enum reftable_hash reftable_merged_table_hash_id(struct reftable_merged_table *mt) { return mt->hash_id; } diff --git a/reftable/merged.h b/reftable/merged.h index 89bd0c4b35..0b7d939e92 100644 --- a/reftable/merged.h +++ b/reftable/merged.h @@ -10,11 +10,12 @@ https://developers.google.com/open-source/licenses/bsd #define MERGED_H #include "system.h" +#include "reftable-basics.h" struct reftable_merged_table { struct reftable_reader **readers; size_t readers_len; - uint32_t hash_id; + enum reftable_hash hash_id; /* If unset, produce deletions. This is useful for compaction. For the * full stack, deletions should be produced. */ diff --git a/reftable/reader.c b/reftable/reader.c index 64eb6938ef..ea82955c9b 100644 --- a/reftable/reader.c +++ b/reftable/reader.c @@ -67,7 +67,7 @@ static int reader_get_block(struct reftable_reader *r, return block_source_read_block(&r->source, dest, off, sz); } -uint32_t reftable_reader_hash_id(struct reftable_reader *r) +enum reftable_hash reftable_reader_hash_id(struct reftable_reader *r) { return r->hash_id; } @@ -107,14 +107,14 @@ static int parse_footer(struct reftable_reader *r, uint8_t *footer, f += 8; if (r->version == 1) { - r->hash_id = GIT_SHA1_FORMAT_ID; + r->hash_id = REFTABLE_HASH_SHA1; } else { switch (get_be32(f)) { case REFTABLE_FORMAT_ID_SHA1: - r->hash_id = GIT_SHA1_FORMAT_ID; + r->hash_id = REFTABLE_HASH_SHA1; break; case REFTABLE_FORMAT_ID_SHA256: - r->hash_id = GIT_SHA256_FORMAT_ID; + r->hash_id = REFTABLE_HASH_SHA256; break; default: err = REFTABLE_FORMAT_ERROR; diff --git a/reftable/reader.h b/reftable/reader.h index 010fbfe851..d2b48a4849 100644 --- a/reftable/reader.h +++ b/reftable/reader.h @@ -37,8 +37,8 @@ struct reftable_reader { /* Size of the file, excluding the footer. */ uint64_t size; - /* 'sha1' for SHA1, 's256' for SHA-256 */ - uint32_t hash_id; + /* The hash function used for ref records. */ + enum reftable_hash hash_id; uint32_t block_size; uint64_t min_update_index; diff --git a/reftable/reftable-basics.h b/reftable/reftable-basics.h index 6e8e636b71..e0397ed583 100644 --- a/reftable/reftable-basics.h +++ b/reftable/reftable-basics.h @@ -11,6 +11,19 @@ #include +/* + * Hash functions understood by the reftable library. Note that the values are + * arbitrary and somewhat random such that we can easily detect cases where the + * hash hasn't been properly set up. + */ +enum reftable_hash { + REFTABLE_HASH_SHA1 = 89, + REFTABLE_HASH_SHA256 = 247, +}; +#define REFTABLE_HASH_SIZE_SHA1 20 +#define REFTABLE_HASH_SIZE_SHA256 32 +#define REFTABLE_HASH_SIZE_MAX REFTABLE_HASH_SIZE_SHA256 + /* Overrides the functions to use for memory management. */ void reftable_set_alloc(void *(*malloc)(size_t), void *(*realloc)(void *, size_t), void (*free)(void *)); diff --git a/reftable/reftable-merged.h b/reftable/reftable-merged.h index a970d5dd89..f2d01c3ef8 100644 --- a/reftable/reftable-merged.h +++ b/reftable/reftable-merged.h @@ -34,7 +34,7 @@ struct reftable_reader; */ int reftable_merged_table_new(struct reftable_merged_table **dest, struct reftable_reader **readers, size_t n, - uint32_t hash_id); + enum reftable_hash hash_id); /* Initialize a merged table iterator for reading refs. */ int reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt, @@ -56,6 +56,6 @@ reftable_merged_table_min_update_index(struct reftable_merged_table *mt); void reftable_merged_table_free(struct reftable_merged_table *m); /* return the hash ID of the merged table. */ -uint32_t reftable_merged_table_hash_id(struct reftable_merged_table *m); +enum reftable_hash reftable_merged_table_hash_id(struct reftable_merged_table *m); #endif diff --git a/reftable/reftable-reader.h b/reftable/reftable-reader.h index 6a2d0b693f..0085fbb903 100644 --- a/reftable/reftable-reader.h +++ b/reftable/reftable-reader.h @@ -54,7 +54,7 @@ int reftable_reader_init_log_iterator(struct reftable_reader *r, struct reftable_iterator *it); /* returns the hash ID used in this table. */ -uint32_t reftable_reader_hash_id(struct reftable_reader *r); +enum reftable_hash reftable_reader_hash_id(struct reftable_reader *r); /* return an iterator for the refs pointing to `oid`. */ int reftable_reader_refs_for(struct reftable_reader *r, diff --git a/reftable/reftable-record.h b/reftable/reftable-record.h index 2d42463c58..ddd48eb579 100644 --- a/reftable/reftable-record.h +++ b/reftable/reftable-record.h @@ -9,7 +9,7 @@ https://developers.google.com/open-source/licenses/bsd #ifndef REFTABLE_RECORD_H #define REFTABLE_RECORD_H -#include "hash.h" +#include "reftable-basics.h" #include /* @@ -40,10 +40,10 @@ struct reftable_ref_record { #define REFTABLE_NR_REF_VALUETYPES 4 } value_type; union { - unsigned char val1[GIT_MAX_RAWSZ]; + unsigned char val1[REFTABLE_HASH_SIZE_MAX]; struct { - unsigned char value[GIT_MAX_RAWSZ]; /* first hash */ - unsigned char target_value[GIT_MAX_RAWSZ]; /* second hash */ + unsigned char value[REFTABLE_HASH_SIZE_MAX]; /* first hash */ + unsigned char target_value[REFTABLE_HASH_SIZE_MAX]; /* second hash */ } val2; char *symref; /* referent, malloced 0-terminated string */ } value; @@ -85,8 +85,8 @@ struct reftable_log_record { union { struct { - unsigned char new_hash[GIT_MAX_RAWSZ]; - unsigned char old_hash[GIT_MAX_RAWSZ]; + unsigned char new_hash[REFTABLE_HASH_SIZE_MAX]; + unsigned char old_hash[REFTABLE_HASH_SIZE_MAX]; char *name; char *email; uint64_t time; diff --git a/reftable/reftable-writer.h b/reftable/reftable-writer.h index e4fc953788..211860d08a 100644 --- a/reftable/reftable-writer.h +++ b/reftable/reftable-writer.h @@ -33,7 +33,7 @@ struct reftable_write_options { /* 4-byte identifier ("sha1", "s256") of the hash. * Defaults to SHA1 if unset */ - uint32_t hash_id; + enum reftable_hash hash_id; /* Default mode for creating files. If unset, use 0666 (+umask) */ unsigned int default_permissions; diff --git a/reftable/stack.c b/reftable/stack.c index c33979536e..9ae716ff37 100644 --- a/reftable/stack.c +++ b/reftable/stack.c @@ -73,7 +73,7 @@ int reftable_new_stack(struct reftable_stack **dest, const char *dir, if (_opts) opts = *_opts; if (opts.hash_id == 0) - opts.hash_id = GIT_SHA1_FORMAT_ID; + opts.hash_id = REFTABLE_HASH_SHA1; *dest = NULL; @@ -1603,7 +1603,7 @@ struct segment suggest_compaction_segment(uint64_t *sizes, size_t n, static uint64_t *stack_table_sizes_for_compaction(struct reftable_stack *st) { - int version = (st->opts.hash_id == GIT_SHA1_FORMAT_ID) ? 1 : 2; + int version = (st->opts.hash_id == REFTABLE_HASH_SHA1) ? 1 : 2; int overhead = header_size(version) - 1; uint64_t *sizes; diff --git a/reftable/system.h b/reftable/system.h index 8564213475..38d3534620 100644 --- a/reftable/system.h +++ b/reftable/system.h @@ -14,8 +14,5 @@ https://developers.google.com/open-source/licenses/bsd #include "git-compat-util.h" #include "lockfile.h" #include "tempfile.h" -#include "hash.h" /* hash ID, sizes.*/ - -int hash_size(uint32_t id); #endif diff --git a/reftable/writer.c b/reftable/writer.c index 9aa45de634..ea2f831fc5 100644 --- a/reftable/writer.c +++ b/reftable/writer.c @@ -79,7 +79,7 @@ static void options_set_defaults(struct reftable_write_options *opts) } if (opts->hash_id == 0) { - opts->hash_id = GIT_SHA1_FORMAT_ID; + opts->hash_id = REFTABLE_HASH_SHA1; } if (opts->block_size == 0) { opts->block_size = DEFAULT_BLOCK_SIZE; @@ -88,7 +88,7 @@ static void options_set_defaults(struct reftable_write_options *opts) static int writer_version(struct reftable_writer *w) { - return (w->opts.hash_id == 0 || w->opts.hash_id == GIT_SHA1_FORMAT_ID) ? + return (w->opts.hash_id == 0 || w->opts.hash_id == REFTABLE_HASH_SHA1) ? 1 : 2; } @@ -106,10 +106,10 @@ static int writer_write_header(struct reftable_writer *w, uint8_t *dest) uint32_t hash_id; switch (w->opts.hash_id) { - case GIT_SHA1_FORMAT_ID: + case REFTABLE_HASH_SHA1: hash_id = REFTABLE_FORMAT_ID_SHA1; break; - case GIT_SHA256_FORMAT_ID: + case REFTABLE_HASH_SHA256: hash_id = REFTABLE_FORMAT_ID_SHA256; break; default: diff --git a/t/helper/test-reftable.c b/t/helper/test-reftable.c index 5c8849d115..3c72ed985b 100644 --- a/t/helper/test-reftable.c +++ b/t/helper/test-reftable.c @@ -156,7 +156,7 @@ int cmd__dump_reftable(int argc, const char **argv) int opt_dump_blocks = 0; int opt_dump_table = 0; int opt_dump_stack = 0; - uint32_t opt_hash_id = GIT_SHA1_FORMAT_ID; + uint32_t opt_hash_id = REFTABLE_HASH_SHA1; const char *arg = NULL, *argv0 = argv[0]; for (; argc > 1; argv++, argc--) @@ -167,7 +167,7 @@ int cmd__dump_reftable(int argc, const char **argv) else if (!strcmp("-t", argv[1])) opt_dump_table = 1; else if (!strcmp("-6", argv[1])) - opt_hash_id = GIT_SHA256_FORMAT_ID; + opt_hash_id = REFTABLE_HASH_SHA256; else if (!strcmp("-s", argv[1])) opt_dump_stack = 1; else if (!strcmp("-?", argv[1]) || !strcmp("-h", argv[1])) { diff --git a/t/unit-tests/lib-reftable.c b/t/unit-tests/lib-reftable.c index 2ddf480588..c1631f4527 100644 --- a/t/unit-tests/lib-reftable.c +++ b/t/unit-tests/lib-reftable.c @@ -3,7 +3,7 @@ #include "reftable/constants.h" #include "reftable/writer.h" -void t_reftable_set_hash(uint8_t *p, int i, uint32_t id) +void t_reftable_set_hash(uint8_t *p, int i, enum reftable_hash id) { memset(p, (uint8_t)i, hash_size(id)); } @@ -82,7 +82,7 @@ void t_reftable_write_to_buf(struct reftable_buf *buf, size_t off = i * (opts.block_size ? opts.block_size : DEFAULT_BLOCK_SIZE); if (!off) - off = header_size(opts.hash_id == GIT_SHA256_FORMAT_ID ? 2 : 1); + off = header_size(opts.hash_id == REFTABLE_HASH_SHA256 ? 2 : 1); check_char(buf->buf[off], ==, 'r'); } diff --git a/t/unit-tests/lib-reftable.h b/t/unit-tests/lib-reftable.h index d4950fed3d..e4c360fa7e 100644 --- a/t/unit-tests/lib-reftable.h +++ b/t/unit-tests/lib-reftable.h @@ -6,7 +6,7 @@ struct reftable_buf; -void t_reftable_set_hash(uint8_t *p, int i, uint32_t id); +void t_reftable_set_hash(uint8_t *p, int i, enum reftable_hash id); struct reftable_writer *t_reftable_strbuf_writer(struct reftable_buf *buf, struct reftable_write_options *opts); diff --git a/t/unit-tests/t-reftable-block.c b/t/unit-tests/t-reftable-block.c index f9af907117..13e10807da 100644 --- a/t/unit-tests/t-reftable-block.c +++ b/t/unit-tests/t-reftable-block.c @@ -36,7 +36,7 @@ static void t_ref_block_read_write(void) block.len = block_size; block_source_from_buf(&block.source ,&buf); ret = block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size, - header_off, hash_size(GIT_SHA1_FORMAT_ID)); + header_off, hash_size(REFTABLE_HASH_SHA1)); check(!ret); rec.u.ref.refname = (char *) ""; @@ -47,7 +47,7 @@ static void t_ref_block_read_write(void) for (i = 0; i < N; i++) { rec.u.ref.refname = xstrfmt("branch%02"PRIuMAX, (uintmax_t)i); rec.u.ref.value_type = REFTABLE_REF_VAL1; - memset(rec.u.ref.value.val1, i, GIT_SHA1_RAWSZ); + memset(rec.u.ref.value.val1, i, REFTABLE_HASH_SIZE_SHA1); recs[i] = rec; ret = block_writer_add(&bw, &rec); @@ -61,7 +61,7 @@ static void t_ref_block_read_write(void) block_writer_release(&bw); - block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ); + block_reader_init(&br, &block, header_off, block_size, REFTABLE_HASH_SIZE_SHA1); block_iter_seek_start(&it, &br); @@ -72,7 +72,7 @@ static void t_ref_block_read_write(void) check_int(i, ==, N); break; } - check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ)); + check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); } for (i = 0; i < N; i++) { @@ -85,7 +85,7 @@ static void t_ref_block_read_write(void) ret = block_iter_next(&it, &rec); check_int(ret, ==, 0); - check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ)); + check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); want.len--; ret = block_iter_seek_key(&it, &br, &want); @@ -93,7 +93,7 @@ static void t_ref_block_read_write(void) ret = block_iter_next(&it, &rec); check_int(ret, ==, 0); - check(reftable_record_equal(&recs[10 * (i / 10)], &rec, GIT_SHA1_RAWSZ)); + check(reftable_record_equal(&recs[10 * (i / 10)], &rec, REFTABLE_HASH_SIZE_SHA1)); } block_reader_release(&br); @@ -130,7 +130,7 @@ static void t_log_block_read_write(void) block.len = block_size; block_source_from_buf(&block.source ,&buf); ret = block_writer_init(&bw, BLOCK_TYPE_LOG, block.data, block_size, - header_off, hash_size(GIT_SHA1_FORMAT_ID)); + header_off, hash_size(REFTABLE_HASH_SHA1)); check(!ret); for (i = 0; i < N; i++) { @@ -150,7 +150,7 @@ static void t_log_block_read_write(void) block_writer_release(&bw); - block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ); + block_reader_init(&br, &block, header_off, block_size, REFTABLE_HASH_SIZE_SHA1); block_iter_seek_start(&it, &br); @@ -161,7 +161,7 @@ static void t_log_block_read_write(void) check_int(i, ==, N); break; } - check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ)); + check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); } for (i = 0; i < N; i++) { @@ -175,7 +175,7 @@ static void t_log_block_read_write(void) ret = block_iter_next(&it, &rec); check_int(ret, ==, 0); - check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ)); + check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); want.len--; ret = block_iter_seek_key(&it, &br, &want); @@ -183,7 +183,7 @@ static void t_log_block_read_write(void) ret = block_iter_next(&it, &rec); check_int(ret, ==, 0); - check(reftable_record_equal(&recs[10 * (i / 10)], &rec, GIT_SHA1_RAWSZ)); + check(reftable_record_equal(&recs[10 * (i / 10)], &rec, REFTABLE_HASH_SIZE_SHA1)); } block_reader_release(&br); @@ -220,7 +220,7 @@ static void t_obj_block_read_write(void) block.len = block_size; block_source_from_buf(&block.source, &buf); ret = block_writer_init(&bw, BLOCK_TYPE_OBJ, block.data, block_size, - header_off, hash_size(GIT_SHA1_FORMAT_ID)); + header_off, hash_size(REFTABLE_HASH_SHA1)); check(!ret); for (i = 0; i < N; i++) { @@ -242,7 +242,7 @@ static void t_obj_block_read_write(void) block_writer_release(&bw); - block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ); + block_reader_init(&br, &block, header_off, block_size, REFTABLE_HASH_SIZE_SHA1); block_iter_seek_start(&it, &br); @@ -253,7 +253,7 @@ static void t_obj_block_read_write(void) check_int(i, ==, N); break; } - check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ)); + check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); } for (i = 0; i < N; i++) { @@ -266,7 +266,7 @@ static void t_obj_block_read_write(void) ret = block_iter_next(&it, &rec); check_int(ret, ==, 0); - check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ)); + check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); } block_reader_release(&br); @@ -304,7 +304,7 @@ static void t_index_block_read_write(void) block.len = block_size; block_source_from_buf(&block.source, &buf); ret = block_writer_init(&bw, BLOCK_TYPE_INDEX, block.data, block_size, - header_off, hash_size(GIT_SHA1_FORMAT_ID)); + header_off, hash_size(REFTABLE_HASH_SHA1)); check(!ret); for (i = 0; i < N; i++) { @@ -326,7 +326,7 @@ static void t_index_block_read_write(void) block_writer_release(&bw); - block_reader_init(&br, &block, header_off, block_size, GIT_SHA1_RAWSZ); + block_reader_init(&br, &block, header_off, block_size, REFTABLE_HASH_SIZE_SHA1); block_iter_seek_start(&it, &br); @@ -337,7 +337,7 @@ static void t_index_block_read_write(void) check_int(i, ==, N); break; } - check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ)); + check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); } for (i = 0; i < N; i++) { @@ -350,7 +350,7 @@ static void t_index_block_read_write(void) ret = block_iter_next(&it, &rec); check_int(ret, ==, 0); - check(reftable_record_equal(&recs[i], &rec, GIT_SHA1_RAWSZ)); + check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); want.len--; ret = block_iter_seek_key(&it, &br, &want); @@ -358,7 +358,7 @@ static void t_index_block_read_write(void) ret = block_iter_next(&it, &rec); check_int(ret, ==, 0); - check(reftable_record_equal(&recs[10 * (i / 10)], &rec, GIT_SHA1_RAWSZ)); + check(reftable_record_equal(&recs[10 * (i / 10)], &rec, REFTABLE_HASH_SIZE_SHA1)); } block_reader_release(&br); diff --git a/t/unit-tests/t-reftable-merged.c b/t/unit-tests/t-reftable-merged.c index 484c18251f..0573d9470a 100644 --- a/t/unit-tests/t-reftable-merged.c +++ b/t/unit-tests/t-reftable-merged.c @@ -42,7 +42,7 @@ merged_table_from_records(struct reftable_ref_record **refs, check(!err); } - err = reftable_merged_table_new(&mt, *readers, n, GIT_SHA1_FORMAT_ID); + err = reftable_merged_table_new(&mt, *readers, n, REFTABLE_HASH_SHA1); check(!err); return mt; } @@ -91,7 +91,7 @@ static void t_merged_single_record(void) err = reftable_iterator_next_ref(&it, &ref); check(!err); - check(reftable_ref_record_equal(&r2[0], &ref, GIT_SHA1_RAWSZ)); + check(reftable_ref_record_equal(&r2[0], &ref, REFTABLE_HASH_SIZE_SHA1)); reftable_ref_record_release(&ref); reftable_iterator_destroy(&it); readers_destroy(readers, 3); @@ -168,7 +168,7 @@ static void t_merged_refs(void) check(!err); err = reftable_iterator_seek_ref(&it, "a"); check(!err); - check_int(reftable_merged_table_hash_id(mt), ==, GIT_SHA1_FORMAT_ID); + check_int(reftable_merged_table_hash_id(mt), ==, REFTABLE_HASH_SHA1); check_int(reftable_merged_table_min_update_index(mt), ==, 1); check_int(reftable_merged_table_max_update_index(mt), ==, 3); @@ -186,7 +186,7 @@ static void t_merged_refs(void) check_int(ARRAY_SIZE(want), ==, len); for (i = 0; i < len; i++) check(reftable_ref_record_equal(want[i], &out[i], - GIT_SHA1_RAWSZ)); + REFTABLE_HASH_SIZE_SHA1)); for (i = 0; i < len; i++) reftable_ref_record_release(&out[i]); reftable_free(out); @@ -252,12 +252,12 @@ static void t_merged_seek_multiple_times(void) err = reftable_iterator_next_ref(&it, &rec); check(!err); - err = reftable_ref_record_equal(&rec, &r1[1], GIT_SHA1_RAWSZ); + err = reftable_ref_record_equal(&rec, &r1[1], REFTABLE_HASH_SIZE_SHA1); check(err == 1); err = reftable_iterator_next_ref(&it, &rec); check(!err); - err = reftable_ref_record_equal(&rec, &r2[1], GIT_SHA1_RAWSZ); + err = reftable_ref_record_equal(&rec, &r2[1], REFTABLE_HASH_SIZE_SHA1); check(err == 1); err = reftable_iterator_next_ref(&it, &rec); @@ -300,7 +300,7 @@ merged_table_from_log_records(struct reftable_log_record **logs, check(!err); } - err = reftable_merged_table_new(&mt, *readers, n, GIT_SHA1_FORMAT_ID); + err = reftable_merged_table_new(&mt, *readers, n, REFTABLE_HASH_SHA1); check(!err); return mt; } @@ -377,7 +377,7 @@ static void t_merged_logs(void) check(!err); err = reftable_iterator_seek_log(&it, "a"); check(!err); - check_int(reftable_merged_table_hash_id(mt), ==, GIT_SHA1_FORMAT_ID); + check_int(reftable_merged_table_hash_id(mt), ==, REFTABLE_HASH_SHA1); check_int(reftable_merged_table_min_update_index(mt), ==, 1); check_int(reftable_merged_table_max_update_index(mt), ==, 3); @@ -395,7 +395,7 @@ static void t_merged_logs(void) check_int(ARRAY_SIZE(want), ==, len); for (i = 0; i < len; i++) check(reftable_log_record_equal(want[i], &out[i], - GIT_SHA1_RAWSZ)); + REFTABLE_HASH_SIZE_SHA1)); err = merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG); check(!err); @@ -404,7 +404,7 @@ static void t_merged_logs(void) reftable_log_record_release(&out[0]); err = reftable_iterator_next_log(&it, &out[0]); check(!err); - check(reftable_log_record_equal(&out[0], &r3[0], GIT_SHA1_RAWSZ)); + check(reftable_log_record_equal(&out[0], &r3[0], REFTABLE_HASH_SIZE_SHA1)); reftable_iterator_destroy(&it); for (i = 0; i < len; i++) @@ -448,11 +448,11 @@ static void t_default_write_opts(void) check(!err); hash_id = reftable_reader_hash_id(rd); - check_int(hash_id, ==, GIT_SHA1_FORMAT_ID); + check_int(hash_id, ==, REFTABLE_HASH_SHA1); - err = reftable_merged_table_new(&merged, &rd, 1, GIT_SHA256_FORMAT_ID); + err = reftable_merged_table_new(&merged, &rd, 1, REFTABLE_HASH_SHA256); check_int(err, ==, REFTABLE_FORMAT_ERROR); - err = reftable_merged_table_new(&merged, &rd, 1, GIT_SHA1_FORMAT_ID); + err = reftable_merged_table_new(&merged, &rd, 1, REFTABLE_HASH_SHA1); check(!err); reftable_reader_decref(rd); diff --git a/t/unit-tests/t-reftable-pq.c b/t/unit-tests/t-reftable-pq.c index ada4c19f18..272da05bea 100644 --- a/t/unit-tests/t-reftable-pq.c +++ b/t/unit-tests/t-reftable-pq.c @@ -132,7 +132,7 @@ static void t_merged_iter_pqueue_top(void) merged_iter_pqueue_check(&pq); check(pq_entry_equal(&top, &e)); - check(reftable_record_equal(top.rec, &recs[i], GIT_SHA1_RAWSZ)); + check(reftable_record_equal(top.rec, &recs[i], REFTABLE_HASH_SIZE_SHA1)); for (size_t j = 0; i < pq.len; j++) { check(pq_less(&top, &pq.heap[j])); check_int(top.index, >, j); diff --git a/t/unit-tests/t-reftable-reader.c b/t/unit-tests/t-reftable-reader.c index 19cb53b641..546df6005e 100644 --- a/t/unit-tests/t-reftable-reader.c +++ b/t/unit-tests/t-reftable-reader.c @@ -31,7 +31,7 @@ static int t_reader_seek_once(void) ret = reftable_iterator_next_ref(&it, &ref); check(!ret); - ret = reftable_ref_record_equal(&ref, &records[0], GIT_SHA1_RAWSZ); + ret = reftable_ref_record_equal(&ref, &records[0], REFTABLE_HASH_SIZE_SHA1); check_int(ret, ==, 1); ret = reftable_iterator_next_ref(&it, &ref); @@ -74,7 +74,7 @@ static int t_reader_reseek(void) ret = reftable_iterator_next_ref(&it, &ref); check(!ret); - ret = reftable_ref_record_equal(&ref, &records[0], GIT_SHA1_RAWSZ); + ret = reftable_ref_record_equal(&ref, &records[0], REFTABLE_HASH_SIZE_SHA1); check_int(ret, ==, 1); ret = reftable_iterator_next_ref(&it, &ref); diff --git a/t/unit-tests/t-reftable-readwrite.c b/t/unit-tests/t-reftable-readwrite.c index d279b86df0..57896922eb 100644 --- a/t/unit-tests/t-reftable-readwrite.c +++ b/t/unit-tests/t-reftable-readwrite.c @@ -41,7 +41,7 @@ static void t_buffer(void) } static void write_table(char ***names, struct reftable_buf *buf, int N, - int block_size, uint32_t hash_id) + int block_size, enum reftable_hash hash_id) { struct reftable_write_options opts = { .block_size = block_size, @@ -62,7 +62,7 @@ static void write_table(char ***names, struct reftable_buf *buf, int N, refs[i].refname = (*names)[i] = xstrfmt("refs/heads/branch%02d", i); refs[i].update_index = update_index; refs[i].value_type = REFTABLE_REF_VAL1; - t_reftable_set_hash(refs[i].value.val1, i, GIT_SHA1_FORMAT_ID); + t_reftable_set_hash(refs[i].value.val1, i, REFTABLE_HASH_SHA1); } for (i = 0; i < N; i++) { @@ -70,7 +70,7 @@ static void write_table(char ***names, struct reftable_buf *buf, int N, logs[i].update_index = update_index; logs[i].value_type = REFTABLE_LOG_UPDATE; t_reftable_set_hash(logs[i].value.update.new_hash, i, - GIT_SHA1_FORMAT_ID); + REFTABLE_HASH_SHA1); logs[i].value.update.message = (char *) "message"; } @@ -104,7 +104,7 @@ static void t_log_buffer_size(void) /* This tests buffer extension for log compression. Must use a random hash, to ensure that the compressed part is larger than the original. */ - for (i = 0; i < GIT_SHA1_RAWSZ; i++) { + for (i = 0; i < REFTABLE_HASH_SIZE_SHA1; i++) { log.value.update.old_hash[i] = (uint8_t)(git_rand() % 256); log.value.update.new_hash[i] = (uint8_t)(git_rand() % 256); } @@ -191,9 +191,9 @@ static void t_log_write_read(void) log.update_index = i; log.value_type = REFTABLE_LOG_UPDATE; t_reftable_set_hash(log.value.update.old_hash, i, - GIT_SHA1_FORMAT_ID); + REFTABLE_HASH_SHA1); t_reftable_set_hash(log.value.update.new_hash, i + 1, - GIT_SHA1_FORMAT_ID); + REFTABLE_HASH_SHA1); err = reftable_writer_add_log(w, &log); check(!err); @@ -326,7 +326,7 @@ static void t_table_read_write_sequential(void) int err = 0; int j = 0; - write_table(&names, &buf, N, 256, GIT_SHA1_FORMAT_ID); + write_table(&names, &buf, N, 256, REFTABLE_HASH_SHA1); block_source_from_buf(&source, &buf); @@ -361,7 +361,7 @@ static void t_table_write_small_table(void) char **names; struct reftable_buf buf = REFTABLE_BUF_INIT; int N = 1; - write_table(&names, &buf, N, 4096, GIT_SHA1_FORMAT_ID); + write_table(&names, &buf, N, 4096, REFTABLE_HASH_SHA1); check_int(buf.len, <, 200); reftable_buf_release(&buf); free_names(names); @@ -378,7 +378,7 @@ static void t_table_read_api(void) struct reftable_log_record log = { 0 }; struct reftable_iterator it = { 0 }; - write_table(&names, &buf, N, 256, GIT_SHA1_FORMAT_ID); + write_table(&names, &buf, N, 256, REFTABLE_HASH_SHA1); block_source_from_buf(&source, &buf); @@ -400,7 +400,7 @@ static void t_table_read_api(void) reftable_buf_release(&buf); } -static void t_table_read_write_seek(int index, int hash_id) +static void t_table_read_write_seek(int index, enum reftable_hash hash_id) { char **names; struct reftable_buf buf = REFTABLE_BUF_INIT; @@ -467,24 +467,24 @@ static void t_table_read_write_seek(int index, int hash_id) static void t_table_read_write_seek_linear(void) { - t_table_read_write_seek(0, GIT_SHA1_FORMAT_ID); + t_table_read_write_seek(0, REFTABLE_HASH_SHA1); } static void t_table_read_write_seek_linear_sha256(void) { - t_table_read_write_seek(0, GIT_SHA256_FORMAT_ID); + t_table_read_write_seek(0, REFTABLE_HASH_SHA256); } static void t_table_read_write_seek_index(void) { - t_table_read_write_seek(1, GIT_SHA1_FORMAT_ID); + t_table_read_write_seek(1, REFTABLE_HASH_SHA1); } static void t_table_refs_for(int indexed) { char **want_names; int want_names_len = 0; - uint8_t want_hash[GIT_SHA1_RAWSZ]; + uint8_t want_hash[REFTABLE_HASH_SIZE_SHA1]; struct reftable_write_options opts = { .block_size = 256, @@ -500,10 +500,10 @@ static void t_table_refs_for(int indexed) want_names = reftable_calloc(N + 1, sizeof(*want_names)); check(want_names != NULL); - t_reftable_set_hash(want_hash, 4, GIT_SHA1_FORMAT_ID); + t_reftable_set_hash(want_hash, 4, REFTABLE_HASH_SHA1); for (i = 0; i < N; i++) { - uint8_t hash[GIT_SHA1_RAWSZ]; + uint8_t hash[REFTABLE_HASH_SIZE_SHA1]; char fill[51] = { 0 }; char name[100]; struct reftable_ref_record ref = { 0 }; @@ -517,9 +517,9 @@ static void t_table_refs_for(int indexed) ref.value_type = REFTABLE_REF_VAL2; t_reftable_set_hash(ref.value.val2.value, i / 4, - GIT_SHA1_FORMAT_ID); + REFTABLE_HASH_SHA1); t_reftable_set_hash(ref.value.val2.target_value, 3 + i / 4, - GIT_SHA1_FORMAT_ID); + REFTABLE_HASH_SHA1); /* 80 bytes / entry, so 3 entries per block. Yields 17 */ @@ -527,8 +527,8 @@ static void t_table_refs_for(int indexed) n = reftable_writer_add_ref(w, &ref); check_int(n, ==, 0); - if (!memcmp(ref.value.val2.value, want_hash, GIT_SHA1_RAWSZ) || - !memcmp(ref.value.val2.target_value, want_hash, GIT_SHA1_RAWSZ)) + if (!memcmp(ref.value.val2.value, want_hash, REFTABLE_HASH_SIZE_SHA1) || + !memcmp(ref.value.val2.target_value, want_hash, REFTABLE_HASH_SIZE_SHA1)) want_names[want_names_len++] = xstrdup(name); } diff --git a/t/unit-tests/t-reftable-record.c b/t/unit-tests/t-reftable-record.c index eb98bf2da9..42bc64cec8 100644 --- a/t/unit-tests/t-reftable-record.c +++ b/t/unit-tests/t-reftable-record.c @@ -7,6 +7,7 @@ */ #include "test-lib.h" +#include "reftable/basics.h" #include "reftable/constants.h" #include "reftable/record.h" @@ -17,10 +18,10 @@ static void t_copy(struct reftable_record *rec) typ = reftable_record_type(rec); reftable_record_init(©, typ); - reftable_record_copy_from(©, rec, GIT_SHA1_RAWSZ); + reftable_record_copy_from(©, rec, REFTABLE_HASH_SIZE_SHA1); /* do it twice to catch memory leaks */ - reftable_record_copy_from(©, rec, GIT_SHA1_RAWSZ); - check(reftable_record_equal(rec, ©, GIT_SHA1_RAWSZ)); + reftable_record_copy_from(©, rec, REFTABLE_HASH_SIZE_SHA1); + check(reftable_record_equal(rec, ©, REFTABLE_HASH_SIZE_SHA1)); reftable_record_release(©); } @@ -59,7 +60,7 @@ static void t_varint_roundtrip(void) static void set_hash(uint8_t *h, int j) { - for (int i = 0; i < hash_size(GIT_SHA1_FORMAT_ID); i++) + for (int i = 0; i < hash_size(REFTABLE_HASH_SHA1); i++) h[i] = (j >> i) & 0xff; } @@ -84,14 +85,14 @@ static void t_reftable_ref_record_comparison(void) }, }; - check(!reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(!reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1)); check(!reftable_record_cmp(&in[0], &in[1])); - check(!reftable_record_equal(&in[1], &in[2], GIT_SHA1_RAWSZ)); + check(!reftable_record_equal(&in[1], &in[2], REFTABLE_HASH_SIZE_SHA1)); check_int(reftable_record_cmp(&in[1], &in[2]), >, 0); in[1].u.ref.value_type = in[0].u.ref.value_type; - check(reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1)); check(!reftable_record_cmp(&in[0], &in[1])); } @@ -155,15 +156,15 @@ static void t_reftable_ref_record_roundtrip(void) check_int(reftable_record_is_deletion(&in), ==, i == REFTABLE_REF_DELETION); reftable_record_key(&in, &key); - n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ); + n = reftable_record_encode(&in, dest, REFTABLE_HASH_SIZE_SHA1); check_int(n, >, 0); /* decode into a non-zero reftable_record to test for leaks. */ - m = reftable_record_decode(&out, key, i, dest, GIT_SHA1_RAWSZ, &scratch); + m = reftable_record_decode(&out, key, i, dest, REFTABLE_HASH_SIZE_SHA1, &scratch); check_int(n, ==, m); check(reftable_ref_record_equal(&in.u.ref, &out.u.ref, - GIT_SHA1_RAWSZ)); + REFTABLE_HASH_SIZE_SHA1)); reftable_record_release(&in); reftable_buf_release(&key); @@ -193,15 +194,15 @@ static void t_reftable_log_record_comparison(void) }, }; - check(!reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); - check(!reftable_record_equal(&in[1], &in[2], GIT_SHA1_RAWSZ)); + check(!reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1)); + check(!reftable_record_equal(&in[1], &in[2], REFTABLE_HASH_SIZE_SHA1)); check_int(reftable_record_cmp(&in[1], &in[2]), >, 0); /* comparison should be reversed for equal keys, because * comparison is now performed on the basis of update indices */ check_int(reftable_record_cmp(&in[0], &in[1]), <, 0); in[1].u.log.update_index = in[0].u.log.update_index; - check(reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1)); check(!reftable_record_cmp(&in[0], &in[1])); } @@ -303,15 +304,15 @@ static void t_reftable_log_record_roundtrip(void) reftable_record_key(&rec, &key); - n = reftable_record_encode(&rec, dest, GIT_SHA1_RAWSZ); + n = reftable_record_encode(&rec, dest, REFTABLE_HASH_SIZE_SHA1); check_int(n, >=, 0); valtype = reftable_record_val_type(&rec); m = reftable_record_decode(&out, key, valtype, dest, - GIT_SHA1_RAWSZ, &scratch); + REFTABLE_HASH_SIZE_SHA1, &scratch); check_int(n, ==, m); check(reftable_log_record_equal(&in[i], &out.u.log, - GIT_SHA1_RAWSZ)); + REFTABLE_HASH_SIZE_SHA1)); reftable_log_record_release(&in[i]); reftable_buf_release(&key); reftable_record_release(&out); @@ -380,20 +381,20 @@ static void t_reftable_obj_record_comparison(void) }, }; - check(!reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(!reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1)); check(!reftable_record_cmp(&in[0], &in[1])); - check(!reftable_record_equal(&in[1], &in[2], GIT_SHA1_RAWSZ)); + check(!reftable_record_equal(&in[1], &in[2], REFTABLE_HASH_SIZE_SHA1)); check_int(reftable_record_cmp(&in[1], &in[2]), >, 0); in[1].u.obj.offset_len = in[0].u.obj.offset_len; - check(reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1)); check(!reftable_record_cmp(&in[0], &in[1])); } static void t_reftable_obj_record_roundtrip(void) { - uint8_t testHash1[GIT_SHA1_RAWSZ] = { 1, 2, 3, 4, 0 }; + uint8_t testHash1[REFTABLE_HASH_SIZE_SHA1] = { 1, 2, 3, 4, 0 }; uint64_t till9[] = { 1, 2, 3, 4, 500, 600, 700, 800, 9000 }; struct reftable_obj_record recs[3] = { { @@ -435,14 +436,14 @@ static void t_reftable_obj_record_roundtrip(void) check(!reftable_record_is_deletion(&in)); t_copy(&in); reftable_record_key(&in, &key); - n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ); + n = reftable_record_encode(&in, dest, REFTABLE_HASH_SIZE_SHA1); check_int(n, >, 0); extra = reftable_record_val_type(&in); m = reftable_record_decode(&out, key, extra, dest, - GIT_SHA1_RAWSZ, &scratch); + REFTABLE_HASH_SIZE_SHA1, &scratch); check_int(n, ==, m); - check(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ)); + check(reftable_record_equal(&in, &out, REFTABLE_HASH_SIZE_SHA1)); reftable_buf_release(&key); reftable_record_release(&out); } @@ -473,14 +474,14 @@ static void t_reftable_index_record_comparison(void) check(!reftable_buf_addstr(&in[1].u.idx.last_key, "refs/heads/master")); check(!reftable_buf_addstr(&in[2].u.idx.last_key, "refs/heads/branch")); - check(!reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(!reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1)); check(!reftable_record_cmp(&in[0], &in[1])); - check(!reftable_record_equal(&in[1], &in[2], GIT_SHA1_RAWSZ)); + check(!reftable_record_equal(&in[1], &in[2], REFTABLE_HASH_SIZE_SHA1)); check_int(reftable_record_cmp(&in[1], &in[2]), >, 0); in[1].u.idx.offset = in[0].u.idx.offset; - check(reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1)); check(!reftable_record_cmp(&in[0], &in[1])); for (size_t i = 0; i < ARRAY_SIZE(in); i++) @@ -516,15 +517,15 @@ static void t_reftable_index_record_roundtrip(void) check(!reftable_record_is_deletion(&in)); check(!reftable_buf_cmp(&key, &in.u.idx.last_key)); - n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ); + n = reftable_record_encode(&in, dest, REFTABLE_HASH_SIZE_SHA1); check_int(n, >, 0); extra = reftable_record_val_type(&in); - m = reftable_record_decode(&out, key, extra, dest, GIT_SHA1_RAWSZ, + m = reftable_record_decode(&out, key, extra, dest, REFTABLE_HASH_SIZE_SHA1, &scratch); check_int(m, ==, n); - check(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ)); + check(reftable_record_equal(&in, &out, REFTABLE_HASH_SIZE_SHA1)); reftable_record_release(&out); reftable_buf_release(&key); diff --git a/t/unit-tests/t-reftable-stack.c b/t/unit-tests/t-reftable-stack.c index 1b4363a58f..13fd8d8f94 100644 --- a/t/unit-tests/t-reftable-stack.c +++ b/t/unit-tests/t-reftable-stack.c @@ -121,7 +121,7 @@ static void write_n_ref_tables(struct reftable_stack *st, snprintf(buf, sizeof(buf), "refs/heads/branch-%04"PRIuMAX, (uintmax_t)i); ref.refname = buf; - t_reftable_set_hash(ref.value.val1, i, GIT_SHA1_FORMAT_ID); + t_reftable_set_hash(ref.value.val1, i, REFTABLE_HASH_SHA1); err = reftable_stack_add(st, &write_test_ref, &ref); check(!err); @@ -169,7 +169,7 @@ static void t_reftable_stack_add_one(void) err = reftable_stack_read_ref(st, ref.refname, &dest); check(!err); - check(reftable_ref_record_equal(&ref, &dest, GIT_SHA1_RAWSZ)); + check(reftable_ref_record_equal(&ref, &dest, REFTABLE_HASH_SIZE_SHA1)); check_int(st->readers_len, >, 0); #ifndef GIT_WINDOWS_NATIVE @@ -280,7 +280,7 @@ static void t_reftable_stack_transaction_api(void) err = reftable_stack_read_ref(st, ref.refname, &dest); check(!err); check_int(REFTABLE_REF_SYMREF, ==, dest.value_type); - check(reftable_ref_record_equal(&ref, &dest, GIT_SHA1_RAWSZ)); + check(reftable_ref_record_equal(&ref, &dest, REFTABLE_HASH_SIZE_SHA1)); reftable_ref_record_release(&dest); reftable_stack_destroy(st); @@ -340,7 +340,7 @@ static void t_reftable_stack_transaction_with_reload(void) for (size_t i = 0; i < ARRAY_SIZE(refs); i++) { err = reftable_stack_read_ref(st2, refs[i].refname, &ref); check(!err); - check(reftable_ref_record_equal(&refs[i], &ref, GIT_SHA1_RAWSZ)); + check(reftable_ref_record_equal(&refs[i], &ref, REFTABLE_HASH_SIZE_SHA1)); } reftable_ref_record_release(&ref); @@ -530,13 +530,13 @@ static void t_reftable_stack_add(void) refs[i].refname = xstrdup(buf); refs[i].update_index = i + 1; refs[i].value_type = REFTABLE_REF_VAL1; - t_reftable_set_hash(refs[i].value.val1, i, GIT_SHA1_FORMAT_ID); + t_reftable_set_hash(refs[i].value.val1, i, REFTABLE_HASH_SHA1); logs[i].refname = xstrdup(buf); logs[i].update_index = N + i + 1; logs[i].value_type = REFTABLE_LOG_UPDATE; logs[i].value.update.email = xstrdup("identity@invalid"); - t_reftable_set_hash(logs[i].value.update.new_hash, i, GIT_SHA1_FORMAT_ID); + t_reftable_set_hash(logs[i].value.update.new_hash, i, REFTABLE_HASH_SHA1); } for (i = 0; i < N; i++) { @@ -562,7 +562,7 @@ static void t_reftable_stack_add(void) int err = reftable_stack_read_ref(st, refs[i].refname, &dest); check(!err); check(reftable_ref_record_equal(&dest, refs + i, - GIT_SHA1_RAWSZ)); + REFTABLE_HASH_SIZE_SHA1)); reftable_ref_record_release(&dest); } @@ -571,7 +571,7 @@ static void t_reftable_stack_add(void) int err = reftable_stack_read_log(st, refs[i].refname, &dest); check(!err); check(reftable_log_record_equal(&dest, logs + i, - GIT_SHA1_RAWSZ)); + REFTABLE_HASH_SIZE_SHA1)); reftable_log_record_release(&dest); } @@ -622,14 +622,14 @@ static void t_reftable_stack_iterator(void) refs[i].refname = xstrfmt("branch%02"PRIuMAX, (uintmax_t)i); refs[i].update_index = i + 1; refs[i].value_type = REFTABLE_REF_VAL1; - t_reftable_set_hash(refs[i].value.val1, i, GIT_SHA1_FORMAT_ID); + t_reftable_set_hash(refs[i].value.val1, i, REFTABLE_HASH_SHA1); logs[i].refname = xstrfmt("branch%02"PRIuMAX, (uintmax_t)i); logs[i].update_index = i + 1; logs[i].value_type = REFTABLE_LOG_UPDATE; logs[i].value.update.email = xstrdup("johndoe@invalid"); logs[i].value.update.message = xstrdup("commit\n"); - t_reftable_set_hash(logs[i].value.update.new_hash, i, GIT_SHA1_FORMAT_ID); + t_reftable_set_hash(logs[i].value.update.new_hash, i, REFTABLE_HASH_SHA1); } for (i = 0; i < N; i++) { @@ -656,7 +656,7 @@ static void t_reftable_stack_iterator(void) if (err > 0) break; check(!err); - check(reftable_ref_record_equal(&ref, &refs[i], GIT_SHA1_RAWSZ)); + check(reftable_ref_record_equal(&ref, &refs[i], REFTABLE_HASH_SIZE_SHA1)); reftable_ref_record_release(&ref); } check_int(i, ==, N); @@ -674,7 +674,7 @@ static void t_reftable_stack_iterator(void) if (err > 0) break; check(!err); - check(reftable_log_record_equal(&log, &logs[i], GIT_SHA1_RAWSZ)); + check(reftable_log_record_equal(&log, &logs[i], REFTABLE_HASH_SIZE_SHA1)); reftable_log_record_release(&log); } check_int(i, ==, N); @@ -767,7 +767,7 @@ static void t_reftable_stack_tombstone(void) if (i % 2 == 0) { refs[i].value_type = REFTABLE_REF_VAL1; t_reftable_set_hash(refs[i].value.val1, i, - GIT_SHA1_FORMAT_ID); + REFTABLE_HASH_SHA1); } logs[i].refname = xstrdup(buf); @@ -776,7 +776,7 @@ static void t_reftable_stack_tombstone(void) if (i % 2 == 0) { logs[i].value_type = REFTABLE_LOG_UPDATE; t_reftable_set_hash(logs[i].value.update.new_hash, i, - GIT_SHA1_FORMAT_ID); + REFTABLE_HASH_SHA1); logs[i].value.update.email = xstrdup("identity@invalid"); } @@ -836,7 +836,7 @@ static void t_reftable_stack_hash_id(void) .value.symref = (char *) "target", .update_index = 1, }; - struct reftable_write_options opts32 = { .hash_id = GIT_SHA256_FORMAT_ID }; + struct reftable_write_options opts32 = { .hash_id = REFTABLE_HASH_SHA256 }; struct reftable_stack *st32 = NULL; struct reftable_write_options opts_default = { 0 }; struct reftable_stack *st_default = NULL; @@ -859,7 +859,7 @@ static void t_reftable_stack_hash_id(void) err = reftable_stack_read_ref(st_default, "master", &dest); check(!err); - check(reftable_ref_record_equal(&ref, &dest, GIT_SHA1_RAWSZ)); + check(reftable_ref_record_equal(&ref, &dest, REFTABLE_HASH_SIZE_SHA1)); reftable_ref_record_release(&dest); reftable_stack_destroy(st); reftable_stack_destroy(st_default); @@ -909,7 +909,7 @@ static void t_reflog_expire(void) logs[i].value.update.time = i; logs[i].value.update.email = xstrdup("identity@invalid"); t_reftable_set_hash(logs[i].value.update.new_hash, i, - GIT_SHA1_FORMAT_ID); + REFTABLE_HASH_SHA1); } for (i = 1; i <= N; i++) { -- cgit v1.2.3 From 86b770b0bbf1aba3c8e43401936258c58648703a Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 18 Nov 2024 16:34:00 +0100 Subject: reftable/stack: stop using `fsync_component()` directly We're executing `fsync_component()` directly in the reftable library so that we can fsync data to disk depending on "core.fsync". But as we're in the process of converting the reftable library to become standalone we cannot use that function in the library anymore. Refactor the code such that users of the library can inject a custom fsync function via the write options. This allows us to get rid of the dependency on "write-or-die.h". Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- refs/reftable-backend.c | 7 +++++++ reftable/reftable-writer.h | 6 ++++++ reftable/stack.c | 49 ++++++++++++++++++++++++++++++---------------- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c index 7d86d92097..2e774176ed 100644 --- a/refs/reftable-backend.c +++ b/refs/reftable-backend.c @@ -24,6 +24,7 @@ #include "../setup.h" #include "../strmap.h" #include "../trace2.h" +#include "../write-or-die.h" #include "parse.h" #include "refs-internal.h" @@ -273,6 +274,11 @@ static int reftable_be_config(const char *var, const char *value, return 0; } +static int reftable_be_fsync(int fd) +{ + return fsync_component(FSYNC_COMPONENT_REFERENCE, fd); +} + static struct ref_store *reftable_be_init(struct repository *repo, const char *gitdir, unsigned int store_flags) @@ -304,6 +310,7 @@ static struct ref_store *reftable_be_init(struct repository *repo, refs->write_options.disable_auto_compact = !git_env_bool("GIT_TEST_REFTABLE_AUTOCOMPACTION", 1); refs->write_options.lock_timeout_ms = 100; + refs->write_options.fsync = reftable_be_fsync; git_config(reftable_be_config, &refs->write_options); diff --git a/reftable/reftable-writer.h b/reftable/reftable-writer.h index 211860d08a..c85ef5a5bd 100644 --- a/reftable/reftable-writer.h +++ b/reftable/reftable-writer.h @@ -62,6 +62,12 @@ struct reftable_write_options { * negative value will cause us to block indefinitely. */ long lock_timeout_ms; + + /* + * Optional callback used to fsync files to disk. Falls back to using + * fsync(3P) when unset. + */ + int (*fsync)(int fd); }; /* reftable_block_stats holds statistics for a single block type */ diff --git a/reftable/stack.c b/reftable/stack.c index 9ae716ff37..c67bdd952c 100644 --- a/reftable/stack.c +++ b/reftable/stack.c @@ -8,7 +8,6 @@ https://developers.google.com/open-source/licenses/bsd #include "stack.h" -#include "../write-or-die.h" #include "system.h" #include "constants.h" #include "merged.h" @@ -43,17 +42,28 @@ static int stack_filename(struct reftable_buf *dest, struct reftable_stack *st, return 0; } -static ssize_t reftable_fd_write(void *arg, const void *data, size_t sz) +static int stack_fsync(const struct reftable_write_options *opts, int fd) { - int *fdp = (int *)arg; - return write_in_full(*fdp, data, sz); + if (opts->fsync) + return opts->fsync(fd); + return fsync(fd); } -static int reftable_fd_flush(void *arg) +struct fd_writer { + const struct reftable_write_options *opts; + int fd; +}; + +static ssize_t fd_writer_write(void *arg, const void *data, size_t sz) { - int *fdp = (int *)arg; + struct fd_writer *writer = arg; + return write_in_full(writer->fd, data, sz); +} - return fsync_component(FSYNC_COMPONENT_REFERENCE, *fdp); +static int fd_writer_flush(void *arg) +{ + struct fd_writer *writer = arg; + return stack_fsync(writer->opts, writer->fd); } int reftable_new_stack(struct reftable_stack **dest, const char *dir, @@ -765,7 +775,7 @@ int reftable_addition_commit(struct reftable_addition *add) goto done; } - err = fsync_component(FSYNC_COMPONENT_REFERENCE, lock_file_fd); + err = stack_fsync(&add->stack->opts, lock_file_fd); if (err < 0) { err = REFTABLE_IO_ERROR; goto done; @@ -858,8 +868,10 @@ int reftable_addition_add(struct reftable_addition *add, struct reftable_buf next_name = REFTABLE_BUF_INIT; struct reftable_writer *wr = NULL; struct tempfile *tab_file = NULL; + struct fd_writer writer = { + .opts = &add->stack->opts, + }; int err = 0; - int tab_fd; reftable_buf_reset(&next_name); @@ -887,10 +899,10 @@ int reftable_addition_add(struct reftable_addition *add, goto done; } } - tab_fd = get_tempfile_fd(tab_file); - err = reftable_writer_new(&wr, reftable_fd_write, reftable_fd_flush, - &tab_fd, &add->stack->opts); + writer.fd = get_tempfile_fd(tab_file); + err = reftable_writer_new(&wr, fd_writer_write, fd_writer_flush, + &writer, &add->stack->opts); if (err < 0) goto done; @@ -973,8 +985,11 @@ static int stack_compact_locked(struct reftable_stack *st, struct reftable_buf next_name = REFTABLE_BUF_INIT; struct reftable_buf tab_file_path = REFTABLE_BUF_INIT; struct reftable_writer *wr = NULL; + struct fd_writer writer= { + .opts = &st->opts, + }; struct tempfile *tab_file; - int tab_fd, err = 0; + int err = 0; err = format_name(&next_name, reftable_reader_min_update_index(st->readers[first]), reftable_reader_max_update_index(st->readers[last])); @@ -994,7 +1009,6 @@ static int stack_compact_locked(struct reftable_stack *st, err = REFTABLE_IO_ERROR; goto done; } - tab_fd = get_tempfile_fd(tab_file); if (st->opts.default_permissions && chmod(get_tempfile_path(tab_file), st->opts.default_permissions) < 0) { @@ -1002,8 +1016,9 @@ static int stack_compact_locked(struct reftable_stack *st, goto done; } - err = reftable_writer_new(&wr, reftable_fd_write, reftable_fd_flush, - &tab_fd, &st->opts); + writer.fd = get_tempfile_fd(tab_file); + err = reftable_writer_new(&wr, fd_writer_write, fd_writer_flush, + &writer, &st->opts); if (err < 0) goto done; @@ -1460,7 +1475,7 @@ static int stack_compact_range(struct reftable_stack *st, goto done; } - err = fsync_component(FSYNC_COMPONENT_REFERENCE, get_lock_file_fd(&tables_list_lock)); + err = stack_fsync(&st->opts, get_lock_file_fd(&tables_list_lock)); if (err < 0) { err = REFTABLE_IO_ERROR; unlink(new_table_path.buf); -- cgit v1.2.3 From 01e49941d6560dfebfac39a2ffe49d3d24b35069 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 18 Nov 2024 16:34:03 +0100 Subject: reftable/system: provide thin wrapper for tempfile subsystem We use the tempfile subsystem to write temporary tables, but given that we're in the process of converting the reftable library to become standalone we cannot use this subsystem directly anymore. While we could in theory convert the code to use mkstemp(3p) instead, we'd lose access to our infrastructure that automatically prunes tempfiles via atexit(3p) or signal handlers. Provide a thin wrapper for the tempfile subsystem instead. Like this, the compatibility shim is fully self-contained in "reftable/system.c". Downstream users of the reftable library would have to implement their own tempfile shims by replacing "system.c" with a custom version. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Makefile | 1 + reftable/stack.c | 57 ++++++++++++++++++++++--------------------------------- reftable/system.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++ reftable/system.h | 42 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 114 insertions(+), 35 deletions(-) create mode 100644 reftable/system.c diff --git a/Makefile b/Makefile index feeed6f932..50a79ad83f 100644 --- a/Makefile +++ b/Makefile @@ -2722,6 +2722,7 @@ REFTABLE_OBJS += reftable/pq.o REFTABLE_OBJS += reftable/reader.o REFTABLE_OBJS += reftable/record.o REFTABLE_OBJS += reftable/stack.o +REFTABLE_OBJS += reftable/system.o REFTABLE_OBJS += reftable/tree.o REFTABLE_OBJS += reftable/writer.o diff --git a/reftable/stack.c b/reftable/stack.c index c67bdd952c..2ac6a37151 100644 --- a/reftable/stack.c +++ b/reftable/stack.c @@ -16,7 +16,6 @@ https://developers.google.com/open-source/licenses/bsd #include "reftable-record.h" #include "reftable-merged.h" #include "writer.h" -#include "tempfile.h" static int stack_try_add(struct reftable_stack *st, int (*write_table)(struct reftable_writer *wr, @@ -867,7 +866,7 @@ int reftable_addition_add(struct reftable_addition *add, struct reftable_buf tab_file_name = REFTABLE_BUF_INIT; struct reftable_buf next_name = REFTABLE_BUF_INIT; struct reftable_writer *wr = NULL; - struct tempfile *tab_file = NULL; + struct reftable_tmpfile tab_file = REFTABLE_TMPFILE_INIT; struct fd_writer writer = { .opts = &add->stack->opts, }; @@ -887,20 +886,18 @@ int reftable_addition_add(struct reftable_addition *add, if (err < 0) goto done; - tab_file = mks_tempfile(temp_tab_file_name.buf); - if (!tab_file) { - err = REFTABLE_IO_ERROR; + err = tmpfile_from_pattern(&tab_file, temp_tab_file_name.buf); + if (err < 0) goto done; - } if (add->stack->opts.default_permissions) { - if (chmod(get_tempfile_path(tab_file), + if (chmod(tab_file.path, add->stack->opts.default_permissions)) { err = REFTABLE_IO_ERROR; goto done; } } - writer.fd = get_tempfile_fd(tab_file); + writer.fd = tab_file.fd; err = reftable_writer_new(&wr, fd_writer_write, fd_writer_flush, &writer, &add->stack->opts); if (err < 0) @@ -918,11 +915,9 @@ int reftable_addition_add(struct reftable_addition *add, if (err < 0) goto done; - err = close_tempfile_gently(tab_file); - if (err < 0) { - err = REFTABLE_IO_ERROR; + err = tmpfile_close(&tab_file); + if (err < 0) goto done; - } if (wr->min_update_index < add->next_update_index) { err = REFTABLE_API_ERROR; @@ -945,11 +940,9 @@ int reftable_addition_add(struct reftable_addition *add, On windows, this relies on rand() picking a unique destination name. Maybe we should do retry loop as well? */ - err = rename_tempfile(&tab_file, tab_file_name.buf); - if (err < 0) { - err = REFTABLE_IO_ERROR; + err = tmpfile_rename(&tab_file, tab_file_name.buf); + if (err < 0) goto done; - } REFTABLE_ALLOC_GROW(add->new_tables, add->new_tables_len + 1, add->new_tables_cap); @@ -960,7 +953,7 @@ int reftable_addition_add(struct reftable_addition *add, add->new_tables[add->new_tables_len++] = reftable_buf_detach(&next_name); done: - delete_tempfile(&tab_file); + tmpfile_delete(&tab_file); reftable_buf_release(&temp_tab_file_name); reftable_buf_release(&tab_file_name); reftable_buf_release(&next_name); @@ -980,7 +973,7 @@ uint64_t reftable_stack_next_update_index(struct reftable_stack *st) static int stack_compact_locked(struct reftable_stack *st, size_t first, size_t last, struct reftable_log_expiry_config *config, - struct tempfile **tab_file_out) + struct reftable_tmpfile *tab_file_out) { struct reftable_buf next_name = REFTABLE_BUF_INIT; struct reftable_buf tab_file_path = REFTABLE_BUF_INIT; @@ -988,7 +981,7 @@ static int stack_compact_locked(struct reftable_stack *st, struct fd_writer writer= { .opts = &st->opts, }; - struct tempfile *tab_file; + struct reftable_tmpfile tab_file = REFTABLE_TMPFILE_INIT; int err = 0; err = format_name(&next_name, reftable_reader_min_update_index(st->readers[first]), @@ -1004,19 +997,17 @@ static int stack_compact_locked(struct reftable_stack *st, if (err < 0) goto done; - tab_file = mks_tempfile(tab_file_path.buf); - if (!tab_file) { - err = REFTABLE_IO_ERROR; + err = tmpfile_from_pattern(&tab_file, tab_file_path.buf); + if (err < 0) goto done; - } if (st->opts.default_permissions && - chmod(get_tempfile_path(tab_file), st->opts.default_permissions) < 0) { + chmod(tab_file.path, st->opts.default_permissions) < 0) { err = REFTABLE_IO_ERROR; goto done; } - writer.fd = get_tempfile_fd(tab_file); + writer.fd = tab_file.fd; err = reftable_writer_new(&wr, fd_writer_write, fd_writer_flush, &writer, &st->opts); if (err < 0) @@ -1030,15 +1021,15 @@ static int stack_compact_locked(struct reftable_stack *st, if (err < 0) goto done; - err = close_tempfile_gently(tab_file); + err = tmpfile_close(&tab_file); if (err < 0) goto done; *tab_file_out = tab_file; - tab_file = NULL; + tab_file = REFTABLE_TMPFILE_INIT; done: - delete_tempfile(&tab_file); + tmpfile_delete(&tab_file); reftable_writer_free(wr); reftable_buf_release(&next_name); reftable_buf_release(&tab_file_path); @@ -1171,7 +1162,7 @@ static int stack_compact_range(struct reftable_stack *st, struct reftable_buf table_name = REFTABLE_BUF_INIT; struct lock_file tables_list_lock = LOCK_INIT; struct lock_file *table_locks = NULL; - struct tempfile *new_table = NULL; + struct reftable_tmpfile new_table = REFTABLE_TMPFILE_INIT; int is_empty_table = 0, err = 0; size_t first_to_replace, last_to_replace; size_t i, nlocks = 0; @@ -1439,11 +1430,9 @@ static int stack_compact_range(struct reftable_stack *st, if (err < 0) goto done; - err = rename_tempfile(&new_table, new_table_path.buf); - if (err < 0) { - err = REFTABLE_IO_ERROR; + err = tmpfile_rename(&new_table, new_table_path.buf); + if (err < 0) goto done; - } } /* @@ -1515,7 +1504,7 @@ done: rollback_lock_file(&table_locks[i]); reftable_free(table_locks); - delete_tempfile(&new_table); + tmpfile_delete(&new_table); reftable_buf_release(&new_table_name); reftable_buf_release(&new_table_path); reftable_buf_release(&tables_list_buf); diff --git a/reftable/system.c b/reftable/system.c new file mode 100644 index 0000000000..01f96f03d8 --- /dev/null +++ b/reftable/system.c @@ -0,0 +1,49 @@ +#include "system.h" +#include "basics.h" +#include "reftable-error.h" +#include "../tempfile.h" + +int tmpfile_from_pattern(struct reftable_tmpfile *out, const char *pattern) +{ + struct tempfile *tempfile; + + tempfile = mks_tempfile(pattern); + if (!tempfile) + return REFTABLE_IO_ERROR; + + out->path = tempfile->filename.buf; + out->fd = tempfile->fd; + out->priv = tempfile; + + return 0; +} + +int tmpfile_close(struct reftable_tmpfile *t) +{ + struct tempfile *tempfile = t->priv; + int ret = close_tempfile_gently(tempfile); + t->fd = -1; + if (ret < 0) + return REFTABLE_IO_ERROR; + return 0; +} + +int tmpfile_delete(struct reftable_tmpfile *t) +{ + struct tempfile *tempfile = t->priv; + int ret = delete_tempfile(&tempfile); + *t = REFTABLE_TMPFILE_INIT; + if (ret < 0) + return REFTABLE_IO_ERROR; + return 0; +} + +int tmpfile_rename(struct reftable_tmpfile *t, const char *path) +{ + struct tempfile *tempfile = t->priv; + int ret = rename_tempfile(&tempfile, path); + *t = REFTABLE_TMPFILE_INIT; + if (ret < 0) + return REFTABLE_IO_ERROR; + return 0; +} diff --git a/reftable/system.h b/reftable/system.h index 38d3534620..858189fd55 100644 --- a/reftable/system.h +++ b/reftable/system.h @@ -13,6 +13,46 @@ https://developers.google.com/open-source/licenses/bsd #include "git-compat-util.h" #include "lockfile.h" -#include "tempfile.h" + +/* + * An implementation-specific temporary file. By making this specific to the + * implementation it becomes possible to tie temporary files into any kind of + * signal or atexit handlers for cleanup on abnormal situations. + */ +struct reftable_tmpfile { + const char *path; + int fd; + void *priv; +}; +#define REFTABLE_TMPFILE_INIT ((struct reftable_tmpfile) { .fd = -1, }) + +/* + * Create a temporary file from a pattern similar to how mkstemp(3p) would. + * The `pattern` shall not be modified. On success, the structure at `out` has + * been initialized such that it is ready for use. Returns 0 on success, a + * reftable error code on error. + */ +int tmpfile_from_pattern(struct reftable_tmpfile *out, const char *pattern); + +/* + * Close the temporary file's file descriptor without removing the file itself. + * This is a no-op in case the file has already been closed beforehand. Returns + * 0 on success, a reftable error code on error. + */ +int tmpfile_close(struct reftable_tmpfile *t); + +/* + * Close the temporary file and delete it. This is a no-op in case the file has + * already been deleted or renamed beforehand. Returns 0 on success, a reftable + * error code on error. + */ +int tmpfile_delete(struct reftable_tmpfile *t); + +/* + * Rename the temporary file to the provided path. The temporary file must be + * active. Return 0 on success, a reftable error code on error. Deactivates the + * temporary file. + */ +int tmpfile_rename(struct reftable_tmpfile *t, const char *path); #endif -- cgit v1.2.3 From 6361226b79d24eb93a14e0b7d25f584269f9d5e6 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 18 Nov 2024 16:34:05 +0100 Subject: reftable/stack: drop only use of `get_locked_file_path()` We've got a single callsite where we call `get_locked_file_path()`. As we're about to convert our usage of the lockfile subsystem to instead be used via a compatibility shim we'd have to implement more logic for this single callsite. While that would be okay if Git was the only supposed user of the reftable library, it's a bit more awkward when considering that we have to reimplement this functionality for every user of the library eventually. Refactor the code such that we don't call `get_locked_file_path()` anymore. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- reftable/stack.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/reftable/stack.c b/reftable/stack.c index 2ac6a37151..223d7c622d 100644 --- a/reftable/stack.c +++ b/reftable/stack.c @@ -1493,9 +1493,15 @@ static int stack_compact_range(struct reftable_stack *st, */ for (i = 0; i < nlocks; i++) { struct lock_file *table_lock = &table_locks[i]; - char *table_path = get_locked_file_path(table_lock); - unlink(table_path); - reftable_free(table_path); + const char *lock_path = get_lock_file_path(table_lock); + + reftable_buf_reset(&table_name); + err = reftable_buf_add(&table_name, lock_path, + strlen(lock_path) - strlen(".lock")); + if (err) + continue; + + unlink(table_name.buf); } done: -- cgit v1.2.3 From 988e7f5e952bbb7b6ae885f4da744f536f22693f Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 18 Nov 2024 16:34:08 +0100 Subject: reftable/system: provide thin wrapper for lockfile subsystem We use the lockfile subsystem to write lockfiles for "tables.list". As with the tempfile subsystem, the lockfile subsystem also hooks into our infrastructure to prune stale locks via atexit(3p) or signal handlers. Furthermore, the lockfile subsystem also handles locking timeouts, which do add quite a bit of logic. Having to reimplement that in the context of Git wouldn't make a whole lot of sense, and it is quite likely that downstream users of the reftable library may have a better idea for how exactly to implement timeouts. So again, provide a thin wrapper for the lockfile subsystem instead such that the compatibility shim is fully self-contained. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- reftable/stack.c | 63 +++++++++++++----------------- reftable/system.c | 77 +++++++++++++++++++++++++++++++++++++ reftable/system.h | 45 +++++++++++++++++++++- t/unit-tests/lib-reftable.c | 1 + t/unit-tests/t-reftable-block.c | 1 + t/unit-tests/t-reftable-pq.c | 1 + t/unit-tests/t-reftable-readwrite.c | 1 + t/unit-tests/t-reftable-stack.c | 2 + 8 files changed, 154 insertions(+), 37 deletions(-) diff --git a/reftable/stack.c b/reftable/stack.c index 223d7c622d..10d45e89d0 100644 --- a/reftable/stack.c +++ b/reftable/stack.c @@ -657,7 +657,7 @@ static int format_name(struct reftable_buf *dest, uint64_t min, uint64_t max) } struct reftable_addition { - struct lock_file tables_list_lock; + struct reftable_flock tables_list_lock; struct reftable_stack *stack; char **new_tables; @@ -676,10 +676,8 @@ static int reftable_stack_init_addition(struct reftable_addition *add, add->stack = st; - err = hold_lock_file_for_update_timeout(&add->tables_list_lock, - st->list_file, - LOCK_NO_DEREF, - st->opts.lock_timeout_ms); + err = flock_acquire(&add->tables_list_lock, st->list_file, + st->opts.lock_timeout_ms); if (err < 0) { if (errno == EEXIST) { err = REFTABLE_LOCK_ERROR; @@ -689,7 +687,7 @@ static int reftable_stack_init_addition(struct reftable_addition *add, goto done; } if (st->opts.default_permissions) { - if (chmod(get_lock_file_path(&add->tables_list_lock), + if (chmod(add->tables_list_lock.path, st->opts.default_permissions) < 0) { err = REFTABLE_IO_ERROR; goto done; @@ -733,7 +731,7 @@ static void reftable_addition_close(struct reftable_addition *add) add->new_tables_len = 0; add->new_tables_cap = 0; - rollback_lock_file(&add->tables_list_lock); + flock_release(&add->tables_list_lock); reftable_buf_release(&nm); } @@ -749,7 +747,6 @@ void reftable_addition_destroy(struct reftable_addition *add) int reftable_addition_commit(struct reftable_addition *add) { struct reftable_buf table_list = REFTABLE_BUF_INIT; - int lock_file_fd = get_lock_file_fd(&add->tables_list_lock); int err = 0; size_t i; @@ -767,20 +764,20 @@ int reftable_addition_commit(struct reftable_addition *add) goto done; } - err = write_in_full(lock_file_fd, table_list.buf, table_list.len); + err = write_in_full(add->tables_list_lock.fd, table_list.buf, table_list.len); reftable_buf_release(&table_list); if (err < 0) { err = REFTABLE_IO_ERROR; goto done; } - err = stack_fsync(&add->stack->opts, lock_file_fd); + err = stack_fsync(&add->stack->opts, add->tables_list_lock.fd); if (err < 0) { err = REFTABLE_IO_ERROR; goto done; } - err = commit_lock_file(&add->tables_list_lock); + err = flock_commit(&add->tables_list_lock); if (err < 0) { err = REFTABLE_IO_ERROR; goto done; @@ -1160,8 +1157,8 @@ static int stack_compact_range(struct reftable_stack *st, struct reftable_buf new_table_name = REFTABLE_BUF_INIT; struct reftable_buf new_table_path = REFTABLE_BUF_INIT; struct reftable_buf table_name = REFTABLE_BUF_INIT; - struct lock_file tables_list_lock = LOCK_INIT; - struct lock_file *table_locks = NULL; + struct reftable_flock tables_list_lock = REFTABLE_FLOCK_INIT; + struct reftable_flock *table_locks = NULL; struct reftable_tmpfile new_table = REFTABLE_TMPFILE_INIT; int is_empty_table = 0, err = 0; size_t first_to_replace, last_to_replace; @@ -1179,10 +1176,7 @@ static int stack_compact_range(struct reftable_stack *st, * Hold the lock so that we can read "tables.list" and lock all tables * which are part of the user-specified range. */ - err = hold_lock_file_for_update_timeout(&tables_list_lock, - st->list_file, - LOCK_NO_DEREF, - st->opts.lock_timeout_ms); + err = flock_acquire(&tables_list_lock, st->list_file, st->opts.lock_timeout_ms); if (err < 0) { if (errno == EEXIST) err = REFTABLE_LOCK_ERROR; @@ -1205,19 +1199,20 @@ static int stack_compact_range(struct reftable_stack *st, * older process is still busy compacting tables which are preexisting * from the point of view of the newer process. */ - REFTABLE_CALLOC_ARRAY(table_locks, last - first + 1); + REFTABLE_ALLOC_ARRAY(table_locks, last - first + 1); if (!table_locks) { err = REFTABLE_OUT_OF_MEMORY_ERROR; goto done; } + for (i = 0; i < last - first + 1; i++) + table_locks[i] = REFTABLE_FLOCK_INIT; for (i = last + 1; i > first; i--) { err = stack_filename(&table_name, st, reader_name(st->readers[i - 1])); if (err < 0) goto done; - err = hold_lock_file_for_update(&table_locks[nlocks], - table_name.buf, LOCK_NO_DEREF); + err = flock_acquire(&table_locks[nlocks], table_name.buf, 0); if (err < 0) { /* * When the table is locked already we may do a @@ -1253,7 +1248,7 @@ static int stack_compact_range(struct reftable_stack *st, * run into file descriptor exhaustion when we compress a lot * of tables. */ - err = close_lock_file_gently(&table_locks[nlocks++]); + err = flock_close(&table_locks[nlocks++]); if (err < 0) { err = REFTABLE_IO_ERROR; goto done; @@ -1265,7 +1260,7 @@ static int stack_compact_range(struct reftable_stack *st, * "tables.list" lock while compacting the locked tables. This allows * concurrent updates to the stack to proceed. */ - err = rollback_lock_file(&tables_list_lock); + err = flock_release(&tables_list_lock); if (err < 0) { err = REFTABLE_IO_ERROR; goto done; @@ -1288,10 +1283,7 @@ static int stack_compact_range(struct reftable_stack *st, * "tables.list". We'll then replace the compacted range of tables with * the new table. */ - err = hold_lock_file_for_update_timeout(&tables_list_lock, - st->list_file, - LOCK_NO_DEREF, - st->opts.lock_timeout_ms); + err = flock_acquire(&tables_list_lock, st->list_file, st->opts.lock_timeout_ms); if (err < 0) { if (errno == EEXIST) err = REFTABLE_LOCK_ERROR; @@ -1301,7 +1293,7 @@ static int stack_compact_range(struct reftable_stack *st, } if (st->opts.default_permissions) { - if (chmod(get_lock_file_path(&tables_list_lock), + if (chmod(tables_list_lock.path, st->opts.default_permissions) < 0) { err = REFTABLE_IO_ERROR; goto done; @@ -1456,7 +1448,7 @@ static int stack_compact_range(struct reftable_stack *st, goto done; } - err = write_in_full(get_lock_file_fd(&tables_list_lock), + err = write_in_full(tables_list_lock.fd, tables_list_buf.buf, tables_list_buf.len); if (err < 0) { err = REFTABLE_IO_ERROR; @@ -1464,14 +1456,14 @@ static int stack_compact_range(struct reftable_stack *st, goto done; } - err = stack_fsync(&st->opts, get_lock_file_fd(&tables_list_lock)); + err = stack_fsync(&st->opts, tables_list_lock.fd); if (err < 0) { err = REFTABLE_IO_ERROR; unlink(new_table_path.buf); goto done; } - err = commit_lock_file(&tables_list_lock); + err = flock_commit(&tables_list_lock); if (err < 0) { err = REFTABLE_IO_ERROR; unlink(new_table_path.buf); @@ -1492,12 +1484,11 @@ static int stack_compact_range(struct reftable_stack *st, * readers, so it is expected that unlinking tables may fail. */ for (i = 0; i < nlocks; i++) { - struct lock_file *table_lock = &table_locks[i]; - const char *lock_path = get_lock_file_path(table_lock); + struct reftable_flock *table_lock = &table_locks[i]; reftable_buf_reset(&table_name); - err = reftable_buf_add(&table_name, lock_path, - strlen(lock_path) - strlen(".lock")); + err = reftable_buf_add(&table_name, table_lock->path, + strlen(table_lock->path) - strlen(".lock")); if (err) continue; @@ -1505,9 +1496,9 @@ static int stack_compact_range(struct reftable_stack *st, } done: - rollback_lock_file(&tables_list_lock); + flock_release(&tables_list_lock); for (i = 0; table_locks && i < nlocks; i++) - rollback_lock_file(&table_locks[i]); + flock_release(&table_locks[i]); reftable_free(table_locks); tmpfile_delete(&new_table); diff --git a/reftable/system.c b/reftable/system.c index 01f96f03d8..adf8e4d30b 100644 --- a/reftable/system.c +++ b/reftable/system.c @@ -1,6 +1,7 @@ #include "system.h" #include "basics.h" #include "reftable-error.h" +#include "../lockfile.h" #include "../tempfile.h" int tmpfile_from_pattern(struct reftable_tmpfile *out, const char *pattern) @@ -47,3 +48,79 @@ int tmpfile_rename(struct reftable_tmpfile *t, const char *path) return REFTABLE_IO_ERROR; return 0; } + +int flock_acquire(struct reftable_flock *l, const char *target_path, + long timeout_ms) +{ + struct lock_file *lockfile; + int err; + + lockfile = reftable_malloc(sizeof(*lockfile)); + if (!lockfile) + return REFTABLE_OUT_OF_MEMORY_ERROR; + + err = hold_lock_file_for_update_timeout(lockfile, target_path, LOCK_NO_DEREF, + timeout_ms); + if (err < 0) { + reftable_free(lockfile); + if (errno == EEXIST) + return REFTABLE_LOCK_ERROR; + return -1; + } + + l->fd = get_lock_file_fd(lockfile); + l->path = get_lock_file_path(lockfile); + l->priv = lockfile; + + return 0; +} + +int flock_close(struct reftable_flock *l) +{ + struct lock_file *lockfile = l->priv; + int ret; + + if (!lockfile) + return REFTABLE_API_ERROR; + + ret = close_lock_file_gently(lockfile); + l->fd = -1; + if (ret < 0) + return REFTABLE_IO_ERROR; + + return 0; +} + +int flock_release(struct reftable_flock *l) +{ + struct lock_file *lockfile = l->priv; + int ret; + + if (!lockfile) + return 0; + + ret = rollback_lock_file(lockfile); + reftable_free(lockfile); + *l = REFTABLE_FLOCK_INIT; + if (ret < 0) + return REFTABLE_IO_ERROR; + + return 0; +} + +int flock_commit(struct reftable_flock *l) +{ + struct lock_file *lockfile = l->priv; + int ret; + + if (!lockfile) + return REFTABLE_API_ERROR; + + ret = commit_lock_file(lockfile); + reftable_free(lockfile); + *l = REFTABLE_FLOCK_INIT; + if (ret < 0) + return REFTABLE_IO_ERROR; + + return 0; +} diff --git a/reftable/system.h b/reftable/system.h index 858189fd55..7d5f803eeb 100644 --- a/reftable/system.h +++ b/reftable/system.h @@ -12,7 +12,6 @@ https://developers.google.com/open-source/licenses/bsd /* This header glues the reftable library to the rest of Git */ #include "git-compat-util.h" -#include "lockfile.h" /* * An implementation-specific temporary file. By making this specific to the @@ -55,4 +54,48 @@ int tmpfile_delete(struct reftable_tmpfile *t); */ int tmpfile_rename(struct reftable_tmpfile *t, const char *path); +/* + * An implementation-specific file lock. Same as with `reftable_tmpfile`, + * making this specific to the implementation makes it possible to tie this + * into signal or atexit handlers such that we know to clean up stale locks on + * abnormal exits. + */ +struct reftable_flock { + const char *path; + int fd; + void *priv; +}; +#define REFTABLE_FLOCK_INIT ((struct reftable_flock){ .fd = -1, }) + +/* + * Acquire the lock for the given target path by exclusively creating a file + * with ".lock" appended to it. If that lock exists, we wait up to `timeout_ms` + * to acquire the lock. If `timeout_ms` is 0 we don't wait, if it is negative + * we block indefinitely. + * + * Retrun 0 on success, a reftable error code on error. + */ +int flock_acquire(struct reftable_flock *l, const char *target_path, + long timeout_ms); + +/* + * Close the lockfile's file descriptor without removing the lock itself. This + * is a no-op in case the lockfile has already been closed beforehand. Returns + * 0 on success, a reftable error code on error. + */ +int flock_close(struct reftable_flock *l); + +/* + * Release the lock by unlinking the lockfile. This is a no-op in case the + * lockfile has already been released or committed beforehand. Returns 0 on + * success, a reftable error code on error. + */ +int flock_release(struct reftable_flock *l); + +/* + * Commit the lock by renaming the lockfile into place. Returns 0 on success, a + * reftable error code on error. + */ +int flock_commit(struct reftable_flock *l); + #endif diff --git a/t/unit-tests/lib-reftable.c b/t/unit-tests/lib-reftable.c index c1631f4527..d795dfb7c9 100644 --- a/t/unit-tests/lib-reftable.c +++ b/t/unit-tests/lib-reftable.c @@ -2,6 +2,7 @@ #include "test-lib.h" #include "reftable/constants.h" #include "reftable/writer.h" +#include "strbuf.h" void t_reftable_set_hash(uint8_t *p, int i, enum reftable_hash id) { diff --git a/t/unit-tests/t-reftable-block.c b/t/unit-tests/t-reftable-block.c index 13e10807da..22040aeefa 100644 --- a/t/unit-tests/t-reftable-block.c +++ b/t/unit-tests/t-reftable-block.c @@ -11,6 +11,7 @@ https://developers.google.com/open-source/licenses/bsd #include "reftable/blocksource.h" #include "reftable/constants.h" #include "reftable/reftable-error.h" +#include "strbuf.h" static void t_ref_block_read_write(void) { diff --git a/t/unit-tests/t-reftable-pq.c b/t/unit-tests/t-reftable-pq.c index 272da05bea..f3f8a0cdf3 100644 --- a/t/unit-tests/t-reftable-pq.c +++ b/t/unit-tests/t-reftable-pq.c @@ -9,6 +9,7 @@ https://developers.google.com/open-source/licenses/bsd #include "test-lib.h" #include "reftable/constants.h" #include "reftable/pq.h" +#include "strbuf.h" static void merged_iter_pqueue_check(const struct merged_iter_pqueue *pq) { diff --git a/t/unit-tests/t-reftable-readwrite.c b/t/unit-tests/t-reftable-readwrite.c index 57896922eb..91c881aedf 100644 --- a/t/unit-tests/t-reftable-readwrite.c +++ b/t/unit-tests/t-reftable-readwrite.c @@ -13,6 +13,7 @@ https://developers.google.com/open-source/licenses/bsd #include "reftable/reader.h" #include "reftable/reftable-error.h" #include "reftable/reftable-writer.h" +#include "strbuf.h" static const int update_index = 5; diff --git a/t/unit-tests/t-reftable-stack.c b/t/unit-tests/t-reftable-stack.c index 13fd8d8f94..b2f6c1c37e 100644 --- a/t/unit-tests/t-reftable-stack.c +++ b/t/unit-tests/t-reftable-stack.c @@ -13,6 +13,8 @@ https://developers.google.com/open-source/licenses/bsd #include "reftable/reader.h" #include "reftable/reftable-error.h" #include "reftable/stack.h" +#include "strbuf.h" +#include "tempfile.h" #include static void clear_dir(const char *dirname) -- cgit v1.2.3 From 2afd8996aec692a26c3cdb039a47c18809148c56 Mon Sep 17 00:00:00 2001 From: Tobias Pietzsch Date: Sat, 9 Jan 2021 23:14:08 +0100 Subject: gitk: check main window visibility before waiting for it to show If the main window is already visible when gitk waits for it to become visible, gitk hangs forever. This commit adds a check whether the window is already visible. See https://wiki.tcl-lang.org/page/tkwait+visibility Signed-off-by: Tobias Pietzsch Signed-off-by: Johannes Sixt --- gitk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitk b/gitk index 7a087f123d..de278557b3 100755 --- a/gitk +++ b/gitk @@ -12687,7 +12687,7 @@ catch { wm iconphoto . -default gitlogo gitlogo32 } # wait for the window to become visible -tkwait visibility . +if {![winfo viewable .]} {tkwait visibility .} set_window_title update readrefs -- cgit v1.2.3 From 54d820d7d4fee3a231b6ecaeb2607cb8f817f74d Mon Sep 17 00:00:00 2001 From: Bence Ferdinandy Date: Fri, 22 Nov 2024 13:28:42 +0100 Subject: t/t5505-remote: set default branch to main Consider the bare repository called "mirror" in the test. Running `git remote add --mirror -f origin ../one` will not change HEAD, consequently if init.defaultBranch is not the same as what HEAD in the remote ("one"), HEAD in "mirror" will be pointing to a non-existent reference. Hence if "mirror" is used as a remote by yet another repository, ls-remote will not show HEAD. On the other hand, if init.defaultBranch happens to match HEAD in "one", then ls-remote will show HEAD. Since the "ci/run-build-and-tests.sh" script globally exports GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main for some (but not all) jobs, there may be a drift in some tests between how the test repositories are set up in the CI and during local testing, if the test itself uses "master" as default instead of "main". In particular, this happens in t5505-remote.sh. This issue does not manifest currently, as the test does not do any remote HEAD manipulation where this would come up, but should such things be added, a locally passing test would break the CI and vice-versa. Set GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main in t5505-remote to be consistent with the CI. Signed-off-by: Bence Ferdinandy Signed-off-by: Junio C Hamano --- t/t5505-remote.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 532035933f..9b50276646 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -2,6 +2,9 @@ test_description='git remote porcelain-ish' +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh -- cgit v1.2.3 From 2fd55558950bdfe43fd28ca17b50691427842c35 Mon Sep 17 00:00:00 2001 From: Bence Ferdinandy Date: Fri, 22 Nov 2024 13:28:43 +0100 Subject: t/t5505-remote: test failure of set-head The test coverage was missing a test for the failure branch of remote set-head auto's output. Add the missing text and while we are at it, correct a small grammatical mistake in the error's output ("setup" is the noun, "set up" is the verb). Signed-off-by: Bence Ferdinandy Signed-off-by: Junio C Hamano --- builtin/remote.c | 2 +- t/t5505-remote.sh | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/builtin/remote.c b/builtin/remote.c index 76670ddd8b..8a182439f2 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -1445,7 +1445,7 @@ static int set_head(int argc, const char **argv, const char *prefix) if (!refs_ref_exists(get_main_ref_store(the_repository), buf2.buf)) result |= error(_("Not a valid ref: %s"), buf2.buf); else if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, "remote set-head")) - result |= error(_("Could not setup %s"), buf.buf); + result |= error(_("Could not set up %s"), buf.buf); else if (opt_a) printf("%s/HEAD set to %s\n", argv[0], head_name); free(head_name); diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 9b50276646..61e3ecc1af 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -432,6 +432,18 @@ test_expect_success 'set-head --auto' ' ) ' +test_expect_success REFFILES 'set-head --auto failure' ' + test_when_finished "rm -f test/.git/refs/remotes/origin/HEAD.lock" && + ( + cd test && + touch .git/refs/remotes/origin/HEAD.lock && + test_must_fail git remote set-head --auto origin 2>err && + tail -n1 err >output && + echo "error: Could not set up refs/remotes/origin/HEAD" >expect && + test_cmp expect output + ) +' + test_expect_success 'set-head --auto has no problem w/multiple HEADs' ' ( cd test && -- cgit v1.2.3 From 8102d10ff8317c1e0ba5afb3a41b6a2bc523ff97 Mon Sep 17 00:00:00 2001 From: Bence Ferdinandy Date: Fri, 22 Nov 2024 13:28:44 +0100 Subject: refs: standardize output of refs_read_symbolic_ref When the symbolic reference we want to read with refs_read_symbolic_ref is actually not a symbolic reference, the files and the reftable backends return different values (1 and -1 respectively). Standardize the returned values so that 0 is success, -1 is a generic error and -2 is that the reference was actually non-symbolic. Signed-off-by: Bence Ferdinandy Signed-off-by: Junio C Hamano --- refs.h | 11 +++++++++++ refs/files-backend.c | 7 +++---- refs/refs-internal.h | 5 +++++ refs/reftable-backend.c | 6 ++++-- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/refs.h b/refs.h index 108dfc93b3..22c2b45b8b 100644 --- a/refs.h +++ b/refs.h @@ -83,6 +83,17 @@ int refs_read_ref_full(struct ref_store *refs, const char *refname, int refs_read_ref(struct ref_store *refs, const char *refname, struct object_id *oid); +#define NOT_A_SYMREF -2 + +/* + * Read the symbolic ref named "refname" and write its immediate referent into + * the provided buffer. Referent is left empty if "refname" is not a symbolic + * ref. It does not resolve the symbolic reference recursively in case the + * target is also a symbolic ref. + * + * Returns 0 on success, -2 if the "refname" is not a symbolic ref, + * -1 otherwise. + */ int refs_read_symbolic_ref(struct ref_store *ref_store, const char *refname, struct strbuf *referent); diff --git a/refs/files-backend.c b/refs/files-backend.c index 0824c0b8a9..4cc43c32f2 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -596,10 +596,9 @@ static int files_read_symbolic_ref(struct ref_store *ref_store, const char *refn unsigned int type; ret = read_ref_internal(ref_store, refname, &oid, referent, &type, &failure_errno, 1); - if (ret) - return ret; - - return !(type & REF_ISSYMREF); + if (!ret && !(type & REF_ISSYMREF)) + return NOT_A_SYMREF; + return ret; } int parse_loose_ref_contents(const struct git_hash_algo *algop, diff --git a/refs/refs-internal.h b/refs/refs-internal.h index 2313c830d8..1399fee61c 100644 --- a/refs/refs-internal.h +++ b/refs/refs-internal.h @@ -673,6 +673,11 @@ struct ref_storage_be { ref_iterator_begin_fn *iterator_begin; read_raw_ref_fn *read_raw_ref; + + /* + * Please refer to `refs_read_symbolic_ref()` for the expected + * behaviour. + */ read_symbolic_ref_fn *read_symbolic_ref; reflog_iterator_begin_fn *reflog_iterator_begin; diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c index 3c96fbf66f..f74b8c4bb4 100644 --- a/refs/reftable-backend.c +++ b/refs/reftable-backend.c @@ -830,10 +830,12 @@ static int reftable_be_read_symbolic_ref(struct ref_store *ref_store, return ret; ret = reftable_stack_read_ref(stack, refname, &ref); - if (ret == 0 && ref.value_type == REFTABLE_REF_SYMREF) + if (ret) + ret = -1; + else if (ref.value_type == REFTABLE_REF_SYMREF) strbuf_addstr(referent, ref.value.symref); else - ret = -1; + ret = NOT_A_SYMREF; reftable_ref_record_release(&ref); return ret; -- cgit v1.2.3 From d842cd130122c6f3d3019d467040570d7d001f7a Mon Sep 17 00:00:00 2001 From: Bence Ferdinandy Date: Fri, 22 Nov 2024 13:28:45 +0100 Subject: refs: atomically record overwritten ref in update_symref When updating a symref with update_symref it's currently not possible to know for sure what was the previous value that was overwritten. Extend refs_update_symref under a new function name, to record the value after the ref has been locked if the caller of refs_update_symref_extended requests it via a new variable in the function call. Make the return value of the function notify the caller, if the previous value was actually not a symbolic reference. Keep the original refs_update_symref function with the same signature, but now as a wrapper around refs_update_symref_extended. Signed-off-by: Bence Ferdinandy Signed-off-by: Junio C Hamano --- refs.c | 22 ++++++++++++++++++++-- refs.h | 4 ++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/refs.c b/refs.c index 5f729ed412..d80efd58f0 100644 --- a/refs.c +++ b/refs.c @@ -2115,6 +2115,13 @@ int peel_iterated_oid(struct repository *r, const struct object_id *base, struct int refs_update_symref(struct ref_store *refs, const char *ref, const char *target, const char *logmsg) +{ + return refs_update_symref_extended(refs, ref, target, logmsg, NULL); +} + +int refs_update_symref_extended(struct ref_store *refs, const char *ref, + const char *target, const char *logmsg, + struct strbuf *referent) { struct ref_transaction *transaction; struct strbuf err = STRBUF_INIT; @@ -2125,10 +2132,22 @@ int refs_update_symref(struct ref_store *refs, const char *ref, ref_transaction_update(transaction, ref, NULL, NULL, target, NULL, REF_NO_DEREF, logmsg, &err) || - ref_transaction_commit(transaction, &err)) { + ref_transaction_prepare(transaction, &err)) { ret = error("%s", err.buf); + goto cleanup; } + if (referent && refs_read_symbolic_ref(refs, ref, referent) == NOT_A_SYMREF) { + struct object_id oid; + if (!refs_read_ref(refs, ref, &oid)) { + strbuf_addstr(referent, oid_to_hex(&oid)); + ret = NOT_A_SYMREF; + } + } + + if (ref_transaction_commit(transaction, &err)) + ret = error("%s", err.buf); +cleanup: strbuf_release(&err); if (transaction) ref_transaction_free(transaction); @@ -2948,4 +2967,3 @@ int ref_update_expects_existing_old_ref(struct ref_update *update) return (update->flags & REF_HAVE_OLD) && (!is_null_oid(&update->old_oid) || update->old_target); } - diff --git a/refs.h b/refs.h index 22c2b45b8b..5c46ac9f34 100644 --- a/refs.h +++ b/refs.h @@ -584,6 +584,10 @@ int refs_copy_existing_ref(struct ref_store *refs, const char *oldref, int refs_update_symref(struct ref_store *refs, const char *refname, const char *target, const char *logmsg); +int refs_update_symref_extended(struct ref_store *refs, const char *refname, + const char *target, const char *logmsg, + struct strbuf *referent); + enum action_on_err { UPDATE_REFS_MSG_ON_ERR, UPDATE_REFS_DIE_ON_ERR, -- cgit v1.2.3 From 4f07c45e25810700cec57c6b01ca9ff97bfb6840 Mon Sep 17 00:00:00 2001 From: Bence Ferdinandy Date: Fri, 22 Nov 2024 13:28:46 +0100 Subject: remote set-head: refactor for readability Make two different readability refactors: Rename strbufs "buf" and "buf2" to something more explanatory. Instead of calling get_main_ref_store(the_repository) multiple times, call it once and store the result in a new refs variable. Although this change probably offers some performance benefits, the main purpose is to shorten the line lengths of function calls using this variable. Signed-off-by: Bence Ferdinandy Signed-off-by: Junio C Hamano --- builtin/remote.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/builtin/remote.c b/builtin/remote.c index 8a182439f2..bcc3ee91ef 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -1402,8 +1402,9 @@ static int show(int argc, const char **argv, const char *prefix) static int set_head(int argc, const char **argv, const char *prefix) { int i, opt_a = 0, opt_d = 0, result = 0; - struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT; + struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT; char *head_name = NULL; + struct ref_store *refs = get_main_ref_store(the_repository); struct option options[] = { OPT_BOOL('a', "auto", &opt_a, @@ -1415,7 +1416,7 @@ static int set_head(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, options, builtin_remote_sethead_usage, 0); if (argc) - strbuf_addf(&buf, "refs/remotes/%s/HEAD", argv[0]); + strbuf_addf(&b_head, "refs/remotes/%s/HEAD", argv[0]); if (!opt_a && !opt_d && argc == 2) { head_name = xstrdup(argv[1]); @@ -1434,25 +1435,25 @@ static int set_head(int argc, const char **argv, const char *prefix) head_name = xstrdup(states.heads.items[0].string); free_remote_ref_states(&states); } else if (opt_d && !opt_a && argc == 1) { - if (refs_delete_ref(get_main_ref_store(the_repository), NULL, buf.buf, NULL, REF_NO_DEREF)) - result |= error(_("Could not delete %s"), buf.buf); + if (refs_delete_ref(refs, NULL, b_head.buf, NULL, REF_NO_DEREF)) + result |= error(_("Could not delete %s"), b_head.buf); } else usage_with_options(builtin_remote_sethead_usage, options); if (head_name) { - strbuf_addf(&buf2, "refs/remotes/%s/%s", argv[0], head_name); + strbuf_addf(&b_remote_head, "refs/remotes/%s/%s", argv[0], head_name); /* make sure it's valid */ - if (!refs_ref_exists(get_main_ref_store(the_repository), buf2.buf)) - result |= error(_("Not a valid ref: %s"), buf2.buf); - else if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, "remote set-head")) - result |= error(_("Could not set up %s"), buf.buf); + if (!refs_ref_exists(refs, b_remote_head.buf)) + result |= error(_("Not a valid ref: %s"), b_remote_head.buf); + else if (refs_update_symref(refs, b_head.buf, b_remote_head.buf, "remote set-head")) + result |= error(_("Could not set up %s"), b_head.buf); else if (opt_a) printf("%s/HEAD set to %s\n", argv[0], head_name); free(head_name); } - strbuf_release(&buf); - strbuf_release(&buf2); + strbuf_release(&b_head); + strbuf_release(&b_remote_head); return result; } -- cgit v1.2.3 From dfe86fa06bdc46f1e5bf1f55e8571bb9a088d20c Mon Sep 17 00:00:00 2001 From: Bence Ferdinandy Date: Fri, 22 Nov 2024 13:28:47 +0100 Subject: remote set-head: better output for --auto Currently, set-head --auto will print a message saying "remote/HEAD set to branch", which implies something was changed. Change the output of --auto, so the output actually reflects what was done: a) set a previously unset HEAD, b) change HEAD because remote changed or c) no updates. As edge cases, if HEAD is changed from a previous symbolic reference that was not a remote branch, explicitly call attention to this fact, and also notify the user if the previous reference was not a symbolic reference. Signed-off-by: Bence Ferdinandy Signed-off-by: Junio C Hamano --- builtin/remote.c | 59 ++++++++++++++++++++++++++++++++++++++++----------- t/t5505-remote.sh | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 109 insertions(+), 13 deletions(-) diff --git a/builtin/remote.c b/builtin/remote.c index bcc3ee91ef..6d659d63ca 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -1399,10 +1399,38 @@ static int show(int argc, const char **argv, const char *prefix) return result; } +static void report_set_head_auto(const char *remote, const char *head_name, + struct strbuf *b_local_head, int was_detached) { + struct strbuf buf_prefix = STRBUF_INIT; + const char *prev_head = NULL; + + strbuf_addf(&buf_prefix, "refs/remotes/%s/", remote); + skip_prefix(b_local_head->buf, buf_prefix.buf, &prev_head); + + if (prev_head && !strcmp(prev_head, head_name)) + printf(_("'%s/HEAD' is unchanged and points to '%s'\n"), + remote, head_name); + else if (prev_head) + printf(_("'%s/HEAD' has changed from '%s' and now points to '%s'\n"), + remote, prev_head, head_name); + else if (!b_local_head->len) + printf(_("'%s/HEAD' is now created and points to '%s'\n"), + remote, head_name); + else if (was_detached && b_local_head->len) + printf(_("'%s/HEAD' was detached at '%s' and now points to '%s'\n"), + remote, b_local_head->buf, head_name); + else + printf(_("'%s/HEAD' used to point to '%s' " + "(which is not a remote branch), but now points to '%s'\n"), + remote, b_local_head->buf, head_name); + strbuf_release(&buf_prefix); +} + static int set_head(int argc, const char **argv, const char *prefix) { - int i, opt_a = 0, opt_d = 0, result = 0; - struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT; + int i, opt_a = 0, opt_d = 0, result = 0, was_detached; + struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT, + b_local_head = STRBUF_INIT; char *head_name = NULL; struct ref_store *refs = get_main_ref_store(the_repository); @@ -1440,20 +1468,27 @@ static int set_head(int argc, const char **argv, const char *prefix) } else usage_with_options(builtin_remote_sethead_usage, options); - if (head_name) { - strbuf_addf(&b_remote_head, "refs/remotes/%s/%s", argv[0], head_name); - /* make sure it's valid */ - if (!refs_ref_exists(refs, b_remote_head.buf)) - result |= error(_("Not a valid ref: %s"), b_remote_head.buf); - else if (refs_update_symref(refs, b_head.buf, b_remote_head.buf, "remote set-head")) - result |= error(_("Could not set up %s"), b_head.buf); - else if (opt_a) - printf("%s/HEAD set to %s\n", argv[0], head_name); - free(head_name); + if (!head_name) + goto cleanup; + strbuf_addf(&b_remote_head, "refs/remotes/%s/%s", argv[0], head_name); + if (!refs_ref_exists(refs, b_remote_head.buf)) { + result |= error(_("Not a valid ref: %s"), b_remote_head.buf); + goto cleanup; + } + was_detached = refs_update_symref_extended(refs, b_head.buf, b_remote_head.buf, + "remote set-head", &b_local_head); + if (was_detached == -1) { + result |= error(_("Could not set up %s"), b_head.buf); + goto cleanup; } + if (opt_a) + report_set_head_auto(argv[0], head_name, &b_local_head, was_detached); +cleanup: + free(head_name); strbuf_release(&b_head); strbuf_release(&b_remote_head); + strbuf_release(&b_local_head); return result; } diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 61e3ecc1af..d15b579c95 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -444,12 +444,63 @@ test_expect_success REFFILES 'set-head --auto failure' ' ) ' +test_expect_success 'set-head --auto detects creation' ' + ( + cd test && + git update-ref --no-deref -d refs/remotes/origin/HEAD && + git remote set-head --auto origin >output && + echo "${SQ}origin/HEAD${SQ} is now created and points to ${SQ}main${SQ}" >expect && + test_cmp expect output + ) +' + +test_expect_success 'set-head --auto to update a non symbolic ref' ' + ( + cd test && + git update-ref --no-deref -d refs/remotes/origin/HEAD && + git update-ref refs/remotes/origin/HEAD HEAD && + HEAD=$(git log --pretty="%H") && + git remote set-head --auto origin >output && + echo "${SQ}origin/HEAD${SQ} was detached at ${SQ}${HEAD}${SQ} and now points to ${SQ}main${SQ}" >expect && + test_cmp expect output + ) +' + +test_expect_success 'set-head --auto detects no change' ' + ( + cd test && + git remote set-head --auto origin >output && + echo "${SQ}origin/HEAD${SQ} is unchanged and points to ${SQ}main${SQ}" >expect && + test_cmp expect output + ) +' + +test_expect_success 'set-head --auto detects change' ' + ( + cd test && + git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/ahead && + git remote set-head --auto origin >output && + echo "${SQ}origin/HEAD${SQ} has changed from ${SQ}ahead${SQ} and now points to ${SQ}main${SQ}" >expect && + test_cmp expect output + ) +' + +test_expect_success 'set-head --auto detects strange ref' ' + ( + cd test && + git symbolic-ref refs/remotes/origin/HEAD refs/heads/main && + git remote set-head --auto origin >output && + echo "${SQ}origin/HEAD${SQ} used to point to ${SQ}refs/heads/main${SQ} (which is not a remote branch), but now points to ${SQ}main${SQ}" >expect && + test_cmp expect output + ) +' + test_expect_success 'set-head --auto has no problem w/multiple HEADs' ' ( cd test && git fetch two "refs/heads/*:refs/remotes/two/*" && git remote set-head --auto two >output 2>&1 && - echo "two/HEAD set to main" >expect && + echo "${SQ}two/HEAD${SQ} is now created and points to ${SQ}main${SQ}" >expect && test_cmp expect output ) ' @@ -468,6 +519,16 @@ test_expect_success 'set-head explicit' ' ) ' +test_expect_success 'set-head --auto reports change' ' + ( + cd test && + git remote set-head origin side2 && + git remote set-head --auto origin >output 2>&1 && + echo "${SQ}origin/HEAD${SQ} has changed from ${SQ}side2${SQ} and now points to ${SQ}main${SQ}" >expect && + test_cmp expect output + ) +' + cat >test/expect < Date: Fri, 22 Nov 2024 13:28:48 +0100 Subject: refs: add TRANSACTION_CREATE_EXISTS error Currently there is only one special error for transaction, for when there is a naming conflict, all other errors are dumped under a generic error. Add a new special error case for when the caller requests the reference to be updated only when it does not yet exist and the reference actually does exist. Signed-off-by: Bence Ferdinandy Signed-off-by: Junio C Hamano --- refs.h | 4 +++- refs/files-backend.c | 24 ++++++++++++++++-------- refs/reftable-backend.c | 6 ++++-- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/refs.h b/refs.h index 5c46ac9f34..b243739e4b 100644 --- a/refs.h +++ b/refs.h @@ -773,8 +773,10 @@ int ref_transaction_verify(struct ref_transaction *transaction, /* Naming conflict (for example, the ref names A and A/B conflict). */ #define TRANSACTION_NAME_CONFLICT -1 +/* When only creation was requested, but the ref already exists. */ +#define TRANSACTION_CREATE_EXISTS -2 /* All other errors. */ -#define TRANSACTION_GENERIC_ERROR -2 +#define TRANSACTION_GENERIC_ERROR -3 /* * Perform the preparatory stages of committing `transaction`. Acquire diff --git a/refs/files-backend.c b/refs/files-backend.c index 4cc43c32f2..23ae74089d 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -2501,14 +2501,18 @@ static int split_symref_update(struct ref_update *update, static int check_old_oid(struct ref_update *update, struct object_id *oid, struct strbuf *err) { + int ret = TRANSACTION_GENERIC_ERROR; + if (!(update->flags & REF_HAVE_OLD) || oideq(oid, &update->old_oid)) return 0; - if (is_null_oid(&update->old_oid)) + if (is_null_oid(&update->old_oid)) { strbuf_addf(err, "cannot lock ref '%s': " "reference already exists", ref_update_original_update_refname(update)); + ret = TRANSACTION_CREATE_EXISTS; + } else if (is_null_oid(oid)) strbuf_addf(err, "cannot lock ref '%s': " "reference is missing but expected %s", @@ -2521,7 +2525,7 @@ static int check_old_oid(struct ref_update *update, struct object_id *oid, oid_to_hex(oid), oid_to_hex(&update->old_oid)); - return -1; + return ret; } /* @@ -2601,9 +2605,11 @@ static int lock_ref_for_update(struct files_ref_store *refs, ret = TRANSACTION_GENERIC_ERROR; goto out; } - } else if (check_old_oid(update, &lock->old_oid, err)) { - ret = TRANSACTION_GENERIC_ERROR; - goto out; + } else { + ret = check_old_oid(update, &lock->old_oid, err); + if (ret) { + goto out; + } } } else { /* @@ -2634,9 +2640,11 @@ static int lock_ref_for_update(struct files_ref_store *refs, update->old_target); ret = TRANSACTION_GENERIC_ERROR; goto out; - } else if (check_old_oid(update, &lock->old_oid, err)) { - ret = TRANSACTION_GENERIC_ERROR; - goto out; + } else { + ret = check_old_oid(update, &lock->old_oid, err); + if (ret) { + goto out; + } } /* diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c index f74b8c4bb4..d764c2c3af 100644 --- a/refs/reftable-backend.c +++ b/refs/reftable-backend.c @@ -1208,10 +1208,13 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store, goto done; } } else if ((u->flags & REF_HAVE_OLD) && !oideq(¤t_oid, &u->old_oid)) { - if (is_null_oid(&u->old_oid)) + ret = TRANSACTION_NAME_CONFLICT; + if (is_null_oid(&u->old_oid)) { strbuf_addf(err, _("cannot lock ref '%s': " "reference already exists"), ref_update_original_update_refname(u)); + ret = TRANSACTION_CREATE_EXISTS; + } else if (is_null_oid(¤t_oid)) strbuf_addf(err, _("cannot lock ref '%s': " "reference is missing but expected %s"), @@ -1223,7 +1226,6 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store, ref_update_original_update_refname(u), oid_to_hex(¤t_oid), oid_to_hex(&u->old_oid)); - ret = -1; goto done; } -- cgit v1.2.3 From 9963746c841dc786529827b7b6755d0a3e208ad4 Mon Sep 17 00:00:00 2001 From: Bence Ferdinandy Date: Fri, 22 Nov 2024 13:28:49 +0100 Subject: refs: add create_only option to refs_update_symref_extended Allow the caller to specify that it only wants to update the symref if it does not already exist. Silently ignore the error from the transaction API if the symref already exists. Signed-off-by: Bence Ferdinandy Signed-off-by: Junio C Hamano --- builtin/remote.c | 2 +- refs.c | 33 ++++++++++++++++++++++++--------- refs.h | 2 +- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/builtin/remote.c b/builtin/remote.c index 6d659d63ca..3dc1135b5c 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -1476,7 +1476,7 @@ static int set_head(int argc, const char **argv, const char *prefix) goto cleanup; } was_detached = refs_update_symref_extended(refs, b_head.buf, b_remote_head.buf, - "remote set-head", &b_local_head); + "remote set-head", &b_local_head, 0); if (was_detached == -1) { result |= error(_("Could not set up %s"), b_head.buf); goto cleanup; diff --git a/refs.c b/refs.c index d80efd58f0..2efa6bcc5c 100644 --- a/refs.c +++ b/refs.c @@ -2116,26 +2116,38 @@ int peel_iterated_oid(struct repository *r, const struct object_id *base, struct int refs_update_symref(struct ref_store *refs, const char *ref, const char *target, const char *logmsg) { - return refs_update_symref_extended(refs, ref, target, logmsg, NULL); + return refs_update_symref_extended(refs, ref, target, logmsg, NULL, 0); } int refs_update_symref_extended(struct ref_store *refs, const char *ref, const char *target, const char *logmsg, - struct strbuf *referent) + struct strbuf *referent, int create_only) { struct ref_transaction *transaction; struct strbuf err = STRBUF_INIT; - int ret = 0; + int ret = 0, prepret = 0; transaction = ref_store_transaction_begin(refs, &err); - if (!transaction || - ref_transaction_update(transaction, ref, NULL, NULL, - target, NULL, REF_NO_DEREF, - logmsg, &err) || - ref_transaction_prepare(transaction, &err)) { + if (!transaction) { + error_return: ret = error("%s", err.buf); goto cleanup; } + if (create_only) { + if (ref_transaction_create(transaction, ref, NULL, target, + REF_NO_DEREF, logmsg, &err)) + goto error_return; + prepret = ref_transaction_prepare(transaction, &err); + if (prepret && prepret != TRANSACTION_CREATE_EXISTS) + goto error_return; + } else { + if (ref_transaction_update(transaction, ref, NULL, NULL, + target, NULL, REF_NO_DEREF, + logmsg, &err) || + ref_transaction_prepare(transaction, &err)) + goto error_return; + } + if (referent && refs_read_symbolic_ref(refs, ref, referent) == NOT_A_SYMREF) { struct object_id oid; if (!refs_read_ref(refs, ref, &oid)) { @@ -2144,8 +2156,11 @@ int refs_update_symref_extended(struct ref_store *refs, const char *ref, } } + if (prepret == TRANSACTION_CREATE_EXISTS) + goto cleanup; + if (ref_transaction_commit(transaction, &err)) - ret = error("%s", err.buf); + goto error_return; cleanup: strbuf_release(&err); diff --git a/refs.h b/refs.h index b243739e4b..be38377b1f 100644 --- a/refs.h +++ b/refs.h @@ -586,7 +586,7 @@ int refs_update_symref(struct ref_store *refs, const char *refname, int refs_update_symref_extended(struct ref_store *refs, const char *refname, const char *target, const char *logmsg, - struct strbuf *referent); + struct strbuf *referent, int create_only); enum action_on_err { UPDATE_REFS_MSG_ON_ERR, -- cgit v1.2.3 From 3f763ddf28d28fe63963991513c8db4045eabadc Mon Sep 17 00:00:00 2001 From: Bence Ferdinandy Date: Fri, 22 Nov 2024 13:28:50 +0100 Subject: fetch: set remote/HEAD if it does not exist When cloning a repository remote/HEAD is created, but when the user creates a repository with git init, and later adds a remote, remote/HEAD is only created if the user explicitly runs a variant of "remote set-head". Attempt to set remote/HEAD during fetch, if the user does not have it already set. Silently ignore any errors. Signed-off-by: Bence Ferdinandy Signed-off-by: Junio C Hamano --- builtin/fetch.c | 68 ++++++++++++++++++++++++++++++++++++++++ t/t4207-log-decoration-colors.sh | 3 +- t/t5505-remote.sh | 21 +++++++++---- t/t5510-fetch.sh | 24 ++++++++++++++ t/t5512-ls-remote.sh | 2 ++ t/t5514-fetch-multiple.sh | 17 ++++++++-- t/t5516-fetch-push.sh | 3 +- t/t5527-fetch-odd-refs.sh | 3 +- t/t7900-maintenance.sh | 3 +- t/t9210-scalar.sh | 5 +-- t/t9211-scalar-clone.sh | 6 ++-- t/t9902-completion.sh | 65 ++++++++++++++++++++++++++++++++++++++ 12 files changed, 203 insertions(+), 17 deletions(-) diff --git a/builtin/fetch.c b/builtin/fetch.c index c900f57721..b2a36a5d95 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1577,6 +1577,66 @@ static int backfill_tags(struct display_state *display_state, return retcode; } +static const char *strip_refshead(const char *name){ + skip_prefix(name, "refs/heads/", &name); + return name; +} + +static int set_head(const struct ref *remote_refs) +{ + int result = 0; + struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT; + const char *remote = gtransport->remote->name; + char *head_name = NULL; + struct ref *ref, *matches; + struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map; + struct refspec_item refspec = { + .force = 0, + .pattern = 1, + .src = (char *) "refs/heads/*", + .dst = (char *) "refs/heads/*", + }; + struct string_list heads = STRING_LIST_INIT_DUP; + struct ref_store *refs = get_main_ref_store(the_repository); + + get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0); + matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"), + fetch_map, 1); + for (ref = matches; ref; ref = ref->next) { + string_list_append(&heads, strip_refshead(ref->name)); + } + + + if (!heads.nr) + result = 1; + else if (heads.nr > 1) + result = 1; + else + head_name = xstrdup(heads.items[0].string); + + if (!head_name) + goto cleanup; + strbuf_addf(&b_head, "refs/remotes/%s/HEAD", remote); + strbuf_addf(&b_remote_head, "refs/remotes/%s/%s", remote, head_name); + /* make sure it's valid */ + if (!refs_ref_exists(refs, b_remote_head.buf)) { + result = 1; + goto cleanup; + } + if (refs_update_symref_extended(refs, b_head.buf, b_remote_head.buf, + "fetch", NULL, 1)) + result = 1; + +cleanup: + free(head_name); + free_refs(fetch_map); + free_refs(matches); + string_list_clear(&heads, 0); + strbuf_release(&b_head); + strbuf_release(&b_remote_head); + return result; +} + static int do_fetch(struct transport *transport, struct refspec *rs, const struct fetch_config *config) @@ -1646,6 +1706,8 @@ static int do_fetch(struct transport *transport, "refs/tags/"); } + strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD"); + if (must_list_refs) { trace2_region_enter("fetch", "remote_refs", the_repository); remote_refs = transport_get_remote_refs(transport, @@ -1790,6 +1852,12 @@ static int do_fetch(struct transport *transport, "you need to specify exactly one branch with the --set-upstream option")); } } + if (set_head(remote_refs)) + ; + /* + * Way too many cases where this can go wrong + * so let's just fail silently for now. + */ cleanup: if (retcode) { diff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh index 73ea9e5155..d55d22cb2f 100755 --- a/t/t4207-log-decoration-colors.sh +++ b/t/t4207-log-decoration-colors.sh @@ -59,7 +59,8 @@ ${c_reset}${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_commit}, \ ${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_commit})${c_reset} B ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\ ${c_tag}tag: ${c_reset}${c_tag}A1${c_reset}${c_commit}, \ -${c_reset}${c_remoteBranch}other/main${c_reset}${c_commit})${c_reset} A1 +${c_reset}${c_remoteBranch}other/main${c_reset}${c_commit}, \ +${c_reset}${c_remoteBranch}other/HEAD${c_reset}${c_commit})${c_reset} A1 ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\ ${c_stash}refs/stash${c_reset}${c_commit})${c_reset} On main: Changes to A.t ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\ diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index d15b579c95..afa261409f 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -74,7 +74,7 @@ test_expect_success 'add another remote' ' cd test && git remote add -f second ../two && tokens_match "origin second" "$(git remote)" && - check_tracking_branch second main side another && + check_tracking_branch second main side another HEAD && git for-each-ref "--format=%(refname)" refs/remotes | sed -e "/^refs\/remotes\/origin\//d" \ -e "/^refs\/remotes\/second\//d" >actual && @@ -500,7 +500,7 @@ test_expect_success 'set-head --auto has no problem w/multiple HEADs' ' cd test && git fetch two "refs/heads/*:refs/remotes/two/*" && git remote set-head --auto two >output 2>&1 && - echo "${SQ}two/HEAD${SQ} is now created and points to ${SQ}main${SQ}" >expect && + echo "${SQ}two/HEAD${SQ} is unchanged and points to ${SQ}main${SQ}" >expect && test_cmp expect output ) ' @@ -788,8 +788,10 @@ test_expect_success 'reject --no-no-tags' ' ' cat >one/expect <<\EOF + apis/HEAD -> apis/main apis/main apis/side + drosophila/HEAD -> drosophila/main drosophila/another drosophila/main drosophila/side @@ -807,11 +809,14 @@ test_expect_success 'update' ' ' cat >one/expect <<\EOF + drosophila/HEAD -> drosophila/main drosophila/another drosophila/main drosophila/side + manduca/HEAD -> manduca/main manduca/main manduca/side + megaloprepus/HEAD -> megaloprepus/main megaloprepus/main megaloprepus/side EOF @@ -819,7 +824,7 @@ EOF test_expect_success 'update with arguments' ' ( cd one && - for b in $(git branch -r) + for b in $(git branch -r | grep -v HEAD) do git branch -r -d $b || exit 1 done && @@ -851,10 +856,13 @@ test_expect_success 'update --prune' ' ' cat >one/expect <<-\EOF + apis/HEAD -> apis/main apis/main apis/side + manduca/HEAD -> manduca/main manduca/main manduca/side + megaloprepus/HEAD -> megaloprepus/main megaloprepus/main megaloprepus/side EOF @@ -862,7 +870,7 @@ EOF test_expect_success 'update default' ' ( cd one && - for b in $(git branch -r) + for b in $(git branch -r | grep -v HEAD) do git branch -r -d $b || exit 1 done && @@ -874,6 +882,7 @@ test_expect_success 'update default' ' ' cat >one/expect <<\EOF + drosophila/HEAD -> drosophila/main drosophila/another drosophila/main drosophila/side @@ -882,7 +891,7 @@ EOF test_expect_success 'update default (overridden, with funny whitespace)' ' ( cd one && - for b in $(git branch -r) + for b in $(git branch -r | grep -v HEAD) do git branch -r -d $b || exit 1 done && @@ -896,7 +905,7 @@ test_expect_success 'update default (overridden, with funny whitespace)' ' test_expect_success 'update (with remotes.default defined)' ' ( cd one && - for b in $(git branch -r) + for b in $(git branch -r | grep -v HEAD) do git branch -r -d $b || exit 1 done && diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 0890b9f61c..87698341f5 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -75,6 +75,30 @@ test_expect_success "fetch test for-merge" ' cut -f -2 .git/FETCH_HEAD >actual && test_cmp expected actual' +test_expect_success "fetch test remote HEAD" ' + cd "$D" && + cd two && + git fetch && + git rev-parse --verify refs/remotes/origin/HEAD && + git rev-parse --verify refs/remotes/origin/main && + head=$(git rev-parse refs/remotes/origin/HEAD) && + branch=$(git rev-parse refs/remotes/origin/main) && + test "z$head" = "z$branch"' + +test_expect_success "fetch test remote HEAD change" ' + cd "$D" && + cd two && + git switch -c other && + git push -u origin other && + git rev-parse --verify refs/remotes/origin/HEAD && + git rev-parse --verify refs/remotes/origin/main && + git rev-parse --verify refs/remotes/origin/other && + git remote set-head origin other && + git fetch && + head=$(git rev-parse refs/remotes/origin/HEAD) && + branch=$(git rev-parse refs/remotes/origin/other) && + test "z$head" = "z$branch"' + test_expect_success 'fetch --prune on its own works as expected' ' cd "$D" && git clone . prune && diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index 64b3491e4e..1b3865e154 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -293,6 +293,8 @@ test_expect_success 'ls-remote with filtered symref (refname)' ' cat >expect <<-EOF && ref: refs/heads/main HEAD $rev HEAD + ref: refs/remotes/origin/main refs/remotes/origin/HEAD + $rev refs/remotes/origin/HEAD EOF git ls-remote --symref . HEAD >actual && test_cmp expect actual diff --git a/t/t5514-fetch-multiple.sh b/t/t5514-fetch-multiple.sh index 579872c258..e3482b27b2 100755 --- a/t/t5514-fetch-multiple.sh +++ b/t/t5514-fetch-multiple.sh @@ -45,14 +45,17 @@ test_expect_success setup ' ' cat > test/expect << EOF + one/HEAD -> one/main one/main one/side origin/HEAD -> origin/main origin/main origin/side + three/HEAD -> three/main three/another three/main three/side + two/HEAD -> two/main two/another two/main two/side @@ -97,6 +100,7 @@ cat > expect << EOF origin/HEAD -> origin/main origin/main origin/side + three/HEAD -> three/main three/another three/main three/side @@ -112,8 +116,10 @@ test_expect_success 'git fetch --multiple (but only one remote)' ' ' cat > expect << EOF + one/HEAD -> one/main one/main one/side + two/HEAD -> two/main two/another two/main two/side @@ -141,7 +147,7 @@ test_expect_success 'git fetch --multiple (bad remote names)' ' test_expect_success 'git fetch --all (skipFetchAll)' ' (cd test4 && - for b in $(git branch -r) + for b in $(git branch -r | grep -v HEAD) do git branch -r -d $b || exit 1 done && @@ -153,11 +159,14 @@ test_expect_success 'git fetch --all (skipFetchAll)' ' ' cat > expect << EOF + one/HEAD -> one/main one/main one/side + three/HEAD -> three/main three/another three/main three/side + two/HEAD -> two/main two/another two/main two/side @@ -165,7 +174,7 @@ EOF test_expect_success 'git fetch --multiple (ignoring skipFetchAll)' ' (cd test4 && - for b in $(git branch -r) + for b in $(git branch -r | grep -v HEAD) do git branch -r -d $b || exit 1 done && @@ -221,14 +230,17 @@ test_expect_success 'git fetch --multiple --jobs=0 picks a default' ' create_fetch_all_expect () { cat >expect <<-\EOF + one/HEAD -> one/main one/main one/side origin/HEAD -> origin/main origin/main origin/side + three/HEAD -> three/main three/another three/main three/side + two/HEAD -> two/main two/another two/main two/side @@ -265,6 +277,7 @@ test_expect_success 'git fetch (fetch all remotes with fetch.all = true)' ' create_fetch_one_expect () { cat >expect <<-\EOF + one/HEAD -> one/main one/main one/side origin/HEAD -> origin/main diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 331778bd42..5a051aa0c7 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -1395,7 +1395,8 @@ test_expect_success 'fetch follows tags by default' ' git tag -m "annotated" tag && git for-each-ref >tmp1 && sed -n "p; s|refs/heads/main$|refs/remotes/origin/main|p" tmp1 | - sort -k 3 >../expect + sed -n "p; s|refs/heads/main$|refs/remotes/origin/HEAD|p" | + sort -k 4 >../expect ) && test_when_finished "rm -rf dst" && git init dst && diff --git a/t/t5527-fetch-odd-refs.sh b/t/t5527-fetch-odd-refs.sh index 98ece27c6a..d3996af6ee 100755 --- a/t/t5527-fetch-odd-refs.sh +++ b/t/t5527-fetch-odd-refs.sh @@ -52,7 +52,8 @@ test_expect_success LONG_REF 'fetch handles extremely long refname' ' long main EOF - git for-each-ref --format="%(subject)" refs/remotes/long >actual && + git for-each-ref --format="%(subject)" refs/remotes/long \ + --exclude=refs/remotes/long/HEAD >actual && test_cmp expect actual ' diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh index 3cd7e1fcac..e53c3bbd6d 100755 --- a/t/t7900-maintenance.sh +++ b/t/t7900-maintenance.sh @@ -328,7 +328,8 @@ test_expect_success 'incremental-repack task' ' # Delete refs that have not been repacked in these packs. git for-each-ref --format="delete %(refname)" \ - refs/prefetch refs/tags refs/remotes >refs && + refs/prefetch refs/tags refs/remotes \ + --exclude=refs/remotes/*/HEAD >refs && git update-ref --stdin actual && - echo "refs/remotes/origin/parallel" >expect && + echo "refs/remotes/origin/HEAD" >>expect && + echo "refs/remotes/origin/parallel" >>expect && test_cmp expect actual && test_path_is_missing 1/2 && @@ -219,7 +220,7 @@ test_expect_success 'scalar reconfigure --all with includeIf.onbranch' ' done ' - test_expect_success 'scalar reconfigure --all with detached HEADs' ' +test_expect_success 'scalar reconfigure --all with detached HEADs' ' repos="two three four" && for num in $repos do diff --git a/t/t9211-scalar-clone.sh b/t/t9211-scalar-clone.sh index 7869f45ee6..01f71910f5 100755 --- a/t/t9211-scalar-clone.sh +++ b/t/t9211-scalar-clone.sh @@ -31,7 +31,7 @@ test_expect_success 'set up repository to clone' ' ) ' -cleanup_clone () { +cleanup_clone() { rm -rf "$1" } @@ -127,7 +127,7 @@ test_expect_success '--single-branch clones HEAD only' ' ( cd $enlistment/src && git for-each-ref refs/remotes/origin >out && - test_line_count = 1 out && + test_line_count = 2 out && grep "refs/remotes/origin/base" out ) && @@ -141,7 +141,7 @@ test_expect_success '--no-single-branch clones all branches' ' ( cd $enlistment/src && git for-each-ref refs/remotes/origin >out && - test_line_count = 2 out && + test_line_count = 3 out && grep "refs/remotes/origin/base" out && grep "refs/remotes/origin/parallel" out ) && diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index cc6aa9f0cd..b663c4609e 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -658,6 +658,7 @@ test_expect_success '__git_refs - simple' ' HEAD main matching-branch + other/HEAD other/branch-in-other other/main-in-other matching-tag @@ -673,6 +674,7 @@ test_expect_success '__git_refs - full refs' ' cat >expected <<-EOF && refs/heads/main refs/heads/matching-branch + refs/remotes/other/HEAD refs/remotes/other/branch-in-other refs/remotes/other/main-in-other refs/tags/matching-tag @@ -729,6 +731,7 @@ test_expect_success '__git_refs - remote on local file system - full refs' ' test_expect_success '__git_refs - configured remote' ' cat >expected <<-EOF && HEAD + HEAD branch-in-other main-in-other EOF @@ -756,6 +759,7 @@ test_expect_success '__git_refs - configured remote - full refs' ' test_expect_success '__git_refs - configured remote - repo given on the command line' ' cat >expected <<-EOF && HEAD + HEAD branch-in-other main-in-other EOF @@ -787,6 +791,7 @@ test_expect_success '__git_refs - configured remote - full refs - repo given on test_expect_success '__git_refs - configured remote - remote name matches a directory' ' cat >expected <<-EOF && HEAD + HEAD branch-in-other main-in-other EOF @@ -875,12 +880,14 @@ test_expect_success '__git_refs - unique remote branches for git checkout DWIMer HEAD main matching-branch + other/HEAD other/ambiguous other/branch-in-other other/main-in-other remote/ambiguous remote/branch-in-remote matching-tag + HEAD branch-in-other branch-in-remote main-in-other @@ -904,6 +911,7 @@ test_expect_success '__git_refs - after --opt=' ' HEAD main matching-branch + other/HEAD other/branch-in-other other/main-in-other matching-tag @@ -919,6 +927,7 @@ test_expect_success '__git_refs - after --opt= - full refs' ' cat >expected <<-EOF && refs/heads/main refs/heads/matching-branch + refs/remotes/other/HEAD refs/remotes/other/branch-in-other refs/remotes/other/main-in-other refs/tags/matching-tag @@ -935,6 +944,7 @@ test_expect_success '__git refs - excluding refs' ' ^HEAD ^main ^matching-branch + ^other/HEAD ^other/branch-in-other ^other/main-in-other ^matching-tag @@ -950,6 +960,7 @@ test_expect_success '__git refs - excluding full refs' ' cat >expected <<-EOF && ^refs/heads/main ^refs/heads/matching-branch + ^refs/remotes/other/HEAD ^refs/remotes/other/branch-in-other ^refs/remotes/other/main-in-other ^refs/tags/matching-tag @@ -975,6 +986,7 @@ test_expect_success '__git_refs - do not filter refs unless told so' ' main matching-branch matching/branch + other/HEAD other/branch-in-other other/main-in-other other/matching/branch-in-other @@ -1095,6 +1107,7 @@ test_expect_success '__git_complete_refs - simple' ' HEAD Z main Z matching-branch Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z matching-tag Z @@ -1123,6 +1136,7 @@ test_expect_success '__git_complete_refs - matching' ' test_expect_success '__git_complete_refs - remote' ' sed -e "s/Z$//" >expected <<-EOF && HEAD Z + HEAD Z branch-in-other Z main-in-other Z EOF @@ -1139,9 +1153,11 @@ test_expect_success '__git_complete_refs - track' ' HEAD Z main Z matching-branch Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z matching-tag Z + HEAD Z branch-in-other Z main-in-other Z EOF @@ -1184,6 +1200,7 @@ test_expect_success '__git_complete_refs - suffix' ' HEAD. main. matching-branch. + other/HEAD. other/branch-in-other. other/main-in-other. matching-tag. @@ -1199,6 +1216,7 @@ test_expect_success '__git_complete_refs - suffix' ' test_expect_success '__git_complete_fetch_refspecs - simple' ' sed -e "s/Z$//" >expected <<-EOF && HEAD:HEAD Z + HEAD:HEAD Z branch-in-other:branch-in-other Z main-in-other:main-in-other Z EOF @@ -1225,6 +1243,7 @@ test_expect_success '__git_complete_fetch_refspecs - matching' ' test_expect_success '__git_complete_fetch_refspecs - prefix' ' sed -e "s/Z$//" >expected <<-EOF && +HEAD:HEAD Z + +HEAD:HEAD Z +branch-in-other:branch-in-other Z +main-in-other:main-in-other Z EOF @@ -1289,6 +1308,7 @@ test_expect_success '__git_complete_worktree_paths with -C' ' test_expect_success 'git switch - with no options, complete local branches and unique remote branch names for DWIM logic' ' test_completion "git switch " <<-\EOF + HEAD Z branch-in-other Z main Z main-in-other Z @@ -1435,11 +1455,13 @@ test_expect_success 'git-bisect - existing view subcommand is recognized and ena test_expect_success 'git checkout - completes refs and unique remote branches for DWIM' ' test_completion "git checkout " <<-\EOF HEAD Z + HEAD Z branch-in-other Z main Z main-in-other Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1461,6 +1483,7 @@ test_expect_success 'git switch - with GIT_COMPLETION_CHECKOUT_NO_GUESS=1, compl test_expect_success 'git switch - --guess overrides GIT_COMPLETION_CHECKOUT_NO_GUESS=1, complete local branches and unique remote names for DWIM logic' ' GIT_COMPLETION_CHECKOUT_NO_GUESS=1 test_completion "git switch --guess " <<-\EOF + HEAD Z branch-in-other Z main Z main-in-other Z @@ -1470,6 +1493,7 @@ test_expect_success 'git switch - --guess overrides GIT_COMPLETION_CHECKOUT_NO_G test_expect_success 'git switch - a later --guess overrides previous --no-guess, complete local and remote unique branches for DWIM' ' test_completion "git switch --no-guess --guess " <<-\EOF + HEAD Z branch-in-other Z main Z main-in-other Z @@ -1490,6 +1514,7 @@ test_expect_success 'git checkout - with GIT_COMPLETION_NO_GUESS=1 only complete main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1498,11 +1523,13 @@ test_expect_success 'git checkout - with GIT_COMPLETION_NO_GUESS=1 only complete test_expect_success 'git checkout - --guess overrides GIT_COMPLETION_NO_GUESS=1, complete refs and unique remote branches for DWIM' ' GIT_COMPLETION_CHECKOUT_NO_GUESS=1 test_completion "git checkout --guess " <<-\EOF HEAD Z + HEAD Z branch-in-other Z main Z main-in-other Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1514,6 +1541,7 @@ test_expect_success 'git checkout - with --no-guess, only completes refs' ' main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1522,11 +1550,13 @@ test_expect_success 'git checkout - with --no-guess, only completes refs' ' test_expect_success 'git checkout - a later --guess overrides previous --no-guess, complete refs and unique remote branches for DWIM' ' test_completion "git checkout --no-guess --guess " <<-\EOF HEAD Z + HEAD Z branch-in-other Z main Z main-in-other Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1538,6 +1568,7 @@ test_expect_success 'git checkout - a later --no-guess overrides previous --gues main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1550,6 +1581,7 @@ test_expect_success 'git checkout - with checkout.guess = false, only completes main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1559,11 +1591,13 @@ test_expect_success 'git checkout - with checkout.guess = true, completes refs a test_config checkout.guess true && test_completion "git checkout " <<-\EOF HEAD Z + HEAD Z branch-in-other Z main Z main-in-other Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1573,11 +1607,13 @@ test_expect_success 'git checkout - a later --guess overrides previous checkout. test_config checkout.guess false && test_completion "git checkout --guess " <<-\EOF HEAD Z + HEAD Z branch-in-other Z main Z main-in-other Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1590,6 +1626,7 @@ test_expect_success 'git checkout - a later --no-guess overrides previous checko main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1601,6 +1638,7 @@ test_expect_success 'git switch - with --detach, complete all references' ' main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1612,6 +1650,7 @@ test_expect_success 'git checkout - with --detach, complete only references' ' main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1783,6 +1822,7 @@ test_expect_success 'git switch - with -d, complete all references' ' main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1794,6 +1834,7 @@ test_expect_success 'git checkout - with -d, complete only references' ' main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1801,10 +1842,12 @@ test_expect_success 'git checkout - with -d, complete only references' ' test_expect_success 'git switch - with --track, complete only remote branches' ' test_completion "git switch --track " <<-\EOF && + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF test_completion "git switch -t " <<-\EOF + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1812,10 +1855,12 @@ test_expect_success 'git switch - with --track, complete only remote branches' ' test_expect_success 'git checkout - with --track, complete only remote branches' ' test_completion "git checkout --track " <<-\EOF && + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF test_completion "git checkout -t " <<-\EOF + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1834,6 +1879,7 @@ test_expect_success 'git checkout - with --no-track, complete only local referen main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1845,6 +1891,7 @@ test_expect_success 'git switch - with -c, complete all references' ' main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1856,6 +1903,7 @@ test_expect_success 'git switch - with -C, complete all references' ' main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1867,6 +1915,7 @@ test_expect_success 'git switch - with -c and --track, complete all references' main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1878,6 +1927,7 @@ test_expect_success 'git switch - with -C and --track, complete all references' main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1889,6 +1939,7 @@ test_expect_success 'git switch - with -c and --no-track, complete all reference main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1900,6 +1951,7 @@ test_expect_success 'git switch - with -C and --no-track, complete all reference main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1911,6 +1963,7 @@ test_expect_success 'git checkout - with -b, complete all references' ' main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1922,6 +1975,7 @@ test_expect_success 'git checkout - with -B, complete all references' ' main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1933,6 +1987,7 @@ test_expect_success 'git checkout - with -b and --track, complete all references main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1944,6 +1999,7 @@ test_expect_success 'git checkout - with -B and --track, complete all references main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1955,6 +2011,7 @@ test_expect_success 'git checkout - with -b and --no-track, complete all referen main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1966,6 +2023,7 @@ test_expect_success 'git checkout - with -B and --no-track, complete all referen main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF @@ -1973,6 +2031,7 @@ test_expect_success 'git checkout - with -B and --no-track, complete all referen test_expect_success 'git switch - for -c, complete local branches and unique remote branches' ' test_completion "git switch -c " <<-\EOF + HEAD Z branch-in-other Z main Z main-in-other Z @@ -1982,6 +2041,7 @@ test_expect_success 'git switch - for -c, complete local branches and unique rem test_expect_success 'git switch - for -C, complete local branches and unique remote branches' ' test_completion "git switch -C " <<-\EOF + HEAD Z branch-in-other Z main Z main-in-other Z @@ -2019,6 +2079,7 @@ test_expect_success 'git switch - for -C with --no-track, complete local branche test_expect_success 'git checkout - for -b, complete local branches and unique remote branches' ' test_completion "git checkout -b " <<-\EOF + HEAD Z branch-in-other Z main Z main-in-other Z @@ -2028,6 +2089,7 @@ test_expect_success 'git checkout - for -b, complete local branches and unique r test_expect_success 'git checkout - for -B, complete local branches and unique remote branches' ' test_completion "git checkout -B " <<-\EOF + HEAD Z branch-in-other Z main Z main-in-other Z @@ -2065,6 +2127,7 @@ test_expect_success 'git checkout - for -B with --no-track, complete local branc test_expect_success 'git switch - with --orphan completes local branch names and unique remote branch names' ' test_completion "git switch --orphan " <<-\EOF + HEAD Z branch-in-other Z main Z main-in-other Z @@ -2080,6 +2143,7 @@ test_expect_success 'git switch - --orphan with branch already provided complete test_expect_success 'git checkout - with --orphan completes local branch names and unique remote branch names' ' test_completion "git checkout --orphan " <<-\EOF + HEAD Z branch-in-other Z main Z main-in-other Z @@ -2093,6 +2157,7 @@ test_expect_success 'git checkout - --orphan with branch already provided comple main Z matching-branch Z matching-tag Z + other/HEAD Z other/branch-in-other Z other/main-in-other Z EOF -- cgit v1.2.3 From b1b713f722894d7f66e9ec64bc934ca32004d3d1 Mon Sep 17 00:00:00 2001 From: Bence Ferdinandy Date: Fri, 22 Nov 2024 13:28:51 +0100 Subject: fetch set_head: handle mirrored bare repositories When adding a remote to bare repository with "git remote add --mirror", running fetch will fail to update HEAD to the remote's HEAD, since it does not know how to handle bare repositories. On the other hand HEAD already has content, since "git init --bare" has already set HEAD to whatever is the default branch set for the user. Unless this - by chance - is the same as the remote's HEAD, HEAD will be pointing to a bad symref. Teach set_head to handle bare repositories, by overwriting HEAD so it mirrors the remote's HEAD. Note, that in this case overriding the local HEAD reference is necessary, since HEAD will exist before fetch can be run, but this should not be an issue, since the whole purpose of --mirror is to be an exact mirror of the remote, so following any changes to HEAD makes sense. Also note, that although "git remote set-head" also fails when trying to update the remote's locally tracked HEAD in a mirrored bare repository, the usage of the command does not make much sense after this patch: fetch will update the remote HEAD correctly, and setting it manually to something else is antithetical to the concept of mirroring. Signed-off-by: Bence Ferdinandy Signed-off-by: Junio C Hamano --- builtin/fetch.c | 16 +++++++++++----- t/t5505-remote.sh | 10 ++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/builtin/fetch.c b/builtin/fetch.c index b2a36a5d95..a64de4485f 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1584,7 +1584,7 @@ static const char *strip_refshead(const char *name){ static int set_head(const struct ref *remote_refs) { - int result = 0; + int result = 0, is_bare; struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT; const char *remote = gtransport->remote->name; char *head_name = NULL; @@ -1616,15 +1616,21 @@ static int set_head(const struct ref *remote_refs) if (!head_name) goto cleanup; - strbuf_addf(&b_head, "refs/remotes/%s/HEAD", remote); - strbuf_addf(&b_remote_head, "refs/remotes/%s/%s", remote, head_name); + is_bare = is_bare_repository(); + if (is_bare) { + strbuf_addstr(&b_head, "HEAD"); + strbuf_addf(&b_remote_head, "refs/heads/%s", head_name); + } else { + strbuf_addf(&b_head, "refs/remotes/%s/HEAD", remote); + strbuf_addf(&b_remote_head, "refs/remotes/%s/%s", remote, head_name); + } /* make sure it's valid */ - if (!refs_ref_exists(refs, b_remote_head.buf)) { + if (!is_bare && !refs_ref_exists(refs, b_remote_head.buf)) { result = 1; goto cleanup; } if (refs_update_symref_extended(refs, b_head.buf, b_remote_head.buf, - "fetch", NULL, 1)) + "fetch", NULL, !is_bare)) result = 1; cleanup: diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index afa261409f..2600add82a 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -569,6 +569,16 @@ test_expect_success 'add --mirror && prune' ' ) ' +test_expect_success 'add --mirror setting HEAD' ' + mkdir headmirror && + ( + cd headmirror && + git init --bare -b notmain && + git remote add --mirror -f origin ../one && + test "$(git symbolic-ref HEAD)" = "refs/heads/main" + ) +' + test_expect_success 'add --mirror=fetch' ' mkdir mirror-fetch && git init -b main mirror-fetch/parent && -- cgit v1.2.3 From fe99a52225d56af16d283c769f14957d3c002471 Mon Sep 17 00:00:00 2001 From: Philippe Blain Date: Fri, 22 Nov 2024 19:50:18 +0000 Subject: completion: complete '--tool-help' in 'git mergetool' Signed-off-by: Philippe Blain Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 3d4dff3185..b3b6aa3bae 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -2331,7 +2331,7 @@ _git_mergetool () return ;; --*) - __gitcomp "--tool= --prompt --no-prompt --gui --no-gui" + __gitcomp "--tool= --tool-help --prompt --no-prompt --gui --no-gui" return ;; esac -- cgit v1.2.3 From 00536761df113c8ad935c78bf407e427fce2f040 Mon Sep 17 00:00:00 2001 From: Philippe Blain Date: Fri, 22 Nov 2024 19:50:19 +0000 Subject: git-mergetool--lib.sh: use TOOL_MODE when erroring about unknown tool In git-mergetool--lib.sh::get_merge_tool_path, we check if the chosen tool is valid via valid_tool and exit with an error message if not. This error message mentions "Unknown merge tool", even if the command the user tried was 'git difftool --tool=unknown'. Use the global 'TOOL_MODE' variable for a more correct error message. Signed-off-by: Philippe Blain Signed-off-by: Junio C Hamano --- git-mergetool--lib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh index 1ff26170ff..269a60ea44 100644 --- a/git-mergetool--lib.sh +++ b/git-mergetool--lib.sh @@ -474,7 +474,7 @@ get_merge_tool_path () { merge_tool="$1" if ! valid_tool "$merge_tool" then - echo >&2 "Unknown merge tool $merge_tool" + echo >&2 "Unknown $TOOL_MODE tool $merge_tool" exit 1 fi if diff_mode -- cgit v1.2.3 From bba503d43ef43a90597795e5e82018ba33d6a095 Mon Sep 17 00:00:00 2001 From: Philippe Blain Date: Fri, 22 Nov 2024 19:50:20 +0000 Subject: git-mergetool--lib.sh: add error message if 'setup_user_tool' fails In git-mergetool--lib.sh::setup_tool, we check if the given tool is a known builtin tool, a known variant, or a user-defined tool by calling setup_user_tool, and we return with the exit code from setup_user_tool if it was called. setup_user_tool checks if {diff,merge}tool.$tool.cmd is set and quietly returns with an error if not. This leads to the following invocation quietly failing: git mergetool --tool=unknown which is not very user-friendly. Adjust setup_tool to output an error message before returning if setup_user_tool returned with an error. Note that we do not check the result of the second call to setup_user_tool in setup_tool, as this call is only meant to allow users to redefine 'cmd' for a builtin tool; it is not an error if they have not done so. Note that this behaviour of quietly failing is a regression dating back to de8dafbada (mergetool: break setup_tool out into separate initialization function, 2021-02-09), as before this commit an unknown mergetool would be diagnosed in get_merge_tool_path when called from run_merge_tool. Signed-off-by: Philippe Blain Signed-off-by: Junio C Hamano --- git-mergetool--lib.sh | 9 +++++++-- t/t7610-mergetool.sh | 8 ++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh index 269a60ea44..d7e410d948 100644 --- a/git-mergetool--lib.sh +++ b/git-mergetool--lib.sh @@ -159,7 +159,7 @@ check_unchanged () { } valid_tool () { - setup_tool "$1" && return 0 + setup_tool "$1" 2>/dev/null && return 0 cmd=$(get_merge_tool_cmd "$1") test -n "$cmd" } @@ -250,7 +250,12 @@ setup_tool () { . "$MERGE_TOOLS_DIR/${tool%[0-9]}" else setup_user_tool - return $? + rc=$? + if test $rc -ne 0 + then + echo >&2 "error: ${TOOL_MODE}tool.$tool.cmd not set for tool '$tool'" + fi + return $rc fi # Now let the user override the default command for the tool. If diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh index 5c5e79e990..4ec11f997e 100755 --- a/t/t7610-mergetool.sh +++ b/t/t7610-mergetool.sh @@ -899,4 +899,12 @@ test_expect_success 'mergetool with guiDefault' ' git commit -m "branch1 resolved with mergetool" ' +test_expect_success 'mergetool with non-existent tool' ' + test_when_finished "git reset --hard" && + git checkout -b test$test_count branch1 && + test_must_fail git merge main && + yes "" | test_must_fail git mergetool --tool=absent >out 2>&1 && + test_grep "mergetool.absent.cmd not set for tool" out +' + test_done -- cgit v1.2.3 From acca46d12464cc64b623b104c04977d8db1a9591 Mon Sep 17 00:00:00 2001 From: Philippe Blain Date: Fri, 22 Nov 2024 19:50:21 +0000 Subject: git-mergetool--lib.sh: add error message for unknown tool variant In setup_tool, we check if the given tool is a known variant of a tool, and quietly return with an error if not. This leads to the following invocation quietly failing: git mergetool --tool=vimdiff4 Add an error message before returning in this case. Signed-off-by: Philippe Blain Signed-off-by: Junio C Hamano --- git-mergetool--lib.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh index d7e410d948..11ea181259 100644 --- a/git-mergetool--lib.sh +++ b/git-mergetool--lib.sh @@ -264,6 +264,7 @@ setup_tool () { if ! list_tool_variants | grep -q "^$tool$" then + echo "error: unknown tool variant '$tool'" >&2 return 1 fi -- cgit v1.2.3 From dbaece3526c30efab07f7f06c849bd8deaf62249 Mon Sep 17 00:00:00 2001 From: Philippe Blain Date: Fri, 22 Nov 2024 19:50:22 +0000 Subject: git-difftool--helper.sh: exit upon initialize_merge_tool errors Since the introduction of 'initialize_merge_tool' in de8dafbada (mergetool: break setup_tool out into separate initialization function, 2021-02-09), any errors from this function are ignored in git-difftool--helper.sh::launch_merge_tool, which is not the case for its call in git-mergetool.sh::merge_file. Despite the in-code comment, initialize_merge_tool (via its call to setup_tool) does different checks than run_merge_tool, so it makes sense to abort early if it encounters errors. Add exit calls if initialize_merge_tool fails. Signed-off-by: Philippe Blain Signed-off-by: Junio C Hamano --- git-difftool--helper.sh | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh index dd0c9a5b7f..d32e47cc09 100755 --- a/git-difftool--helper.sh +++ b/git-difftool--helper.sh @@ -61,9 +61,7 @@ launch_merge_tool () { export BASE eval $GIT_DIFFTOOL_EXTCMD '"$LOCAL"' '"$REMOTE"' else - initialize_merge_tool "$merge_tool" - # ignore the error from the above --- run_merge_tool - # will diagnose unusable tool by itself + initialize_merge_tool "$merge_tool" || exit 1 run_merge_tool "$merge_tool" fi } @@ -87,9 +85,7 @@ if test -n "$GIT_DIFFTOOL_DIRDIFF" then LOCAL="$1" REMOTE="$2" - initialize_merge_tool "$merge_tool" - # ignore the error from the above --- run_merge_tool - # will diagnose unusable tool by itself + initialize_merge_tool "$merge_tool" || exit 1 run_merge_tool "$merge_tool" false status=$? -- cgit v1.2.3 From 1bc1e940918cd44cc78bff1dfd518e16fc5bad57 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 25 Nov 2024 12:14:01 +0900 Subject: doc: option value may be separate for valid reasons Even though `git help cli` recommends users to prefer using "--option=value" over "--option value", there can be reasons why giving them separately is a good idea. One reason is that shells do not perform tilde expansion for `--option=~/path/name` but they expand `--options ~/path/name` just fine. This is not a problem for many options whose option parsing is properly written using OPT_FILENAME(), because the value given to OPT_FILENAME() is tilde-expanded internally by us, but some commands take a pathname as a mere string, which needs this trick to have the shell help us. I think the reason we originally decided to recommend the stuck form was because an option that takes an optional value requires you to use it in the stuck form, and it is one less thing for users to worry about if they get into the habit to always use the stuck form. But we should be discouraging ourselves from adding an option with an optional value in the first place, and we might want to weaken the current recommendation. In any case, let's describe this one case where it is necessary to use the separate form, with an example. Reviewed-by: Eric Sunshine Signed-off-by: Junio C Hamano --- Documentation/gitcli.txt | 9 +++++++++ Documentation/gitcredentials.txt | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt index 7c709324ba..bd62cbd043 100644 --- a/Documentation/gitcli.txt +++ b/Documentation/gitcli.txt @@ -90,6 +90,15 @@ scripting Git: for long options. An option that takes optional option-argument must be written in the 'stuck' form. + * Despite the above suggestion, when Arg is a path relative to the + home directory of a user, e.g. ~/directory/file or ~u/d/f, you + may want to use the separate form, e.g. `git foo --file ~/mine`, + not `git foo --file=~/mine`. The shell will expand `~/` in the + former to your home directory, but most shells keep the tilde in + the latter. Some of our commands know how to tilde-expand the + option value even when given in the stuck form, but not all of + them do. + * When you give a revision parameter to a command, make sure the parameter is not ambiguous with a name of a file in the work tree. E.g. do not write `git log -1 HEAD` but write `git log -1 HEAD --`; the former will not work diff --git a/Documentation/gitcredentials.txt b/Documentation/gitcredentials.txt index 71dd19731a..35a7452c8f 100644 --- a/Documentation/gitcredentials.txt +++ b/Documentation/gitcredentials.txt @@ -242,6 +242,12 @@ Here are some example specifications: [credential] helper = "foo --bar='whitespace arg'" +# store helper (discouraged) with custom location for the db file; +# use `--file ~/.git-secret.txt`, rather than `--file=~/.git-secret.txt`, +# to allow the shell to expand tilde to the home directory. +[credential] + helper = "store --file ~/.git-secret.txt" + # you can also use an absolute path, which will not use the git wrapper [credential] helper = "/path/to/my/helper --with-arguments" -- cgit v1.2.3 From 4a2790a257b314ab59f6f2e25f3d7ca120219922 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Mon, 25 Nov 2024 19:00:48 +0000 Subject: fast-import: disallow "." and ".." path components If a user specified e.g. M 100644 :1 ../some-file then fast-import previously would happily create a git history where there is a tree in the top-level directory named "..", and with a file inside that directory named "some-file". The top-level ".." directory causes problems. While git checkout will die with errors and fsck will report hasDotdot problems, the user is going to have problems trying to remove the problematic file. Simply avoid creating this bad history in the first place. Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- builtin/fast-import.c | 2 ++ t/t9300-fast-import.sh | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/builtin/fast-import.c b/builtin/fast-import.c index 1e7ab67f6e..3e7ec1f119 100644 --- a/builtin/fast-import.c +++ b/builtin/fast-import.c @@ -1468,6 +1468,8 @@ static int tree_content_set( root->tree = t = grow_tree_content(t, t->entry_count); e = new_tree_entry(); e->name = to_atom(p, n); + if (is_dot_or_dotdot(e->name->str_dat)) + die("path %s contains invalid component", p); e->versions[0].mode = 0; oidclr(&e->versions[0].oid, the_repository->hash_algo); t->entries[t->entry_count++] = e; diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 3b3c371740..5a5127fffa 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -522,6 +522,26 @@ test_expect_success 'B: fail on invalid committer (5)' ' test_must_fail git fast-import input <<-INPUT_END && + blob + mark :1 + data < $GIT_COMMITTER_DATE + data < Date: Tue, 26 Nov 2024 07:42:52 +0100 Subject: refs/reftable: encapsulate reftable stack The reftable ref store needs to keep track of multiple stacks, one for the main worktree and an arbitrary number of stacks for worktrees. This is done by storing pointers to `struct reftable_stack`, which we then access directly. Wrap the stack in a new `struct reftable_backend`. This will allow us to attach more data to each respective stack in subsequent commits. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- refs/reftable-backend.c | 135 +++++++++++++++++++++++++++--------------------- 1 file changed, 76 insertions(+), 59 deletions(-) diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c index f560bc2b67..acd26f8928 100644 --- a/refs/reftable-backend.c +++ b/refs/reftable-backend.c @@ -34,24 +34,41 @@ */ #define REF_UPDATE_VIA_HEAD (1 << 8) +struct reftable_backend { + struct reftable_stack *stack; +}; + +static int reftable_backend_init(struct reftable_backend *be, + const char *path, + const struct reftable_write_options *opts) +{ + return reftable_new_stack(&be->stack, path, opts); +} + +static void reftable_backend_release(struct reftable_backend *be) +{ + reftable_stack_destroy(be->stack); + be->stack = NULL; +} + struct reftable_ref_store { struct ref_store base; /* - * The main stack refers to the common dir and thus contains common + * The main backend refers to the common dir and thus contains common * refs as well as refs of the main repository. */ - struct reftable_stack *main_stack; + struct reftable_backend main_backend; /* - * The worktree stack refers to the gitdir in case the refdb is opened + * The worktree backend refers to the gitdir in case the refdb is opened * via a worktree. It thus contains the per-worktree refs. */ - struct reftable_stack *worktree_stack; + struct reftable_backend worktree_backend; /* - * Map of worktree stacks by their respective worktree names. The map + * Map of worktree backends by their respective worktree names. The map * is populated lazily when we try to resolve `worktrees/$worktree` refs. */ - struct strmap worktree_stacks; + struct strmap worktree_backends; struct reftable_write_options write_options; unsigned int store_flags; @@ -97,21 +114,21 @@ static struct reftable_ref_store *reftable_be_downcast(struct ref_store *ref_sto * like `worktrees/$worktree/refs/heads/foo` as worktree stacks will store * those references in their normalized form. */ -static struct reftable_stack *stack_for(struct reftable_ref_store *store, - const char *refname, - const char **rewritten_ref) +static struct reftable_backend *backend_for(struct reftable_ref_store *store, + const char *refname, + const char **rewritten_ref) { const char *wtname; int wtname_len; if (!refname) - return store->main_stack; + return &store->main_backend; switch (parse_worktree_ref(refname, &wtname, &wtname_len, rewritten_ref)) { case REF_WORKTREE_OTHER: { static struct strbuf wtname_buf = STRBUF_INIT; struct strbuf wt_dir = STRBUF_INIT; - struct reftable_stack *stack; + struct reftable_backend *be; /* * We're using a static buffer here so that we don't need to @@ -125,37 +142,39 @@ static struct reftable_stack *stack_for(struct reftable_ref_store *store, /* * There is an edge case here: when the worktree references the * current worktree, then we set up the stack once via - * `worktree_stacks` and once via `worktree_stack`. This is + * `worktree_backends` and once via `worktree_backend`. This is * wasteful, but in the reading case it shouldn't matter. And * in the writing case we would notice that the stack is locked * already and error out when trying to write a reference via * both stacks. */ - stack = strmap_get(&store->worktree_stacks, wtname_buf.buf); - if (!stack) { + be = strmap_get(&store->worktree_backends, wtname_buf.buf); + if (!be) { strbuf_addf(&wt_dir, "%s/worktrees/%s/reftable", store->base.repo->commondir, wtname_buf.buf); - store->err = reftable_new_stack(&stack, wt_dir.buf, - &store->write_options); + CALLOC_ARRAY(be, 1); + store->err = reftable_backend_init(be, wt_dir.buf, + &store->write_options); assert(store->err != REFTABLE_API_ERROR); - strmap_put(&store->worktree_stacks, wtname_buf.buf, stack); + + strmap_put(&store->worktree_backends, wtname_buf.buf, be); } strbuf_release(&wt_dir); - return stack; + return be; } case REF_WORKTREE_CURRENT: /* * If there is no worktree stack then we're currently in the * main worktree. We thus return the main stack in that case. */ - if (!store->worktree_stack) - return store->main_stack; - return store->worktree_stack; + if (!store->worktree_backend.stack) + return &store->main_backend; + return &store->worktree_backend; case REF_WORKTREE_MAIN: case REF_WORKTREE_SHARED: - return store->main_stack; + return &store->main_backend; default: BUG("unhandled worktree reference type"); } @@ -292,7 +311,7 @@ static struct ref_store *reftable_be_init(struct repository *repo, umask(mask); base_ref_store_init(&refs->base, repo, gitdir, &refs_be_reftable); - strmap_init(&refs->worktree_stacks); + strmap_init(&refs->worktree_backends); refs->store_flags = store_flags; refs->log_all_ref_updates = repo_settings_get_log_all_ref_updates(repo); @@ -337,8 +356,8 @@ static struct ref_store *reftable_be_init(struct repository *repo, strbuf_realpath(&path, gitdir, 0); } strbuf_addstr(&path, "/reftable"); - refs->err = reftable_new_stack(&refs->main_stack, path.buf, - &refs->write_options); + refs->err = reftable_backend_init(&refs->main_backend, path.buf, + &refs->write_options); if (refs->err) goto done; @@ -354,8 +373,8 @@ static struct ref_store *reftable_be_init(struct repository *repo, strbuf_reset(&path); strbuf_addf(&path, "%s/reftable", gitdir); - refs->err = reftable_new_stack(&refs->worktree_stack, path.buf, - &refs->write_options); + refs->err = reftable_backend_init(&refs->worktree_backend, path.buf, + &refs->write_options); if (refs->err) goto done; } @@ -374,19 +393,17 @@ static void reftable_be_release(struct ref_store *ref_store) struct strmap_entry *entry; struct hashmap_iter iter; - if (refs->main_stack) { - reftable_stack_destroy(refs->main_stack); - refs->main_stack = NULL; - } + if (refs->main_backend.stack) + reftable_backend_release(&refs->main_backend); + if (refs->worktree_backend.stack) + reftable_backend_release(&refs->worktree_backend); - if (refs->worktree_stack) { - reftable_stack_destroy(refs->worktree_stack); - refs->worktree_stack = NULL; + strmap_for_each_entry(&refs->worktree_backends, &iter, entry) { + struct reftable_backend *be = entry->value; + reftable_backend_release(be); + free(be); } - - strmap_for_each_entry(&refs->worktree_stacks, &iter, entry) - reftable_stack_destroy(entry->value); - strmap_clear(&refs->worktree_stacks, 0); + strmap_clear(&refs->worktree_backends, 0); } static int reftable_be_create_on_disk(struct ref_store *ref_store, @@ -781,7 +798,7 @@ static struct ref_iterator *reftable_be_iterator_begin(struct ref_store *ref_sto required_flags |= REF_STORE_ODB; refs = reftable_be_downcast(ref_store, required_flags, "ref_iterator_begin"); - main_iter = ref_iterator_for_stack(refs, refs->main_stack, prefix, + main_iter = ref_iterator_for_stack(refs, refs->main_backend.stack, prefix, exclude_patterns, flags); /* @@ -789,14 +806,14 @@ static struct ref_iterator *reftable_be_iterator_begin(struct ref_store *ref_sto * right now. If we aren't, then we return the common reftable * iterator, only. */ - if (!refs->worktree_stack) + if (!refs->worktree_backend.stack) return &main_iter->base; /* * Otherwise we merge both the common and the per-worktree refs into a * single iterator. */ - worktree_iter = ref_iterator_for_stack(refs, refs->worktree_stack, prefix, + worktree_iter = ref_iterator_for_stack(refs, refs->worktree_backend.stack, prefix, exclude_patterns, flags); return merge_ref_iterator_begin(&worktree_iter->base, &main_iter->base, ref_iterator_select, NULL); @@ -811,7 +828,7 @@ static int reftable_be_read_raw_ref(struct ref_store *ref_store, { struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_READ, "read_raw_ref"); - struct reftable_stack *stack = stack_for(refs, refname, &refname); + struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack; int ret; if (refs->err < 0) @@ -838,7 +855,7 @@ static int reftable_be_read_symbolic_ref(struct ref_store *ref_store, { struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_READ, "read_symbolic_ref"); - struct reftable_stack *stack = stack_for(refs, refname, &refname); + struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack; struct reftable_ref_record ref = {0}; int ret; @@ -898,7 +915,7 @@ static int prepare_transaction_update(struct write_transaction_table_arg **out, struct ref_update *update, struct strbuf *err) { - struct reftable_stack *stack = stack_for(refs, update->refname, NULL); + struct reftable_stack *stack = backend_for(refs, update->refname, NULL)->stack; struct write_transaction_table_arg *arg = NULL; size_t i; int ret; @@ -1031,7 +1048,7 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store, goto done; } - ret = read_ref_without_reload(refs, stack_for(refs, "HEAD", NULL), "HEAD", + ret = read_ref_without_reload(refs, backend_for(refs, "HEAD", NULL)->stack, "HEAD", &head_oid, &head_referent, &head_type); if (ret < 0) goto done; @@ -1043,7 +1060,7 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store, struct reftable_stack *stack; const char *rewritten_ref; - stack = stack_for(refs, u->refname, &rewritten_ref); + stack = backend_for(refs, u->refname, &rewritten_ref)->stack; /* Verify that the new object ID is valid. */ if ((u->flags & REF_HAVE_NEW) && !is_null_oid(&u->new_oid) && @@ -1525,9 +1542,9 @@ static int reftable_be_pack_refs(struct ref_store *ref_store, if (refs->err) return refs->err; - stack = refs->worktree_stack; + stack = refs->worktree_backend.stack; if (!stack) - stack = refs->main_stack; + stack = refs->main_backend.stack; if (opts->flags & PACK_REFS_AUTO) ret = reftable_stack_auto_compact(stack); @@ -1782,7 +1799,7 @@ static int reftable_be_rename_ref(struct ref_store *ref_store, { struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_WRITE, "rename_ref"); - struct reftable_stack *stack = stack_for(refs, newrefname, &newrefname); + struct reftable_stack *stack = backend_for(refs, newrefname, &newrefname)->stack; struct write_copy_arg arg = { .refs = refs, .stack = stack, @@ -1814,7 +1831,7 @@ static int reftable_be_copy_ref(struct ref_store *ref_store, { struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_WRITE, "copy_ref"); - struct reftable_stack *stack = stack_for(refs, newrefname, &newrefname); + struct reftable_stack *stack = backend_for(refs, newrefname, &newrefname)->stack; struct write_copy_arg arg = { .refs = refs, .stack = stack, @@ -1952,11 +1969,11 @@ static struct ref_iterator *reftable_be_reflog_iterator_begin(struct ref_store * reftable_be_downcast(ref_store, REF_STORE_READ, "reflog_iterator_begin"); struct reftable_reflog_iterator *main_iter, *worktree_iter; - main_iter = reflog_iterator_for_stack(refs, refs->main_stack); - if (!refs->worktree_stack) + main_iter = reflog_iterator_for_stack(refs, refs->main_backend.stack); + if (!refs->worktree_backend.stack) return &main_iter->base; - worktree_iter = reflog_iterator_for_stack(refs, refs->worktree_stack); + worktree_iter = reflog_iterator_for_stack(refs, refs->worktree_backend.stack); return merge_ref_iterator_begin(&worktree_iter->base, &main_iter->base, ref_iterator_select, NULL); @@ -1995,7 +2012,7 @@ static int reftable_be_for_each_reflog_ent_reverse(struct ref_store *ref_store, { struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_READ, "for_each_reflog_ent_reverse"); - struct reftable_stack *stack = stack_for(refs, refname, &refname); + struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack; struct reftable_log_record log = {0}; struct reftable_iterator it = {0}; int ret; @@ -2035,7 +2052,7 @@ static int reftable_be_for_each_reflog_ent(struct ref_store *ref_store, { struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_READ, "for_each_reflog_ent"); - struct reftable_stack *stack = stack_for(refs, refname, &refname); + struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack; struct reftable_log_record *logs = NULL; struct reftable_iterator it = {0}; size_t logs_alloc = 0, logs_nr = 0, i; @@ -2084,7 +2101,7 @@ static int reftable_be_reflog_exists(struct ref_store *ref_store, { struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_READ, "reflog_exists"); - struct reftable_stack *stack = stack_for(refs, refname, &refname); + struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack; struct reftable_log_record log = {0}; struct reftable_iterator it = {0}; int ret; @@ -2169,7 +2186,7 @@ static int reftable_be_create_reflog(struct ref_store *ref_store, { struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_WRITE, "create_reflog"); - struct reftable_stack *stack = stack_for(refs, refname, &refname); + struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack; struct write_reflog_existence_arg arg = { .refs = refs, .stack = stack, @@ -2243,7 +2260,7 @@ static int reftable_be_delete_reflog(struct ref_store *ref_store, { struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_WRITE, "delete_reflog"); - struct reftable_stack *stack = stack_for(refs, refname, &refname); + struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack; struct write_reflog_delete_arg arg = { .stack = stack, .refname = refname, @@ -2352,7 +2369,7 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store, */ struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_WRITE, "reflog_expire"); - struct reftable_stack *stack = stack_for(refs, refname, &refname); + struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack; struct reftable_log_record *logs = NULL; struct reftable_log_record *rewritten = NULL; struct reftable_ref_record ref_record = {0}; -- cgit v1.2.3 From 46b5f67019bbf9864416d13693f6292bca62d7af Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 26 Nov 2024 07:42:53 +0100 Subject: refs/reftable: handle reloading stacks in the reftable backend When accessing a stack we almost always have to reload the stack before reading data from it. This is mostly because Git does not have a notification mechanism for when underlying data has been changed, and thus we are forced to opportunistically reload the stack every single time to account for any changes that may have happened concurrently. Handle the reload internally in `backend_for()`. For one this forces callsites to think about whether or not they need to reload the stack. But second this makes the logic to access stacks more self-contained by letting the `struct reftable_backend` manage themselves. Update callsites where we don't reload the stack to document why we don't. In some cases it's unclear whether it is the right thing to do in the first place, but fixing that is outside of the scope of this patch series. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- refs/reftable-backend.c | 184 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 126 insertions(+), 58 deletions(-) diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c index acd26f8928..8be9cc43c9 100644 --- a/refs/reftable-backend.c +++ b/refs/reftable-backend.c @@ -114,21 +114,25 @@ static struct reftable_ref_store *reftable_be_downcast(struct ref_store *ref_sto * like `worktrees/$worktree/refs/heads/foo` as worktree stacks will store * those references in their normalized form. */ -static struct reftable_backend *backend_for(struct reftable_ref_store *store, - const char *refname, - const char **rewritten_ref) +static int backend_for(struct reftable_backend **out, + struct reftable_ref_store *store, + const char *refname, + const char **rewritten_ref, + int reload) { + struct reftable_backend *be; const char *wtname; int wtname_len; - if (!refname) - return &store->main_backend; + if (!refname) { + be = &store->main_backend; + goto out; + } switch (parse_worktree_ref(refname, &wtname, &wtname_len, rewritten_ref)) { case REF_WORKTREE_OTHER: { static struct strbuf wtname_buf = STRBUF_INIT; struct strbuf wt_dir = STRBUF_INIT; - struct reftable_backend *be; /* * We're using a static buffer here so that we don't need to @@ -162,7 +166,7 @@ static struct reftable_backend *backend_for(struct reftable_ref_store *store, } strbuf_release(&wt_dir); - return be; + goto out; } case REF_WORKTREE_CURRENT: /* @@ -170,14 +174,27 @@ static struct reftable_backend *backend_for(struct reftable_ref_store *store, * main worktree. We thus return the main stack in that case. */ if (!store->worktree_backend.stack) - return &store->main_backend; - return &store->worktree_backend; + be = &store->main_backend; + else + be = &store->worktree_backend; + goto out; case REF_WORKTREE_MAIN: case REF_WORKTREE_SHARED: - return &store->main_backend; + be = &store->main_backend; + goto out; default: BUG("unhandled worktree reference type"); } + +out: + if (reload) { + int ret = reftable_stack_reload(be->stack); + if (ret) + return ret; + } + *out = be; + + return 0; } static int should_write_log(struct reftable_ref_store *refs, const char *refname) @@ -828,17 +845,17 @@ static int reftable_be_read_raw_ref(struct ref_store *ref_store, { struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_READ, "read_raw_ref"); - struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack; + struct reftable_backend *be; int ret; if (refs->err < 0) return refs->err; - ret = reftable_stack_reload(stack); + ret = backend_for(&be, refs, refname, &refname, 1); if (ret) return ret; - ret = read_ref_without_reload(refs, stack, refname, oid, referent, type); + ret = read_ref_without_reload(refs, be->stack, refname, oid, referent, type); if (ret < 0) return ret; if (ret > 0) { @@ -855,15 +872,15 @@ static int reftable_be_read_symbolic_ref(struct ref_store *ref_store, { struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_READ, "read_symbolic_ref"); - struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack; struct reftable_ref_record ref = {0}; + struct reftable_backend *be; int ret; - ret = reftable_stack_reload(stack); + ret = backend_for(&be, refs, refname, &refname, 1); if (ret) return ret; - ret = reftable_stack_read_ref(stack, refname, &ref); + ret = reftable_stack_read_ref(be->stack, refname, &ref); if (ret == 0 && ref.value_type == REFTABLE_REF_SYMREF) strbuf_addstr(referent, ref.value.symref); else @@ -880,7 +897,7 @@ struct reftable_transaction_update { struct write_transaction_table_arg { struct reftable_ref_store *refs; - struct reftable_stack *stack; + struct reftable_backend *be; struct reftable_addition *addition; struct reftable_transaction_update *updates; size_t updates_nr; @@ -915,27 +932,37 @@ static int prepare_transaction_update(struct write_transaction_table_arg **out, struct ref_update *update, struct strbuf *err) { - struct reftable_stack *stack = backend_for(refs, update->refname, NULL)->stack; struct write_transaction_table_arg *arg = NULL; + struct reftable_backend *be; size_t i; int ret; + /* + * This function gets called in a loop, and we don't want to repeatedly + * reload the stack for every single ref update. Instead, we manually + * reload further down in the case where we haven't yet prepared the + * specific `reftable_backend`. + */ + ret = backend_for(&be, refs, update->refname, NULL, 0); + if (ret) + return ret; + /* * Search for a preexisting stack update. If there is one then we add * the update to it, otherwise we set up a new stack update. */ for (i = 0; !arg && i < tx_data->args_nr; i++) - if (tx_data->args[i].stack == stack) + if (tx_data->args[i].be == be) arg = &tx_data->args[i]; if (!arg) { struct reftable_addition *addition; - ret = reftable_stack_reload(stack); + ret = reftable_stack_reload(be->stack); if (ret) return ret; - ret = reftable_stack_new_addition(&addition, stack, + ret = reftable_stack_new_addition(&addition, be->stack, REFTABLE_STACK_NEW_ADDITION_RELOAD); if (ret) { if (ret == REFTABLE_LOCK_ERROR) @@ -947,7 +974,7 @@ static int prepare_transaction_update(struct write_transaction_table_arg **out, tx_data->args_alloc); arg = &tx_data->args[tx_data->args_nr++]; arg->refs = refs; - arg->stack = stack; + arg->be = be; arg->addition = addition; arg->updates = NULL; arg->updates_nr = 0; @@ -1002,6 +1029,7 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store, struct strbuf referent = STRBUF_INIT, head_referent = STRBUF_INIT; struct string_list affected_refnames = STRING_LIST_INIT_NODUP; struct reftable_transaction_data *tx_data = NULL; + struct reftable_backend *be; struct object_id head_oid; unsigned int head_type = 0; size_t i; @@ -1048,7 +1076,22 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store, goto done; } - ret = read_ref_without_reload(refs, backend_for(refs, "HEAD", NULL)->stack, "HEAD", + /* + * TODO: it's dubious whether we should reload the stack that "HEAD" + * belongs to or not. In theory, it may happen that we only modify + * stacks which are _not_ part of the "HEAD" stack. In that case we + * wouldn't have prepared any transaction for its stack and would not + * have reloaded it, which may mean that it is stale. + * + * On the other hand, reloading that stack without locking it feels + * wrong, too, as the value of "HEAD" could be modified concurrently at + * any point in time. + */ + ret = backend_for(&be, refs, "HEAD", NULL, 0); + if (ret) + goto done; + + ret = read_ref_without_reload(refs, be->stack, "HEAD", &head_oid, &head_referent, &head_type); if (ret < 0) goto done; @@ -1057,10 +1100,18 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store, for (i = 0; i < transaction->nr; i++) { struct ref_update *u = transaction->updates[i]; struct object_id current_oid = {0}; - struct reftable_stack *stack; const char *rewritten_ref; - stack = backend_for(refs, u->refname, &rewritten_ref)->stack; + /* + * There is no need to reload the respective backends here as + * we have already reloaded them when preparing the transaction + * update. And given that the stacks have been locked there + * shouldn't have been any concurrent modifications of the + * stack. + */ + ret = backend_for(&be, refs, u->refname, &rewritten_ref, 0); + if (ret) + goto done; /* Verify that the new object ID is valid. */ if ((u->flags & REF_HAVE_NEW) && !is_null_oid(&u->new_oid) && @@ -1116,7 +1167,7 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store, string_list_insert(&affected_refnames, new_update->refname); } - ret = read_ref_without_reload(refs, stack, rewritten_ref, + ret = read_ref_without_reload(refs, be->stack, rewritten_ref, ¤t_oid, &referent, &u->type); if (ret < 0) goto done; @@ -1318,7 +1369,7 @@ static int transaction_update_cmp(const void *a, const void *b) static int write_transaction_table(struct reftable_writer *writer, void *cb_data) { struct write_transaction_table_arg *arg = cb_data; - uint64_t ts = reftable_stack_next_update_index(arg->stack); + uint64_t ts = reftable_stack_next_update_index(arg->be->stack); struct reftable_log_record *logs = NULL; struct ident_split committer_ident = {0}; size_t logs_nr = 0, logs_alloc = 0, i; @@ -1354,7 +1405,7 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data struct reftable_log_record log = {0}; struct reftable_iterator it = {0}; - ret = reftable_stack_init_log_iterator(arg->stack, &it); + ret = reftable_stack_init_log_iterator(arg->be->stack, &it); if (ret < 0) goto done; @@ -1799,10 +1850,9 @@ static int reftable_be_rename_ref(struct ref_store *ref_store, { struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_WRITE, "rename_ref"); - struct reftable_stack *stack = backend_for(refs, newrefname, &newrefname)->stack; + struct reftable_backend *be; struct write_copy_arg arg = { .refs = refs, - .stack = stack, .oldname = oldrefname, .newname = newrefname, .logmsg = logmsg, @@ -1814,10 +1864,11 @@ static int reftable_be_rename_ref(struct ref_store *ref_store, if (ret < 0) goto done; - ret = reftable_stack_reload(stack); + ret = backend_for(&be, refs, newrefname, &newrefname, 1); if (ret) goto done; - ret = reftable_stack_add(stack, &write_copy_table, &arg); + arg.stack = be->stack; + ret = reftable_stack_add(be->stack, &write_copy_table, &arg); done: assert(ret != REFTABLE_API_ERROR); @@ -1831,10 +1882,9 @@ static int reftable_be_copy_ref(struct ref_store *ref_store, { struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_WRITE, "copy_ref"); - struct reftable_stack *stack = backend_for(refs, newrefname, &newrefname)->stack; + struct reftable_backend *be; struct write_copy_arg arg = { .refs = refs, - .stack = stack, .oldname = oldrefname, .newname = newrefname, .logmsg = logmsg, @@ -1845,10 +1895,11 @@ static int reftable_be_copy_ref(struct ref_store *ref_store, if (ret < 0) goto done; - ret = reftable_stack_reload(stack); + ret = backend_for(&be, refs, newrefname, &newrefname, 1); if (ret) goto done; - ret = reftable_stack_add(stack, &write_copy_table, &arg); + arg.stack = be->stack; + ret = reftable_stack_add(be->stack, &write_copy_table, &arg); done: assert(ret != REFTABLE_API_ERROR); @@ -2012,15 +2063,23 @@ static int reftable_be_for_each_reflog_ent_reverse(struct ref_store *ref_store, { struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_READ, "for_each_reflog_ent_reverse"); - struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack; struct reftable_log_record log = {0}; struct reftable_iterator it = {0}; + struct reftable_backend *be; int ret; if (refs->err < 0) return refs->err; - ret = reftable_stack_init_log_iterator(stack, &it); + /* + * TODO: we should adapt this callsite to reload the stack. There is no + * obvious reason why we shouldn't. + */ + ret = backend_for(&be, refs, refname, &refname, 0); + if (ret) + goto done; + + ret = reftable_stack_init_log_iterator(be->stack, &it); if (ret < 0) goto done; @@ -2052,16 +2111,24 @@ static int reftable_be_for_each_reflog_ent(struct ref_store *ref_store, { struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_READ, "for_each_reflog_ent"); - struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack; struct reftable_log_record *logs = NULL; struct reftable_iterator it = {0}; + struct reftable_backend *be; size_t logs_alloc = 0, logs_nr = 0, i; int ret; if (refs->err < 0) return refs->err; - ret = reftable_stack_init_log_iterator(stack, &it); + /* + * TODO: we should adapt this callsite to reload the stack. There is no + * obvious reason why we shouldn't. + */ + ret = backend_for(&be, refs, refname, &refname, 0); + if (ret) + goto done; + + ret = reftable_stack_init_log_iterator(be->stack, &it); if (ret < 0) goto done; @@ -2101,20 +2168,20 @@ static int reftable_be_reflog_exists(struct ref_store *ref_store, { struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_READ, "reflog_exists"); - struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack; struct reftable_log_record log = {0}; struct reftable_iterator it = {0}; + struct reftable_backend *be; int ret; ret = refs->err; if (ret < 0) goto done; - ret = reftable_stack_reload(stack); + ret = backend_for(&be, refs, refname, &refname, 1); if (ret < 0) goto done; - ret = reftable_stack_init_log_iterator(stack, &it); + ret = reftable_stack_init_log_iterator(be->stack, &it); if (ret < 0) goto done; @@ -2186,10 +2253,9 @@ static int reftable_be_create_reflog(struct ref_store *ref_store, { struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_WRITE, "create_reflog"); - struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack; + struct reftable_backend *be; struct write_reflog_existence_arg arg = { .refs = refs, - .stack = stack, .refname = refname, }; int ret; @@ -2198,11 +2264,12 @@ static int reftable_be_create_reflog(struct ref_store *ref_store, if (ret < 0) goto done; - ret = reftable_stack_reload(stack); + ret = backend_for(&be, refs, refname, &refname, 1); if (ret) goto done; + arg.stack = be->stack; - ret = reftable_stack_add(stack, &write_reflog_existence_table, &arg); + ret = reftable_stack_add(be->stack, &write_reflog_existence_table, &arg); done: return ret; @@ -2260,17 +2327,18 @@ static int reftable_be_delete_reflog(struct ref_store *ref_store, { struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_WRITE, "delete_reflog"); - struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack; + struct reftable_backend *be; struct write_reflog_delete_arg arg = { - .stack = stack, .refname = refname, }; int ret; - ret = reftable_stack_reload(stack); + ret = backend_for(&be, refs, refname, &refname, 1); if (ret) return ret; - ret = reftable_stack_add(stack, &write_reflog_delete_table, &arg); + arg.stack = be->stack; + + ret = reftable_stack_add(be->stack, &write_reflog_delete_table, &arg); assert(ret != REFTABLE_API_ERROR); return ret; @@ -2369,13 +2437,13 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store, */ struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_WRITE, "reflog_expire"); - struct reftable_stack *stack = backend_for(refs, refname, &refname)->stack; struct reftable_log_record *logs = NULL; struct reftable_log_record *rewritten = NULL; struct reftable_ref_record ref_record = {0}; struct reftable_iterator it = {0}; struct reftable_addition *add = NULL; struct reflog_expiry_arg arg = {0}; + struct reftable_backend *be; struct object_id oid = {0}; uint8_t *last_hash = NULL; size_t logs_nr = 0, logs_alloc = 0, i; @@ -2384,11 +2452,11 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store, if (refs->err < 0) return refs->err; - ret = reftable_stack_reload(stack); + ret = backend_for(&be, refs, refname, &refname, 1); if (ret < 0) goto done; - ret = reftable_stack_init_log_iterator(stack, &it); + ret = reftable_stack_init_log_iterator(be->stack, &it); if (ret < 0) goto done; @@ -2396,11 +2464,11 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store, if (ret < 0) goto done; - ret = reftable_stack_new_addition(&add, stack, 0); + ret = reftable_stack_new_addition(&add, be->stack, 0); if (ret < 0) goto done; - ret = reftable_stack_read_ref(stack, refname, &ref_record); + ret = reftable_stack_read_ref(be->stack, refname, &ref_record); if (ret < 0) goto done; if (reftable_ref_record_val1(&ref_record)) @@ -2479,8 +2547,8 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store, arg.refs = refs; arg.records = rewritten; arg.len = logs_nr; - arg.stack = stack, - arg.refname = refname, + arg.stack = be->stack; + arg.refname = refname; ret = reftable_addition_add(add, &write_reflog_expiry_table, &arg); if (ret < 0) -- cgit v1.2.3 From c9f76fc7d197d9ed2624400d5fc34d6ab53b7a22 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 26 Nov 2024 07:42:54 +0100 Subject: reftable/stack: add accessor for the hash ID Add an accessor function that allows callers to access the hash ID of a reftable stack. This function will be used in a subsequent commit. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- reftable/reftable-stack.h | 3 +++ reftable/stack.c | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/reftable/reftable-stack.h b/reftable/reftable-stack.h index 54787f2ef5..ae14270ea7 100644 --- a/reftable/reftable-stack.h +++ b/reftable/reftable-stack.h @@ -149,4 +149,7 @@ struct reftable_compaction_stats { struct reftable_compaction_stats * reftable_stack_compaction_stats(struct reftable_stack *st); +/* Return the hash of the stack. */ +enum reftable_hash reftable_stack_hash_id(struct reftable_stack *st); + #endif diff --git a/reftable/stack.c b/reftable/stack.c index 10d45e89d0..8beb5c0541 100644 --- a/reftable/stack.c +++ b/reftable/stack.c @@ -1791,3 +1791,8 @@ done: reftable_addition_destroy(add); return err; } + +enum reftable_hash reftable_stack_hash_id(struct reftable_stack *st) +{ + return reftable_merged_table_hash_id(st->merged); +} -- cgit v1.2.3 From 3ec8022bb0bd20da40e9d4a173331ac864d1bd28 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 26 Nov 2024 07:42:55 +0100 Subject: refs/reftable: figure out hash via `reftable_stack` The function `read_ref_without_reload()` accepts a ref store as input only so that we can figure out the hash function used by it. This is duplicate information though because the reftable stack knows about its hash function, too. Drop the superfluous parameter to simplify the calling convention a bit. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- refs/reftable-backend.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c index 8be9cc43c9..302de622d4 100644 --- a/refs/reftable-backend.c +++ b/refs/reftable-backend.c @@ -243,8 +243,7 @@ static void fill_reftable_log_record(struct reftable_log_record *log, const stru log->value.update.tz_offset = sign * atoi(tz_begin); } -static int read_ref_without_reload(struct reftable_ref_store *refs, - struct reftable_stack *stack, +static int read_ref_without_reload(struct reftable_stack *stack, const char *refname, struct object_id *oid, struct strbuf *referent, @@ -262,8 +261,21 @@ static int read_ref_without_reload(struct reftable_ref_store *refs, strbuf_addstr(referent, ref.value.symref); *type |= REF_ISSYMREF; } else if (reftable_ref_record_val1(&ref)) { + unsigned int hash_id; + + switch (reftable_stack_hash_id(stack)) { + case REFTABLE_HASH_SHA1: + hash_id = GIT_HASH_SHA1; + break; + case REFTABLE_HASH_SHA256: + hash_id = GIT_HASH_SHA256; + break; + default: + BUG("unhandled hash ID %d", reftable_stack_hash_id(stack)); + } + oidread(oid, reftable_ref_record_val1(&ref), - refs->base.repo->hash_algo); + &hash_algos[hash_id]); } else { /* We got a tombstone, which should not happen. */ BUG("unhandled reference value type %d", ref.value_type); @@ -855,7 +867,7 @@ static int reftable_be_read_raw_ref(struct ref_store *ref_store, if (ret) return ret; - ret = read_ref_without_reload(refs, be->stack, refname, oid, referent, type); + ret = read_ref_without_reload(be->stack, refname, oid, referent, type); if (ret < 0) return ret; if (ret > 0) { @@ -1091,7 +1103,7 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store, if (ret) goto done; - ret = read_ref_without_reload(refs, be->stack, "HEAD", + ret = read_ref_without_reload(be->stack, "HEAD", &head_oid, &head_referent, &head_type); if (ret < 0) goto done; @@ -1167,7 +1179,7 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store, string_list_insert(&affected_refnames, new_update->refname); } - ret = read_ref_without_reload(refs, be->stack, rewritten_ref, + ret = read_ref_without_reload(be->stack, rewritten_ref, ¤t_oid, &referent, &u->type); if (ret < 0) goto done; @@ -1733,7 +1745,7 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data) memcpy(logs[logs_nr].value.update.old_hash, old_ref.value.val1, GIT_MAX_RAWSZ); logs_nr++; - ret = read_ref_without_reload(arg->refs, arg->stack, "HEAD", &head_oid, + ret = read_ref_without_reload(arg->stack, "HEAD", &head_oid, &head_referent, &head_type); if (ret < 0) goto done; -- cgit v1.2.3 From 27fdf8f4ed0b76f4c21c6ee1f95886c731c4e196 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 26 Nov 2024 07:42:56 +0100 Subject: refs/reftable: read references via `struct reftable_backend` Refactor `read_ref_without_reload()` to accept `struct reftable_backend` as parameter instead of `struct reftable_stack`. Rename the function to `reftable_backend_read_ref()` to clarify its scope and move it close to other functions operating on `struct reftable_backend`. This change allows us to implement an additional caching layer when reading refs where we can reuse reftable iterators. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- refs/reftable-backend.c | 122 +++++++++++++++++++++++------------------------- 1 file changed, 59 insertions(+), 63 deletions(-) diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c index 302de622d4..88910207b8 100644 --- a/refs/reftable-backend.c +++ b/refs/reftable-backend.c @@ -51,6 +51,50 @@ static void reftable_backend_release(struct reftable_backend *be) be->stack = NULL; } +static int reftable_backend_read_ref(struct reftable_backend *be, + const char *refname, + struct object_id *oid, + struct strbuf *referent, + unsigned int *type) +{ + struct reftable_ref_record ref = {0}; + int ret; + + ret = reftable_stack_read_ref(be->stack, refname, &ref); + if (ret) + goto done; + + if (ref.value_type == REFTABLE_REF_SYMREF) { + strbuf_reset(referent); + strbuf_addstr(referent, ref.value.symref); + *type |= REF_ISSYMREF; + } else if (reftable_ref_record_val1(&ref)) { + unsigned int hash_id; + + switch (reftable_stack_hash_id(be->stack)) { + case REFTABLE_HASH_SHA1: + hash_id = GIT_HASH_SHA1; + break; + case REFTABLE_HASH_SHA256: + hash_id = GIT_HASH_SHA256; + break; + default: + BUG("unhandled hash ID %d", reftable_stack_hash_id(be->stack)); + } + + oidread(oid, reftable_ref_record_val1(&ref), + &hash_algos[hash_id]); + } else { + /* We got a tombstone, which should not happen. */ + BUG("unhandled reference value type %d", ref.value_type); + } + +done: + assert(ret != REFTABLE_API_ERROR); + reftable_ref_record_release(&ref); + return ret; +} + struct reftable_ref_store { struct ref_store base; @@ -243,50 +287,6 @@ static void fill_reftable_log_record(struct reftable_log_record *log, const stru log->value.update.tz_offset = sign * atoi(tz_begin); } -static int read_ref_without_reload(struct reftable_stack *stack, - const char *refname, - struct object_id *oid, - struct strbuf *referent, - unsigned int *type) -{ - struct reftable_ref_record ref = {0}; - int ret; - - ret = reftable_stack_read_ref(stack, refname, &ref); - if (ret) - goto done; - - if (ref.value_type == REFTABLE_REF_SYMREF) { - strbuf_reset(referent); - strbuf_addstr(referent, ref.value.symref); - *type |= REF_ISSYMREF; - } else if (reftable_ref_record_val1(&ref)) { - unsigned int hash_id; - - switch (reftable_stack_hash_id(stack)) { - case REFTABLE_HASH_SHA1: - hash_id = GIT_HASH_SHA1; - break; - case REFTABLE_HASH_SHA256: - hash_id = GIT_HASH_SHA256; - break; - default: - BUG("unhandled hash ID %d", reftable_stack_hash_id(stack)); - } - - oidread(oid, reftable_ref_record_val1(&ref), - &hash_algos[hash_id]); - } else { - /* We got a tombstone, which should not happen. */ - BUG("unhandled reference value type %d", ref.value_type); - } - -done: - assert(ret != REFTABLE_API_ERROR); - reftable_ref_record_release(&ref); - return ret; -} - static int reftable_be_config(const char *var, const char *value, const struct config_context *ctx, void *_opts) @@ -867,7 +867,7 @@ static int reftable_be_read_raw_ref(struct ref_store *ref_store, if (ret) return ret; - ret = read_ref_without_reload(be->stack, refname, oid, referent, type); + ret = reftable_backend_read_ref(be, refname, oid, referent, type); if (ret < 0) return ret; if (ret > 0) { @@ -1103,8 +1103,8 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store, if (ret) goto done; - ret = read_ref_without_reload(be->stack, "HEAD", - &head_oid, &head_referent, &head_type); + ret = reftable_backend_read_ref(be, "HEAD", &head_oid, + &head_referent, &head_type); if (ret < 0) goto done; ret = 0; @@ -1179,8 +1179,8 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store, string_list_insert(&affected_refnames, new_update->refname); } - ret = read_ref_without_reload(be->stack, rewritten_ref, - ¤t_oid, &referent, &u->type); + ret = reftable_backend_read_ref(be, rewritten_ref, + ¤t_oid, &referent, &u->type); if (ret < 0) goto done; if (ret > 0 && !ref_update_expects_existing_old_ref(u)) { @@ -1638,7 +1638,7 @@ struct write_create_symref_arg { struct write_copy_arg { struct reftable_ref_store *refs; - struct reftable_stack *stack; + struct reftable_backend *be; const char *oldname; const char *newname; const char *logmsg; @@ -1663,7 +1663,7 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data) if (split_ident_line(&committer_ident, committer_info, strlen(committer_info))) BUG("failed splitting committer info"); - if (reftable_stack_read_ref(arg->stack, arg->oldname, &old_ref)) { + if (reftable_stack_read_ref(arg->be->stack, arg->oldname, &old_ref)) { ret = error(_("refname %s not found"), arg->oldname); goto done; } @@ -1702,7 +1702,7 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data) * the old branch and the creation of the new branch, and we cannot do * two changes to a reflog in a single update. */ - deletion_ts = creation_ts = reftable_stack_next_update_index(arg->stack); + deletion_ts = creation_ts = reftable_stack_next_update_index(arg->be->stack); if (arg->delete_old) creation_ts++; reftable_writer_set_limits(writer, deletion_ts, creation_ts); @@ -1745,8 +1745,8 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data) memcpy(logs[logs_nr].value.update.old_hash, old_ref.value.val1, GIT_MAX_RAWSZ); logs_nr++; - ret = read_ref_without_reload(arg->stack, "HEAD", &head_oid, - &head_referent, &head_type); + ret = reftable_backend_read_ref(arg->be, "HEAD", &head_oid, + &head_referent, &head_type); if (ret < 0) goto done; append_head_reflog = (head_type & REF_ISSYMREF) && !strcmp(head_referent.buf, arg->oldname); @@ -1789,7 +1789,7 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data) * copy over all log entries from the old reflog. Last but not least, * when renaming we also have to delete all the old reflog entries. */ - ret = reftable_stack_init_log_iterator(arg->stack, &it); + ret = reftable_stack_init_log_iterator(arg->be->stack, &it); if (ret < 0) goto done; @@ -1862,7 +1862,6 @@ static int reftable_be_rename_ref(struct ref_store *ref_store, { struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_WRITE, "rename_ref"); - struct reftable_backend *be; struct write_copy_arg arg = { .refs = refs, .oldname = oldrefname, @@ -1876,11 +1875,10 @@ static int reftable_be_rename_ref(struct ref_store *ref_store, if (ret < 0) goto done; - ret = backend_for(&be, refs, newrefname, &newrefname, 1); + ret = backend_for(&arg.be, refs, newrefname, &newrefname, 1); if (ret) goto done; - arg.stack = be->stack; - ret = reftable_stack_add(be->stack, &write_copy_table, &arg); + ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg); done: assert(ret != REFTABLE_API_ERROR); @@ -1894,7 +1892,6 @@ static int reftable_be_copy_ref(struct ref_store *ref_store, { struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_WRITE, "copy_ref"); - struct reftable_backend *be; struct write_copy_arg arg = { .refs = refs, .oldname = oldrefname, @@ -1907,11 +1904,10 @@ static int reftable_be_copy_ref(struct ref_store *ref_store, if (ret < 0) goto done; - ret = backend_for(&be, refs, newrefname, &newrefname, 1); + ret = backend_for(&arg.be, refs, newrefname, &newrefname, 1); if (ret) goto done; - arg.stack = be->stack; - ret = reftable_stack_add(be->stack, &write_copy_table, &arg); + ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg); done: assert(ret != REFTABLE_API_ERROR); -- cgit v1.2.3 From ad6c41f4b7e93f9c16a69d03a32d8f99d8428144 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 26 Nov 2024 07:42:57 +0100 Subject: refs/reftable: refactor reading symbolic refs to use reftable backend Refactor the callback function that reads symbolic references in the reftable backend to use `reftable_backend_read_ref()` instead of accessing the reftable stack directly. This ensures that the function will benefit from the new caching layer that we're about to introduce. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- refs/reftable-backend.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c index 88910207b8..2d06620ac8 100644 --- a/refs/reftable-backend.c +++ b/refs/reftable-backend.c @@ -884,21 +884,18 @@ static int reftable_be_read_symbolic_ref(struct ref_store *ref_store, { struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_READ, "read_symbolic_ref"); - struct reftable_ref_record ref = {0}; struct reftable_backend *be; + struct object_id oid; + unsigned int type = 0; int ret; ret = backend_for(&be, refs, refname, &refname, 1); if (ret) return ret; - ret = reftable_stack_read_ref(be->stack, refname, &ref); - if (ret == 0 && ref.value_type == REFTABLE_REF_SYMREF) - strbuf_addstr(referent, ref.value.symref); - else + ret = reftable_backend_read_ref(be, refname, &oid, referent, &type); + if (type != REF_ISSYMREF) ret = -1; - - reftable_ref_record_release(&ref); return ret; } -- cgit v1.2.3 From 96e7cb83b65622c8189678ea52d469786bdf0240 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 26 Nov 2024 07:42:58 +0100 Subject: refs/reftable: refactor reflog expiry to use reftable backend Refactor the callback function that expires reflog entries in the reftable backend to use `reftable_backend_read_ref()` instead of accessing the reftable stack directly. This ensures that the function will benefit from the new caching layer that we're about to introduce. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- refs/reftable-backend.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c index 2d06620ac8..b6638d4302 100644 --- a/refs/reftable-backend.c +++ b/refs/reftable-backend.c @@ -2444,14 +2444,15 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store, reftable_be_downcast(ref_store, REF_STORE_WRITE, "reflog_expire"); struct reftable_log_record *logs = NULL; struct reftable_log_record *rewritten = NULL; - struct reftable_ref_record ref_record = {0}; struct reftable_iterator it = {0}; struct reftable_addition *add = NULL; struct reflog_expiry_arg arg = {0}; struct reftable_backend *be; struct object_id oid = {0}; + struct strbuf referent = STRBUF_INIT; uint8_t *last_hash = NULL; size_t logs_nr = 0, logs_alloc = 0, i; + unsigned int type = 0; int ret; if (refs->err < 0) @@ -2473,12 +2474,9 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store, if (ret < 0) goto done; - ret = reftable_stack_read_ref(be->stack, refname, &ref_record); + ret = reftable_backend_read_ref(be, refname, &oid, &referent, &type); if (ret < 0) goto done; - if (reftable_ref_record_val1(&ref_record)) - oidread(&oid, reftable_ref_record_val1(&ref_record), - ref_store->repo->hash_algo); prepare_fn(refname, &oid, policy_cb_data); while (1) { @@ -2545,8 +2543,7 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store, } } - if (flags & EXPIRE_REFLOGS_UPDATE_REF && last_hash && - reftable_ref_record_val1(&ref_record)) + if (flags & EXPIRE_REFLOGS_UPDATE_REF && last_hash && !is_null_oid(&oid)) oidread(&arg.update_oid, last_hash, ref_store->repo->hash_algo); arg.refs = refs; @@ -2571,11 +2568,11 @@ done: cleanup_fn(policy_cb_data); assert(ret != REFTABLE_API_ERROR); - reftable_ref_record_release(&ref_record); reftable_iterator_destroy(&it); reftable_addition_destroy(add); for (i = 0; i < logs_nr; i++) reftable_log_record_release(&logs[i]); + strbuf_release(&referent); free(logs); free(rewritten); return ret; -- cgit v1.2.3 From eb22c1b46b85f7fac8467f991890d50853e4ca4d Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 26 Nov 2024 07:42:59 +0100 Subject: reftable/stack: add mechanism to notify callers on reload Reftable stacks are reloaded in two cases: - When calling `reftable_stack_reload()`, if the stat-cache tells us that the stack has been modified. - When committing a reftable addition. While callers can figure out the second case, they do not have a mechanism to figure out whether `reftable_stack_reload()` led to an actual reload of the on-disk data. All they can do is thus to assume that data is always being reloaded in that case. Improve the situation by introducing a new `on_reload()` callback to the reftable options. If provided, the function will be invoked every time the stack has indeed been reloaded. This allows callers to invalidate data that depends on the current stack data. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- reftable/reftable-writer.h | 9 +++++++++ reftable/stack.c | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/reftable/reftable-writer.h b/reftable/reftable-writer.h index c85ef5a5bd..5f9afa620b 100644 --- a/reftable/reftable-writer.h +++ b/reftable/reftable-writer.h @@ -68,6 +68,15 @@ struct reftable_write_options { * fsync(3P) when unset. */ int (*fsync)(int fd); + + /* + * Callback function to execute whenever the stack is being reloaded. + * This can be used e.g. to discard cached information that relies on + * the old stack's data. The payload data will be passed as argument to + * the callback. + */ + void (*on_reload)(void *payload); + void *on_reload_payload; }; /* reftable_block_stats holds statistics for a single block type */ diff --git a/reftable/stack.c b/reftable/stack.c index 8beb5c0541..59fd695a12 100644 --- a/reftable/stack.c +++ b/reftable/stack.c @@ -548,6 +548,10 @@ out: close(fd); free_names(names); free_names(names_after); + + if (st->opts.on_reload) + st->opts.on_reload(st->opts.on_reload_payload); + return err; } -- cgit v1.2.3 From 9d471b9dfed15f023572133893a2d0817e5e8004 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 26 Nov 2024 07:43:00 +0100 Subject: reftable/merged: drain priority queue on reseek In 5bf96e0c39 (reftable/generic: move seeking of records into the iterator, 2024-05-13) we have refactored the reftable codebase such that iterators can be initialized once and then re-seeked multiple times. This feature is used by 1869525066 (refs/reftable: wire up support for exclude patterns, 2024-09-16) in order to skip records based on exclude patterns provided by the caller. The logic to re-seek the merged iterator is insufficient though because we don't drain the priority queue on a re-seek. This means that the queue may contain stale entries and thus reading the next record in the queue will return the wrong entry. While this is an obvious bug, it is harmless in the context of above exclude patterns: - If the queue contained stale entries that match the pattern then the caller would already know to filter out such refs. This is because our codebase is prepared to handle backends that don't have a way to efficiently implement exclude patterns. - If the queue contained stale entries that don't match the pattern we'd eventually filter out any duplicates. This is because the reftable code discards items with the same ref name and sorts any remaining entries properly. So things happen to work in this context regardless of the bug, and there is no other use case yet where we re-seek iterators. We're about to introduce a caching mechanism though where iterators are reused by the reftable backend, and that will expose the bug. Fix the issue by draining the priority queue when seeking and add a testcase that surfaces the issue. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- reftable/merged.c | 2 ++ t/unit-tests/t-reftable-merged.c | 73 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/reftable/merged.c b/reftable/merged.c index 5b93e20f42..bb0836e344 100644 --- a/reftable/merged.c +++ b/reftable/merged.c @@ -66,6 +66,8 @@ static int merged_iter_seek(struct merged_iter *mi, struct reftable_record *want int err; mi->advance_index = -1; + while (!merged_iter_pqueue_is_empty(mi->pq)) + merged_iter_pqueue_remove(&mi->pq); for (size_t i = 0; i < mi->subiters_len; i++) { err = iterator_seek(&mi->subiters[i].iter, want); diff --git a/t/unit-tests/t-reftable-merged.c b/t/unit-tests/t-reftable-merged.c index 2591b5e597..a12bd0e1a3 100644 --- a/t/unit-tests/t-reftable-merged.c +++ b/t/unit-tests/t-reftable-merged.c @@ -273,6 +273,78 @@ static void t_merged_seek_multiple_times(void) reftable_free(sources); } +static void t_merged_seek_multiple_times_without_draining(void) +{ + struct reftable_ref_record r1[] = { + { + .refname = (char *) "a", + .update_index = 1, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = { 1 }, + }, + { + .refname = (char *) "c", + .update_index = 1, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = { 2 }, + } + }; + struct reftable_ref_record r2[] = { + { + .refname = (char *) "b", + .update_index = 2, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = { 3 }, + }, + { + .refname = (char *) "d", + .update_index = 2, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = { 4 }, + }, + }; + struct reftable_ref_record *refs[] = { + r1, r2, + }; + size_t sizes[] = { + ARRAY_SIZE(r1), ARRAY_SIZE(r2), + }; + struct reftable_buf bufs[] = { + REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, + }; + struct reftable_block_source *sources = NULL; + struct reftable_reader **readers = NULL; + struct reftable_ref_record rec = { 0 }; + struct reftable_iterator it = { 0 }; + struct reftable_merged_table *mt; + int err; + + mt = merged_table_from_records(refs, &sources, &readers, sizes, bufs, 2); + merged_table_init_iter(mt, &it, BLOCK_TYPE_REF); + + err = reftable_iterator_seek_ref(&it, "b"); + check(!err); + err = reftable_iterator_next_ref(&it, &rec); + check(!err); + err = reftable_ref_record_equal(&rec, &r2[0], REFTABLE_HASH_SIZE_SHA1); + check(err == 1); + + err = reftable_iterator_seek_ref(&it, "a"); + check(!err); + err = reftable_iterator_next_ref(&it, &rec); + check(!err); + err = reftable_ref_record_equal(&rec, &r1[0], REFTABLE_HASH_SIZE_SHA1); + check(err == 1); + + for (size_t i = 0; i < ARRAY_SIZE(bufs); i++) + reftable_buf_release(&bufs[i]); + readers_destroy(readers, ARRAY_SIZE(refs)); + reftable_ref_record_release(&rec); + reftable_iterator_destroy(&it); + reftable_merged_table_free(mt); + reftable_free(sources); +} + static struct reftable_merged_table * merged_table_from_log_records(struct reftable_log_record **logs, struct reftable_block_source **source, @@ -467,6 +539,7 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED) TEST(t_merged_logs(), "merged table with multiple log updates for same ref"); TEST(t_merged_refs(), "merged table with multiple updates to same ref"); TEST(t_merged_seek_multiple_times(), "merged table can seek multiple times"); + TEST(t_merged_seek_multiple_times_without_draining(), "merged table can seek multiple times without draining"); TEST(t_merged_single_record(), "ref occurring in only one record can be fetched"); return test_done(); -- cgit v1.2.3 From 7cf65e266020f23d31863a1f9508f375be818071 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 26 Nov 2024 07:43:01 +0100 Subject: refs/reftable: reuse iterators when reading refs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When reading references the reftable backend has to: 1. Create a new ref iterator. 2. Seek the iterator to the record we're searching for. 3. Read the record. We cannot really avoid the last two steps, but re-creating the iterator every single time we want to read a reference is kind of expensive and a waste of resources. We couldn't help it in the past though because it was not possible to reuse iterators. But starting with 5bf96e0c39 (reftable/generic: move seeking of records into the iterator, 2024-05-13) we have split up the iterator lifecycle such that creating the iterator and seeking are two different concerns. Refactor the code such that we cache iterators in the reftable backend. This cache is invalidated whenever the respective stack is reloaded such that we know to recreate the iterator in that case. This leads to a sizeable speedup when creating many refs, which requires a lot of random reference reads: Benchmark 1: update-ref: create many refs (refcount = 100000, revision = master) Time (mean ± σ): 1.793 s ± 0.010 s [User: 0.954 s, System: 0.835 s] Range (min … max): 1.781 s … 1.811 s 10 runs Benchmark 2: update-ref: create many refs (refcount = 100000, revision = HEAD) Time (mean ± σ): 1.680 s ± 0.013 s [User: 0.846 s, System: 0.831 s] Range (min … max): 1.664 s … 1.702 s 10 runs Summary update-ref: create many refs (refcount = 100000, revision = HEAD) ran 1.07 ± 0.01 times faster than update-ref: create many refs (refcount = 100000, revision = master) While 7% is not a huge win, you have to consider that the benchmark is _writing_ data, so _reading_ references is only one part of what we do. Flame graphs show that we spend around 40% of our time reading refs, so the speedup when reading refs is approximately ~2.5x that. I could not find better benchmarks where we perform a lot of random ref reads. You can also see a sizeable impact on memory usage when creating 100k references. Before this change: HEAP SUMMARY: in use at exit: 19,112,538 bytes in 200,170 blocks total heap usage: 8,400,426 allocs, 8,200,256 frees, 454,367,048 bytes allocated After this change: HEAP SUMMARY: in use at exit: 674,416 bytes in 169 blocks total heap usage: 7,929,872 allocs, 7,929,703 frees, 281,509,985 bytes allocated As an additional factor, this refactoring opens up the possibility for more performance optimizations in how we re-seek iterators. Any change that allows us to optimize re-seeking by e.g. reusing data structures would thus also directly speed up random reads. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- refs/reftable-backend.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c index b6638d4302..a80c334f38 100644 --- a/refs/reftable-backend.c +++ b/refs/reftable-backend.c @@ -36,19 +36,30 @@ struct reftable_backend { struct reftable_stack *stack; + struct reftable_iterator it; }; +static void reftable_backend_on_reload(void *payload) +{ + struct reftable_backend *be = payload; + reftable_iterator_destroy(&be->it); +} + static int reftable_backend_init(struct reftable_backend *be, const char *path, - const struct reftable_write_options *opts) + const struct reftable_write_options *_opts) { - return reftable_new_stack(&be->stack, path, opts); + struct reftable_write_options opts = *_opts; + opts.on_reload = reftable_backend_on_reload; + opts.on_reload_payload = be; + return reftable_new_stack(&be->stack, path, &opts); } static void reftable_backend_release(struct reftable_backend *be) { reftable_stack_destroy(be->stack); be->stack = NULL; + reftable_iterator_destroy(&be->it); } static int reftable_backend_read_ref(struct reftable_backend *be, @@ -60,10 +71,25 @@ static int reftable_backend_read_ref(struct reftable_backend *be, struct reftable_ref_record ref = {0}; int ret; - ret = reftable_stack_read_ref(be->stack, refname, &ref); + if (!be->it.ops) { + ret = reftable_stack_init_ref_iterator(be->stack, &be->it); + if (ret) + goto done; + } + + ret = reftable_iterator_seek_ref(&be->it, refname); if (ret) goto done; + ret = reftable_iterator_next_ref(&be->it, &ref); + if (ret) + goto done; + + if (strcmp(ref.refname, refname)) { + ret = 1; + goto done; + } + if (ref.value_type == REFTABLE_REF_SYMREF) { strbuf_reset(referent); strbuf_addstr(referent, ref.value.symref); -- cgit v1.2.3 From c903985bf7e772e2d08275c1a95c8a55ab011577 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 7 Nov 2024 08:57:52 +0100 Subject: credential_format(): also encode [:] An upcoming change wants to sanitize the credential password prompt where a URL is displayed that may potentially come from a `.gitmodules` file. To this end, the `credential_format()` function is employed. To sanitize the host name (and optional port) part of the URL, we need a new mode of the `strbuf_add_percentencode()` function because the current mode is both too strict and too lenient: too strict because it encodes `:`, `[` and `]` (which should be left unencoded in `:` and in IPv6 addresses), and too lenient because it does not encode invalid host name characters `/`, `_` and `~`. So let's introduce and use a new mode specifically to encode the host name and optional port part of a URI, leaving alpha-numerical characters, periods, colons and brackets alone and encoding all others. This only leads to a change of behavior for URLs that contain invalid host names. Signed-off-by: Johannes Schindelin --- credential.c | 3 ++- strbuf.c | 4 +++- strbuf.h | 1 + t/t0300-credentials.sh | 13 +++++++++++++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/credential.c b/credential.c index f32011343f..572f1785da 100644 --- a/credential.c +++ b/credential.c @@ -164,7 +164,8 @@ static void credential_format(struct credential *c, struct strbuf *out) strbuf_addch(out, '@'); } if (c->host) - strbuf_addstr(out, c->host); + strbuf_add_percentencode(out, c->host, + STRBUF_ENCODE_HOST_AND_PORT); if (c->path) { strbuf_addch(out, '/'); strbuf_add_percentencode(out, c->path, 0); diff --git a/strbuf.c b/strbuf.c index c383f41a3c..756b96c561 100644 --- a/strbuf.c +++ b/strbuf.c @@ -492,7 +492,9 @@ void strbuf_add_percentencode(struct strbuf *dst, const char *src, int flags) unsigned char ch = src[i]; if (ch <= 0x1F || ch >= 0x7F || (ch == '/' && (flags & STRBUF_ENCODE_SLASH)) || - strchr(URL_UNSAFE_CHARS, ch)) + ((flags & STRBUF_ENCODE_HOST_AND_PORT) ? + !isalnum(ch) && !strchr("-.:[]", ch) : + !!strchr(URL_UNSAFE_CHARS, ch))) strbuf_addf(dst, "%%%02X", (unsigned char)ch); else strbuf_addch(dst, ch); diff --git a/strbuf.h b/strbuf.h index f6dbb9681e..f9f8bb0381 100644 --- a/strbuf.h +++ b/strbuf.h @@ -380,6 +380,7 @@ size_t strbuf_expand_dict_cb(struct strbuf *sb, void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src); #define STRBUF_ENCODE_SLASH 1 +#define STRBUF_ENCODE_HOST_AND_PORT 2 /** * Append the contents of a string to a strbuf, percent-encoding any characters diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh index c66d91e82d..cb91be1427 100755 --- a/t/t0300-credentials.sh +++ b/t/t0300-credentials.sh @@ -514,6 +514,19 @@ test_expect_success 'match percent-encoded values in username' ' EOF ' +test_expect_success 'match percent-encoded values in hostname' ' + test_config "credential.https://a%20b%20c/.helper" "$HELPER" && + check fill <<-\EOF + url=https://a b c/ + -- + protocol=https + host=a b c + username=foo + password=bar + -- + EOF +' + test_expect_success 'fetch with multiple path components' ' test_unconfig credential.helper && test_config credential.https://example.com/foo/repo.git.helper "verbatim foo bar" && -- cgit v1.2.3 From 7725b8100ffbbff2750ee4d61a0fcc1f53a086e8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 30 Oct 2024 13:26:10 +0100 Subject: credential: sanitize the user prompt When asking the user interactively for credentials, we want to avoid misleading them e.g. via control sequences that pretend that the URL targets a trusted host when it does not. While Git learned, over the course of the preceding commits, to disallow URLs containing URL-encoded control characters by default, credential helpers are still allowed to specify values very freely (apart from Line Feed and NUL characters, anything is allowed), and this would allow, say, a username containing control characters to be specified that would then be displayed in the interactive terminal prompt asking the user for the password, potentially sending those control characters directly to the terminal. This is undesirable because control characters can be used to mislead users to divulge secret information to untrusted sites. To prevent such an attack vector, let's add a `git_prompt()` that forces the displayed text to be sanitized, i.e. displaying question marks instead of control characters. Note: While this commit's diff changes a lot of `user@host` strings to `user%40host`, which may look suspicious on the surface, there is a good reason for that: this string specifies a user name, not a @ combination! In the context of t5541, the actual combination looks like this: `user%40@127.0.0.1:5541`. Therefore, these string replacements document a net improvement introduced by this commit, as `user@host@127.0.0.1` could have left readers wondering where the user name ends and where the host name begins. Hinted-at-by: Jeff King Signed-off-by: Johannes Schindelin --- Documentation/config/credential.txt | 6 ++++++ credential.c | 7 ++++++- credential.h | 4 +++- t/t0300-credentials.sh | 20 ++++++++++++++++++++ t/t5541-http-push-smart.sh | 6 +++--- t/t5550-http-fetch-dumb.sh | 14 +++++++------- t/t5551-http-fetch-smart.sh | 16 ++++++++-------- 7 files changed, 53 insertions(+), 20 deletions(-) diff --git a/Documentation/config/credential.txt b/Documentation/config/credential.txt index 512f31876e..fd8113d6d4 100644 --- a/Documentation/config/credential.txt +++ b/Documentation/config/credential.txt @@ -14,6 +14,12 @@ credential.useHttpPath:: or https URL to be important. Defaults to false. See linkgit:gitcredentials[7] for more information. +credential.sanitizePrompt:: + By default, user names and hosts that are shown as part of the + password prompt are not allowed to contain control characters (they + will be URL-encoded by default). Configure this setting to `false` to + override that behavior. + credential.username:: If no username is set for a network authentication, use this username by default. See credential..* below, and diff --git a/credential.c b/credential.c index 572f1785da..1392a54d5c 100644 --- a/credential.c +++ b/credential.c @@ -67,6 +67,8 @@ static int credential_config_callback(const char *var, const char *value, } else if (!strcmp(key, "usehttppath")) c->use_http_path = git_config_bool(var, value); + else if (!strcmp(key, "sanitizeprompt")) + c->sanitize_prompt = git_config_bool(var, value); return 0; } @@ -179,7 +181,10 @@ static char *credential_ask_one(const char *what, struct credential *c, struct strbuf prompt = STRBUF_INIT; char *r; - credential_describe(c, &desc); + if (c->sanitize_prompt) + credential_format(c, &desc); + else + credential_describe(c, &desc); if (desc.len) strbuf_addf(&prompt, "%s for '%s': ", what, desc.buf); else diff --git a/credential.h b/credential.h index 935b28a70f..0364d436d2 100644 --- a/credential.h +++ b/credential.h @@ -119,7 +119,8 @@ struct credential { configured:1, quit:1, use_http_path:1, - username_from_proto:1; + username_from_proto:1, + sanitize_prompt:1; char *username; char *password; @@ -132,6 +133,7 @@ struct credential { #define CREDENTIAL_INIT { \ .helpers = STRING_LIST_INIT_DUP, \ .password_expiry_utc = TIME_MAX, \ + .sanitize_prompt = 1, \ } /* Initialize a credential structure, setting all fields to empty. */ diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh index cb91be1427..b62c70c193 100755 --- a/t/t0300-credentials.sh +++ b/t/t0300-credentials.sh @@ -45,6 +45,10 @@ test_expect_success 'setup helper scripts' ' test -z "$pexpiry" || echo password_expiry_utc=$pexpiry EOF + write_script git-credential-cntrl-in-username <<-\EOF && + printf "username=\\007latrix Lestrange\\n" + EOF + PATH="$PWD:$PATH" ' @@ -825,4 +829,20 @@ test_expect_success 'credential config with partial URLs' ' test_i18ngrep "skipping credential lookup for key" stderr ' +BEL="$(printf '\007')" + +test_expect_success 'interactive prompt is sanitized' ' + check fill cntrl-in-username <<-EOF + protocol=https + host=example.org + -- + protocol=https + host=example.org + username=${BEL}latrix Lestrange + password=askpass-password + -- + askpass: Password for ${SQ}https://%07latrix%20Lestrange@example.org${SQ}: + EOF +' + test_done diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh index d0211cd8be..2cd2e1a059 100755 --- a/t/t5541-http-push-smart.sh +++ b/t/t5541-http-push-smart.sh @@ -351,7 +351,7 @@ test_expect_success 'push over smart http with auth' ' git push "$HTTPD_URL"/auth/smart/test_repo.git && git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \ log -1 --format=%s >actual && - expect_askpass both user@host && + expect_askpass both user%40host && test_cmp expect actual ' @@ -363,7 +363,7 @@ test_expect_success 'push to auth-only-for-push repo' ' git push "$HTTPD_URL"/auth-push/smart/test_repo.git && git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \ log -1 --format=%s >actual && - expect_askpass both user@host && + expect_askpass both user%40host && test_cmp expect actual ' @@ -393,7 +393,7 @@ test_expect_success 'push into half-auth-complete requires password' ' git push "$HTTPD_URL/half-auth-complete/smart/half-auth.git" && git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/half-auth.git" \ log -1 --format=%s >actual && - expect_askpass both user@host && + expect_askpass both user%40host && test_cmp expect actual ' diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh index 8f182a3cbf..5d0e394609 100755 --- a/t/t5550-http-fetch-dumb.sh +++ b/t/t5550-http-fetch-dumb.sh @@ -90,13 +90,13 @@ test_expect_success 'http auth can use user/pass in URL' ' test_expect_success 'http auth can use just user in URL' ' set_askpass wrong pass@host && git clone "$HTTPD_URL_USER/auth/dumb/repo.git" clone-auth-pass && - expect_askpass pass user@host + expect_askpass pass user%40host ' test_expect_success 'http auth can request both user and pass' ' set_askpass user@host pass@host && git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-both && - expect_askpass both user@host + expect_askpass both user%40host ' test_expect_success 'http auth respects credential helper config' ' @@ -114,14 +114,14 @@ test_expect_success 'http auth can get username from config' ' test_config_global "credential.$HTTPD_URL.username" user@host && set_askpass wrong pass@host && git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-user && - expect_askpass pass user@host + expect_askpass pass user%40host ' test_expect_success 'configured username does not override URL' ' test_config_global "credential.$HTTPD_URL.username" wrong && set_askpass wrong pass@host && git clone "$HTTPD_URL_USER/auth/dumb/repo.git" clone-auth-user2 && - expect_askpass pass user@host + expect_askpass pass user%40host ' test_expect_success 'set up repo with http submodules' ' @@ -142,7 +142,7 @@ test_expect_success 'cmdline credential config passes to submodule via clone' ' set_askpass wrong pass@host && git -c "credential.$HTTPD_URL.username=user@host" \ clone --recursive super super-clone && - expect_askpass pass user@host + expect_askpass pass user%40host ' test_expect_success 'cmdline credential config passes submodule via fetch' ' @@ -153,7 +153,7 @@ test_expect_success 'cmdline credential config passes submodule via fetch' ' git -C super-clone \ -c "credential.$HTTPD_URL.username=user@host" \ fetch --recurse-submodules && - expect_askpass pass user@host + expect_askpass pass user%40host ' test_expect_success 'cmdline credential config passes submodule update' ' @@ -170,7 +170,7 @@ test_expect_success 'cmdline credential config passes submodule update' ' git -C super-clone \ -c "credential.$HTTPD_URL.username=user@host" \ submodule update && - expect_askpass pass user@host + expect_askpass pass user%40host ' test_expect_success 'fetch changes via http' ' diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh index 0908534f25..8a27768dfb 100755 --- a/t/t5551-http-fetch-smart.sh +++ b/t/t5551-http-fetch-smart.sh @@ -181,7 +181,7 @@ test_expect_success 'clone from password-protected repository' ' echo two >expect && set_askpass user@host pass@host && git clone --bare "$HTTPD_URL/auth/smart/repo.git" smart-auth && - expect_askpass both user@host && + expect_askpass both user%40host && git --git-dir=smart-auth log -1 --format=%s >actual && test_cmp expect actual ' @@ -199,7 +199,7 @@ test_expect_success 'clone from auth-only-for-objects repository' ' echo two >expect && set_askpass user@host pass@host && git clone --bare "$HTTPD_URL/auth-fetch/smart/repo.git" half-auth && - expect_askpass both user@host && + expect_askpass both user%40host && git --git-dir=half-auth log -1 --format=%s >actual && test_cmp expect actual ' @@ -224,14 +224,14 @@ test_expect_success 'redirects send auth to new location' ' set_askpass user@host pass@host && git -c credential.useHttpPath=true \ clone $HTTPD_URL/smart-redir-auth/repo.git repo-redir-auth && - expect_askpass both user@host auth/smart/repo.git + expect_askpass both user%40host auth/smart/repo.git ' test_expect_success 'GIT_TRACE_CURL redacts auth details' ' rm -rf redact-auth trace && set_askpass user@host pass@host && GIT_TRACE_CURL="$(pwd)/trace" git clone --bare "$HTTPD_URL/auth/smart/repo.git" redact-auth && - expect_askpass both user@host && + expect_askpass both user%40host && # Ensure that there is no "Basic" followed by a base64 string, but that # the auth details are redacted @@ -243,7 +243,7 @@ test_expect_success 'GIT_CURL_VERBOSE redacts auth details' ' rm -rf redact-auth trace && set_askpass user@host pass@host && GIT_CURL_VERBOSE=1 git clone --bare "$HTTPD_URL/auth/smart/repo.git" redact-auth 2>trace && - expect_askpass both user@host && + expect_askpass both user%40host && # Ensure that there is no "Basic" followed by a base64 string, but that # the auth details are redacted @@ -256,7 +256,7 @@ test_expect_success 'GIT_TRACE_CURL does not redact auth details if GIT_TRACE_RE set_askpass user@host pass@host && GIT_TRACE_REDACT=0 GIT_TRACE_CURL="$(pwd)/trace" \ git clone --bare "$HTTPD_URL/auth/smart/repo.git" redact-auth && - expect_askpass both user@host && + expect_askpass both user%40host && grep -i "Authorization: Basic [0-9a-zA-Z+/]" trace ' @@ -568,7 +568,7 @@ test_expect_success 'http auth remembers successful credentials' ' # the first request prompts the user... set_askpass user@host pass@host && git ls-remote "$HTTPD_URL/auth/smart/repo.git" >/dev/null && - expect_askpass both user@host && + expect_askpass both user%40host && # ...and the second one uses the stored value rather than # prompting the user. @@ -599,7 +599,7 @@ test_expect_success 'http auth forgets bogus credentials' ' # us to prompt the user again. set_askpass user@host pass@host && git ls-remote "$HTTPD_URL/auth/smart/repo.git" >/dev/null && - expect_askpass both user@host + expect_askpass both user%40host ' test_expect_success 'client falls back from v2 to v0 to match server' ' -- cgit v1.2.3 From b01b9b81d36759cdcd07305e78765199e1bc2060 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 4 Nov 2024 14:48:22 +0100 Subject: credential: disallow Carriage Returns in the protocol by default While Git has documented that the credential protocol is line-based, with newlines as terminators, the exact shape of a newline has not been documented. From Git's perspective, which is firmly rooted in the Linux ecosystem, it is clear that "a newline" means a Line Feed character. However, even Git's credential protocol respects Windows line endings (a Carriage Return character followed by a Line Feed character, "CR/LF") by virtue of using `strbuf_getline()`. There is a third category of line endings that has been used originally by MacOS, and that is respected by the default line readers of .NET and node.js: bare Carriage Returns. Git cannot handle those, and what is worse: Git's remedy against CVE-2020-5260 does not catch when credential helpers are used that interpret bare Carriage Returns as newlines. Git Credential Manager addressed this as CVE-2024-50338, but other credential helpers may still be vulnerable. So let's not only disallow Line Feed characters as part of the values in the credential protocol, but also disallow Carriage Return characters. In the unlikely event that a credential helper relies on Carriage Returns in the protocol, introduce an escape hatch via the `credential.protectProtocol` config setting. This addresses CVE-2024-52006. Signed-off-by: Johannes Schindelin --- Documentation/config/credential.txt | 5 +++++ credential.c | 21 ++++++++++++++------- credential.h | 4 +++- t/t0300-credentials.sh | 16 ++++++++++++++++ 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/Documentation/config/credential.txt b/Documentation/config/credential.txt index fd8113d6d4..9cadca7f73 100644 --- a/Documentation/config/credential.txt +++ b/Documentation/config/credential.txt @@ -20,6 +20,11 @@ credential.sanitizePrompt:: will be URL-encoded by default). Configure this setting to `false` to override that behavior. +credential.protectProtocol:: + By default, Carriage Return characters are not allowed in the protocol + that is used when Git talks to a credential helper. This setting allows + users to override this default. + credential.username:: If no username is set for a network authentication, use this username by default. See credential..* below, and diff --git a/credential.c b/credential.c index 1392a54d5c..b76a730901 100644 --- a/credential.c +++ b/credential.c @@ -69,6 +69,8 @@ static int credential_config_callback(const char *var, const char *value, c->use_http_path = git_config_bool(var, value); else if (!strcmp(key, "sanitizeprompt")) c->sanitize_prompt = git_config_bool(var, value); + else if (!strcmp(key, "protectprotocol")) + c->protect_protocol = git_config_bool(var, value); return 0; } @@ -262,7 +264,8 @@ int credential_read(struct credential *c, FILE *fp) return 0; } -static void credential_write_item(FILE *fp, const char *key, const char *value, +static void credential_write_item(const struct credential *c, + FILE *fp, const char *key, const char *value, int required) { if (!value && required) @@ -271,19 +274,23 @@ static void credential_write_item(FILE *fp, const char *key, const char *value, return; if (strchr(value, '\n')) die("credential value for %s contains newline", key); + if (c->protect_protocol && strchr(value, '\r')) + die("credential value for %s contains carriage return\n" + "If this is intended, set `credential.protectProtocol=false`", + key); fprintf(fp, "%s=%s\n", key, value); } void credential_write(const struct credential *c, FILE *fp) { - credential_write_item(fp, "protocol", c->protocol, 1); - credential_write_item(fp, "host", c->host, 1); - credential_write_item(fp, "path", c->path, 0); - credential_write_item(fp, "username", c->username, 0); - credential_write_item(fp, "password", c->password, 0); + credential_write_item(c, fp, "protocol", c->protocol, 1); + credential_write_item(c, fp, "host", c->host, 1); + credential_write_item(c, fp, "path", c->path, 0); + credential_write_item(c, fp, "username", c->username, 0); + credential_write_item(c, fp, "password", c->password, 0); if (c->password_expiry_utc != TIME_MAX) { char *s = xstrfmt("%"PRItime, c->password_expiry_utc); - credential_write_item(fp, "password_expiry_utc", s, 0); + credential_write_item(c, fp, "password_expiry_utc", s, 0); free(s); } } diff --git a/credential.h b/credential.h index 0364d436d2..2c0b39a925 100644 --- a/credential.h +++ b/credential.h @@ -120,7 +120,8 @@ struct credential { quit:1, use_http_path:1, username_from_proto:1, - sanitize_prompt:1; + sanitize_prompt:1, + protect_protocol:1; char *username; char *password; @@ -134,6 +135,7 @@ struct credential { .helpers = STRING_LIST_INIT_DUP, \ .password_expiry_utc = TIME_MAX, \ .sanitize_prompt = 1, \ + .protect_protocol = 1, \ } /* Initialize a credential structure, setting all fields to empty. */ diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh index b62c70c193..168ae76550 100755 --- a/t/t0300-credentials.sh +++ b/t/t0300-credentials.sh @@ -720,6 +720,22 @@ test_expect_success 'url parser rejects embedded newlines' ' test_cmp expect stderr ' +test_expect_success 'url parser rejects embedded carriage returns' ' + test_config credential.helper "!true" && + test_must_fail git credential fill 2>stderr <<-\EOF && + url=https://example%0d.com/ + EOF + cat >expect <<-\EOF && + fatal: credential value for host contains carriage return + If this is intended, set `credential.protectProtocol=false` + EOF + test_cmp expect stderr && + GIT_ASKPASS=true \ + git -c credential.protectProtocol=false credential fill <<-\EOF + url=https://example%0d.com/ + EOF +' + test_expect_success 'host-less URLs are parsed as empty host' ' check fill "verbatim foo bar" <<-\EOF url=cert:///path/to/cert.pem -- cgit v1.2.3 From 54a3711a9dd968a04249beef157393d64b579d64 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 30 Oct 2024 00:17:53 +0100 Subject: Git 2.40.4 Signed-off-by: Johannes Schindelin --- Documentation/RelNotes/2.40.4.txt | 5 +++++ GIT-VERSION-GEN | 2 +- RelNotes | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 Documentation/RelNotes/2.40.4.txt diff --git a/Documentation/RelNotes/2.40.4.txt b/Documentation/RelNotes/2.40.4.txt new file mode 100644 index 0000000000..0ff29f3cfc --- /dev/null +++ b/Documentation/RelNotes/2.40.4.txt @@ -0,0 +1,5 @@ +Git v2.40.4 Release Notes +========================= + +This release lets Git refuse to accept URLs that contain control +sequences. This addresses CVE-2024-50349 and CVE-2024-52006. diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index b345e89cbe..4f4d294651 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.40.3 +DEF_VER=v2.40.4 LF=' ' diff --git a/RelNotes b/RelNotes index afb47e28e0..b401038a56 120000 --- a/RelNotes +++ b/RelNotes @@ -1 +1 @@ -Documentation/RelNotes/2.40.3.txt \ No newline at end of file +Documentation/RelNotes/2.40.4.txt \ No newline at end of file -- cgit v1.2.3 From 6fd641a521a722e438b291ec7b852b7bb508b18b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 30 Oct 2024 00:27:54 +0100 Subject: Git 2.41.3 Signed-off-by: Johannes Schindelin --- Documentation/RelNotes/2.41.3.txt | 6 ++++++ GIT-VERSION-GEN | 2 +- RelNotes | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 Documentation/RelNotes/2.41.3.txt diff --git a/Documentation/RelNotes/2.41.3.txt b/Documentation/RelNotes/2.41.3.txt new file mode 100644 index 0000000000..b5aba88790 --- /dev/null +++ b/Documentation/RelNotes/2.41.3.txt @@ -0,0 +1,6 @@ +Git v2.41.3 Release Notes +========================= + +This release merges up the fix that appears in v2.40.4 to address +the security issues CVE-2024-50349 and CVE-2024-52006; see the +release notes for that version for details. diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 990ca9c643..664b521986 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.41.2 +DEF_VER=v2.41.3 LF=' ' diff --git a/RelNotes b/RelNotes index 04f6c71310..5bd6fdad36 120000 --- a/RelNotes +++ b/RelNotes @@ -1 +1 @@ -Documentation/RelNotes/2.41.2.txt \ No newline at end of file +Documentation/RelNotes/2.41.3.txt \ No newline at end of file -- cgit v1.2.3 From 54ddf17f827969c989576f2411d9ff519fa8091f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 30 Oct 2024 00:39:06 +0100 Subject: Git 2.42.4 Signed-off-by: Johannes Schindelin --- Documentation/RelNotes/2.42.4.txt | 6 ++++++ GIT-VERSION-GEN | 2 +- RelNotes | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 Documentation/RelNotes/2.42.4.txt diff --git a/Documentation/RelNotes/2.42.4.txt b/Documentation/RelNotes/2.42.4.txt new file mode 100644 index 0000000000..3129d76e75 --- /dev/null +++ b/Documentation/RelNotes/2.42.4.txt @@ -0,0 +1,6 @@ +Git v2.42.4 Release Notes +========================= + +This release merges up the fix that appears in v2.40.4 and v2.41.3 +to address the security issues CVE-2024-50349 and CVE-2024-52006; +see the release notes for these versions for details. diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 070d22c6d1..69948fce1b 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.42.3 +DEF_VER=v2.42.4 LF=' ' diff --git a/RelNotes b/RelNotes index 7af3372ac2..e0d3afd77a 120000 --- a/RelNotes +++ b/RelNotes @@ -1 +1 @@ -Documentation/RelNotes/2.42.3.txt \ No newline at end of file +Documentation/RelNotes/2.42.4.txt \ No newline at end of file -- cgit v1.2.3 From 664d4fa692cb8637a7c9297c94abf0de8593e585 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 30 Oct 2024 00:52:18 +0100 Subject: Git 2.43.6 Signed-off-by: Johannes Schindelin --- Documentation/RelNotes/2.43.6.txt | 7 +++++++ GIT-VERSION-GEN | 2 +- RelNotes | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 Documentation/RelNotes/2.43.6.txt diff --git a/Documentation/RelNotes/2.43.6.txt b/Documentation/RelNotes/2.43.6.txt new file mode 100644 index 0000000000..2114b9f78d --- /dev/null +++ b/Documentation/RelNotes/2.43.6.txt @@ -0,0 +1,7 @@ +Git v2.43.6 Release Notes +========================= + +This release merges up the fix that appears in v2.40.4, v2.41.3 +and v2.42.4 to address the security issues CVE-2024-50349 and +CVE-2024-52006; see the release notes for these versions for +details. diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index fcaa390a61..81630dde84 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.43.5 +DEF_VER=v2.43.6 LF=' ' diff --git a/RelNotes b/RelNotes index 1abe69c298..0a9d8a03d7 120000 --- a/RelNotes +++ b/RelNotes @@ -1 +1 @@ -Documentation/RelNotes/2.43.5.txt \ No newline at end of file +Documentation/RelNotes/2.43.6.txt \ No newline at end of file -- cgit v1.2.3 From 2f323bb16219c105e0c576ea4c2ece9863f5d926 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 30 Oct 2024 00:55:00 +0100 Subject: Git 2.44.3 Signed-off-by: Johannes Schindelin --- Documentation/RelNotes/2.44.3.txt | 7 +++++++ GIT-VERSION-GEN | 2 +- RelNotes | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 Documentation/RelNotes/2.44.3.txt diff --git a/Documentation/RelNotes/2.44.3.txt b/Documentation/RelNotes/2.44.3.txt new file mode 100644 index 0000000000..5862845458 --- /dev/null +++ b/Documentation/RelNotes/2.44.3.txt @@ -0,0 +1,7 @@ +Git v2.44.3 Release Notes +========================= + +This release merges up the fix that appears in v2.40.4, v2.41.3, +v2.42.4 and v2.43.6 to address the security issues CVE-2024-50349 +and CVE-2024-52006; see the release notes for these versions +for details. diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 9c631da5ce..33476e262d 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.44.2 +DEF_VER=v2.44.3 LF=' ' diff --git a/RelNotes b/RelNotes index 6ba9e6f4ce..509eba5f1a 120000 --- a/RelNotes +++ b/RelNotes @@ -1 +1 @@ -Documentation/RelNotes/2.44.2.txt \ No newline at end of file +Documentation/RelNotes/2.44.3.txt \ No newline at end of file -- cgit v1.2.3 From fc16eb306c2ad25c080612ae85fdeba1fbcbfc98 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 30 Oct 2024 00:59:32 +0100 Subject: Git 2.45.3 Signed-off-by: Johannes Schindelin --- Documentation/RelNotes/2.45.3.txt | 7 ++++++- GIT-VERSION-GEN | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Documentation/RelNotes/2.45.3.txt b/Documentation/RelNotes/2.45.3.txt index 2a1e9aa608..ddb3cb694b 100644 --- a/Documentation/RelNotes/2.45.3.txt +++ b/Documentation/RelNotes/2.45.3.txt @@ -1,7 +1,12 @@ Git v2.45.3 Release Notes ========================= -This primarily is to backport various small fixes accumulated on the +This release merges up the fix that appears in v2.40.4, v2.41.3, +v2.42.4, v2.43.6 and v2.44.3 to address the security issues +CVE-2024-50349 and CVE-2024-52006; see the release notes for +these versions for details. + +This version also backports various small fixes accumulated on the 'master' front during the development towards Git 2.46, the next feature release. diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index eb53b0ee01..f7c5d8f070 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.45.2 +DEF_VER=v2.45.3 LF=' ' -- cgit v1.2.3 From 5c21db3a0d5f4414b65e114ca21c5a1fe736f2bc Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 30 Oct 2024 01:03:46 +0100 Subject: Git 2.46.3 Signed-off-by: Johannes Schindelin --- Documentation/RelNotes/2.46.3.txt | 6 ++++++ GIT-VERSION-GEN | 2 +- RelNotes | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 Documentation/RelNotes/2.46.3.txt diff --git a/Documentation/RelNotes/2.46.3.txt b/Documentation/RelNotes/2.46.3.txt new file mode 100644 index 0000000000..4af032b63c --- /dev/null +++ b/Documentation/RelNotes/2.46.3.txt @@ -0,0 +1,6 @@ +Git v2.46.3 Release Notes +========================= + +This release merges up the fix that appears in v2.40.4, v2.41.3, v2.42.4, +v2.43.6, v2.44.3 and v2.45.3 to address the security issues CVE-2024-50349 and +CVE-2024-52006; see the release notes for these versions for details. diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 05fa12fec7..7cde816ede 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.46.2 +DEF_VER=v2.46.3 LF=' ' diff --git a/RelNotes b/RelNotes index 0dfe046c88..686ec8709b 120000 --- a/RelNotes +++ b/RelNotes @@ -1 +1 @@ -Documentation/RelNotes/2.46.2.txt \ No newline at end of file +Documentation/RelNotes/2.46.3.txt \ No newline at end of file -- cgit v1.2.3 From e1fbebe347426ef7974dc2198f8a277b7c31c8fe Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 30 Oct 2024 01:12:43 +0100 Subject: Git 2.47.2 Signed-off-by: Johannes Schindelin --- Documentation/RelNotes/2.47.2.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 Documentation/RelNotes/2.47.2.txt diff --git a/Documentation/RelNotes/2.47.2.txt b/Documentation/RelNotes/2.47.2.txt new file mode 100644 index 0000000000..7a52ad8cb4 --- /dev/null +++ b/Documentation/RelNotes/2.47.2.txt @@ -0,0 +1,7 @@ +Git v2.47.2 Release Notes +========================= + +This release merges up the fix that appears in v2.40.4, v2.41.3, +v2.42.4, v2.43.6, v2.44.3, v2.45.3 and v2.46.3 to address the +security issues CVE-2024-50349 and CVE-2024-52006; see the release +notes for these versions for details. -- cgit v1.2.3 From 87c01003cdff8c99ebdf053441e4527d85952284 Mon Sep 17 00:00:00 2001 From: Justin Tobler Date: Wed, 27 Nov 2024 17:33:09 -0600 Subject: bundle: add bundle verification options type When `unbundle()` is invoked, fsck verification may be configured by passing the `VERIFY_BUNDLE_FSCK` flag. This mechanism allows fsck checks on the bundle to be enabled or disabled entirely. To facilitate more fine-grained fsck configuration, additional context must be provided to `unbundle()`. Introduce the `unbundle_opts` type, which wraps the existing `verify_bundle_flags`, to facilitate future extension of `unbundle()` configuration. Also update `unbundle()` and its call sites to accept this new options type instead of the flags directly. The end behavior is functionally the same, but allows for the set of configurable options to be extended. This is leveraged in a subsequent commit to enable fsck message severity configuration. Signed-off-by: Justin Tobler Signed-off-by: Junio C Hamano --- builtin/bundle.c | 2 +- bundle-uri.c | 7 +++++-- bundle.c | 6 +++++- bundle.h | 10 +++++++--- transport.c | 6 ++++-- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/builtin/bundle.c b/builtin/bundle.c index 127518c2a8..15ac75ab51 100644 --- a/builtin/bundle.c +++ b/builtin/bundle.c @@ -218,7 +218,7 @@ static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix) strvec_pushl(&extra_index_pack_args, "-v", "--progress-title", _("Unbundling objects"), NULL); ret = !!unbundle(the_repository, &header, bundle_fd, - &extra_index_pack_args, 0) || + &extra_index_pack_args, NULL) || list_bundle_refs(&header, argc, argv); bundle_header_release(&header); diff --git a/bundle-uri.c b/bundle-uri.c index 0df66e2872..cdf9e4f9e1 100644 --- a/bundle-uri.c +++ b/bundle-uri.c @@ -367,6 +367,10 @@ static int unbundle_from_file(struct repository *r, const char *file) struct string_list_item *refname; struct strbuf bundle_ref = STRBUF_INIT; size_t bundle_prefix_len; + struct unbundle_opts opts = { + .flags = VERIFY_BUNDLE_QUIET | + (fetch_pack_fsck_objects() ? VERIFY_BUNDLE_FSCK : 0), + }; bundle_fd = read_bundle_header(file, &header); if (bundle_fd < 0) { @@ -379,8 +383,7 @@ static int unbundle_from_file(struct repository *r, const char *file) * a reachable ref pointing to the new tips, which will reach * the prerequisite commits. */ - result = unbundle(r, &header, bundle_fd, NULL, - VERIFY_BUNDLE_QUIET | (fetch_pack_fsck_objects() ? VERIFY_BUNDLE_FSCK : 0)); + result = unbundle(r, &header, bundle_fd, NULL, &opts); if (result) { result = 1; goto cleanup; diff --git a/bundle.c b/bundle.c index 4773b51eb1..485033ea3f 100644 --- a/bundle.c +++ b/bundle.c @@ -628,9 +628,13 @@ out: int unbundle(struct repository *r, struct bundle_header *header, int bundle_fd, struct strvec *extra_index_pack_args, - enum verify_bundle_flags flags) + struct unbundle_opts *opts) { struct child_process ip = CHILD_PROCESS_INIT; + enum verify_bundle_flags flags = 0; + + if (opts) + flags = opts->flags; if (verify_bundle(r, header, flags)) return -1; diff --git a/bundle.h b/bundle.h index 5ccc9a061a..6a09cc7bfb 100644 --- a/bundle.h +++ b/bundle.h @@ -39,6 +39,10 @@ enum verify_bundle_flags { int verify_bundle(struct repository *r, struct bundle_header *header, enum verify_bundle_flags flags); +struct unbundle_opts { + enum verify_bundle_flags flags; +}; + /** * Unbundle after reading the header with read_bundle_header(). * @@ -49,12 +53,12 @@ int verify_bundle(struct repository *r, struct bundle_header *header, * (e.g. "-v" for verbose/progress), NULL otherwise. The provided * "extra_index_pack_args" (if any) will be strvec_clear()'d for you. * - * Before unbundling, this method will call verify_bundle() with the - * given 'flags'. + * Before unbundling, this method will call verify_bundle() with 'flags' + * provided in 'opts'. */ int unbundle(struct repository *r, struct bundle_header *header, int bundle_fd, struct strvec *extra_index_pack_args, - enum verify_bundle_flags flags); + struct unbundle_opts *opts); int list_bundle_refs(struct bundle_header *header, int argc, const char **argv); diff --git a/transport.c b/transport.c index 47fda6a773..8536b14181 100644 --- a/transport.c +++ b/transport.c @@ -176,6 +176,9 @@ static int fetch_refs_from_bundle(struct transport *transport, int nr_heads UNUSED, struct ref **to_fetch UNUSED) { + struct unbundle_opts opts = { + .flags = fetch_pack_fsck_objects() ? VERIFY_BUNDLE_FSCK : 0, + }; struct bundle_transport_data *data = transport->data; struct strvec extra_index_pack_args = STRVEC_INIT; int ret; @@ -186,8 +189,7 @@ static int fetch_refs_from_bundle(struct transport *transport, if (!data->get_refs_from_bundle_called) get_refs_from_bundle_inner(transport); ret = unbundle(the_repository, &data->header, data->fd, - &extra_index_pack_args, - fetch_pack_fsck_objects() ? VERIFY_BUNDLE_FSCK : 0); + &extra_index_pack_args, &opts); transport->hash_algo = data->header.hash_algo; strvec_clear(&extra_index_pack_args); -- cgit v1.2.3 From 187574ce869f1244de83fc6a0a5b6d614fe979f2 Mon Sep 17 00:00:00 2001 From: Justin Tobler Date: Wed, 27 Nov 2024 17:33:10 -0600 Subject: bundle: support fsck message configuration If the `VERIFY_BUNDLE_FLAG` is set during `unbundle()`, the git-index-pack(1) spawned is configured with the `--fsck-options` flag to perform fsck verification. With this flag enabled, there is not a way to configure fsck message severity though. Extend the `unbundle_opts` type to store fsck message severity configuration and update `unbundle()` to conditionally append it to the `--fsck-objects` flag if provided. This enables `unbundle()` call sites to support optionally setting the severity for specific fsck messages. Signed-off-by: Justin Tobler Signed-off-by: Junio C Hamano --- bundle.c | 13 +++++++------ bundle.h | 7 +++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/bundle.c b/bundle.c index 485033ea3f..4e53ddfca2 100644 --- a/bundle.c +++ b/bundle.c @@ -631,12 +631,12 @@ int unbundle(struct repository *r, struct bundle_header *header, struct unbundle_opts *opts) { struct child_process ip = CHILD_PROCESS_INIT; - enum verify_bundle_flags flags = 0; + struct unbundle_opts opts_fallback = { 0 }; - if (opts) - flags = opts->flags; + if (!opts) + opts = &opts_fallback; - if (verify_bundle(r, header, flags)) + if (verify_bundle(r, header, opts->flags)) return -1; strvec_pushl(&ip.args, "index-pack", "--fix-thin", "--stdin", NULL); @@ -645,8 +645,9 @@ int unbundle(struct repository *r, struct bundle_header *header, if (header->filter.choice) strvec_push(&ip.args, "--promisor=from-bundle"); - if (flags & VERIFY_BUNDLE_FSCK) - strvec_push(&ip.args, "--fsck-objects"); + if (opts->flags & VERIFY_BUNDLE_FSCK) + strvec_pushf(&ip.args, "--fsck-objects%s", + opts->fsck_msg_types ? opts->fsck_msg_types : ""); if (extra_index_pack_args) strvec_pushv(&ip.args, extra_index_pack_args->v); diff --git a/bundle.h b/bundle.h index 6a09cc7bfb..a80aa8ad9b 100644 --- a/bundle.h +++ b/bundle.h @@ -41,6 +41,13 @@ int verify_bundle(struct repository *r, struct bundle_header *header, struct unbundle_opts { enum verify_bundle_flags flags; + /* + * fsck_msg_types may optionally contain fsck message severity + * configuration. If present, this configuration gets directly appended + * to a '--fsck-objects' option and therefore must be prefixed with '='. + * (E.g. "=missingEmail=ignore,gitmodulesUrl=ignore") + */ + const char *fsck_msg_types; }; /** -- cgit v1.2.3 From 05596e93c50b286fa445af8ae572759be079092d Mon Sep 17 00:00:00 2001 From: Justin Tobler Date: Wed, 27 Nov 2024 17:33:11 -0600 Subject: fetch-pack: split out fsck config parsing When `fetch_pack_config()` is invoked, fetch-pack configuration is parsed from the config. As part of this operation, fsck message severity configuration is assigned to the `fsck_msg_types` global variable. This is optionally used to configure the downstream git-index-pack(1) when the `--strict` option is specified. The same parsed fsck message severity configuration is also needed outside of fetch-pack. Instead of exposing/relying on the existing global state, split out the fsck config parsing logic into `fetch_pack_fsck_config()` and expose it. In a subsequent commit, this is used to provide fsck configuration when invoking `unbundle()`. For `fetch_pack_fsck_config()` to discern between errors and unhandled config variables, the return code when `git_config_path()` errors is changed to a different value also indicating success. This frees up the previous return code to now indicate the provided config variable was unhandled. The behavior remains functionally the same. Signed-off-by: Justin Tobler Signed-off-by: Junio C Hamano --- fetch-pack.c | 26 ++++++++++++++++++-------- fetch-pack.h | 11 +++++++++++ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/fetch-pack.c b/fetch-pack.c index fe1fb3c1b7..c095f3a84b 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -1857,8 +1857,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args, return ref; } -static int fetch_pack_config_cb(const char *var, const char *value, - const struct config_context *ctx, void *cb) +int fetch_pack_fsck_config(const char *var, const char *value, + struct strbuf *msg_types) { const char *msg_id; @@ -1866,9 +1866,9 @@ static int fetch_pack_config_cb(const char *var, const char *value, char *path ; if (git_config_pathname(&path, var, value)) - return 1; - strbuf_addf(&fsck_msg_types, "%cskiplist=%s", - fsck_msg_types.len ? ',' : '=', path); + return 0; + strbuf_addf(msg_types, "%cskiplist=%s", + msg_types->len ? ',' : '=', path); free(path); return 0; } @@ -1877,14 +1877,24 @@ static int fetch_pack_config_cb(const char *var, const char *value, if (!value) return config_error_nonbool(var); if (is_valid_msg_type(msg_id, value)) - strbuf_addf(&fsck_msg_types, "%c%s=%s", - fsck_msg_types.len ? ',' : '=', msg_id, value); + strbuf_addf(msg_types, "%c%s=%s", + msg_types->len ? ',' : '=', msg_id, value); else warning("Skipping unknown msg id '%s'", msg_id); return 0; } - return git_default_config(var, value, ctx, cb); + return 1; +} + +static int fetch_pack_config_cb(const char *var, const char *value, + const struct config_context *ctx, void *cb) +{ + int ret = fetch_pack_fsck_config(var, value, &fsck_msg_types); + if (ret > 0) + return git_default_config(var, value, ctx, cb); + + return ret; } static void fetch_pack_config(void) diff --git a/fetch-pack.h b/fetch-pack.h index b5c579cdae..9d3470366f 100644 --- a/fetch-pack.h +++ b/fetch-pack.h @@ -106,4 +106,15 @@ int report_unmatched_refs(struct ref **sought, int nr_sought); */ int fetch_pack_fsck_objects(void); +/* + * Check if the provided config variable pertains to fetch fsck and if so append + * the configuration to the provided strbuf. + * + * When a fetch fsck config option is successfully processed the function + * returns 0. If the provided config option is unrelated to fetch fsck, 1 is + * returned. Errors return -1. + */ +int fetch_pack_fsck_config(const char *var, const char *value, + struct strbuf *msg_types); + #endif -- cgit v1.2.3 From baa159137be36965e03192528b001ffc39b8352f Mon Sep 17 00:00:00 2001 From: Justin Tobler Date: Wed, 27 Nov 2024 17:33:12 -0600 Subject: transport: propagate fsck configuration during bundle fetch When fetching directly from a bundle, fsck message severity configuration is not propagated to the underlying git-index-pack(1). It is only capable of enabling or disabling fsck checks entirely. This does not align with the fsck behavior for fetches through git-fetch-pack(1). Use the fsck config parsing from fetch-pack to populate fsck message severity configuration and wire it through to `unbundle()` to enable the same fsck verification as done through fetch-pack. Signed-off-by: Justin Tobler Signed-off-by: Junio C Hamano --- t/t5607-clone-bundle.sh | 7 +++++++ transport.c | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/t/t5607-clone-bundle.sh b/t/t5607-clone-bundle.sh index 7ceaa8194d..c69aa88eae 100755 --- a/t/t5607-clone-bundle.sh +++ b/t/t5607-clone-bundle.sh @@ -171,6 +171,13 @@ test_expect_success 'clone bundle with different fsckObjects configurations' ' test_must_fail git -c transfer.fsckObjects=true \ clone bundle-fsck/bad.bundle bundle-transfer-fsck 2>err && + test_grep "missingEmail" err && + + git -c fetch.fsckObjects=true -c fetch.fsck.missingEmail=ignore \ + clone bundle-fsck/bad.bundle bundle-fsck-ignore && + + test_must_fail git -c fetch.fsckObjects=true -c fetch.fsck.missingEmail=error \ + clone bundle-fsck/bad.bundle bundle-fsck-error 2>err && test_grep "missingEmail" err ' diff --git a/transport.c b/transport.c index 8536b14181..6966df51a8 100644 --- a/transport.c +++ b/transport.c @@ -19,6 +19,7 @@ #include "branch.h" #include "url.h" #include "submodule.h" +#include "strbuf.h" #include "string-list.h" #include "oid-array.h" #include "sigchain.h" @@ -172,6 +173,19 @@ static struct ref *get_refs_from_bundle(struct transport *transport, return result; } +static int fetch_fsck_config_cb(const char *var, const char *value, + const struct config_context *ctx UNUSED, void *cb) +{ + struct strbuf *msg_types = cb; + int ret; + + ret = fetch_pack_fsck_config(var, value, msg_types); + if (ret > 0) + return 0; + + return ret; +} + static int fetch_refs_from_bundle(struct transport *transport, int nr_heads UNUSED, struct ref **to_fetch UNUSED) @@ -181,6 +195,7 @@ static int fetch_refs_from_bundle(struct transport *transport, }; struct bundle_transport_data *data = transport->data; struct strvec extra_index_pack_args = STRVEC_INIT; + struct strbuf msg_types = STRBUF_INIT; int ret; if (transport->progress) @@ -188,11 +203,16 @@ static int fetch_refs_from_bundle(struct transport *transport, if (!data->get_refs_from_bundle_called) get_refs_from_bundle_inner(transport); + + git_config(fetch_fsck_config_cb, &msg_types); + opts.fsck_msg_types = msg_types.buf; + ret = unbundle(the_repository, &data->header, data->fd, &extra_index_pack_args, &opts); transport->hash_algo = data->header.hash_algo; strvec_clear(&extra_index_pack_args); + strbuf_release(&msg_types); return ret; } -- cgit v1.2.3 From 168ebb7159584df425797dd13d8d8986dc08051e Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 27 Nov 2024 22:23:45 +0900 Subject: CodingGuidelines: a handful of error message guidelines It is more efficient to have something in the coding guidelines document to point at, when we want to review and comment on a new message in the codebase to make sure it "fits" in the set of existing messages. Let's write down established best practice we are aware of. Helped-by: Eric Sunshine Signed-off-by: Junio C Hamano --- Documentation/CodingGuidelines | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines index 3263245b03..31714227ca 100644 --- a/Documentation/CodingGuidelines +++ b/Documentation/CodingGuidelines @@ -689,16 +689,30 @@ Program Output Error Messages - - Do not end error messages with a full stop. + - Do not end a single-sentence error message with a full stop. - Do not capitalize the first word, only because it is the first word - in the message ("unable to open %s", not "Unable to open %s"). But + in the message ("unable to open '%s'", not "Unable to open '%s'"). But "SHA-3 not supported" is fine, because the reason the first word is capitalized is not because it is at the beginning of the sentence, but because the word would be spelled in capital letters even when it appeared in the middle of the sentence. - - Say what the error is first ("cannot open %s", not "%s: cannot open") + - Say what the error is first ("cannot open '%s'", not "%s: cannot open"). + + - Enclose the subject of an error inside a pair of single quotes, + e.g. `die(_("unable to open '%s'"), path)`. + + - Unless there is a compelling reason not to, error messages from + porcelain commands should be marked for translation, e.g. + `die(_("bad revision %s"), revision)`. + + - Error messages from the plumbing commands are sometimes meant for + machine consumption and should not be marked for translation, + e.g., `die("bad revision %s", revision)`. + + - BUG("message") are for communicating the specific error to developers, + thus should not be translated. Externally Visible Names -- cgit v1.2.3 From d897f2c16da9ab9588d2015121449d5bc54c9736 Mon Sep 17 00:00:00 2001 From: Caleb White Date: Fri, 29 Nov 2024 22:22:26 +0000 Subject: setup: correctly reinitialize repository version When reinitializing a repository, Git does not account for extensions other than `objectformat` and `refstorage` when determining the repository version. This can lead to a repository being downgraded to version 0 if extensions are set, causing Git future operations to fail. This patch teaches Git to check if other extensions are defined in the config to ensure that the repository version is set correctly. Signed-off-by: Caleb White Signed-off-by: Junio C Hamano --- setup.c | 32 +++++++++++++++++++++++--------- t/t5504-fetch-receive-strict.sh | 6 +++--- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/setup.c b/setup.c index 7b648de027..1e5c2eacb1 100644 --- a/setup.c +++ b/setup.c @@ -2204,8 +2204,8 @@ void initialize_repository_version(int hash_algo, enum ref_storage_format ref_storage_format, int reinit) { - char repo_version_string[10]; - int repo_version = GIT_REPO_VERSION; + struct strbuf repo_version = STRBUF_INIT; + int target_version = GIT_REPO_VERSION; /* * Note that we initialize the repository version to 1 when the ref @@ -2216,12 +2216,7 @@ void initialize_repository_version(int hash_algo, */ if (hash_algo != GIT_HASH_SHA1 || ref_storage_format != REF_STORAGE_FORMAT_FILES) - repo_version = GIT_REPO_VERSION_READ; - - /* This forces creation of new config file */ - xsnprintf(repo_version_string, sizeof(repo_version_string), - "%d", repo_version); - git_config_set("core.repositoryformatversion", repo_version_string); + target_version = GIT_REPO_VERSION_READ; if (hash_algo != GIT_HASH_SHA1 && hash_algo != GIT_HASH_UNKNOWN) git_config_set("extensions.objectformat", @@ -2234,6 +2229,25 @@ void initialize_repository_version(int hash_algo, ref_storage_format_to_name(ref_storage_format)); else if (reinit) git_config_set_gently("extensions.refstorage", NULL); + + if (reinit) { + struct strbuf config = STRBUF_INIT; + struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT; + + strbuf_git_common_path(&config, the_repository, "config"); + read_repository_format(&repo_fmt, config.buf); + + if (repo_fmt.v1_only_extensions.nr) + target_version = GIT_REPO_VERSION_READ; + + strbuf_release(&config); + clear_repository_format(&repo_fmt); + } + + strbuf_addf(&repo_version, "%d", target_version); + git_config_set("core.repositoryformatversion", repo_version.buf); + + strbuf_release(&repo_version); } static int is_reinit(void) @@ -2333,7 +2347,7 @@ static int create_default_files(const char *template_path, adjust_shared_perm(repo_get_git_dir(the_repository)); } - initialize_repository_version(fmt->hash_algo, fmt->ref_storage_format, 0); + initialize_repository_version(fmt->hash_algo, fmt->ref_storage_format, reinit); /* Check filemode trustability */ path = git_path_buf(&buf, "config"); diff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh index 138e6778a4..290d2a591a 100755 --- a/t/t5504-fetch-receive-strict.sh +++ b/t/t5504-fetch-receive-strict.sh @@ -171,7 +171,7 @@ test_expect_success 'fsck with invalid or bogus skipList input' ' test_must_fail git -c fsck.skipList=does-not-exist -c fsck.missingEmail=ignore fsck 2>err && test_grep "could not open.*: does-not-exist" err && test_must_fail git -c fsck.skipList=.git/config -c fsck.missingEmail=ignore fsck 2>err && - test_grep "invalid object name: \[core\]" err + test_grep "invalid object name: " err ' test_expect_success 'fsck with other accepted skipList input (comments & empty lines)' ' @@ -234,7 +234,7 @@ test_expect_success 'push with receive.fsck.skipList' ' test_grep "could not open.*: does-not-exist" err && git --git-dir=dst/.git config receive.fsck.skipList config && test_must_fail git push --porcelain dst bogus 2>err && - test_grep "invalid object name: \[core\]" err && + test_grep "invalid object name: " err && git --git-dir=dst/.git config receive.fsck.skipList SKIP && git push --porcelain dst bogus @@ -263,7 +263,7 @@ test_expect_success 'fetch with fetch.fsck.skipList' ' test_grep "could not open.*: does-not-exist" err && git --git-dir=dst/.git config fetch.fsck.skipList dst/.git/config && test_must_fail git --git-dir=dst/.git fetch "file://$(pwd)" $refspec 2>err && - test_grep "invalid object name: \[core\]" err && + test_grep "invalid object name: " err && git --git-dir=dst/.git config fetch.fsck.skipList dst/.git/SKIP && git --git-dir=dst/.git fetch "file://$(pwd)" $refspec -- cgit v1.2.3 From 1860ba1a2a96c587fca1c294d8288accf9554096 Mon Sep 17 00:00:00 2001 From: Caleb White Date: Fri, 29 Nov 2024 22:22:34 +0000 Subject: worktree: add `relativeWorktrees` extension A new extension, `relativeWorktrees`, is added to indicate that at least one worktree in the repository has been linked with relative paths. This ensures older Git versions do not attempt to automatically prune worktrees with relative paths, as they would not not recognize the paths as being valid. Suggested-by: Junio C Hamano Signed-off-by: Caleb White Signed-off-by: Junio C Hamano --- Documentation/config/extensions.txt | 6 ++++++ repository.c | 1 + repository.h | 1 + setup.c | 7 +++++++ setup.h | 1 + 5 files changed, 16 insertions(+) diff --git a/Documentation/config/extensions.txt b/Documentation/config/extensions.txt index 5dc569d1c9..5cb4721a0e 100644 --- a/Documentation/config/extensions.txt +++ b/Documentation/config/extensions.txt @@ -63,6 +63,12 @@ Note that this setting should only be set by linkgit:git-init[1] or linkgit:git-clone[1]. Trying to change it after initialization will not work and will produce hard-to-diagnose issues. +relativeWorktrees:: + If enabled, indicates at least one worktree has been linked with + relative paths. Automatically set if a worktree has been created or + repaired with either the `--relative-paths` option or with the + `worktree.useRelativePaths` config set to `true`. + worktreeConfig:: If enabled, then worktrees will load config settings from the `$GIT_DIR/config.worktree` file in addition to the diff --git a/repository.c b/repository.c index f988b8ae68..1a6a62bbd0 100644 --- a/repository.c +++ b/repository.c @@ -283,6 +283,7 @@ int repo_init(struct repository *repo, repo_set_compat_hash_algo(repo, format.compat_hash_algo); repo_set_ref_storage_format(repo, format.ref_storage_format); repo->repository_format_worktree_config = format.worktree_config; + repo->repository_format_relative_worktrees = format.relative_worktrees; /* take ownership of format.partial_clone */ repo->repository_format_partial_clone = format.partial_clone; diff --git a/repository.h b/repository.h index 24a66a496a..c4c92b2ab9 100644 --- a/repository.h +++ b/repository.h @@ -150,6 +150,7 @@ struct repository { /* Configurations */ int repository_format_worktree_config; + int repository_format_relative_worktrees; /* Indicate if a repository has a different 'commondir' from 'gitdir' */ unsigned different_commondir:1; diff --git a/setup.c b/setup.c index 1e5c2eacb1..39ff48d9dc 100644 --- a/setup.c +++ b/setup.c @@ -683,6 +683,9 @@ static enum extension_result handle_extension(const char *var, "extensions.refstorage", value); data->ref_storage_format = format; return EXTENSION_OK; + } else if (!strcmp(ext, "relativeworktrees")) { + data->relative_worktrees = git_config_bool(var, value); + return EXTENSION_OK; } return EXTENSION_UNKNOWN; } @@ -1854,6 +1857,8 @@ const char *setup_git_directory_gently(int *nongit_ok) repo_fmt.ref_storage_format); the_repository->repository_format_worktree_config = repo_fmt.worktree_config; + the_repository->repository_format_relative_worktrees = + repo_fmt.relative_worktrees; /* take ownership of repo_fmt.partial_clone */ the_repository->repository_format_partial_clone = repo_fmt.partial_clone; @@ -1950,6 +1955,8 @@ void check_repository_format(struct repository_format *fmt) fmt->ref_storage_format); the_repository->repository_format_worktree_config = fmt->worktree_config; + the_repository->repository_format_relative_worktrees = + fmt->relative_worktrees; the_repository->repository_format_partial_clone = xstrdup_or_null(fmt->partial_clone); clear_repository_format(&repo_fmt); diff --git a/setup.h b/setup.h index e496ab3e4d..18dc3b7368 100644 --- a/setup.h +++ b/setup.h @@ -129,6 +129,7 @@ struct repository_format { int precious_objects; char *partial_clone; /* value of extensions.partialclone */ int worktree_config; + int relative_worktrees; int is_bare; int hash_algo; int compat_hash_algo; -- cgit v1.2.3 From 5976310916458868b5cbd9d8c7cc7de5af418230 Mon Sep 17 00:00:00 2001 From: Caleb White Date: Fri, 29 Nov 2024 22:22:41 +0000 Subject: worktree: refactor infer_backlink return The previous round[1] was merged a bit early before reviewer feedback could be applied. This correctly indents a code block and updates the `infer_backlink` function to return `-1` on failure and strbuf.len on success. [1]: https://lore.kernel.org/git/20241007-wt_relative_paths-v3-0-622cf18c45eb@pm.me Signed-off-by: Caleb White Signed-off-by: Junio C Hamano --- worktree.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/worktree.c b/worktree.c index 77ff484d3e..afde5394c8 100644 --- a/worktree.c +++ b/worktree.c @@ -111,9 +111,9 @@ struct worktree *get_linked_worktree(const char *id, strbuf_strip_suffix(&worktree_path, "/.git"); if (!is_absolute_path(worktree_path.buf)) { - strbuf_strip_suffix(&path, "gitdir"); - strbuf_addbuf(&path, &worktree_path); - strbuf_realpath_forgiving(&worktree_path, path.buf, 0); + strbuf_strip_suffix(&path, "gitdir"); + strbuf_addbuf(&path, &worktree_path); + strbuf_realpath_forgiving(&worktree_path, path.buf, 0); } CALLOC_ARRAY(worktree, 1); @@ -725,8 +725,10 @@ static int is_main_worktree_path(const char *path) * won't know which /worktrees//gitdir to repair. However, we may * be able to infer the gitdir by manually reading /path/to/worktree/.git, * extracting the , and checking if /worktrees/ exists. + * + * Returns -1 on failure and strbuf.len on success. */ -static int infer_backlink(const char *gitfile, struct strbuf *inferred) +static ssize_t infer_backlink(const char *gitfile, struct strbuf *inferred) { struct strbuf actual = STRBUF_INIT; const char *id; @@ -747,12 +749,11 @@ static int infer_backlink(const char *gitfile, struct strbuf *inferred) goto error; strbuf_release(&actual); - return 1; - + return inferred->len; error: strbuf_release(&actual); strbuf_reset(inferred); /* clear invalid path */ - return 0; + return -1; } /* -- cgit v1.2.3 From 4dac9e3c01cf056edd315e0ed26e6df1c4d94571 Mon Sep 17 00:00:00 2001 From: Caleb White Date: Fri, 29 Nov 2024 22:22:47 +0000 Subject: worktree: add `write_worktree_linking_files()` function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A new helper function, `write_worktree_linking_files()`, centralizes the logic for computing and writing either relative or absolute paths, based on the provided configuration. This function accepts `strbuf` pointers to both the worktree’s `.git` link and the repository’s `gitdir`, and then writes the appropriate path to each. The `relativeWorktrees` extension is automatically set when a worktree is linked with relative paths. Signed-off-by: Caleb White Signed-off-by: Junio C Hamano --- worktree.c | 35 +++++++++++++++++++++++++++++++++++ worktree.h | 13 +++++++++++++ 2 files changed, 48 insertions(+) diff --git a/worktree.c b/worktree.c index afde5394c8..cf05045cc9 100644 --- a/worktree.c +++ b/worktree.c @@ -1032,3 +1032,38 @@ cleanup: free(main_worktree_file); return res; } + +void write_worktree_linking_files(struct strbuf dotgit, struct strbuf gitdir, + int use_relative_paths) +{ + struct strbuf path = STRBUF_INIT; + struct strbuf repo = STRBUF_INIT; + struct strbuf tmp = STRBUF_INIT; + + strbuf_addbuf(&path, &dotgit); + strbuf_strip_suffix(&path, "/.git"); + strbuf_realpath(&path, path.buf, 1); + strbuf_addbuf(&repo, &gitdir); + strbuf_strip_suffix(&repo, "/gitdir"); + strbuf_realpath(&repo, repo.buf, 1); + + if (use_relative_paths && !the_repository->repository_format_relative_worktrees) { + if (upgrade_repository_format(1) < 0) + die(_("unable to upgrade repository format to support relative worktrees")); + if (git_config_set_gently("extensions.relativeWorktrees", "true")) + die(_("unable to set extensions.relativeWorktrees setting")); + the_repository->repository_format_relative_worktrees = 1; + } + + if (use_relative_paths) { + write_file(gitdir.buf, "%s/.git", relative_path(path.buf, repo.buf, &tmp)); + write_file(dotgit.buf, "gitdir: %s", relative_path(repo.buf, path.buf, &tmp)); + } else { + write_file(gitdir.buf, "%s/.git", path.buf); + write_file(dotgit.buf, "gitdir: %s", repo.buf); + } + + strbuf_release(&path); + strbuf_release(&repo); + strbuf_release(&tmp); +} diff --git a/worktree.h b/worktree.h index e961186216..fd040f5d99 100644 --- a/worktree.h +++ b/worktree.h @@ -215,4 +215,17 @@ void strbuf_worktree_ref(const struct worktree *wt, */ int init_worktree_config(struct repository *r); +/** + * Write the .git file and gitdir file that links the worktree to the repository. + * + * The `dotgit` parameter is the path to the worktree's .git file, and `gitdir` + * is the path to the repository's `gitdir` file. + * + * Example + * dotgit: "/path/to/foo/.git" + * gitdir: "/path/to/repo/worktrees/foo/gitdir" + */ +void write_worktree_linking_files(struct strbuf dotgit, struct strbuf gitdir, + int use_relative_paths); + #endif -- cgit v1.2.3 From b7016344f1d4ef8457821e0436f335ec388b8dac Mon Sep 17 00:00:00 2001 From: Caleb White Date: Fri, 29 Nov 2024 22:22:55 +0000 Subject: worktree: add relative cli/config options to `add` command This introduces the `--[no-]relative-paths` CLI option and `worktree.useRelativePaths` configuration setting to the `worktree add` command. When enabled these options allow worktrees to be linked using relative paths, enhancing portability across environments where absolute paths may differ (e.g., containerized setups, shared network drives). Git still creates absolute paths by default, but these options allow users to opt-in to relative paths if desired. The t2408 test file is removed and more comprehensive tests are written for the various worktree operations in their own files. Signed-off-by: Caleb White Signed-off-by: Junio C Hamano --- Documentation/config/worktree.txt | 10 +++++++++ Documentation/git-worktree.txt | 5 +++++ builtin/worktree.c | 19 ++++++++-------- t/t2400-worktree-add.sh | 46 +++++++++++++++++++++++++++++++++++++++ t/t2401-worktree-prune.sh | 3 ++- t/t2402-worktree-list.sh | 22 +++++++++++++++++++ t/t2408-worktree-relative.sh | 39 --------------------------------- 7 files changed, 95 insertions(+), 49 deletions(-) delete mode 100755 t/t2408-worktree-relative.sh diff --git a/Documentation/config/worktree.txt b/Documentation/config/worktree.txt index 048e349482..5e35c7d018 100644 --- a/Documentation/config/worktree.txt +++ b/Documentation/config/worktree.txt @@ -7,3 +7,13 @@ worktree.guessRemote:: such a branch exists, it is checked out and set as "upstream" for the new branch. If no such match can be found, it falls back to creating a new branch from the current HEAD. + +worktree.useRelativePaths:: + Link worktrees using relative paths (when "true") or absolute + paths (when "false"). This is particularly useful for setups + where the repository and worktrees may be moved between + different locations or environments. Defaults to "false". ++ +Note that setting `worktree.useRelativePaths` to "true" implies enabling the +`extension.relativeWorktrees` config (see linkgit:git-config[1]), +thus making it incompatible with older versions of Git. diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt index 70437c815f..60a671bbc2 100644 --- a/Documentation/git-worktree.txt +++ b/Documentation/git-worktree.txt @@ -216,6 +216,11 @@ To remove a locked worktree, specify `--force` twice. This can also be set up as the default behaviour by using the `worktree.guessRemote` config option. +--[no-]relative-paths:: + Link worktrees using relative paths or absolute paths (default). + Overrides the `worktree.useRelativePaths` config option, see + linkgit:git-config[1]. + --[no-]track:: When creating a new branch, if `` is a branch, mark it as "upstream" from the new branch. This is the diff --git a/builtin/worktree.c b/builtin/worktree.c index dae63dedf4..e3b4a71ee0 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -120,12 +120,14 @@ struct add_opts { int quiet; int checkout; int orphan; + int relative_paths; const char *keep_locked; }; static int show_only; static int verbose; static int guess_remote; +static int use_relative_paths; static timestamp_t expire; static int git_worktree_config(const char *var, const char *value, @@ -134,6 +136,9 @@ static int git_worktree_config(const char *var, const char *value, if (!strcmp(var, "worktree.guessremote")) { guess_remote = git_config_bool(var, value); return 0; + } else if (!strcmp(var, "worktree.userelativepaths")) { + use_relative_paths = git_config_bool(var, value); + return 0; } return git_default_config(var, value, ctx, cb); @@ -414,8 +419,7 @@ static int add_worktree(const char *path, const char *refname, const struct add_opts *opts) { struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT; - struct strbuf sb = STRBUF_INIT, sb_tmp = STRBUF_INIT; - struct strbuf sb_path_realpath = STRBUF_INIT, sb_repo_realpath = STRBUF_INIT; + struct strbuf sb = STRBUF_INIT; const char *name; struct strvec child_env = STRVEC_INIT; unsigned int counter = 0; @@ -491,10 +495,7 @@ static int add_worktree(const char *path, const char *refname, strbuf_reset(&sb); strbuf_addf(&sb, "%s/gitdir", sb_repo.buf); - strbuf_realpath(&sb_path_realpath, path, 1); - strbuf_realpath(&sb_repo_realpath, sb_repo.buf, 1); - write_file(sb.buf, "%s/.git", relative_path(sb_path_realpath.buf, sb_repo_realpath.buf, &sb_tmp)); - write_file(sb_git.buf, "gitdir: %s", relative_path(sb_repo_realpath.buf, sb_path_realpath.buf, &sb_tmp)); + write_worktree_linking_files(sb_git, sb, opts->relative_paths); strbuf_reset(&sb); strbuf_addf(&sb, "%s/commondir", sb_repo.buf); write_file(sb.buf, "../.."); @@ -578,12 +579,9 @@ done: strvec_clear(&child_env); strbuf_release(&sb); - strbuf_release(&sb_tmp); strbuf_release(&symref); strbuf_release(&sb_repo); - strbuf_release(&sb_repo_realpath); strbuf_release(&sb_git); - strbuf_release(&sb_path_realpath); strbuf_release(&sb_name); free_worktree(wt); return ret; @@ -796,12 +794,15 @@ static int add(int ac, const char **av, const char *prefix) PARSE_OPT_NOARG | PARSE_OPT_OPTARG), OPT_BOOL(0, "guess-remote", &guess_remote, N_("try to match the new branch name with a remote-tracking branch")), + OPT_BOOL(0, "relative-paths", &opts.relative_paths, + N_("use relative paths for worktrees")), OPT_END() }; int ret; memset(&opts, 0, sizeof(opts)); opts.checkout = 1; + opts.relative_paths = use_relative_paths; ac = parse_options(ac, av, prefix, options, git_worktree_add_usage, 0); if (!!opts.detach + !!new_branch + !!new_branch_force > 1) die(_("options '%s', '%s', and '%s' cannot be used together"), "-b", "-B", "--detach"); diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh index cfc4aeb179..bc4f4e90d6 100755 --- a/t/t2400-worktree-add.sh +++ b/t/t2400-worktree-add.sh @@ -1207,4 +1207,50 @@ test_expect_success '"add" with initialized submodule, with submodule.recurse se git -C project-clone -c submodule.recurse worktree add ../project-5 ' +test_expect_success 'can create worktrees with relative paths' ' + test_when_finished "git worktree remove relative" && + test_config worktree.useRelativePaths false && + git worktree add --relative-paths ./relative && + echo "gitdir: ../.git/worktrees/relative" >expect && + test_cmp expect relative/.git && + echo "../../../relative/.git" >expect && + test_cmp expect .git/worktrees/relative/gitdir +' + +test_expect_success 'can create worktrees with absolute paths' ' + test_config worktree.useRelativePaths true && + git worktree add ./relative && + echo "gitdir: ../.git/worktrees/relative" >expect && + test_cmp expect relative/.git && + git worktree add --no-relative-paths ./absolute && + echo "gitdir: $(pwd)/.git/worktrees/absolute" >expect && + test_cmp expect absolute/.git && + echo "$(pwd)/absolute/.git" >expect && + test_cmp expect .git/worktrees/absolute/gitdir +' + +test_expect_success 'move repo without breaking relative internal links' ' + test_when_finished rm -rf repo moved && + git init repo && + ( + cd repo && + test_commit initial && + git worktree add --relative-paths wt1 && + cd .. && + mv repo moved && + cd moved/wt1 && + git worktree list >out 2>err && + test_must_be_empty err + ) +' + +test_expect_success 'relative worktree sets extension config' ' + test_when_finished "rm -rf repo" && + git init repo && + git -C repo commit --allow-empty -m base && + git -C repo worktree add --relative-paths ./foo && + test_cmp_config -C repo 1 core.repositoryformatversion && + test_cmp_config -C repo true extensions.relativeworktrees +' + test_done diff --git a/t/t2401-worktree-prune.sh b/t/t2401-worktree-prune.sh index 976d048e3e..5eb52b9abb 100755 --- a/t/t2401-worktree-prune.sh +++ b/t/t2401-worktree-prune.sh @@ -120,11 +120,12 @@ test_expect_success 'prune duplicate (main/linked)' ' ! test -d .git/worktrees/wt ' -test_expect_success 'not prune proper worktrees when run inside linked worktree' ' +test_expect_success 'not prune proper worktrees inside linked worktree with relative paths' ' test_when_finished rm -rf repo wt_ext && git init repo && ( cd repo && + git config worktree.useRelativePaths true && echo content >file && git add file && git commit -m msg && diff --git a/t/t2402-worktree-list.sh b/t/t2402-worktree-list.sh index 33ea9cb21b..780daa6cd6 100755 --- a/t/t2402-worktree-list.sh +++ b/t/t2402-worktree-list.sh @@ -261,6 +261,7 @@ test_expect_success 'broken main worktree still at the top' ' ' test_expect_success 'linked worktrees are sorted' ' + test_when_finished "rm -rf sorted" && mkdir sorted && git init sorted/main && ( @@ -280,6 +281,27 @@ test_expect_success 'linked worktrees are sorted' ' test_cmp expected sorted/main/actual ' +test_expect_success 'linked worktrees with relative paths are shown with absolute paths' ' + test_when_finished "rm -rf sorted" && + mkdir sorted && + git init sorted/main && + ( + cd sorted/main && + test_tick && + test_commit new && + git worktree add --relative-paths ../first && + git worktree add ../second && + git worktree list --porcelain >out && + grep ^worktree out >actual + ) && + cat >expected <<-EOF && + worktree $(pwd)/sorted/main + worktree $(pwd)/sorted/first + worktree $(pwd)/sorted/second + EOF + test_cmp expected sorted/main/actual +' + test_expect_success 'worktree path when called in .git directory' ' git worktree list >list1 && git -C .git worktree list >list2 && diff --git a/t/t2408-worktree-relative.sh b/t/t2408-worktree-relative.sh deleted file mode 100755 index a3136db7e2..0000000000 --- a/t/t2408-worktree-relative.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/sh - -test_description='test worktrees linked with relative paths' - -TEST_PASSES_SANITIZE_LEAK=true -. ./test-lib.sh - -test_expect_success 'links worktrees with relative paths' ' - test_when_finished rm -rf repo && - git init repo && - ( - cd repo && - test_commit initial && - git worktree add wt1 && - echo "../../../wt1/.git" >expected_gitdir && - cat .git/worktrees/wt1/gitdir >actual_gitdir && - echo "gitdir: ../.git/worktrees/wt1" >expected_git && - cat wt1/.git >actual_git && - test_cmp expected_gitdir actual_gitdir && - test_cmp expected_git actual_git - ) -' - -test_expect_success 'move repo without breaking relative internal links' ' - test_when_finished rm -rf repo moved && - git init repo && - ( - cd repo && - test_commit initial && - git worktree add wt1 && - cd .. && - mv repo moved && - cd moved/wt1 && - git status >out 2>err && - test_must_be_empty err - ) -' - -test_done -- cgit v1.2.3 From 298d2917e26520791b47ba5d38c1866e21894cc7 Mon Sep 17 00:00:00 2001 From: Caleb White Date: Fri, 29 Nov 2024 22:23:03 +0000 Subject: worktree: add relative cli/config options to `move` command This teaches the `worktree move` command to respect the `--[no-]relative-paths` CLI option and `worktree.useRelativePaths` config setting. If an existing worktree is moved with `--relative-paths` the new path will be relative (and visa-versa). Signed-off-by: Caleb White Signed-off-by: Junio C Hamano --- builtin/worktree.c | 4 +++- t/t2403-worktree-move.sh | 25 +++++++++++++++++++++++++ worktree.c | 22 +++++++++------------- worktree.h | 4 ++-- 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/builtin/worktree.c b/builtin/worktree.c index e3b4a71ee0..3021515069 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -1190,6 +1190,8 @@ static int move_worktree(int ac, const char **av, const char *prefix) OPT__FORCE(&force, N_("force move even if worktree is dirty or locked"), PARSE_OPT_NOCOMPLETE), + OPT_BOOL(0, "relative-paths", &use_relative_paths, + N_("use relative paths for worktrees")), OPT_END() }; struct worktree **worktrees, *wt; @@ -1242,7 +1244,7 @@ static int move_worktree(int ac, const char **av, const char *prefix) if (rename(wt->path, dst.buf) == -1) die_errno(_("failed to move '%s' to '%s'"), wt->path, dst.buf); - update_worktree_location(wt, dst.buf); + update_worktree_location(wt, dst.buf, use_relative_paths); strbuf_release(&dst); free_worktrees(worktrees); diff --git a/t/t2403-worktree-move.sh b/t/t2403-worktree-move.sh index 901342ea09..422c1a0558 100755 --- a/t/t2403-worktree-move.sh +++ b/t/t2403-worktree-move.sh @@ -247,4 +247,29 @@ test_expect_success 'not remove a repo with initialized submodule' ' ) ' +test_expect_success 'move worktree with absolute path to relative path' ' + test_config worktree.useRelativePaths false && + git worktree add ./absolute && + git worktree move --relative-paths absolute relative && + echo "gitdir: ../.git/worktrees/absolute" >expect && + test_cmp expect relative/.git && + echo "../../../relative/.git" >expect && + test_cmp expect .git/worktrees/absolute/gitdir && + test_config worktree.useRelativePaths true && + git worktree move relative relative2 && + echo "gitdir: ../.git/worktrees/absolute" >expect && + test_cmp expect relative2/.git && + echo "../../../relative2/.git" >expect && + test_cmp expect .git/worktrees/absolute/gitdir +' + +test_expect_success 'move worktree with relative path to absolute path' ' + test_config worktree.useRelativePaths true && + git worktree move --no-relative-paths relative2 absolute && + echo "gitdir: $(pwd)/.git/worktrees/absolute" >expect && + test_cmp expect absolute/.git && + echo "$(pwd)/absolute/.git" >expect && + test_cmp expect .git/worktrees/absolute/gitdir +' + test_done diff --git a/worktree.c b/worktree.c index cf05045cc9..c749cb1699 100644 --- a/worktree.c +++ b/worktree.c @@ -376,32 +376,28 @@ done: return ret; } -void update_worktree_location(struct worktree *wt, const char *path_) +void update_worktree_location(struct worktree *wt, const char *path_, + int use_relative_paths) { struct strbuf path = STRBUF_INIT; - struct strbuf repo = STRBUF_INIT; - struct strbuf file = STRBUF_INIT; - struct strbuf tmp = STRBUF_INIT; + struct strbuf dotgit = STRBUF_INIT; + struct strbuf gitdir = STRBUF_INIT; if (is_main_worktree(wt)) BUG("can't relocate main worktree"); - strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1); + strbuf_realpath(&gitdir, git_common_path("worktrees/%s/gitdir", wt->id), 1); strbuf_realpath(&path, path_, 1); + strbuf_addf(&dotgit, "%s/.git", path.buf); if (fspathcmp(wt->path, path.buf)) { - strbuf_addf(&file, "%s/gitdir", repo.buf); - write_file(file.buf, "%s/.git", relative_path(path.buf, repo.buf, &tmp)); - strbuf_reset(&file); - strbuf_addf(&file, "%s/.git", path.buf); - write_file(file.buf, "gitdir: %s", relative_path(repo.buf, path.buf, &tmp)); + write_worktree_linking_files(dotgit, gitdir, use_relative_paths); free(wt->path); wt->path = strbuf_detach(&path, NULL); } strbuf_release(&path); - strbuf_release(&repo); - strbuf_release(&file); - strbuf_release(&tmp); + strbuf_release(&dotgit); + strbuf_release(&gitdir); } int is_worktree_being_rebased(const struct worktree *wt, diff --git a/worktree.h b/worktree.h index fd040f5d99..9c699d080d 100644 --- a/worktree.h +++ b/worktree.h @@ -117,8 +117,8 @@ int validate_worktree(const struct worktree *wt, /* * Update worktrees/xxx/gitdir with the new path. */ -void update_worktree_location(struct worktree *wt, - const char *path_); +void update_worktree_location(struct worktree *wt, const char *path_, + int use_relative_paths); typedef void (* worktree_repair_fn)(int iserr, const char *path, const char *msg, void *cb_data); -- cgit v1.2.3 From e6df1ee2c13405ef7077256fef49424f69d61125 Mon Sep 17 00:00:00 2001 From: Caleb White Date: Fri, 29 Nov 2024 22:23:10 +0000 Subject: worktree: add relative cli/config options to `repair` command This teaches the `worktree repair` command to respect the `--[no-]relative-paths` CLI option and `worktree.useRelativePaths` config setting. If an existing worktree with an absolute path is repaired with `--relative-paths`, the links will be replaced with relative paths, even if the original path was correct. This allows a user to covert existing worktrees between absolute/relative as desired. To simplify things, both linking files are written when one of the files needs to be repaired. In some cases, this fixes the other file before it is checked, in other cases this results in a correct file being written with the same contents. Signed-off-by: Caleb White Signed-off-by: Junio C Hamano --- Documentation/git-worktree.txt | 3 +++ builtin/worktree.c | 6 +++-- t/t2406-worktree-repair.sh | 39 +++++++++++++++++++++++++++++ worktree.c | 56 ++++++++++++++++++++---------------------- worktree.h | 5 ++-- 5 files changed, 76 insertions(+), 33 deletions(-) diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt index 60a671bbc2..8340b7f028 100644 --- a/Documentation/git-worktree.txt +++ b/Documentation/git-worktree.txt @@ -220,6 +220,9 @@ This can also be set up as the default behaviour by using the Link worktrees using relative paths or absolute paths (default). Overrides the `worktree.useRelativePaths` config option, see linkgit:git-config[1]. ++ +With `repair`, the linking files will be updated if there's an absolute/relative +mismatch, even if the links are correct. --[no-]track:: When creating a new branch, if `` is a branch, diff --git a/builtin/worktree.c b/builtin/worktree.c index 3021515069..fde9ff4dc9 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -1385,6 +1385,8 @@ static int repair(int ac, const char **av, const char *prefix) const char **p; const char *self[] = { ".", NULL }; struct option options[] = { + OPT_BOOL(0, "relative-paths", &use_relative_paths, + N_("use relative paths for worktrees")), OPT_END() }; int rc = 0; @@ -1392,8 +1394,8 @@ static int repair(int ac, const char **av, const char *prefix) ac = parse_options(ac, av, prefix, options, git_worktree_repair_usage, 0); p = ac > 0 ? av : self; for (; *p; p++) - repair_worktree_at_path(*p, report_repair, &rc); - repair_worktrees(report_repair, &rc); + repair_worktree_at_path(*p, report_repair, &rc, use_relative_paths); + repair_worktrees(report_repair, &rc, use_relative_paths); return rc; } diff --git a/t/t2406-worktree-repair.sh b/t/t2406-worktree-repair.sh index 7686e60f6a..49b70b9995 100755 --- a/t/t2406-worktree-repair.sh +++ b/t/t2406-worktree-repair.sh @@ -216,4 +216,43 @@ test_expect_success 'repair copied main and linked worktrees' ' test_cmp dup/linked.expect dup/linked/.git ' +test_expect_success 'repair worktree with relative path with missing gitfile' ' + test_when_finished "rm -rf main wt" && + test_create_repo main && + git -C main config worktree.useRelativePaths true && + test_commit -C main init && + git -C main worktree add --detach ../wt && + rm wt/.git && + test_path_is_missing wt/.git && + git -C main worktree repair && + echo "gitdir: ../main/.git/worktrees/wt" >expect && + test_cmp expect wt/.git +' + +test_expect_success 'repair absolute worktree to use relative paths' ' + test_when_finished "rm -rf main side sidemoved" && + test_create_repo main && + test_commit -C main init && + git -C main worktree add --detach ../side && + echo "../../../../sidemoved/.git" >expect-gitdir && + echo "gitdir: ../main/.git/worktrees/side" >expect-gitfile && + mv side sidemoved && + git -C main worktree repair --relative-paths ../sidemoved && + test_cmp expect-gitdir main/.git/worktrees/side/gitdir && + test_cmp expect-gitfile sidemoved/.git +' + +test_expect_success 'repair relative worktree to use absolute paths' ' + test_when_finished "rm -rf main side sidemoved" && + test_create_repo main && + test_commit -C main init && + git -C main worktree add --relative-paths --detach ../side && + echo "$(pwd)/sidemoved/.git" >expect-gitdir && + echo "gitdir: $(pwd)/main/.git/worktrees/side" >expect-gitfile && + mv side sidemoved && + git -C main worktree repair ../sidemoved && + test_cmp expect-gitdir main/.git/worktrees/side/gitdir && + test_cmp expect-gitfile sidemoved/.git +' + test_done diff --git a/worktree.c b/worktree.c index c749cb1699..2e76bbc149 100644 --- a/worktree.c +++ b/worktree.c @@ -573,12 +573,13 @@ int other_head_refs(each_ref_fn fn, void *cb_data) * pointing at /worktrees/. */ static void repair_gitfile(struct worktree *wt, - worktree_repair_fn fn, void *cb_data) + worktree_repair_fn fn, void *cb_data, + int use_relative_paths) { struct strbuf dotgit = STRBUF_INIT; + struct strbuf gitdir = STRBUF_INIT; struct strbuf repo = STRBUF_INIT; struct strbuf backlink = STRBUF_INIT; - struct strbuf tmp = STRBUF_INIT; char *dotgit_contents = NULL; const char *repair = NULL; int err; @@ -594,6 +595,7 @@ static void repair_gitfile(struct worktree *wt, strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1); strbuf_addf(&dotgit, "%s/.git", wt->path); + strbuf_addf(&gitdir, "%s/gitdir", repo.buf); dotgit_contents = xstrdup_or_null(read_gitfile_gently(dotgit.buf, &err)); if (dotgit_contents) { @@ -611,18 +613,20 @@ static void repair_gitfile(struct worktree *wt, repair = _(".git file broken"); else if (fspathcmp(backlink.buf, repo.buf)) repair = _(".git file incorrect"); + else if (use_relative_paths == is_absolute_path(dotgit_contents)) + repair = _(".git file absolute/relative path mismatch"); if (repair) { fn(0, wt->path, repair, cb_data); - write_file(dotgit.buf, "gitdir: %s", relative_path(repo.buf, wt->path, &tmp)); + write_worktree_linking_files(dotgit, gitdir, use_relative_paths); } done: free(dotgit_contents); strbuf_release(&repo); strbuf_release(&dotgit); + strbuf_release(&gitdir); strbuf_release(&backlink); - strbuf_release(&tmp); } static void repair_noop(int iserr UNUSED, @@ -633,7 +637,7 @@ static void repair_noop(int iserr UNUSED, /* nothing */ } -void repair_worktrees(worktree_repair_fn fn, void *cb_data) +void repair_worktrees(worktree_repair_fn fn, void *cb_data, int use_relative_paths) { struct worktree **worktrees = get_worktrees_internal(1); struct worktree **wt = worktrees + 1; /* +1 skips main worktree */ @@ -641,7 +645,7 @@ void repair_worktrees(worktree_repair_fn fn, void *cb_data) if (!fn) fn = repair_noop; for (; *wt; wt++) - repair_gitfile(*wt, fn, cb_data); + repair_gitfile(*wt, fn, cb_data, use_relative_paths); free_worktrees(worktrees); } @@ -757,16 +761,14 @@ error: * the worktree's path. */ void repair_worktree_at_path(const char *path, - worktree_repair_fn fn, void *cb_data) + worktree_repair_fn fn, void *cb_data, + int use_relative_paths) { struct strbuf dotgit = STRBUF_INIT; - struct strbuf realdotgit = STRBUF_INIT; struct strbuf backlink = STRBUF_INIT; struct strbuf inferred_backlink = STRBUF_INIT; struct strbuf gitdir = STRBUF_INIT; struct strbuf olddotgit = STRBUF_INIT; - struct strbuf realolddotgit = STRBUF_INIT; - struct strbuf tmp = STRBUF_INIT; char *dotgit_contents = NULL; const char *repair = NULL; int err; @@ -778,25 +780,25 @@ void repair_worktree_at_path(const char *path, goto done; strbuf_addf(&dotgit, "%s/.git", path); - if (!strbuf_realpath(&realdotgit, dotgit.buf, 0)) { + if (!strbuf_realpath(&dotgit, dotgit.buf, 0)) { fn(1, path, _("not a valid path"), cb_data); goto done; } - infer_backlink(realdotgit.buf, &inferred_backlink); + infer_backlink(dotgit.buf, &inferred_backlink); strbuf_realpath_forgiving(&inferred_backlink, inferred_backlink.buf, 0); - dotgit_contents = xstrdup_or_null(read_gitfile_gently(realdotgit.buf, &err)); + dotgit_contents = xstrdup_or_null(read_gitfile_gently(dotgit.buf, &err)); if (dotgit_contents) { if (is_absolute_path(dotgit_contents)) { strbuf_addstr(&backlink, dotgit_contents); } else { - strbuf_addbuf(&backlink, &realdotgit); + strbuf_addbuf(&backlink, &dotgit); strbuf_strip_suffix(&backlink, ".git"); strbuf_addstr(&backlink, dotgit_contents); strbuf_realpath_forgiving(&backlink, backlink.buf, 0); } } else if (err == READ_GITFILE_ERR_NOT_A_FILE) { - fn(1, realdotgit.buf, _("unable to locate repository; .git is not a file"), cb_data); + fn(1, dotgit.buf, _("unable to locate repository; .git is not a file"), cb_data); goto done; } else if (err == READ_GITFILE_ERR_NOT_A_REPO) { if (inferred_backlink.len) { @@ -809,11 +811,11 @@ void repair_worktree_at_path(const char *path, */ strbuf_swap(&backlink, &inferred_backlink); } else { - fn(1, realdotgit.buf, _("unable to locate repository; .git file does not reference a repository"), cb_data); + fn(1, dotgit.buf, _("unable to locate repository; .git file does not reference a repository"), cb_data); goto done; } } else { - fn(1, realdotgit.buf, _("unable to locate repository; .git file broken"), cb_data); + fn(1, dotgit.buf, _("unable to locate repository; .git file broken"), cb_data); goto done; } @@ -835,39 +837,35 @@ void repair_worktree_at_path(const char *path, * in the "copy" repository. In this case, point the "copy" worktree's * .git file at the "copy" repository. */ - if (inferred_backlink.len && fspathcmp(backlink.buf, inferred_backlink.buf)) { + if (inferred_backlink.len && fspathcmp(backlink.buf, inferred_backlink.buf)) strbuf_swap(&backlink, &inferred_backlink); - } strbuf_addf(&gitdir, "%s/gitdir", backlink.buf); if (strbuf_read_file(&olddotgit, gitdir.buf, 0) < 0) repair = _("gitdir unreadable"); + else if (use_relative_paths == is_absolute_path(olddotgit.buf)) + repair = _("gitdir absolute/relative path mismatch"); else { strbuf_rtrim(&olddotgit); - if (is_absolute_path(olddotgit.buf)) { - strbuf_addbuf(&realolddotgit, &olddotgit); - } else { - strbuf_addf(&realolddotgit, "%s/%s", backlink.buf, olddotgit.buf); - strbuf_realpath_forgiving(&realolddotgit, realolddotgit.buf, 0); + if (!is_absolute_path(olddotgit.buf)) { + strbuf_insertf(&olddotgit, 0, "%s/", backlink.buf); + strbuf_realpath_forgiving(&olddotgit, olddotgit.buf, 0); } - if (fspathcmp(realolddotgit.buf, realdotgit.buf)) + if (fspathcmp(olddotgit.buf, dotgit.buf)) repair = _("gitdir incorrect"); } if (repair) { fn(0, gitdir.buf, repair, cb_data); - write_file(gitdir.buf, "%s", relative_path(realdotgit.buf, backlink.buf, &tmp)); + write_worktree_linking_files(dotgit, gitdir, use_relative_paths); } done: free(dotgit_contents); strbuf_release(&olddotgit); - strbuf_release(&realolddotgit); strbuf_release(&backlink); strbuf_release(&inferred_backlink); strbuf_release(&gitdir); - strbuf_release(&realdotgit); strbuf_release(&dotgit); - strbuf_release(&tmp); } int should_prune_worktree(const char *id, struct strbuf *reason, char **wtpath, timestamp_t expire) diff --git a/worktree.h b/worktree.h index 9c699d080d..38145df80f 100644 --- a/worktree.h +++ b/worktree.h @@ -129,7 +129,7 @@ typedef void (* worktree_repair_fn)(int iserr, const char *path, * function, if non-NULL, is called with the path of the worktree and a * description of the repair or error, along with the callback user-data. */ -void repair_worktrees(worktree_repair_fn, void *cb_data); +void repair_worktrees(worktree_repair_fn, void *cb_data, int use_relative_paths); /* * Repair the linked worktrees after the gitdir has been moved. @@ -151,7 +151,8 @@ void repair_worktree_after_gitdir_move(struct worktree *wt, const char *old_path * worktree and a description of the repair or error, along with the callback * user-data. */ -void repair_worktree_at_path(const char *, worktree_repair_fn, void *cb_data); +void repair_worktree_at_path(const char *, worktree_repair_fn, + void *cb_data, int use_relative_paths); /* * Free up the memory for a worktree. -- cgit v1.2.3 From 2037ca85ad93ec905b46543df6df4080f6ca258b Mon Sep 17 00:00:00 2001 From: Caleb White Date: Fri, 29 Nov 2024 22:23:16 +0000 Subject: worktree: refactor `repair_worktree_after_gitdir_move()` This refactors `repair_worktree_after_gitdir_move()` to use the new `write_worktree_linking_files` function. It also preserves the relativity of the linking files; e.g., if an existing worktree used absolute paths then the repaired paths will be absolute (and visa-versa). `repair_worktree_after_gitdir_move()` is used to repair both sets of worktree linking files if the `.git` directory is moved during a re-initialization using `git init`. This also adds a test case for reinitializing a repository that has relative worktrees. Signed-off-by: Caleb White Signed-off-by: Junio C Hamano --- t/t0001-init.sh | 22 ++++++++++++++++++---- worktree.c | 29 ++++++++--------------------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 0178aa62a4..e394147b84 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -434,6 +434,12 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' ' sep_git_dir_worktree () { test_when_finished "rm -rf mainwt linkwt seprepo" && git init mainwt && + if test "relative" = $2 + then + test_config -C mainwt worktree.useRelativePaths true + else + test_config -C mainwt worktree.useRelativePaths false + fi test_commit -C mainwt gumby && git -C mainwt worktree add --detach ../linkwt && git -C "$1" init --separate-git-dir ../seprepo && @@ -442,12 +448,20 @@ sep_git_dir_worktree () { test_cmp expect actual } -test_expect_success 're-init to move gitdir with linked worktrees' ' - sep_git_dir_worktree mainwt +test_expect_success 're-init to move gitdir with linked worktrees (absolute)' ' + sep_git_dir_worktree mainwt absolute +' + +test_expect_success 're-init to move gitdir within linked worktree (absolute)' ' + sep_git_dir_worktree linkwt absolute +' + +test_expect_success 're-init to move gitdir with linked worktrees (relative)' ' + sep_git_dir_worktree mainwt relative ' -test_expect_success 're-init to move gitdir within linked worktree' ' - sep_git_dir_worktree linkwt +test_expect_success 're-init to move gitdir within linked worktree (relative)' ' + sep_git_dir_worktree linkwt relative ' test_expect_success MINGW '.git hidden' ' diff --git a/worktree.c b/worktree.c index 2e76bbc149..af68b24f9d 100644 --- a/worktree.c +++ b/worktree.c @@ -651,45 +651,32 @@ void repair_worktrees(worktree_repair_fn fn, void *cb_data, int use_relative_pat void repair_worktree_after_gitdir_move(struct worktree *wt, const char *old_path) { - struct strbuf path = STRBUF_INIT; - struct strbuf repo = STRBUF_INIT; struct strbuf gitdir = STRBUF_INIT; struct strbuf dotgit = STRBUF_INIT; - struct strbuf olddotgit = STRBUF_INIT; - struct strbuf tmp = STRBUF_INIT; + int is_relative_path; if (is_main_worktree(wt)) goto done; - strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1); - strbuf_addf(&gitdir, "%s/gitdir", repo.buf); + strbuf_realpath(&gitdir, git_common_path("worktrees/%s/gitdir", wt->id), 1); - if (strbuf_read_file(&olddotgit, gitdir.buf, 0) < 0) + if (strbuf_read_file(&dotgit, gitdir.buf, 0) < 0) goto done; - strbuf_rtrim(&olddotgit); - if (is_absolute_path(olddotgit.buf)) { - strbuf_addbuf(&dotgit, &olddotgit); - } else { - strbuf_addf(&dotgit, "%s/worktrees/%s/%s", old_path, wt->id, olddotgit.buf); + strbuf_rtrim(&dotgit); + is_relative_path = ! is_absolute_path(dotgit.buf); + if (is_relative_path) { + strbuf_insertf(&dotgit, 0, "%s/worktrees/%s/", old_path, wt->id); strbuf_realpath_forgiving(&dotgit, dotgit.buf, 0); } if (!file_exists(dotgit.buf)) goto done; - strbuf_addbuf(&path, &dotgit); - strbuf_strip_suffix(&path, "/.git"); - - write_file(dotgit.buf, "gitdir: %s", relative_path(repo.buf, path.buf, &tmp)); - write_file(gitdir.buf, "%s", relative_path(dotgit.buf, repo.buf, &tmp)); + write_worktree_linking_files(dotgit, gitdir, is_relative_path); done: - strbuf_release(&path); - strbuf_release(&repo); strbuf_release(&gitdir); strbuf_release(&dotgit); - strbuf_release(&olddotgit); - strbuf_release(&tmp); } void repair_worktrees_after_gitdir_move(const char *old_path) -- cgit v1.2.3 From b7f7d16562c3c5af31d77254577e4afe9bf3e99a Mon Sep 17 00:00:00 2001 From: Bence Ferdinandy Date: Fri, 29 Nov 2024 00:06:46 +0100 Subject: fetch: add configuration for set_head behaviour In the current implementation, if refs/remotes/$remote/HEAD does not exist, running fetch will create it, but if it does exist it will not do anything, which is a somewhat safe and minimal approach. Unfortunately, for users who wish to NOT have refs/remotes/$remote/HEAD set for any reason (e.g. so that `git rev-parse origin` doesn't accidentally point them somewhere they do not want to), there is no way to remove this behaviour. On the other side of the spectrum, users may want fetch to automatically update HEAD or at least give them a warning if something changed on the remote. Introduce a new setting, remote.$remote.followRemoteHEAD with four options: - "never": do not ever do anything, not even create - "create": the current behaviour, now the default behaviour - "warn": print a message if remote and local HEAD is different - "always": silently update HEAD on every change Signed-off-by: Bence Ferdinandy Signed-off-by: Junio C Hamano --- Documentation/config/remote.txt | 11 +++++ builtin/fetch.c | 46 +++++++++++++++--- remote.c | 9 ++++ remote.h | 9 ++++ t/t5510-fetch.sh | 102 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 171 insertions(+), 6 deletions(-) diff --git a/Documentation/config/remote.txt b/Documentation/config/remote.txt index 6d8b7d6c63..024f92befc 100644 --- a/Documentation/config/remote.txt +++ b/Documentation/config/remote.txt @@ -101,6 +101,17 @@ remote..serverOption:: The default set of server options used when fetching from this remote. These server options can be overridden by the `--server-option=` command line arguments. + +remote..followRemoteHEAD:: + How linkgit:git-fetch[1] should handle updates to `remotes//HEAD`. + The default value is "create", which will create `remotes//HEAD` + if it exists on the remote, but not locally, but will not touch an + already existing local reference. Setting to "warn" will print + a message if the remote has a different value, than the local one and + in case there is no local reference, it behaves like "create". Setting + to "always" will silently update it to the value on the remote. + Finally, setting it to "never" will never change or create the local + reference. + This is a multi-valued variable, and an empty value can be used in a higher priority configuration file (e.g. `.git/config` in a repository) to clear diff --git a/builtin/fetch.c b/builtin/fetch.c index 2f416cf867..88c5c5d781 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1579,10 +1579,35 @@ static const char *strip_refshead(const char *name){ return name; } -static int set_head(const struct ref *remote_refs) +static void report_set_head(const char *remote, const char *head_name, + struct strbuf *buf_prev, int updateres) { + struct strbuf buf_prefix = STRBUF_INIT; + const char *prev_head = NULL; + + strbuf_addf(&buf_prefix, "refs/remotes/%s/", remote); + skip_prefix(buf_prev->buf, buf_prefix.buf, &prev_head); + + if (prev_head && strcmp(prev_head, head_name)) { + printf("'HEAD' at '%s' is '%s', but we have '%s' locally.\n", + remote, head_name, prev_head); + printf("Run 'git remote set-head %s %s' to follow the change.\n", + remote, head_name); + } + else if (updateres && buf_prev->len) { + printf("'HEAD' at '%s' is '%s', " + "but we have a detached HEAD pointing to '%s' locally.\n", + remote, head_name, buf_prev->buf); + printf("Run 'git remote set-head %s %s' to follow the change.\n", + remote, head_name); + } + strbuf_release(&buf_prefix); +} + +static int set_head(const struct ref *remote_refs, int follow_remote_head) { - int result = 0, is_bare; - struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT; + int result = 0, create_only, is_bare, was_detached; + struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT, + b_local_head = STRBUF_INIT; const char *remote = gtransport->remote->name; char *head_name = NULL; struct ref *ref, *matches; @@ -1603,6 +1628,8 @@ static int set_head(const struct ref *remote_refs) string_list_append(&heads, strip_refshead(ref->name)); } + if (follow_remote_head == FOLLOW_REMOTE_NEVER) + goto cleanup; if (!heads.nr) result = 1; @@ -1614,6 +1641,7 @@ static int set_head(const struct ref *remote_refs) if (!head_name) goto cleanup; is_bare = is_bare_repository(); + create_only = follow_remote_head == FOLLOW_REMOTE_ALWAYS ? 0 : !is_bare; if (is_bare) { strbuf_addstr(&b_head, "HEAD"); strbuf_addf(&b_remote_head, "refs/heads/%s", head_name); @@ -1626,9 +1654,14 @@ static int set_head(const struct ref *remote_refs) result = 1; goto cleanup; } - if (refs_update_symref_extended(refs, b_head.buf, b_remote_head.buf, - "fetch", NULL, !is_bare)) + was_detached = refs_update_symref_extended(refs, b_head.buf, b_remote_head.buf, + "fetch", &b_local_head, create_only); + if (was_detached == -1) { result = 1; + goto cleanup; + } + if (follow_remote_head == FOLLOW_REMOTE_WARN && verbosity >= 0) + report_set_head(remote, head_name, &b_local_head, was_detached); cleanup: free(head_name); @@ -1636,6 +1669,7 @@ cleanup: free_refs(matches); string_list_clear(&heads, 0); strbuf_release(&b_head); + strbuf_release(&b_local_head); strbuf_release(&b_remote_head); return result; } @@ -1855,7 +1889,7 @@ static int do_fetch(struct transport *transport, "you need to specify exactly one branch with the --set-upstream option")); } } - if (set_head(remote_refs)) + if (set_head(remote_refs, transport->remote->follow_remote_head)) ; /* * Way too many cases where this can go wrong diff --git a/remote.c b/remote.c index 10104d11e3..0b18840d43 100644 --- a/remote.c +++ b/remote.c @@ -514,6 +514,15 @@ static int handle_config(const char *key, const char *value, } else if (!strcmp(subkey, "serveroption")) { return parse_transport_option(key, value, &remote->server_options); + } else if (!strcmp(subkey, "followremotehead")) { + if (!strcmp(value, "never")) + remote->follow_remote_head = FOLLOW_REMOTE_NEVER; + else if (!strcmp(value, "create")) + remote->follow_remote_head = FOLLOW_REMOTE_CREATE; + else if (!strcmp(value, "warn")) + remote->follow_remote_head = FOLLOW_REMOTE_WARN; + else if (!strcmp(value, "always")) + remote->follow_remote_head = FOLLOW_REMOTE_ALWAYS; } return 0; } diff --git a/remote.h b/remote.h index a7e5c4e07c..184b35653d 100644 --- a/remote.h +++ b/remote.h @@ -59,6 +59,13 @@ struct remote_state { void remote_state_clear(struct remote_state *remote_state); struct remote_state *remote_state_new(void); + enum follow_remote_head_settings { + FOLLOW_REMOTE_NEVER = -1, + FOLLOW_REMOTE_CREATE = 0, + FOLLOW_REMOTE_WARN = 1, + FOLLOW_REMOTE_ALWAYS = 2, + }; + struct remote { struct hashmap_entry ent; @@ -107,6 +114,8 @@ struct remote { char *http_proxy_authmethod; struct string_list server_options; + + enum follow_remote_head_settings follow_remote_head; }; /** diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 87698341f5..2467027d34 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -99,6 +99,108 @@ test_expect_success "fetch test remote HEAD change" ' branch=$(git rev-parse refs/remotes/origin/other) && test "z$head" = "z$branch"' +test_expect_success "fetch test followRemoteHEAD never" ' + test_when_finished "git config unset remote.origin.followRemoteHEAD" && + ( + cd "$D" && + cd two && + git update-ref --no-deref -d refs/remotes/origin/HEAD && + git config set remote.origin.followRemoteHEAD "never" && + git fetch && + test_must_fail git rev-parse --verify refs/remotes/origin/HEAD + ) +' + +test_expect_success "fetch test followRemoteHEAD warn no change" ' + test_when_finished "git config unset remote.origin.followRemoteHEAD" && + ( + cd "$D" && + cd two && + git rev-parse --verify refs/remotes/origin/other && + git remote set-head origin other && + git rev-parse --verify refs/remotes/origin/HEAD && + git rev-parse --verify refs/remotes/origin/main && + git config set remote.origin.followRemoteHEAD "warn" && + git fetch >output && + echo "${SQ}HEAD${SQ} at ${SQ}origin${SQ} is ${SQ}main${SQ}," \ + "but we have ${SQ}other${SQ} locally." >expect && + echo "Run ${SQ}git remote set-head origin main${SQ} to follow the change." >>expect && + test_cmp expect output && + head=$(git rev-parse refs/remotes/origin/HEAD) && + branch=$(git rev-parse refs/remotes/origin/other) && + test "z$head" = "z$branch" + ) +' + +test_expect_success "fetch test followRemoteHEAD warn create" ' + test_when_finished "git config unset remote.origin.followRemoteHEAD" && + ( + cd "$D" && + cd two && + git update-ref --no-deref -d refs/remotes/origin/HEAD && + git config set remote.origin.followRemoteHEAD "warn" && + git rev-parse --verify refs/remotes/origin/main && + output=$(git fetch) && + test "z" = "z$output" && + head=$(git rev-parse refs/remotes/origin/HEAD) && + branch=$(git rev-parse refs/remotes/origin/main) && + test "z$head" = "z$branch" + ) +' + +test_expect_success "fetch test followRemoteHEAD warn detached" ' + test_when_finished "git config unset remote.origin.followRemoteHEAD" && + ( + cd "$D" && + cd two && + git update-ref --no-deref -d refs/remotes/origin/HEAD && + git update-ref refs/remotes/origin/HEAD HEAD && + HEAD=$(git log --pretty="%H") && + git config set remote.origin.followRemoteHEAD "warn" && + git fetch >output && + echo "${SQ}HEAD${SQ} at ${SQ}origin${SQ} is ${SQ}main${SQ}," \ + "but we have a detached HEAD pointing to" \ + "${SQ}${HEAD}${SQ} locally." >expect && + echo "Run ${SQ}git remote set-head origin main${SQ} to follow the change." >>expect && + test_cmp expect output + ) +' + +test_expect_success "fetch test followRemoteHEAD warn quiet" ' + test_when_finished "git config unset remote.origin.followRemoteHEAD" && + ( + cd "$D" && + cd two && + git rev-parse --verify refs/remotes/origin/other && + git remote set-head origin other && + git rev-parse --verify refs/remotes/origin/HEAD && + git rev-parse --verify refs/remotes/origin/main && + git config set remote.origin.followRemoteHEAD "warn" && + output=$(git fetch --quiet) && + test "z" = "z$output" && + head=$(git rev-parse refs/remotes/origin/HEAD) && + branch=$(git rev-parse refs/remotes/origin/other) && + test "z$head" = "z$branch" + ) +' + +test_expect_success "fetch test followRemoteHEAD always" ' + test_when_finished "git config unset remote.origin.followRemoteHEAD" && + ( + cd "$D" && + cd two && + git rev-parse --verify refs/remotes/origin/other && + git remote set-head origin other && + git rev-parse --verify refs/remotes/origin/HEAD && + git rev-parse --verify refs/remotes/origin/main && + git config set remote.origin.followRemoteHEAD "always" && + git fetch && + head=$(git rev-parse refs/remotes/origin/HEAD) && + branch=$(git rev-parse refs/remotes/origin/main) && + test "z$head" = "z$branch" + ) +' + test_expect_success 'fetch --prune on its own works as expected' ' cd "$D" && git clone . prune && -- cgit v1.2.3 From da91a90c2f42f4b4e1fffa916a51e0e7ecb86ed9 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Sat, 30 Nov 2024 01:09:29 +0000 Subject: fast-import: disallow more path components Instead of just disallowing '.' and '..', make use of verify_path() to ensure that fast-import will disallow anything we wouldn't allow into the index, such as anything under .git/, .gitmodules as a symlink, or a dos drive prefix on Windows. Since a few fast-export and fast-import tests that tried to stress-test the correct handling of quoting relied on filenames that fail is_valid_win32_path(), such as spaces or periods at the end of filenames or backslashes within the filename, turn off core.protectNTFS for those tests to ensure they keep passing. Helped-by: Jeff King Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- builtin/fast-import.c | 8 +++-- t/t9300-fast-import.sh | 88 +++++++++++++++++++++++++++++++++++++++++++++++--- t/t9350-fast-export.sh | 2 +- 3 files changed, 91 insertions(+), 7 deletions(-) diff --git a/builtin/fast-import.c b/builtin/fast-import.c index 3e7ec1f119..265d1b7d52 100644 --- a/builtin/fast-import.c +++ b/builtin/fast-import.c @@ -13,6 +13,7 @@ #include "delta.h" #include "pack.h" #include "path.h" +#include "read-cache-ll.h" #include "refs.h" #include "csum-file.h" #include "quote.h" @@ -1468,8 +1469,6 @@ static int tree_content_set( root->tree = t = grow_tree_content(t, t->entry_count); e = new_tree_entry(); e->name = to_atom(p, n); - if (is_dot_or_dotdot(e->name->str_dat)) - die("path %s contains invalid component", p); e->versions[0].mode = 0; oidclr(&e->versions[0].oid, the_repository->hash_algo); t->entries[t->entry_count++] = e; @@ -2416,6 +2415,9 @@ static void file_change_m(const char *p, struct branch *b) tree_content_replace(&b->branch_tree, &oid, mode, NULL); return; } + + if (!verify_path(path.buf, mode)) + die("invalid path '%s'", path.buf); tree_content_set(&b->branch_tree, path.buf, &oid, mode, NULL); } @@ -2453,6 +2455,8 @@ static void file_change_cr(const char *p, struct branch *b, int rename) leaf.tree); return; } + if (!verify_path(dest.buf, leaf.versions[1].mode)) + die("invalid path '%s'", dest.buf); tree_content_set(&b->branch_tree, dest.buf, &leaf.versions[1].oid, leaf.versions[1].mode, diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 5a5127fffa..e2b1db6bc2 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -522,7 +522,7 @@ test_expect_success 'B: fail on invalid committer (5)' ' test_must_fail git fast-import input <<-INPUT_END && blob mark :1 @@ -542,6 +542,86 @@ test_expect_success 'B: fail on invalid file path' ' test_must_fail git fast-import input <<-INPUT_END && + blob + mark :1 + data < $GIT_COMMITTER_DATE + data <input <<-INPUT_END && + blob + mark :1 + data < $GIT_COMMITTER_DATE + data <input <<-INPUT_END && + blob + mark :1 + data < $GIT_COMMITTER_DATE + data <input <<-INPUT_END && + blob + mark :1 + data < $GIT_COMMITTER_DATE + data <output && cut -d" " -f1,2,5 output >actual && test_cmp expect actual @@ -3117,7 +3197,7 @@ test_path_eol_success () { test_expect_success "S: paths at EOL with $test must work" ' test_when_finished "git branch -D S-path-eol" && - git fast-import --export-marks=marks.out <<-EOF >out 2>err && + git -c core.protectNTFS=false fast-import --export-marks=marks.out <<-EOF >out 2>err && blob mark :401 data <err && + git -c core.protectNTFS=false fast-import --export-marks=marks.out <<-EOF 2>err && blob mark :401 data <expect && git init result && cd result && - git fast-import <../export.out && + git -c core.protectNTFS=false fast-import <../export.out && git rev-list HEAD >actual && test_cmp ../expect actual ) -- cgit v1.2.3 From 18693d7d65eb793eb64ef32685922c5739d53c26 Mon Sep 17 00:00:00 2001 From: Kristoffer Haugsbakk Date: Thu, 28 Nov 2024 20:44:51 +0100 Subject: Documentation/git-bundle.txt: fix word join typo Signed-off-by: Kristoffer Haugsbakk Signed-off-by: Junio C Hamano --- Documentation/git-bundle.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/git-bundle.txt b/Documentation/git-bundle.txt index 3ab42a19ca..344e7cd829 100644 --- a/Documentation/git-bundle.txt +++ b/Documentation/git-bundle.txt @@ -31,7 +31,7 @@ Git commands that fetch or otherwise "read" via protocols such as possible linkgit:git-clone[1] a new repository from a bundle, to use linkgit:git-fetch[1] to fetch from one, and to list the references contained within it with linkgit:git-ls-remote[1]. There's no -corresponding "write" support, i.e.a 'git push' into a bundle is not +corresponding "write" support, i.e. a 'git push' into a bundle is not supported. See the "EXAMPLES" section below for examples of how to use bundles. -- cgit v1.2.3 From e2f5d3b491ee8becb37549f29a3cee50573d0bd3 Mon Sep 17 00:00:00 2001 From: Kristoffer Haugsbakk Date: Fri, 29 Nov 2024 19:52:29 +0100 Subject: Documentation/git-update-ref.txt: add missing word MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing word “that” in the phrase “after verifying that”, like what was done in 1b2dfb70504 (Documentation/git-update-ref.txt: drop “flag”, 2024-10-21) Signed-off-by: Kristoffer Haugsbakk Signed-off-by: Junio C Hamano --- Documentation/git-update-ref.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/git-update-ref.txt b/Documentation/git-update-ref.txt index afcf33cf60..70ad72717e 100644 --- a/Documentation/git-update-ref.txt +++ b/Documentation/git-update-ref.txt @@ -114,11 +114,11 @@ update:: ref does not exist before the update. create:: - Create with after verifying it does not + Create with after verifying that it does not exist. The given may not be zero. delete:: - Delete after verifying it exists with , if + Delete after verifying that it exists with , if given. If given, may not be zero. symref-update:: @@ -131,11 +131,11 @@ verify:: is zero or missing, the ref must not exist. symref-create: - Create symbolic ref with after verifying + Create symbolic ref with after verifying that it does not exist. symref-delete:: - Delete after verifying it exists with , if given. + Delete after verifying that it exists with , if given. symref-verify:: Verify symbolic against but do not change it. -- cgit v1.2.3 From 5bcbde9e49c14f4e47a0ed5fc60470f3d4447efd Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 3 Dec 2024 11:32:37 +0900 Subject: refs: move ref name helpers around strbuf_branchname(), strbuf_check_{branch,tag}_ref() are helper functions to deal with branch and tag names, and the fact that they happen to use strbuf to hold the name of a branch or a tag is not essential. These functions fit better in the refs API than strbuf API, the latter of which is about string manipulations. Signed-off-by: Junio C Hamano --- builtin/tag.c | 11 ----------- object-name.c | 36 ------------------------------------ refs.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ refs.h | 29 +++++++++++++++++++++++++++++ strbuf.h | 22 ---------------------- 5 files changed, 76 insertions(+), 69 deletions(-) diff --git a/builtin/tag.c b/builtin/tag.c index 93d10d5915..8279dccbe0 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -447,17 +447,6 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset) return 0; } -static int strbuf_check_tag_ref(struct strbuf *sb, const char *name) -{ - if (name[0] == '-') - return -1; - - strbuf_reset(sb); - strbuf_addf(sb, "refs/tags/%s", name); - - return check_refname_format(sb->buf, 0); -} - int cmd_tag(int argc, const char **argv, const char *prefix, diff --git a/object-name.c b/object-name.c index c892fbe80a..9f2ae164e4 100644 --- a/object-name.c +++ b/object-name.c @@ -1734,42 +1734,6 @@ int repo_interpret_branch_name(struct repository *r, return -1; } -void strbuf_branchname(struct strbuf *sb, const char *name, unsigned allowed) -{ - int len = strlen(name); - struct interpret_branch_name_options options = { - .allowed = allowed - }; - int used = repo_interpret_branch_name(the_repository, name, len, sb, - &options); - - if (used < 0) - used = 0; - strbuf_add(sb, name + used, len - used); -} - -int strbuf_check_branch_ref(struct strbuf *sb, const char *name) -{ - if (startup_info->have_repository) - strbuf_branchname(sb, name, INTERPRET_BRANCH_LOCAL); - else - strbuf_addstr(sb, name); - - /* - * This splice must be done even if we end up rejecting the - * name; builtin/branch.c::copy_or_rename_branch() still wants - * to see what the name expanded to so that "branch -m" can be - * used as a tool to correct earlier mistakes. - */ - strbuf_splice(sb, 0, 0, "refs/heads/", 11); - - if (*name == '-' || - !strcmp(sb->buf, "refs/heads/HEAD")) - return -1; - - return check_refname_format(sb->buf, 0); -} - void object_context_release(struct object_context *ctx) { free(ctx->path); diff --git a/refs.c b/refs.c index 5f729ed412..59a9223d4c 100644 --- a/refs.c +++ b/refs.c @@ -697,6 +697,53 @@ static char *substitute_branch_name(struct repository *r, return NULL; } +void strbuf_branchname(struct strbuf *sb, const char *name, unsigned allowed) +{ + int len = strlen(name); + struct interpret_branch_name_options options = { + .allowed = allowed + }; + int used = repo_interpret_branch_name(the_repository, name, len, sb, + &options); + + if (used < 0) + used = 0; + strbuf_add(sb, name + used, len - used); +} + +int strbuf_check_branch_ref(struct strbuf *sb, const char *name) +{ + if (startup_info->have_repository) + strbuf_branchname(sb, name, INTERPRET_BRANCH_LOCAL); + else + strbuf_addstr(sb, name); + + /* + * This splice must be done even if we end up rejecting the + * name; builtin/branch.c::copy_or_rename_branch() still wants + * to see what the name expanded to so that "branch -m" can be + * used as a tool to correct earlier mistakes. + */ + strbuf_splice(sb, 0, 0, "refs/heads/", 11); + + if (*name == '-' || + !strcmp(sb->buf, "refs/heads/HEAD")) + return -1; + + return check_refname_format(sb->buf, 0); +} + +int strbuf_check_tag_ref(struct strbuf *sb, const char *name) +{ + if (name[0] == '-') + return -1; + + strbuf_reset(sb); + strbuf_addf(sb, "refs/tags/%s", name); + + return check_refname_format(sb->buf, 0); +} + int repo_dwim_ref(struct repository *r, const char *str, int len, struct object_id *oid, char **ref, int nonfatal_dangling_mark) { diff --git a/refs.h b/refs.h index 108dfc93b3..f19b0ad92f 100644 --- a/refs.h +++ b/refs.h @@ -180,6 +180,35 @@ int repo_dwim_log(struct repository *r, const char *str, int len, struct object_ */ char *repo_default_branch_name(struct repository *r, int quiet); +/* + * Copy "name" to "sb", expanding any special @-marks as handled by + * repo_interpret_branch_name(). The result is a non-qualified branch name + * (so "foo" or "origin/master" instead of "refs/heads/foo" or + * "refs/remotes/origin/master"). + * + * Note that the resulting name may not be a syntactically valid refname. + * + * If "allowed" is non-zero, restrict the set of allowed expansions. See + * repo_interpret_branch_name() for details. + */ +void strbuf_branchname(struct strbuf *sb, const char *name, + unsigned allowed); + +/* + * Like strbuf_branchname() above, but confirm that the result is + * syntactically valid to be used as a local branch name in refs/heads/. + * + * The return value is "0" if the result is valid, and "-1" otherwise. + */ +int strbuf_check_branch_ref(struct strbuf *sb, const char *name); + +/* + * Similar for a tag name in refs/tags/. + * + * The return value is "0" if the result is valid, and "-1" otherwise. + */ +int strbuf_check_tag_ref(struct strbuf *sb, const char *name); + /* * A ref_transaction represents a collection of reference updates that * should succeed or fail together. diff --git a/strbuf.h b/strbuf.h index 003f880ff7..4dc05b4ba7 100644 --- a/strbuf.h +++ b/strbuf.h @@ -637,28 +637,6 @@ static inline void strbuf_complete_line(struct strbuf *sb) strbuf_complete(sb, '\n'); } -/* - * Copy "name" to "sb", expanding any special @-marks as handled by - * repo_interpret_branch_name(). The result is a non-qualified branch name - * (so "foo" or "origin/master" instead of "refs/heads/foo" or - * "refs/remotes/origin/master"). - * - * Note that the resulting name may not be a syntactically valid refname. - * - * If "allowed" is non-zero, restrict the set of allowed expansions. See - * repo_interpret_branch_name() for details. - */ -void strbuf_branchname(struct strbuf *sb, const char *name, - unsigned allowed); - -/* - * Like strbuf_branchname() above, but confirm that the result is - * syntactically valid to be used as a local branch name in refs/heads/. - * - * The return value is "0" if the result is valid, and "-1" otherwise. - */ -int strbuf_check_branch_ref(struct strbuf *sb, const char *name); - typedef int (*char_predicate)(char ch); void strbuf_addstr_urlencode(struct strbuf *sb, const char *name, -- cgit v1.2.3 From 93e5e048f84138a632b239632c9b45ae238cdf1c Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 3 Dec 2024 11:32:38 +0900 Subject: refs: drop strbuf_ prefix from helpers The helper functions (strbuf_branchname, strbuf_check_branch_ref, and strbuf_check_tag_ref) are about handling branch and tag names, and it is a non-essential fact that these functions use strbuf to hold these names. Rename them to make it clarify that these are more about "ref". Signed-off-by: Junio C Hamano --- branch.c | 2 +- builtin/branch.c | 10 +++++----- builtin/check-ref-format.c | 2 +- builtin/checkout.c | 2 +- builtin/merge.c | 2 +- builtin/tag.c | 2 +- builtin/worktree.c | 8 ++++---- gitweb/gitweb.perl | 2 +- refs.c | 8 ++++---- refs.h | 8 ++++---- 10 files changed, 23 insertions(+), 23 deletions(-) diff --git a/branch.c b/branch.c index 08fa4094d2..58b61831af 100644 --- a/branch.c +++ b/branch.c @@ -372,7 +372,7 @@ int read_branch_desc(struct strbuf *buf, const char *branch_name) */ int validate_branchname(const char *name, struct strbuf *ref) { - if (strbuf_check_branch_ref(ref, name)) { + if (check_branch_ref(ref, name)) { int code = die_message(_("'%s' is not a valid branch name"), name); advise_if_enabled(ADVICE_REF_SYNTAX, _("See `man git check-ref-format`")); diff --git a/builtin/branch.c b/builtin/branch.c index fd1611ebf5..17acf598d2 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -257,7 +257,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, char *target = NULL; int flags = 0; - strbuf_branchname(&bname, argv[i], allowed_interpret); + copy_branchname(&bname, argv[i], allowed_interpret); free(name); name = mkpathdup(fmt, bname.buf); @@ -579,7 +579,7 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int int recovery = 0, oldref_usage = 0; struct worktree **worktrees = get_worktrees(); - if (strbuf_check_branch_ref(&oldref, oldname)) { + if (check_branch_ref(&oldref, oldname)) { /* * Bad name --- this could be an attempt to rename a * ref that we used to allow to be created by accident. @@ -894,7 +894,7 @@ int cmd_branch(int argc, die(_("cannot give description to detached HEAD")); branch_name = head; } else if (argc == 1) { - strbuf_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL); + copy_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL); branch_name = buf.buf; } else { die(_("cannot edit description of more than one branch")); @@ -933,7 +933,7 @@ int cmd_branch(int argc, if (!argc) branch = branch_get(NULL); else if (argc == 1) { - strbuf_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL); + copy_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL); branch = branch_get(buf.buf); } else die(_("too many arguments to set new upstream")); @@ -963,7 +963,7 @@ int cmd_branch(int argc, if (!argc) branch = branch_get(NULL); else if (argc == 1) { - strbuf_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL); + copy_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL); branch = branch_get(buf.buf); } else die(_("too many arguments to unset upstream")); diff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c index e86d8ef980..cef1ffe3ce 100644 --- a/builtin/check-ref-format.c +++ b/builtin/check-ref-format.c @@ -42,7 +42,7 @@ static int check_ref_format_branch(const char *arg) int nongit; setup_git_directory_gently(&nongit); - if (strbuf_check_branch_ref(&sb, arg) || + if (check_branch_ref(&sb, arg) || !skip_prefix(sb.buf, "refs/heads/", &name)) die("'%s' is not a valid branch name", arg); printf("%s\n", name); diff --git a/builtin/checkout.c b/builtin/checkout.c index c449558e66..5e5afa0f26 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -742,7 +742,7 @@ static void setup_branch_path(struct branch_info *branch) &branch->oid, &branch->refname, 0)) repo_get_oid_committish(the_repository, branch->name, &branch->oid); - strbuf_branchname(&buf, branch->name, INTERPRET_BRANCH_LOCAL); + copy_branchname(&buf, branch->name, INTERPRET_BRANCH_LOCAL); if (strcmp(buf.buf, branch->name)) { free(branch->name); branch->name = xstrdup(buf.buf); diff --git a/builtin/merge.c b/builtin/merge.c index 84d0f3604b..d0c31d7714 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -498,7 +498,7 @@ static void merge_name(const char *remote, struct strbuf *msg) char *found_ref = NULL; int len, early; - strbuf_branchname(&bname, remote, 0); + copy_branchname(&bname, remote, 0); remote = bname.buf; oidclr(&branch_head, the_repository->hash_algo); diff --git a/builtin/tag.c b/builtin/tag.c index 8279dccbe0..670e564178 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -639,7 +639,7 @@ int cmd_tag(int argc, if (repo_get_oid(the_repository, object_ref, &object)) die(_("Failed to resolve '%s' as a valid ref."), object_ref); - if (strbuf_check_tag_ref(&ref, tag)) + if (check_tag_ref(&ref, tag)) die(_("'%s' is not a valid tag name."), tag); if (refs_read_ref(get_main_ref_store(the_repository), ref.buf, &prev)) diff --git a/builtin/worktree.c b/builtin/worktree.c index fc31d072a6..c68f601358 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -432,7 +432,7 @@ static int add_worktree(const char *path, const char *refname, worktrees = NULL; /* is 'refname' a branch or commit? */ - if (!opts->detach && !strbuf_check_branch_ref(&symref, refname) && + if (!opts->detach && !check_branch_ref(&symref, refname) && refs_ref_exists(get_main_ref_store(the_repository), symref.buf)) { is_branch = 1; if (!opts->force) @@ -604,7 +604,7 @@ static void print_preparing_worktree_line(int detach, fprintf_ln(stderr, _("Preparing worktree (new branch '%s')"), new_branch); } else { struct strbuf s = STRBUF_INIT; - if (!detach && !strbuf_check_branch_ref(&s, branch) && + if (!detach && !check_branch_ref(&s, branch) && refs_ref_exists(get_main_ref_store(the_repository), s.buf)) fprintf_ln(stderr, _("Preparing worktree (checking out '%s')"), branch); @@ -745,7 +745,7 @@ static char *dwim_branch(const char *path, char **new_branch) char *branchname = xstrndup(s, n); struct strbuf ref = STRBUF_INIT; - branch_exists = !strbuf_check_branch_ref(&ref, branchname) && + branch_exists = !check_branch_ref(&ref, branchname) && refs_ref_exists(get_main_ref_store(the_repository), ref.buf); strbuf_release(&ref); @@ -838,7 +838,7 @@ static int add(int ac, const char **av, const char *prefix) new_branch = new_branch_force; if (!opts.force && - !strbuf_check_branch_ref(&symref, new_branch) && + !check_branch_ref(&symref, new_branch) && refs_ref_exists(get_main_ref_store(the_repository), symref.buf)) die_if_checked_out(symref.buf, 0); strbuf_release(&symref); diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index b09a8d0523..8cdb0d9b9f 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2094,7 +2094,7 @@ sub format_log_line_html { ( # The output of "git describe", e.g. v2.10.0-297-gf6727b0 # or hadoop-20160921-113441-20-g094fb7d - (?have_repository) - strbuf_branchname(sb, name, INTERPRET_BRANCH_LOCAL); + copy_branchname(sb, name, INTERPRET_BRANCH_LOCAL); else strbuf_addstr(sb, name); @@ -733,7 +733,7 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name) return check_refname_format(sb->buf, 0); } -int strbuf_check_tag_ref(struct strbuf *sb, const char *name) +int check_tag_ref(struct strbuf *sb, const char *name) { if (name[0] == '-') return -1; diff --git a/refs.h b/refs.h index f19b0ad92f..c5280477f0 100644 --- a/refs.h +++ b/refs.h @@ -191,23 +191,23 @@ char *repo_default_branch_name(struct repository *r, int quiet); * If "allowed" is non-zero, restrict the set of allowed expansions. See * repo_interpret_branch_name() for details. */ -void strbuf_branchname(struct strbuf *sb, const char *name, +void copy_branchname(struct strbuf *sb, const char *name, unsigned allowed); /* - * Like strbuf_branchname() above, but confirm that the result is + * Like copy_branchname() above, but confirm that the result is * syntactically valid to be used as a local branch name in refs/heads/. * * The return value is "0" if the result is valid, and "-1" otherwise. */ -int strbuf_check_branch_ref(struct strbuf *sb, const char *name); +int check_branch_ref(struct strbuf *sb, const char *name); /* * Similar for a tag name in refs/tags/. * * The return value is "0" if the result is valid, and "-1" otherwise. */ -int strbuf_check_tag_ref(struct strbuf *sb, const char *name); +int check_tag_ref(struct strbuf *sb, const char *name); /* * A ref_transaction represents a collection of reference updates that -- cgit v1.2.3 From e5ce5b05d09c17c3d6a1d95c4c822dd3a73a9100 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 3 Dec 2024 11:32:39 +0900 Subject: t5604: do not expect that HEAD can be a valid tagname 09116a1c (refs: loosen over-strict "format" check, 2011-11-16) introduced a test piece (originally in t5700) that expects to be able to create a tag named "HEAD" and then a local clone using the repository as its own reference works correctly. Later, another test piece started using this tag starting at acede2eb (t5700: document a failure of alternates to affect fetch, 2012-02-11). But the breakage 09116a1c fixed was not specific to the tagname HEAD. It would have failed exactly the same way if the tag used were foo instead of HEAD. Before forbidding "git tag" from creating "refs/tags/HEAD", update these tests to use 'foo', not 'HEAD', as the name of the test tag. Note that the test piece that uses the tag learned the value of the tag in unnecessarily inefficient and convoluted way with for-each-ref. Just use "rev-parse" instead. Signed-off-by: Junio C Hamano --- t/t5604-clone-reference.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/t5604-clone-reference.sh b/t/t5604-clone-reference.sh index 9b32db8478..5f5c650ff8 100755 --- a/t/t5604-clone-reference.sh +++ b/t/t5604-clone-reference.sh @@ -131,7 +131,7 @@ test_expect_success 'cloning with multiple references drops duplicates' ' test_expect_success 'clone with reference from a tagged repository' ' ( - cd A && git tag -a -m tagged HEAD + cd A && git tag -a -m tagged foo ) && git clone --reference=A A I ' @@ -156,10 +156,10 @@ test_expect_success 'fetch with incomplete alternates' ' git remote add J "file://$base_dir/J" && GIT_TRACE_PACKET=$U.K git fetch J ) && - main_object=$(cd A && git for-each-ref --format="%(objectname)" refs/heads/main) && + main_object=$(git -C A rev-parse --verify refs/heads/main) && test -s "$U.K" && ! grep " want $main_object" "$U.K" && - tag_object=$(cd A && git for-each-ref --format="%(objectname)" refs/tags/HEAD) && + tag_object=$(git -C A rev-parse --verify refs/tags/foo) && ! grep " want $tag_object" "$U.K" ' -- cgit v1.2.3 From bbd445d5efd415d43ac6102a3e9541b9ac4f0329 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 3 Dec 2024 11:32:40 +0900 Subject: tag: "git tag" refuses to use HEAD as a tagname MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Even though the plumbing level allows you to create refs/tags/HEAD and refs/heads/HEAD, doing so makes it confusing within the context of the UI Git Porcelain commands provides. Just like we prevent a branch from getting called "HEAD" at the Porcelain layer (i.e. "git branch" command), teach "git tag" to refuse to create a tag "HEAD". With a few new tests, we make sure that - "git tag HEAD" and "git tag -a HEAD" are rejected - "git update-ref refs/tags/HEAD" is still allowed (this is a deliberate design decision to allow others to create their own UI on top of Git infrastructure that may be different from our UI). - "git tag -d HEAD" can remove refs/tags/HEAD to recover from an mistake. Helped-by: Jeff King Helped-by: Rubén Justo Signed-off-by: Junio C Hamano --- refs.c | 2 +- t/t7004-tag.sh | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/refs.c b/refs.c index a24bfe3845..01ef2a3093 100644 --- a/refs.c +++ b/refs.c @@ -735,7 +735,7 @@ int check_branch_ref(struct strbuf *sb, const char *name) int check_tag_ref(struct strbuf *sb, const char *name) { - if (name[0] == '-') + if (name[0] == '-' || !strcmp(name, "HEAD")) return -1; strbuf_reset(sb); diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index b1316e62f4..34d34b0dfb 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -91,6 +91,18 @@ test_expect_success 'creating a tag using default HEAD should succeed' ' test_must_fail git reflog exists refs/tags/mytag ' +test_expect_success 'HEAD is forbidden as a tagname' ' + test_when_finished "git update-ref --no-deref -d refs/tags/HEAD || :" && + test_must_fail git tag HEAD && + test_must_fail git tag -a -m "useless" HEAD +' + +test_expect_success '"git tag" can remove a tag named HEAD' ' + test_when_finished "git update-ref --no-deref -d refs/tags/HEAD || :" && + git update-ref refs/tags/HEAD HEAD && + git tag -d HEAD +' + test_expect_success 'creating a tag with --create-reflog should create reflog' ' git log -1 \ --format="format:tag: tagging %h (%s, %cd)%n" \ -- cgit v1.2.3 From 2cf3fe63f6eedd6d132c530b897595345a05088b Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Tue, 3 Dec 2024 15:43:55 +0100 Subject: packfile: add repository to struct `packed_git` The struct `packed_git` holds information regarding a packed object file. Let's add the repository variable to this object, to represent the repository that this packfile belongs to. This helps remove dependency on the global `the_repository` object in `packfile.c` by simply using repository information now readily available in the struct. We do need to consider that a packfile could be part of the alternates of a repository, but considering that we only have one repository struct and also that we currently anyways use 'the_repository', we should be OK with this change. We also modify `alloc_packed_git` to ensure that the repository is added to newly created `packed_git` structs. This requires modifying the function and all its callee to pass the repository object down the levels. Helped-by: Taylor Blau Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- builtin/fast-import.c | 3 ++- builtin/index-pack.c | 6 ++++-- commit-graph.c | 2 +- connected.c | 3 ++- http.c | 2 +- midx-write.c | 2 +- midx.c | 2 +- object-store-ll.h | 5 +++++ packfile.c | 15 +++++++++------ packfile.h | 6 ++++-- 10 files changed, 30 insertions(+), 16 deletions(-) diff --git a/builtin/fast-import.c b/builtin/fast-import.c index 76d5c20f14..da7e2d613b 100644 --- a/builtin/fast-import.c +++ b/builtin/fast-import.c @@ -765,6 +765,7 @@ static void start_packfile(void) p->pack_fd = pack_fd; p->do_not_close = 1; + p->repo = the_repository; pack_file = hashfd(pack_fd, p->pack_name); pack_data = p; @@ -888,7 +889,7 @@ static void end_packfile(void) idx_name = keep_pack(create_index()); /* Register the packfile with core git's machinery. */ - new_p = add_packed_git(idx_name, strlen(idx_name), 1); + new_p = add_packed_git(pack_data->repo, idx_name, strlen(idx_name), 1); if (!new_p) die("core git rejected index %s", idx_name); all_packs[pack_id] = new_p; diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 9d23b41b3a..be2f99625e 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -1552,7 +1552,8 @@ static void final(const char *final_pack_name, const char *curr_pack_name, if (do_fsck_object) { struct packed_git *p; - p = add_packed_git(final_index_name, strlen(final_index_name), 0); + p = add_packed_git(the_repository, final_index_name, + strlen(final_index_name), 0); if (p) install_packed_git(the_repository, p); } @@ -1650,7 +1651,8 @@ static void read_v2_anomalous_offsets(struct packed_git *p, static void read_idx_option(struct pack_idx_option *opts, const char *pack_name) { - struct packed_git *p = add_packed_git(pack_name, strlen(pack_name), 1); + struct packed_git *p = add_packed_git(the_repository, pack_name, + strlen(pack_name), 1); if (!p) die(_("Cannot open existing pack file '%s'"), pack_name); diff --git a/commit-graph.c b/commit-graph.c index 5bd89c0acd..83dd69bfeb 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -1914,7 +1914,7 @@ static int fill_oids_from_packs(struct write_commit_graph_context *ctx, struct packed_git *p; strbuf_setlen(&packname, dirlen); strbuf_addstr(&packname, pack_indexes->items[i].string); - p = add_packed_git(packname.buf, packname.len, 1); + p = add_packed_git(ctx->r, packname.buf, packname.len, 1); if (!p) { ret = error(_("error adding pack %s"), packname.buf); goto cleanup; diff --git a/connected.c b/connected.c index a9e2e13995..3099da84f3 100644 --- a/connected.c +++ b/connected.c @@ -54,7 +54,8 @@ int check_connected(oid_iterate_fn fn, void *cb_data, strbuf_add(&idx_file, transport->pack_lockfiles.items[0].string, base_len); strbuf_addstr(&idx_file, ".idx"); - new_pack = add_packed_git(idx_file.buf, idx_file.len, 1); + new_pack = add_packed_git(the_repository, idx_file.buf, + idx_file.len, 1); strbuf_release(&idx_file); } diff --git a/http.c b/http.c index 58242b9d2d..6744e18409 100644 --- a/http.c +++ b/http.c @@ -2439,7 +2439,7 @@ static int fetch_and_setup_pack_index(struct packed_git **packs_head, if (!tmp_idx) return -1; - new_pack = parse_pack_index(sha1, tmp_idx); + new_pack = parse_pack_index(the_repository, sha1, tmp_idx); if (!new_pack) { unlink(tmp_idx); free(tmp_idx); diff --git a/midx-write.c b/midx-write.c index b3a5f6c516..c57726ef94 100644 --- a/midx-write.c +++ b/midx-write.c @@ -154,7 +154,7 @@ static void add_pack_to_midx(const char *full_path, size_t full_path_len, return; ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc); - p = add_packed_git(full_path, full_path_len, 0); + p = add_packed_git(the_repository, full_path, full_path_len, 0); if (!p) { warning(_("failed to add packfile '%s'"), full_path); diff --git a/midx.c b/midx.c index e82d4f2e65..8edb75f51d 100644 --- a/midx.c +++ b/midx.c @@ -464,7 +464,7 @@ int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, strhash(key.buf), key.buf, struct packed_git, packmap_ent); if (!p) { - p = add_packed_git(pack_name.buf, pack_name.len, m->local); + p = add_packed_git(r, pack_name.buf, pack_name.len, m->local); if (p) { install_packed_git(r, p); list_add_tail(&p->mru, &r->objects->packed_git_mru); diff --git a/object-store-ll.h b/object-store-ll.h index 53b8e693b1..d46cd0e654 100644 --- a/object-store-ll.h +++ b/object-store-ll.h @@ -10,6 +10,7 @@ struct oidmap; struct oidtree; struct strbuf; +struct repository; struct object_directory { struct object_directory *next; @@ -135,6 +136,10 @@ struct packed_git { */ const uint32_t *mtimes_map; size_t mtimes_size; + + /* repo denotes the repository this packfile belongs to */ + struct repository *repo; + /* something like ".git/objects/pack/xxxxx.pack" */ char pack_name[FLEX_ARRAY]; /* more */ }; diff --git a/packfile.c b/packfile.c index 9560f0a33c..6058eddf35 100644 --- a/packfile.c +++ b/packfile.c @@ -217,11 +217,12 @@ uint32_t get_pack_fanout(struct packed_git *p, uint32_t value) return ntohl(level1_ofs[value]); } -static struct packed_git *alloc_packed_git(int extra) +static struct packed_git *alloc_packed_git(struct repository *r, int extra) { struct packed_git *p = xmalloc(st_add(sizeof(*p), extra)); memset(p, 0, sizeof(*p)); p->pack_fd = -1; + p->repo = r; return p; } @@ -233,11 +234,12 @@ static char *pack_path_from_idx(const char *idx_path) return xstrfmt("%.*s.pack", (int)len, idx_path); } -struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path) +struct packed_git *parse_pack_index(struct repository *r, unsigned char *sha1, + const char *idx_path) { char *path = pack_path_from_idx(idx_path); size_t alloc = st_add(strlen(path), 1); - struct packed_git *p = alloc_packed_git(alloc); + struct packed_git *p = alloc_packed_git(r, alloc); memcpy(p->pack_name, path, alloc); /* includes NUL */ free(path); @@ -703,7 +705,8 @@ void unuse_pack(struct pack_window **w_cursor) } } -struct packed_git *add_packed_git(const char *path, size_t path_len, int local) +struct packed_git *add_packed_git(struct repository *r, const char *path, + size_t path_len, int local) { struct stat st; size_t alloc; @@ -721,7 +724,7 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local) * the use xsnprintf double-checks that) */ alloc = st_add3(path_len, strlen(".promisor"), 1); - p = alloc_packed_git(alloc); + p = alloc_packed_git(r, alloc); memcpy(p->pack_name, path, path_len); xsnprintf(p->pack_name + path_len, alloc - path_len, ".keep"); @@ -877,7 +880,7 @@ static void prepare_pack(const char *full_name, size_t full_name_len, /* Don't reopen a pack we already have. */ if (!hashmap_get(&data->r->objects->pack_map, &hent, pack_name)) { - p = add_packed_git(full_name, full_name_len, data->local); + p = add_packed_git(data->r, full_name, full_name_len, data->local); if (p) install_packed_git(data->r, p); } diff --git a/packfile.h b/packfile.h index 08f88a7ff5..aee69d1a0b 100644 --- a/packfile.h +++ b/packfile.h @@ -46,7 +46,8 @@ const char *pack_basename(struct packed_git *p); * and does not add the resulting packed_git struct to the internal list of * packs. You probably want add_packed_git() instead. */ -struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path); +struct packed_git *parse_pack_index(struct repository *r, unsigned char *sha1, + const char *idx_path); typedef void each_file_in_pack_dir_fn(const char *full_path, size_t full_path_len, const char *file_name, void *data); @@ -113,7 +114,8 @@ void close_pack(struct packed_git *); void close_object_store(struct raw_object_store *o); void unuse_pack(struct pack_window **); void clear_delta_base_cache(void); -struct packed_git *add_packed_git(const char *path, size_t path_len, int local); +struct packed_git *add_packed_git(struct repository *r, const char *path, + size_t path_len, int local); /* * Unlink the .pack and associated extension files. -- cgit v1.2.3 From 9c5ce06d74251601ca0dcb3ebe2284639f96f9a2 Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Tue, 3 Dec 2024 15:43:56 +0100 Subject: packfile: use `repository` from `packed_git` directly In the previous commit, we introduced the `repository` structure inside `packed_git`. This provides an alternative route instead of using the global `the_repository` variable. Let's modify `packfile.c` now to use this field wherever possible instead of relying on the global state. There are still a few instances of `the_repository` usage in the file, where there is no struct `packed_git` locally available, which will be fixed in the following commits. Helped-by: Taylor Blau Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- packfile.c | 50 +++++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/packfile.c b/packfile.c index 6058eddf35..5bfa1e17c2 100644 --- a/packfile.c +++ b/packfile.c @@ -79,7 +79,7 @@ static int check_packed_git_idx(const char *path, struct packed_git *p) size_t idx_size; int fd = git_open(path), ret; struct stat st; - const unsigned int hashsz = the_hash_algo->rawsz; + const unsigned int hashsz = p->repo->hash_algo->rawsz; if (fd < 0) return -1; @@ -243,7 +243,7 @@ struct packed_git *parse_pack_index(struct repository *r, unsigned char *sha1, memcpy(p->pack_name, path, alloc); /* includes NUL */ free(path); - hashcpy(p->hash, sha1, the_repository->hash_algo); + hashcpy(p->hash, sha1, p->repo->hash_algo); if (check_packed_git_idx(idx_path, p)) { free(p); return NULL; @@ -278,7 +278,7 @@ static int unuse_one_window(struct packed_git *current) if (current) scan_windows(current, &lru_p, &lru_w, &lru_l); - for (p = the_repository->objects->packed_git; p; p = p->next) + for (p = current->repo->objects->packed_git; p; p = p->next) scan_windows(p, &lru_p, &lru_w, &lru_l); if (lru_p) { munmap(lru_w->base, lru_w->len); @@ -540,7 +540,7 @@ static int open_packed_git_1(struct packed_git *p) unsigned char hash[GIT_MAX_RAWSZ]; unsigned char *idx_hash; ssize_t read_result; - const unsigned hashsz = the_hash_algo->rawsz; + const unsigned hashsz = p->repo->hash_algo->rawsz; if (open_pack_index(p)) return error("packfile %s index unavailable", p->pack_name); @@ -597,7 +597,7 @@ static int open_packed_git_1(struct packed_git *p) if (read_result != hashsz) return error("packfile %s signature is unavailable", p->pack_name); idx_hash = ((unsigned char *)p->index_data) + p->index_size - hashsz * 2; - if (!hasheq(hash, idx_hash, the_repository->hash_algo)) + if (!hasheq(hash, idx_hash, p->repo->hash_algo)) return error("packfile %s does not match index", p->pack_name); return 0; } @@ -637,7 +637,7 @@ unsigned char *use_pack(struct packed_git *p, */ if (!p->pack_size && p->pack_fd == -1 && open_packed_git(p)) die("packfile %s cannot be accessed", p->pack_name); - if (offset > (p->pack_size - the_hash_algo->rawsz)) + if (offset > (p->pack_size - p->repo->hash_algo->rawsz)) die("offset beyond end of packfile (truncated pack?)"); if (offset < 0) die(_("offset before end of packfile (broken .idx?)")); @@ -711,6 +711,7 @@ struct packed_git *add_packed_git(struct repository *r, const char *path, struct stat st; size_t alloc; struct packed_git *p; + struct object_id oid; /* * Make sure a corresponding .pack file exists and that @@ -751,9 +752,13 @@ struct packed_git *add_packed_git(struct repository *r, const char *path, p->pack_size = st.st_size; p->pack_local = local; p->mtime = st.st_mtime; - if (path_len < the_hash_algo->hexsz || - get_hash_hex(path + path_len - the_hash_algo->hexsz, p->hash)) - hashclr(p->hash, the_repository->hash_algo); + if (path_len < r->hash_algo->hexsz || + get_oid_hex_algop(path + path_len - r->hash_algo->hexsz, &oid, + r->hash_algo)) + hashclr(p->hash, r->hash_algo); + else + hashcpy(p->hash, oid.hash, r->hash_algo); + return p; } @@ -1243,9 +1248,9 @@ off_t get_delta_base(struct packed_git *p, } else if (type == OBJ_REF_DELTA) { /* The base entry _must_ be in the same pack */ struct object_id oid; - oidread(&oid, base_info, the_repository->hash_algo); + oidread(&oid, base_info, p->repo->hash_algo); base_offset = find_pack_entry_one(&oid, p); - *curpos += the_hash_algo->rawsz; + *curpos += p->repo->hash_algo->rawsz; } else die("I am totally screwed"); return base_offset; @@ -1266,7 +1271,7 @@ static int get_delta_base_oid(struct packed_git *p, { if (type == OBJ_REF_DELTA) { unsigned char *base = use_pack(p, w_curs, curpos, NULL); - oidread(oid, base, the_repository->hash_algo); + oidread(oid, base, p->repo->hash_algo); return 0; } else if (type == OBJ_OFS_DELTA) { uint32_t base_pos; @@ -1608,7 +1613,7 @@ int packed_object_info(struct repository *r, struct packed_git *p, goto out; } } else - oidclr(oi->delta_base_oid, the_repository->hash_algo); + oidclr(oi->delta_base_oid, p->repo->hash_algo); } oi->whence = in_delta_base_cache(p, obj_offset) ? OI_DBCACHED : @@ -1897,7 +1902,7 @@ int bsearch_pack(const struct object_id *oid, const struct packed_git *p, uint32 { const unsigned char *index_fanout = p->index_data; const unsigned char *index_lookup; - const unsigned int hashsz = the_hash_algo->rawsz; + const unsigned int hashsz = p->repo->hash_algo->rawsz; int index_lookup_width; if (!index_fanout) @@ -1922,7 +1927,7 @@ int nth_packed_object_id(struct object_id *oid, uint32_t n) { const unsigned char *index = p->index_data; - const unsigned int hashsz = the_hash_algo->rawsz; + const unsigned int hashsz = p->repo->hash_algo->rawsz; if (!index) { if (open_pack_index(p)) return -1; @@ -1933,11 +1938,10 @@ int nth_packed_object_id(struct object_id *oid, index += 4 * 256; if (p->index_version == 1) { oidread(oid, index + st_add(st_mult(hashsz + 4, n), 4), - the_repository->hash_algo); + p->repo->hash_algo); } else { index += 8; - oidread(oid, index + st_mult(hashsz, n), - the_repository->hash_algo); + oidread(oid, index + st_mult(hashsz, n), p->repo->hash_algo); } return 0; } @@ -1959,7 +1963,7 @@ void check_pack_index_ptr(const struct packed_git *p, const void *vptr) off_t nth_packed_object_offset(const struct packed_git *p, uint32_t n) { const unsigned char *index = p->index_data; - const unsigned int hashsz = the_hash_algo->rawsz; + const unsigned int hashsz = p->repo->hash_algo->rawsz; index += 4 * 256; if (p->index_version == 1) { return ntohl(*((uint32_t *)(index + st_mult(hashsz + 4, n)))); @@ -2159,7 +2163,7 @@ int for_each_object_in_pack(struct packed_git *p, int r = 0; if (flags & FOR_EACH_OBJECT_PACK_ORDER) { - if (load_pack_revindex(the_repository, p)) + if (load_pack_revindex(p->repo, p)) return -1; } @@ -2227,7 +2231,7 @@ int for_each_packed_object(each_packed_object_fn cb, void *data, } static int add_promisor_object(const struct object_id *oid, - struct packed_git *pack UNUSED, + struct packed_git *pack, uint32_t pos UNUSED, void *set_) { @@ -2235,12 +2239,12 @@ static int add_promisor_object(const struct object_id *oid, struct object *obj; int we_parsed_object; - obj = lookup_object(the_repository, oid); + obj = lookup_object(pack->repo, oid); if (obj && obj->parsed) { we_parsed_object = 0; } else { we_parsed_object = 1; - obj = parse_object(the_repository, oid); + obj = parse_object(pack->repo, oid); } if (!obj) -- cgit v1.2.3 From 4f9e6bd4923728053669c300d3ee8483d95f599b Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Tue, 3 Dec 2024 15:43:57 +0100 Subject: packfile: pass `repository` to static function in the file Some of the static functions in the `packfile.c` access global variables, which can simply be avoided by passing the `repository` struct down to them. Let's do that. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- packfile.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/packfile.c b/packfile.c index 5bfa1e17c2..c96ebc4c69 100644 --- a/packfile.c +++ b/packfile.c @@ -460,13 +460,13 @@ static void find_lru_pack(struct packed_git *p, struct packed_git **lru_p, struc *accept_windows_inuse = has_windows_inuse; } -static int close_one_pack(void) +static int close_one_pack(struct repository *r) { struct packed_git *p, *lru_p = NULL; struct pack_window *mru_w = NULL; int accept_windows_inuse = 1; - for (p = the_repository->objects->packed_git; p; p = p->next) { + for (p = r->objects->packed_git; p; p = p->next) { if (p->pack_fd == -1) continue; find_lru_pack(p, &lru_p, &mru_w, &accept_windows_inuse); @@ -555,7 +555,7 @@ static int open_packed_git_1(struct packed_git *p) pack_max_fds = 1; } - while (pack_max_fds <= pack_open_fds && close_one_pack()) + while (pack_max_fds <= pack_open_fds && close_one_pack(p->repo)) ; /* nothing */ p->pack_fd = git_open(p->pack_name); @@ -610,7 +610,8 @@ static int open_packed_git(struct packed_git *p) return -1; } -static int in_window(struct pack_window *win, off_t offset) +static int in_window(struct repository *r, struct pack_window *win, + off_t offset) { /* We must promise at least one full hash after the * offset is available from this window, otherwise the offset @@ -620,7 +621,7 @@ static int in_window(struct pack_window *win, off_t offset) */ off_t win_off = win->offset; return win_off <= offset - && (offset + the_hash_algo->rawsz) <= (win_off + win->len); + && (offset + r->hash_algo->rawsz) <= (win_off + win->len); } unsigned char *use_pack(struct packed_git *p, @@ -642,11 +643,11 @@ unsigned char *use_pack(struct packed_git *p, if (offset < 0) die(_("offset before end of packfile (broken .idx?)")); - if (!win || !in_window(win, offset)) { + if (!win || !in_window(p->repo, win, offset)) { if (win) win->inuse_cnt--; for (win = p->windows; win; win = win->next) { - if (in_window(win, offset)) + if (in_window(p->repo, win, offset)) break; } if (!win) { -- cgit v1.2.3 From 873b00597bbf20c1bcda089a687641167b148fa2 Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Tue, 3 Dec 2024 15:43:58 +0100 Subject: packfile: pass down repository to `odb_pack_name` The function `odb_pack_name` currently relies on the global variable `the_repository`. To eliminate global variable usage in `packfile.c`, we should progressively shift the dependency on the_repository to higher layers. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- builtin/fast-import.c | 8 ++++---- builtin/index-pack.c | 4 ++-- builtin/pack-redundant.c | 2 +- http.c | 2 +- packfile.c | 9 ++++----- packfile.h | 3 ++- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/builtin/fast-import.c b/builtin/fast-import.c index da7e2d613b..3ccc4c5722 100644 --- a/builtin/fast-import.c +++ b/builtin/fast-import.c @@ -806,7 +806,7 @@ static char *keep_pack(const char *curr_index_name) struct strbuf name = STRBUF_INIT; int keep_fd; - odb_pack_name(&name, pack_data->hash, "keep"); + odb_pack_name(pack_data->repo, &name, pack_data->hash, "keep"); keep_fd = odb_pack_keep(name.buf); if (keep_fd < 0) die_errno("cannot create keep file"); @@ -814,11 +814,11 @@ static char *keep_pack(const char *curr_index_name) if (close(keep_fd)) die_errno("failed to write keep file"); - odb_pack_name(&name, pack_data->hash, "pack"); + odb_pack_name(pack_data->repo, &name, pack_data->hash, "pack"); if (finalize_object_file(pack_data->pack_name, name.buf)) die("cannot store pack file"); - odb_pack_name(&name, pack_data->hash, "idx"); + odb_pack_name(pack_data->repo, &name, pack_data->hash, "idx"); if (finalize_object_file(curr_index_name, name.buf)) die("cannot store index file"); free((void *)curr_index_name); @@ -832,7 +832,7 @@ static void unkeep_all_packs(void) for (k = 0; k < pack_id; k++) { struct packed_git *p = all_packs[k]; - odb_pack_name(&name, p->hash, "keep"); + odb_pack_name(p->repo, &name, p->hash, "keep"); unlink_or_warn(name.buf); } strbuf_release(&name); diff --git a/builtin/index-pack.c b/builtin/index-pack.c index be2f99625e..eaefb41761 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -1479,7 +1479,7 @@ static void write_special_file(const char *suffix, const char *msg, if (pack_name) filename = derive_filename(pack_name, "pack", suffix, &name_buf); else - filename = odb_pack_name(&name_buf, hash, suffix); + filename = odb_pack_name(the_repository, &name_buf, hash, suffix); fd = odb_pack_keep(filename); if (fd < 0) { @@ -1507,7 +1507,7 @@ static void rename_tmp_packfile(const char **final_name, { if (!*final_name || strcmp(*final_name, curr_name)) { if (!*final_name) - *final_name = odb_pack_name(name, hash, ext); + *final_name = odb_pack_name(the_repository, name, hash, ext); if (finalize_object_file(curr_name, *final_name)) die(_("unable to rename temporary '*.%s' file to '%s'"), ext, *final_name); diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c index d2c1c4e5ec..bc61990a93 100644 --- a/builtin/pack-redundant.c +++ b/builtin/pack-redundant.c @@ -690,7 +690,7 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED, s pl = red = pack_list_difference(local_packs, min); while (pl) { printf("%s\n%s\n", - odb_pack_name(&idx_name, pl->pack->hash, "idx"), + odb_pack_name(pl->pack->repo, &idx_name, pl->pack->hash, "idx"), pl->pack->pack_name); pl = pl->next; } diff --git a/http.c b/http.c index 6744e18409..420f1566f0 100644 --- a/http.c +++ b/http.c @@ -2581,7 +2581,7 @@ struct http_pack_request *new_direct_http_pack_request( preq->url = url; - odb_pack_name(&preq->tmpfile, packed_git_hash, "pack"); + odb_pack_name(the_repository, &preq->tmpfile, packed_git_hash, "pack"); strbuf_addstr(&preq->tmpfile, ".temp"); preq->packfile = fopen(preq->tmpfile.buf, "a"); if (!preq->packfile) { diff --git a/packfile.c b/packfile.c index c96ebc4c69..1015dac6db 100644 --- a/packfile.c +++ b/packfile.c @@ -25,13 +25,12 @@ #include "pack-revindex.h" #include "promisor-remote.h" -char *odb_pack_name(struct strbuf *buf, - const unsigned char *hash, - const char *ext) +char *odb_pack_name(struct repository *r, struct strbuf *buf, + const unsigned char *hash, const char *ext) { strbuf_reset(buf); - strbuf_addf(buf, "%s/pack/pack-%s.%s", repo_get_object_directory(the_repository), - hash_to_hex(hash), ext); + strbuf_addf(buf, "%s/pack/pack-%s.%s", repo_get_object_directory(r), + hash_to_hex_algop(hash, r->hash_algo), ext); return buf->buf; } diff --git a/packfile.h b/packfile.h index aee69d1a0b..51187f2393 100644 --- a/packfile.h +++ b/packfile.h @@ -29,7 +29,8 @@ struct pack_entry { * * Example: odb_pack_name(out, sha1, "idx") => ".git/objects/pack/pack-1234..idx" */ -char *odb_pack_name(struct strbuf *buf, const unsigned char *sha1, const char *ext); +char *odb_pack_name(struct repository *r, struct strbuf *buf, + const unsigned char *hash, const char *ext); /* * Return the basename of the packfile, omitting any containing directory -- cgit v1.2.3 From cc656f4eb2b7b10bc530c96844909c869bdd1fdf Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Tue, 3 Dec 2024 15:43:59 +0100 Subject: packfile: pass down repository to `has_object[_kept]_pack` The functions `has_object[_kept]_pack` currently rely on the global variable `the_repository`. To eliminate global variable usage in `packfile.c`, we should progressively shift the dependency on the_repository to higher layers. Let's remove its usage from these functions and any related ones. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- builtin/count-objects.c | 2 +- builtin/fsck.c | 2 +- builtin/pack-objects.c | 4 ++-- diff.c | 3 ++- list-objects.c | 3 ++- pack-bitmap.c | 2 +- packfile.c | 9 +++++---- packfile.h | 5 +++-- prune-packed.c | 2 +- reachable.c | 2 +- revision.c | 4 ++-- 11 files changed, 21 insertions(+), 17 deletions(-) diff --git a/builtin/count-objects.c b/builtin/count-objects.c index 04d80887e0..1e89148ed7 100644 --- a/builtin/count-objects.c +++ b/builtin/count-objects.c @@ -67,7 +67,7 @@ static int count_loose(const struct object_id *oid, const char *path, else { loose_size += on_disk_bytes(st); loose++; - if (verbose && has_object_pack(oid)) + if (verbose && has_object_pack(the_repository, oid)) packed_loose++; } return 0; diff --git a/builtin/fsck.c b/builtin/fsck.c index 7f4e2f0414..bb56eb98ac 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -272,7 +272,7 @@ static void check_reachable_object(struct object *obj) if (!(obj->flags & HAS_OBJ)) { if (is_promisor_object(&obj->oid)) return; - if (has_object_pack(&obj->oid)) + if (has_object_pack(the_repository, &obj->oid)) return; /* it is in pack - forget about it */ printf_ln(_("missing %s %s"), printable_type(&obj->oid, obj->type), diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 0800714267..0f32e92a3a 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -1529,7 +1529,7 @@ static int want_found_object(const struct object_id *oid, int exclude, return 0; if (ignore_packed_keep_in_core && p->pack_keep_in_core) return 0; - if (has_object_kept_pack(oid, flags)) + if (has_object_kept_pack(p->repo, oid, flags)) return 0; } @@ -3627,7 +3627,7 @@ static void show_cruft_commit(struct commit *commit, void *data) static int cruft_include_check_obj(struct object *obj, void *data UNUSED) { - return !has_object_kept_pack(&obj->oid, IN_CORE_KEEP_PACKS); + return !has_object_kept_pack(to_pack.repo, &obj->oid, IN_CORE_KEEP_PACKS); } static int cruft_include_check(struct commit *commit, void *data) diff --git a/diff.c b/diff.c index dceac20d18..266ddf18e7 100644 --- a/diff.c +++ b/diff.c @@ -4041,7 +4041,8 @@ static int reuse_worktree_file(struct index_state *istate, * objects however would tend to be slower as they need * to be individually opened and inflated. */ - if (!FAST_WORKING_DIRECTORY && !want_file && has_object_pack(oid)) + if (!FAST_WORKING_DIRECTORY && !want_file && + has_object_pack(istate->repo, oid)) return 0; /* diff --git a/list-objects.c b/list-objects.c index 985d008799..31236a8dc9 100644 --- a/list-objects.c +++ b/list-objects.c @@ -41,7 +41,8 @@ static void show_object(struct traversal_context *ctx, { if (!ctx->show_object) return; - if (ctx->revs->unpacked && has_object_pack(&object->oid)) + if (ctx->revs->unpacked && has_object_pack(ctx->revs->repo, + &object->oid)) return; ctx->show_object(object, name, ctx->show_data); diff --git a/pack-bitmap.c b/pack-bitmap.c index 4fa9dfc771..d34ba9909a 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -1889,7 +1889,7 @@ static void filter_packed_objects_from_bitmap(struct bitmap_index *bitmap_git, bitmap_unset(result, i); for (i = 0; i < eindex->count; ++i) { - if (has_object_pack(&eindex->objects[i]->oid)) + if (has_object_pack(the_repository, &eindex->objects[i]->oid)) bitmap_unset(result, objects_nr + i); } } diff --git a/packfile.c b/packfile.c index 1015dac6db..e7dd270217 100644 --- a/packfile.c +++ b/packfile.c @@ -2143,16 +2143,17 @@ int find_kept_pack_entry(struct repository *r, return 0; } -int has_object_pack(const struct object_id *oid) +int has_object_pack(struct repository *r, const struct object_id *oid) { struct pack_entry e; - return find_pack_entry(the_repository, oid, &e); + return find_pack_entry(r, oid, &e); } -int has_object_kept_pack(const struct object_id *oid, unsigned flags) +int has_object_kept_pack(struct repository *r, const struct object_id *oid, + unsigned flags) { struct pack_entry e; - return find_kept_pack_entry(the_repository, oid, flags, &e); + return find_kept_pack_entry(r, oid, flags, &e); } int for_each_object_in_pack(struct packed_git *p, diff --git a/packfile.h b/packfile.h index 51187f2393..b09fb2c530 100644 --- a/packfile.h +++ b/packfile.h @@ -193,8 +193,9 @@ const struct packed_git *has_packed_and_bad(struct repository *, const struct ob int find_pack_entry(struct repository *r, const struct object_id *oid, struct pack_entry *e); int find_kept_pack_entry(struct repository *r, const struct object_id *oid, unsigned flags, struct pack_entry *e); -int has_object_pack(const struct object_id *oid); -int has_object_kept_pack(const struct object_id *oid, unsigned flags); +int has_object_pack(struct repository *r, const struct object_id *oid); +int has_object_kept_pack(struct repository *r, const struct object_id *oid, + unsigned flags); /* * Return 1 if an object in a promisor packfile is or refers to the given diff --git a/prune-packed.c b/prune-packed.c index 2bb99c29df..d1c65ab10e 100644 --- a/prune-packed.c +++ b/prune-packed.c @@ -24,7 +24,7 @@ static int prune_object(const struct object_id *oid, const char *path, { int *opts = data; - if (!has_object_pack(oid)) + if (!has_object_pack(the_repository, oid)) return 0; if (*opts & PRUNE_PACKED_DRY_RUN) diff --git a/reachable.c b/reachable.c index 3e9b3dd0a4..09d2c50079 100644 --- a/reachable.c +++ b/reachable.c @@ -239,7 +239,7 @@ static int want_recent_object(struct recent_data *data, const struct object_id *oid) { if (data->ignore_in_core_kept_packs && - has_object_kept_pack(oid, IN_CORE_KEEP_PACKS)) + has_object_kept_pack(data->revs->repo, oid, IN_CORE_KEEP_PACKS)) return 0; return 1; } diff --git a/revision.c b/revision.c index f5f5b84f2b..d1d152a67b 100644 --- a/revision.c +++ b/revision.c @@ -4103,10 +4103,10 @@ enum commit_action get_commit_action(struct rev_info *revs, struct commit *commi { if (commit->object.flags & SHOWN) return commit_ignore; - if (revs->unpacked && has_object_pack(&commit->object.oid)) + if (revs->unpacked && has_object_pack(revs->repo, &commit->object.oid)) return commit_ignore; if (revs->no_kept_objects) { - if (has_object_kept_pack(&commit->object.oid, + if (has_object_kept_pack(revs->repo, &commit->object.oid, revs->keep_pack_cache_flags)) return commit_ignore; } -- cgit v1.2.3 From c87910b96b1223d4a1dfe65c04e03863fadef6bc Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Tue, 3 Dec 2024 15:44:00 +0100 Subject: packfile: pass down repository to `for_each_packed_object` The function `for_each_packed_object` currently relies on the global variable `the_repository`. To eliminate global variable usage in `packfile.c`, we should progressively shift the dependency on the_repository to higher layers. Let's remove its usage from this function and closely related function `is_promisor_object`. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- builtin/cat-file.c | 7 ++++--- builtin/fsck.c | 18 +++++++++++------- builtin/pack-objects.c | 7 +++++-- builtin/repack.c | 2 +- builtin/rev-list.c | 2 +- commit-graph.c | 2 +- fsck.c | 2 +- list-objects.c | 4 ++-- object-store-ll.h | 4 ++-- packfile.c | 14 +++++++------- packfile.h | 2 +- promisor-remote.c | 2 +- reachable.c | 2 +- revision.c | 9 +++++---- tag.c | 2 +- 15 files changed, 44 insertions(+), 35 deletions(-) diff --git a/builtin/cat-file.c b/builtin/cat-file.c index bfdfb51c7c..d67b101c20 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -827,15 +827,16 @@ static int batch_objects(struct batch_options *opt) cb.seen = &seen; for_each_loose_object(batch_unordered_loose, &cb, 0); - for_each_packed_object(batch_unordered_packed, &cb, - FOR_EACH_OBJECT_PACK_ORDER); + for_each_packed_object(the_repository, batch_unordered_packed, + &cb, FOR_EACH_OBJECT_PACK_ORDER); oidset_clear(&seen); } else { struct oid_array sa = OID_ARRAY_INIT; for_each_loose_object(collect_loose_object, &sa, 0); - for_each_packed_object(collect_packed_object, &sa, 0); + for_each_packed_object(the_repository, collect_packed_object, + &sa, 0); oid_array_for_each_unique(&sa, batch_object_cb, &cb); diff --git a/builtin/fsck.c b/builtin/fsck.c index bb56eb98ac..0196c54eb6 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -150,7 +150,7 @@ static int mark_object(struct object *obj, enum object_type type, return 0; obj->flags |= REACHABLE; - if (is_promisor_object(&obj->oid)) + if (is_promisor_object(the_repository, &obj->oid)) /* * Further recursion does not need to be performed on this * object since it is a promisor object (so it does not need to @@ -270,7 +270,7 @@ static void check_reachable_object(struct object *obj) * do a full fsck */ if (!(obj->flags & HAS_OBJ)) { - if (is_promisor_object(&obj->oid)) + if (is_promisor_object(the_repository, &obj->oid)) return; if (has_object_pack(the_repository, &obj->oid)) return; /* it is in pack - forget about it */ @@ -391,7 +391,10 @@ static void check_connectivity(void) * traversal. */ for_each_loose_object(mark_loose_unreachable_referents, NULL, 0); - for_each_packed_object(mark_packed_unreachable_referents, NULL, 0); + for_each_packed_object(the_repository, + mark_packed_unreachable_referents, + NULL, + 0); } /* Look up all the requirements, warn about missing objects.. */ @@ -488,7 +491,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid, refname, timestamp); obj->flags |= USED; mark_object_reachable(obj); - } else if (!is_promisor_object(oid)) { + } else if (!is_promisor_object(the_repository, oid)) { error(_("%s: invalid reflog entry %s"), refname, oid_to_hex(oid)); errors_found |= ERROR_REACHABLE; @@ -531,7 +534,7 @@ static int fsck_handle_ref(const char *refname, const char *referent UNUSED, con obj = parse_object(the_repository, oid); if (!obj) { - if (is_promisor_object(oid)) { + if (is_promisor_object(the_repository, oid)) { /* * Increment default_refs anyway, because this is a * valid ref. @@ -966,7 +969,8 @@ int cmd_fsck(int argc, if (connectivity_only) { for_each_loose_object(mark_loose_for_connectivity, NULL, 0); - for_each_packed_object(mark_packed_for_connectivity, NULL, 0); + for_each_packed_object(the_repository, + mark_packed_for_connectivity, NULL, 0); } else { prepare_alt_odb(the_repository); for (odb = the_repository->objects->odb; odb; odb = odb->next) @@ -1011,7 +1015,7 @@ int cmd_fsck(int argc, &oid); if (!obj || !(obj->flags & HAS_OBJ)) { - if (is_promisor_object(&oid)) + if (is_promisor_object(the_repository, &oid)) continue; error(_("%s: object missing"), oid_to_hex(&oid)); errors_found |= ERROR_OBJECT; diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 0f32e92a3a..db20f0cf51 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -3858,7 +3858,8 @@ static void show_object__ma_allow_promisor(struct object *obj, const char *name, * Quietly ignore EXPECTED missing objects. This avoids problems with * staging them now and getting an odd error later. */ - if (!has_object(the_repository, &obj->oid, 0) && is_promisor_object(&obj->oid)) + if (!has_object(the_repository, &obj->oid, 0) && + is_promisor_object(to_pack.repo, &obj->oid)) return; show_object(obj, name, data); @@ -3927,7 +3928,9 @@ static int add_object_in_unpacked_pack(const struct object_id *oid, static void add_objects_in_unpacked_packs(void) { - if (for_each_packed_object(add_object_in_unpacked_pack, NULL, + if (for_each_packed_object(to_pack.repo, + add_object_in_unpacked_pack, + NULL, FOR_EACH_OBJECT_PACK_ORDER | FOR_EACH_OBJECT_LOCAL_ONLY | FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS | diff --git a/builtin/repack.c b/builtin/repack.c index d6bb37e84a..96a4fa234b 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -404,7 +404,7 @@ static void repack_promisor_objects(const struct pack_objects_args *args, * {type -> existing pack order} ordering when computing deltas instead * of a {type -> size} ordering, which may produce better deltas. */ - for_each_packed_object(write_oid, &cmd, + for_each_packed_object(the_repository, write_oid, &cmd, FOR_EACH_OBJECT_PROMISOR_ONLY); if (cmd.in == -1) { diff --git a/builtin/rev-list.c b/builtin/rev-list.c index f62bcbf2b1..43c42621e3 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -121,7 +121,7 @@ static inline void finish_object__ma(struct object *obj) return; case MA_ALLOW_PROMISOR: - if (is_promisor_object(&obj->oid)) + if (is_promisor_object(the_repository, &obj->oid)) return; die("unexpected missing %s object '%s'", type_name(obj->type), oid_to_hex(&obj->oid)); diff --git a/commit-graph.c b/commit-graph.c index 83dd69bfeb..e2e2083951 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -1960,7 +1960,7 @@ static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx) ctx->progress = start_delayed_progress( _("Finding commits for commit graph among packed objects"), ctx->approx_nr_objects); - for_each_packed_object(add_packed_commits, ctx, + for_each_packed_object(ctx->r, add_packed_commits, ctx, FOR_EACH_OBJECT_PACK_ORDER); if (ctx->progress_done < ctx->approx_nr_objects) display_progress(ctx->progress, ctx->approx_nr_objects); diff --git a/fsck.c b/fsck.c index 3756f52459..87ce999a49 100644 --- a/fsck.c +++ b/fsck.c @@ -1295,7 +1295,7 @@ static int fsck_blobs(struct oidset *blobs_found, struct oidset *blobs_done, buf = repo_read_object_file(the_repository, oid, &type, &size); if (!buf) { - if (is_promisor_object(oid)) + if (is_promisor_object(the_repository, oid)) continue; ret |= report(options, oid, OBJ_BLOB, msg_missing, diff --git a/list-objects.c b/list-objects.c index 31236a8dc9..d11a389b3a 100644 --- a/list-objects.c +++ b/list-objects.c @@ -75,7 +75,7 @@ static void process_blob(struct traversal_context *ctx, */ if (ctx->revs->exclude_promisor_objects && !repo_has_object_file(the_repository, &obj->oid) && - is_promisor_object(&obj->oid)) + is_promisor_object(ctx->revs->repo, &obj->oid)) return; pathlen = path->len; @@ -180,7 +180,7 @@ static void process_tree(struct traversal_context *ctx, * an incomplete list of missing objects. */ if (revs->exclude_promisor_objects && - is_promisor_object(&obj->oid)) + is_promisor_object(revs->repo, &obj->oid)) return; if (!revs->do_not_die_on_missing_objects) diff --git a/object-store-ll.h b/object-store-ll.h index d46cd0e654..cd3bd5bd99 100644 --- a/object-store-ll.h +++ b/object-store-ll.h @@ -550,7 +550,7 @@ typedef int each_packed_object_fn(const struct object_id *oid, int for_each_object_in_pack(struct packed_git *p, each_packed_object_fn, void *data, enum for_each_object_flags flags); -int for_each_packed_object(each_packed_object_fn, void *, - enum for_each_object_flags flags); +int for_each_packed_object(struct repository *repo, each_packed_object_fn cb, + void *data, enum for_each_object_flags flags); #endif /* OBJECT_STORE_LL_H */ diff --git a/packfile.c b/packfile.c index e7dd270217..5e8019b1fe 100644 --- a/packfile.c +++ b/packfile.c @@ -2200,15 +2200,15 @@ int for_each_object_in_pack(struct packed_git *p, return r; } -int for_each_packed_object(each_packed_object_fn cb, void *data, - enum for_each_object_flags flags) +int for_each_packed_object(struct repository *repo, each_packed_object_fn cb, + void *data, enum for_each_object_flags flags) { struct packed_git *p; int r = 0; int pack_errors = 0; - prepare_packed_git(the_repository); - for (p = get_all_packs(the_repository); p; p = p->next) { + prepare_packed_git(repo); + for (p = get_all_packs(repo); p; p = p->next) { if ((flags & FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local) continue; if ((flags & FOR_EACH_OBJECT_PROMISOR_ONLY) && @@ -2286,14 +2286,14 @@ static int add_promisor_object(const struct object_id *oid, return 0; } -int is_promisor_object(const struct object_id *oid) +int is_promisor_object(struct repository *r, const struct object_id *oid) { static struct oidset promisor_objects; static int promisor_objects_prepared; if (!promisor_objects_prepared) { - if (repo_has_promisor_remote(the_repository)) { - for_each_packed_object(add_promisor_object, + if (repo_has_promisor_remote(r)) { + for_each_packed_object(r, add_promisor_object, &promisor_objects, FOR_EACH_OBJECT_PROMISOR_ONLY | FOR_EACH_OBJECT_PACK_ORDER); diff --git a/packfile.h b/packfile.h index b09fb2c530..addb95b0c4 100644 --- a/packfile.h +++ b/packfile.h @@ -201,7 +201,7 @@ int has_object_kept_pack(struct repository *r, const struct object_id *oid, * Return 1 if an object in a promisor packfile is or refers to the given * object, 0 otherwise. */ -int is_promisor_object(const struct object_id *oid); +int is_promisor_object(struct repository *r, const struct object_id *oid); /* * Expose a function for fuzz testing. diff --git a/promisor-remote.c b/promisor-remote.c index 9345ae3db2..c714f4f007 100644 --- a/promisor-remote.c +++ b/promisor-remote.c @@ -283,7 +283,7 @@ void promisor_remote_get_direct(struct repository *repo, } for (i = 0; i < remaining_nr; i++) { - if (is_promisor_object(&remaining_oids[i])) + if (is_promisor_object(repo, &remaining_oids[i])) die(_("could not fetch %s from promisor remote"), oid_to_hex(&remaining_oids[i])); } diff --git a/reachable.c b/reachable.c index 09d2c50079..ecf7ccf504 100644 --- a/reachable.c +++ b/reachable.c @@ -324,7 +324,7 @@ int add_unseen_recent_objects_to_traversal(struct rev_info *revs, if (ignore_in_core_kept_packs) flags |= FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS; - r = for_each_packed_object(add_recent_packed, &data, flags); + r = for_each_packed_object(revs->repo, add_recent_packed, &data, flags); done: oidset_clear(&data.extra_recent_oids); diff --git a/revision.c b/revision.c index d1d152a67b..45dc6d2819 100644 --- a/revision.c +++ b/revision.c @@ -390,7 +390,8 @@ static struct object *get_reference(struct rev_info *revs, const char *name, if (!object) { if (revs->ignore_missing) return NULL; - if (revs->exclude_promisor_objects && is_promisor_object(oid)) + if (revs->exclude_promisor_objects && + is_promisor_object(revs->repo, oid)) return NULL; if (revs->do_not_die_on_missing_objects) { oidset_insert(&revs->missing_commits, oid); @@ -432,7 +433,7 @@ static struct commit *handle_commit(struct rev_info *revs, if (revs->ignore_missing_links || (flags & UNINTERESTING)) return NULL; if (revs->exclude_promisor_objects && - is_promisor_object(&tag->tagged->oid)) + is_promisor_object(revs->repo, &tag->tagged->oid)) return NULL; if (revs->do_not_die_on_missing_objects && oid) { oidset_insert(&revs->missing_commits, oid); @@ -1211,7 +1212,7 @@ static int process_parents(struct rev_info *revs, struct commit *commit, revs->do_not_die_on_missing_objects; if (repo_parse_commit_gently(revs->repo, p, gently) < 0) { if (revs->exclude_promisor_objects && - is_promisor_object(&p->object.oid)) { + is_promisor_object(revs->repo, &p->object.oid)) { if (revs->first_parent_only) break; continue; @@ -3915,7 +3916,7 @@ int prepare_revision_walk(struct rev_info *revs) revs->treesame.name = "treesame"; if (revs->exclude_promisor_objects) { - for_each_packed_object(mark_uninteresting, revs, + for_each_packed_object(revs->repo, mark_uninteresting, revs, FOR_EACH_OBJECT_PROMISOR_ONLY); } diff --git a/tag.c b/tag.c index d24170e340..beef9571b5 100644 --- a/tag.c +++ b/tag.c @@ -84,7 +84,7 @@ struct object *deref_tag(struct repository *r, struct object *o, const char *war o = NULL; } if (!o && warn) { - if (last_oid && is_promisor_object(last_oid)) + if (last_oid && is_promisor_object(r, last_oid)) return NULL; if (!warnlen) warnlen = strlen(warn); -- cgit v1.2.3 From d6b2d21fbf269db7a6be56d28a62cb65a7d7a660 Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Tue, 3 Dec 2024 15:44:01 +0100 Subject: config: make `delta_base_cache_limit` a non-global variable The `delta_base_cache_limit` variable is a global config variable used by multiple subsystems. Let's make this non-global, by adding this variable independently to the subsystems where it is used. First, add the setting to the `repo_settings` struct, this provides access to the config in places where the repository is available. Use this in `packfile.c`. In `index-pack.c` we add it to the `pack_idx_option` struct and its constructor. While the repository struct is available here, it may not be set because `git index-pack` can be used without a repository. In `gc.c` add it to the `gc_config` struct and also the constructor function. The gc functions currently do not have direct access to a repository struct. These changes are made to remove the usage of `delta_base_cache_limit` as a global variable in `packfile.c`. This brings us one step closer to removing the `USE_THE_REPOSITORY_VARIABLE` definition in `packfile.c` which we complete in the next patch. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- builtin/gc.c | 12 +++++++++++- builtin/index-pack.c | 10 +++++++--- config.c | 5 ----- environment.c | 1 - environment.h | 1 - pack-objects.h | 3 ++- pack-write.c | 1 + pack.h | 2 ++ packfile.c | 10 ++++++++-- repo-settings.c | 5 +++++ repo-settings.h | 3 +++ 11 files changed, 39 insertions(+), 14 deletions(-) diff --git a/builtin/gc.c b/builtin/gc.c index d52735354c..efb6162fb0 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -138,6 +138,11 @@ struct gc_config { char *repack_filter_to; unsigned long big_pack_threshold; unsigned long max_delta_cache_size; + /* + * Remove this member from gc_config once repo_settings is passed + * through the callchain. + */ + size_t delta_base_cache_limit; }; #define GC_CONFIG_INIT { \ @@ -153,6 +158,7 @@ struct gc_config { .prune_expire = xstrdup("2.weeks.ago"), \ .prune_worktrees_expire = xstrdup("3.months.ago"), \ .max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE, \ + .delta_base_cache_limit = DEFAULT_DELTA_BASE_CACHE_LIMIT, \ } static void gc_config_release(struct gc_config *cfg) @@ -168,6 +174,7 @@ static void gc_config(struct gc_config *cfg) { const char *value; char *owned = NULL; + unsigned long ulongval; if (!git_config_get_value("gc.packrefs", &value)) { if (value && !strcmp(value, "notbare")) @@ -206,6 +213,9 @@ static void gc_config(struct gc_config *cfg) git_config_get_ulong("gc.bigpackthreshold", &cfg->big_pack_threshold); git_config_get_ulong("pack.deltacachesize", &cfg->max_delta_cache_size); + if (!git_config_get_ulong("core.deltabasecachelimit", &ulongval)) + cfg->delta_base_cache_limit = ulongval; + if (!git_config_get_string("gc.repackfilter", &owned)) { free(cfg->repack_filter); cfg->repack_filter = owned; @@ -416,7 +426,7 @@ static uint64_t estimate_repack_memory(struct gc_config *cfg, * read_sha1_file() (either at delta calculation phase, or * writing phase) also fills up the delta base cache */ - heap += delta_base_cache_limit; + heap += cfg->delta_base_cache_limit; /* and of course pack-objects has its own delta cache */ heap += cfg->max_delta_cache_size; diff --git a/builtin/index-pack.c b/builtin/index-pack.c index eaefb41761..23bfa45403 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -1238,7 +1238,7 @@ static void parse_pack_objects(unsigned char *hash) * recursively checking if the resulting object is used as a base * for some more deltas. */ -static void resolve_deltas(void) +static void resolve_deltas(struct pack_idx_option *opts) { int i; @@ -1254,7 +1254,7 @@ static void resolve_deltas(void) nr_ref_deltas + nr_ofs_deltas); nr_dispatched = 0; - base_cache_limit = delta_base_cache_limit * nr_threads; + base_cache_limit = opts->delta_base_cache_limit * nr_threads; if (nr_threads > 1 || getenv("GIT_FORCE_THREADS")) { init_thread(); work_lock(); @@ -1604,6 +1604,10 @@ static int git_index_pack_config(const char *k, const char *v, else opts->flags &= ~WRITE_REV; } + if (!strcmp(k, "core.deltabasecachelimit")) { + opts->delta_base_cache_limit = git_config_ulong(k, v, ctx->kvi); + return 0; + } return git_default_config(k, v, ctx, cb); } @@ -1930,7 +1934,7 @@ int cmd_index_pack(int argc, parse_pack_objects(pack_hash); if (report_end_of_input) write_in_full(2, "\0", 1); - resolve_deltas(); + resolve_deltas(&opts); conclude_pack(fix_thin_pack, curr_pack, pack_hash); free(ofs_deltas); free(ref_deltas); diff --git a/config.c b/config.c index a11bb85da3..728ef98e42 100644 --- a/config.c +++ b/config.c @@ -1515,11 +1515,6 @@ static int git_default_core_config(const char *var, const char *value, return 0; } - if (!strcmp(var, "core.deltabasecachelimit")) { - delta_base_cache_limit = git_config_ulong(var, value, ctx->kvi); - return 0; - } - if (!strcmp(var, "core.autocrlf")) { if (value && !strcasecmp(value, "input")) { auto_crlf = AUTO_CRLF_INPUT; diff --git a/environment.c b/environment.c index a2ce998081..8e5022c282 100644 --- a/environment.c +++ b/environment.c @@ -51,7 +51,6 @@ enum fsync_method fsync_method = FSYNC_METHOD_DEFAULT; enum fsync_component fsync_components = FSYNC_COMPONENTS_DEFAULT; size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE; size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT; -size_t delta_base_cache_limit = 96 * 1024 * 1024; unsigned long big_file_threshold = 512 * 1024 * 1024; char *editor_program; char *askpass_program; diff --git a/environment.h b/environment.h index 923e12661e..2f43340f0b 100644 --- a/environment.h +++ b/environment.h @@ -165,7 +165,6 @@ extern int zlib_compression_level; extern int pack_compression_level; extern size_t packed_git_window_size; extern size_t packed_git_limit; -extern size_t delta_base_cache_limit; extern unsigned long big_file_threshold; extern unsigned long pack_size_limit_cfg; extern int max_allowed_tree_depth; diff --git a/pack-objects.h b/pack-objects.h index b9898a4e64..3f6f504203 100644 --- a/pack-objects.h +++ b/pack-objects.h @@ -7,7 +7,8 @@ struct repository; -#define DEFAULT_DELTA_CACHE_SIZE (256 * 1024 * 1024) +#define DEFAULT_DELTA_CACHE_SIZE (256 * 1024 * 1024) +#define DEFAULT_DELTA_BASE_CACHE_LIMIT (96 * 1024 * 1024) #define OE_DFS_STATE_BITS 2 #define OE_DEPTH_BITS 12 diff --git a/pack-write.c b/pack-write.c index 8c7dfddc5a..98a8c0e785 100644 --- a/pack-write.c +++ b/pack-write.c @@ -21,6 +21,7 @@ void reset_pack_idx_option(struct pack_idx_option *opts) memset(opts, 0, sizeof(*opts)); opts->version = 2; opts->off32_limit = 0x7fffffff; + opts->delta_base_cache_limit = DEFAULT_DELTA_BASE_CACHE_LIMIT; } static int sha1_compare(const void *_a, const void *_b) diff --git a/pack.h b/pack.h index 02bbdfb19c..a8da040629 100644 --- a/pack.h +++ b/pack.h @@ -58,6 +58,8 @@ struct pack_idx_option { */ int anomaly_alloc, anomaly_nr; uint32_t *anomaly; + + size_t delta_base_cache_limit; }; void reset_pack_idx_option(struct pack_idx_option *); diff --git a/packfile.c b/packfile.c index 5e8019b1fe..64248ca664 100644 --- a/packfile.c +++ b/packfile.c @@ -1496,7 +1496,9 @@ void clear_delta_base_cache(void) } static void add_delta_base_cache(struct packed_git *p, off_t base_offset, - void *base, unsigned long base_size, enum object_type type) + void *base, unsigned long base_size, + unsigned long delta_base_cache_limit, + enum object_type type) { struct delta_base_cache_entry *ent; struct list_head *lru, *tmp; @@ -1698,6 +1700,8 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset, int delta_stack_nr = 0, delta_stack_alloc = UNPACK_ENTRY_STACK_PREALLOC; int base_from_cache = 0; + prepare_repo_settings(p->repo); + write_pack_access_log(p, obj_offset); /* PHASE 1: drill down to the innermost base object */ @@ -1878,7 +1882,9 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset, * before we are done using it. */ if (!external_base) - add_delta_base_cache(p, base_obj_offset, base, base_size, type); + add_delta_base_cache(p, base_obj_offset, base, base_size, + p->repo->settings.delta_base_cache_limit, + type); free(delta_data); free(external_base); diff --git a/repo-settings.c b/repo-settings.c index 4699b4b365..acc27eb8fe 100644 --- a/repo-settings.c +++ b/repo-settings.c @@ -3,6 +3,7 @@ #include "repo-settings.h" #include "repository.h" #include "midx.h" +#include "pack-objects.h" static void repo_cfg_bool(struct repository *r, const char *key, int *dest, int def) @@ -26,6 +27,7 @@ void prepare_repo_settings(struct repository *r) const char *strval; int manyfiles; int read_changed_paths; + unsigned long ulongval; if (!r->gitdir) BUG("Cannot add settings for uninitialized repository"); @@ -123,6 +125,9 @@ void prepare_repo_settings(struct repository *r) * removed. */ r->settings.command_requires_full_index = 1; + + if (!repo_config_get_ulong(r, "core.deltabasecachelimit", &ulongval)) + r->settings.delta_base_cache_limit = ulongval; } enum log_refs_config repo_settings_get_log_all_ref_updates(struct repository *repo) diff --git a/repo-settings.h b/repo-settings.h index 51d6156a11..10a6f7ed64 100644 --- a/repo-settings.h +++ b/repo-settings.h @@ -57,12 +57,15 @@ struct repo_settings { int core_multi_pack_index; int warn_ambiguous_refs; /* lazily loaded via accessor */ + + size_t delta_base_cache_limit; }; #define REPO_SETTINGS_INIT { \ .index_version = -1, \ .core_untracked_cache = UNTRACKED_CACHE_KEEP, \ .fetch_negotiation_algorithm = FETCH_NEGOTIATION_CONSECUTIVE, \ .warn_ambiguous_refs = -1, \ + .delta_base_cache_limit = DEFAULT_DELTA_BASE_CACHE_LIMIT, \ } void prepare_repo_settings(struct repository *r); -- cgit v1.2.3 From d284713bae71877577cf1a07501c8528f8c44bb2 Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Tue, 3 Dec 2024 15:44:02 +0100 Subject: config: make `packed_git_(limit|window_size)` non-global variables The variables `packed_git_window_size` and `packed_git_limit` are global config variables used in the `packfile.c` file. Since it is only used in this file, let's change it from being a global config variable to a local variable for the subsystem. With this, we rid `packfile.c` from all global variable usage and this means we can also remove the `USE_THE_REPOSITORY_VARIABLE` guard from the file. Helped-by: Taylor Blau Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- builtin/fast-import.c | 4 ++-- config.c | 17 ----------------- environment.c | 2 -- packfile.c | 23 +++++++++++++++-------- packfile.h | 2 +- repo-settings.c | 13 +++++++++++++ repo-settings.h | 4 ++++ 7 files changed, 35 insertions(+), 30 deletions(-) diff --git a/builtin/fast-import.c b/builtin/fast-import.c index 3ccc4c5722..0ece070260 100644 --- a/builtin/fast-import.c +++ b/builtin/fast-import.c @@ -3539,7 +3539,7 @@ static void parse_argv(void) int cmd_fast_import(int argc, const char **argv, const char *prefix, - struct repository *repo UNUSED) + struct repository *repo) { unsigned int i; @@ -3660,7 +3660,7 @@ int cmd_fast_import(int argc, fprintf(stderr, " pools: %10lu KiB\n", (unsigned long)((tree_entry_allocd + fi_mem_pool.pool_alloc) /1024)); fprintf(stderr, " objects: %10" PRIuMAX " KiB\n", (alloc_count*sizeof(struct object_entry))/1024); fprintf(stderr, "---------------------------------------------------------------------\n"); - pack_report(); + pack_report(repo); fprintf(stderr, "---------------------------------------------------------------------\n"); fprintf(stderr, "\n"); } diff --git a/config.c b/config.c index 728ef98e42..2c295f7430 100644 --- a/config.c +++ b/config.c @@ -1493,28 +1493,11 @@ static int git_default_core_config(const char *var, const char *value, return 0; } - if (!strcmp(var, "core.packedgitwindowsize")) { - int pgsz_x2 = getpagesize() * 2; - packed_git_window_size = git_config_ulong(var, value, ctx->kvi); - - /* This value must be multiple of (pagesize * 2) */ - packed_git_window_size /= pgsz_x2; - if (packed_git_window_size < 1) - packed_git_window_size = 1; - packed_git_window_size *= pgsz_x2; - return 0; - } - if (!strcmp(var, "core.bigfilethreshold")) { big_file_threshold = git_config_ulong(var, value, ctx->kvi); return 0; } - if (!strcmp(var, "core.packedgitlimit")) { - packed_git_limit = git_config_ulong(var, value, ctx->kvi); - return 0; - } - if (!strcmp(var, "core.autocrlf")) { if (value && !strcasecmp(value, "input")) { auto_crlf = AUTO_CRLF_INPUT; diff --git a/environment.c b/environment.c index 8e5022c282..8389a27270 100644 --- a/environment.c +++ b/environment.c @@ -49,8 +49,6 @@ int fsync_object_files = -1; int use_fsync = -1; enum fsync_method fsync_method = FSYNC_METHOD_DEFAULT; enum fsync_component fsync_components = FSYNC_COMPONENTS_DEFAULT; -size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE; -size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT; unsigned long big_file_threshold = 512 * 1024 * 1024; char *editor_program; char *askpass_program; diff --git a/packfile.c b/packfile.c index 64248ca664..2e0e28c7de 100644 --- a/packfile.c +++ b/packfile.c @@ -1,4 +1,3 @@ -#define USE_THE_REPOSITORY_VARIABLE #include "git-compat-util.h" #include "environment.h" @@ -46,15 +45,15 @@ static size_t pack_mapped; #define SZ_FMT PRIuMAX static inline uintmax_t sz_fmt(size_t s) { return s; } -void pack_report(void) +void pack_report(struct repository *repo) { fprintf(stderr, "pack_report: getpagesize() = %10" SZ_FMT "\n" "pack_report: core.packedGitWindowSize = %10" SZ_FMT "\n" "pack_report: core.packedGitLimit = %10" SZ_FMT "\n", sz_fmt(getpagesize()), - sz_fmt(packed_git_window_size), - sz_fmt(packed_git_limit)); + sz_fmt(repo->settings.packed_git_window_size), + sz_fmt(repo->settings.packed_git_limit)); fprintf(stderr, "pack_report: pack_used_ctr = %10u\n" "pack_report: pack_mmap_calls = %10u\n" @@ -650,8 +649,15 @@ unsigned char *use_pack(struct packed_git *p, break; } if (!win) { - size_t window_align = packed_git_window_size / 2; + size_t window_align; off_t len; + struct repo_settings *settings; + + /* lazy load the settings in case it hasn't been setup */ + prepare_repo_settings(p->repo); + settings = &p->repo->settings; + + window_align = settings->packed_git_window_size / 2; if (p->pack_fd == -1 && open_packed_git(p)) die("packfile %s cannot be accessed", p->pack_name); @@ -659,11 +665,12 @@ unsigned char *use_pack(struct packed_git *p, CALLOC_ARRAY(win, 1); win->offset = (offset / window_align) * window_align; len = p->pack_size - win->offset; - if (len > packed_git_window_size) - len = packed_git_window_size; + if (len > settings->packed_git_window_size) + len = settings->packed_git_window_size; win->len = (size_t)len; pack_mapped += win->len; - while (packed_git_limit < pack_mapped + + while (settings->packed_git_limit < pack_mapped && unuse_one_window(p)) ; /* nothing */ win->base = xmmap_gently(NULL, win->len, diff --git a/packfile.h b/packfile.h index addb95b0c4..58104fa009 100644 --- a/packfile.h +++ b/packfile.h @@ -89,7 +89,7 @@ unsigned long repo_approximate_object_count(struct repository *r); struct packed_git *find_oid_pack(const struct object_id *oid, struct packed_git *packs); -void pack_report(void); +void pack_report(struct repository *repo); /* * mmap the index file for the specified packfile (if it is not diff --git a/repo-settings.c b/repo-settings.c index acc27eb8fe..9d16d5399e 100644 --- a/repo-settings.c +++ b/repo-settings.c @@ -128,6 +128,19 @@ void prepare_repo_settings(struct repository *r) if (!repo_config_get_ulong(r, "core.deltabasecachelimit", &ulongval)) r->settings.delta_base_cache_limit = ulongval; + + if (!repo_config_get_ulong(r, "core.packedgitwindowsize", &ulongval)) { + int pgsz_x2 = getpagesize() * 2; + + /* This value must be multiple of (pagesize * 2) */ + ulongval /= pgsz_x2; + if (ulongval < 1) + ulongval = 1; + r->settings.packed_git_window_size = ulongval * pgsz_x2; + } + + if (!repo_config_get_ulong(r, "core.packedgitlimit", &ulongval)) + r->settings.packed_git_limit = ulongval; } enum log_refs_config repo_settings_get_log_all_ref_updates(struct repository *repo) diff --git a/repo-settings.h b/repo-settings.h index 10a6f7ed64..93ea0c3274 100644 --- a/repo-settings.h +++ b/repo-settings.h @@ -59,6 +59,8 @@ struct repo_settings { int warn_ambiguous_refs; /* lazily loaded via accessor */ size_t delta_base_cache_limit; + size_t packed_git_window_size; + size_t packed_git_limit; }; #define REPO_SETTINGS_INIT { \ .index_version = -1, \ @@ -66,6 +68,8 @@ struct repo_settings { .fetch_negotiation_algorithm = FETCH_NEGOTIATION_CONSECUTIVE, \ .warn_ambiguous_refs = -1, \ .delta_base_cache_limit = DEFAULT_DELTA_BASE_CACHE_LIMIT, \ + .packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE, \ + .packed_git_limit = DEFAULT_PACKED_GIT_LIMIT, \ } void prepare_repo_settings(struct repository *r); -- cgit v1.2.3 From e106040722c746346c3c40d3790789d9e196f60d Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Tue, 3 Dec 2024 15:44:03 +0100 Subject: midx: add repository to `multi_pack_index` struct The `multi_pack_index` struct represents the MIDX for a repository. Here, we add a pointer to the repository in this struct, allowing direct use of the repository variable without relying on the global `the_repository` struct. With this addition, we can determine the repository associated with a `bitmap_index` struct. A `bitmap_index` points to either a `packed_git` or a `multi_pack_index`, both of which have direct repository references. To support this, we introduce a static helper function, `bitmap_repo`, in `pack-bitmap.c`, which retrieves a repository given a `bitmap_index`. With this, we clear up all usages of `the_repository` within `pack-bitmap.c` and also remove the `USE_THE_REPOSITORY_VARIABLE` definition. Bringing us another step closer to remove all global variable usage. Although this change also opens up the potential to clean up `midx.c`, doing so would require additional refactoring to pass the repository struct to functions where the MIDX struct is created: a task better suited for future patches. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- midx.c | 1 + midx.h | 3 ++ pack-bitmap.c | 90 ++++++++++++++++++++++++++++++++++++----------------------- 3 files changed, 59 insertions(+), 35 deletions(-) diff --git a/midx.c b/midx.c index 8edb75f51d..079c45a1aa 100644 --- a/midx.c +++ b/midx.c @@ -131,6 +131,7 @@ static struct multi_pack_index *load_multi_pack_index_one(const char *object_dir m->data = midx_map; m->data_len = midx_size; m->local = local; + m->repo = the_repository; m->signature = get_be32(m->data); if (m->signature != MIDX_SIGNATURE) diff --git a/midx.h b/midx.h index 42d4f8d149..3b0ac4d878 100644 --- a/midx.h +++ b/midx.h @@ -71,6 +71,9 @@ struct multi_pack_index { const char **pack_names; struct packed_git **packs; + + struct repository *repo; + char object_dir[FLEX_ARRAY]; }; diff --git a/pack-bitmap.c b/pack-bitmap.c index d34ba9909a..0cb1b56c9d 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -1,5 +1,3 @@ -#define USE_THE_REPOSITORY_VARIABLE - #include "git-compat-util.h" #include "commit.h" #include "gettext.h" @@ -177,12 +175,21 @@ static uint32_t bitmap_num_objects(struct bitmap_index *index) return index->pack->num_objects; } +static struct repository *bitmap_repo(struct bitmap_index *bitmap_git) +{ + if (bitmap_is_midx(bitmap_git)) + return bitmap_git->midx->repo; + return bitmap_git->pack->repo; +} + static int load_bitmap_header(struct bitmap_index *index) { struct bitmap_disk_header *header = (void *)index->map; - size_t header_size = sizeof(*header) - GIT_MAX_RAWSZ + the_hash_algo->rawsz; + const struct git_hash_algo *hash_algo = bitmap_repo(index)->hash_algo; + + size_t header_size = sizeof(*header) - GIT_MAX_RAWSZ + hash_algo->rawsz; - if (index->map_size < header_size + the_hash_algo->rawsz) + if (index->map_size < header_size + hash_algo->rawsz) return error(_("corrupted bitmap index (too small)")); if (memcmp(header->magic, BITMAP_IDX_SIGNATURE, sizeof(BITMAP_IDX_SIGNATURE)) != 0) @@ -196,7 +203,7 @@ static int load_bitmap_header(struct bitmap_index *index) { uint32_t flags = ntohs(header->options); size_t cache_size = st_mult(bitmap_num_objects(index), sizeof(uint32_t)); - unsigned char *index_end = index->map + index->map_size - the_hash_algo->rawsz; + unsigned char *index_end = index->map + index->map_size - hash_algo->rawsz; if ((flags & BITMAP_OPT_FULL_DAG) == 0) BUG("unsupported options for bitmap index file " @@ -409,7 +416,7 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git, if (bitmap_git->pack || bitmap_git->midx) { struct strbuf buf = STRBUF_INIT; get_midx_filename(&buf, midx->object_dir); - trace2_data_string("bitmap", the_repository, + trace2_data_string("bitmap", bitmap_repo(bitmap_git), "ignoring extra midx bitmap file", buf.buf); close(fd); strbuf_release(&buf); @@ -427,7 +434,7 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git, goto cleanup; if (!hasheq(get_midx_checksum(bitmap_git->midx), bitmap_git->checksum, - the_repository->hash_algo)) { + bitmap_repo(bitmap_git)->hash_algo)) { error(_("checksum doesn't match in MIDX and bitmap")); goto cleanup; } @@ -438,7 +445,9 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git, } for (i = 0; i < bitmap_git->midx->num_packs; i++) { - if (prepare_midx_pack(the_repository, bitmap_git->midx, i)) { + if (prepare_midx_pack(bitmap_repo(bitmap_git), + bitmap_git->midx, + i)) { warning(_("could not open pack %s"), bitmap_git->midx->pack_names[i]); goto cleanup; @@ -492,8 +501,9 @@ static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git } if (bitmap_git->pack || bitmap_git->midx) { - trace2_data_string("bitmap", the_repository, - "ignoring extra bitmap file", packfile->pack_name); + trace2_data_string("bitmap", bitmap_repo(bitmap_git), + "ignoring extra bitmap file", + packfile->pack_name); close(fd); return -1; } @@ -518,8 +528,8 @@ static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git return -1; } - trace2_data_string("bitmap", the_repository, "opened bitmap file", - packfile->pack_name); + trace2_data_string("bitmap", bitmap_repo(bitmap_git), + "opened bitmap file", packfile->pack_name); return 0; } @@ -649,7 +659,7 @@ struct bitmap_index *prepare_bitmap_git(struct repository *r) struct bitmap_index *prepare_midx_bitmap_git(struct multi_pack_index *midx) { - struct repository *r = the_repository; + struct repository *r = midx->repo; struct bitmap_index *bitmap_git = xcalloc(1, sizeof(*bitmap_git)); if (!open_midx_bitmap_1(bitmap_git, midx) && !load_bitmap(r, bitmap_git)) @@ -1213,6 +1223,7 @@ static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git, { struct bitmap_boundary_cb cb; struct object_list *root; + struct repository *repo; unsigned int i; unsigned int tmp_blobs, tmp_trees, tmp_tags; int any_missing = 0; @@ -1222,6 +1233,8 @@ static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git, cb.base = bitmap_new(); object_array_init(&cb.boundary); + repo = bitmap_repo(bitmap_git); + revs->ignore_missing_links = 1; if (bitmap_git->pseudo_merges.nr) { @@ -1280,19 +1293,19 @@ static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git, * revision walk to (a) OR in any bitmaps that are UNINTERESTING * between the tips and boundary, and (b) record the boundary. */ - trace2_region_enter("pack-bitmap", "boundary-prepare", the_repository); + trace2_region_enter("pack-bitmap", "boundary-prepare", repo); if (prepare_revision_walk(revs)) die("revision walk setup failed"); - trace2_region_leave("pack-bitmap", "boundary-prepare", the_repository); + trace2_region_leave("pack-bitmap", "boundary-prepare", repo); - trace2_region_enter("pack-bitmap", "boundary-traverse", the_repository); + trace2_region_enter("pack-bitmap", "boundary-traverse", repo); revs->boundary = 1; traverse_commit_list_filtered(revs, show_boundary_commit, show_boundary_object, &cb, NULL); revs->boundary = 0; - trace2_region_leave("pack-bitmap", "boundary-traverse", the_repository); + trace2_region_leave("pack-bitmap", "boundary-traverse", repo); revs->blob_objects = tmp_blobs; revs->tree_objects = tmp_trees; @@ -1304,7 +1317,7 @@ static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git, /* * Then add the boundary commit(s) as fill-in traversal tips. */ - trace2_region_enter("pack-bitmap", "boundary-fill-in", the_repository); + trace2_region_enter("pack-bitmap", "boundary-fill-in", repo); for (i = 0; i < cb.boundary.nr; i++) { struct object *obj = cb.boundary.objects[i].item; if (bitmap_walk_contains(bitmap_git, cb.base, &obj->oid)) @@ -1314,7 +1327,7 @@ static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git, } if (revs->pending.nr) cb.base = fill_in_bitmap(bitmap_git, revs, cb.base, NULL); - trace2_region_leave("pack-bitmap", "boundary-fill-in", the_repository); + trace2_region_leave("pack-bitmap", "boundary-fill-in", repo); cleanup: object_array_clear(&cb.boundary); @@ -1718,7 +1731,8 @@ static unsigned long get_size_by_pos(struct bitmap_index *bitmap_git, ofs = pack_pos_to_offset(pack, pos); } - if (packed_object_info(the_repository, pack, ofs, &oi) < 0) { + if (packed_object_info(bitmap_repo(bitmap_git), pack, ofs, + &oi) < 0) { struct object_id oid; nth_bitmap_object_oid(bitmap_git, &oid, pack_pos_to_index(pack, pos)); @@ -1727,7 +1741,8 @@ static unsigned long get_size_by_pos(struct bitmap_index *bitmap_git, } else { struct eindex *eindex = &bitmap_git->ext_index; struct object *obj = eindex->objects[pos - bitmap_num_objects(bitmap_git)]; - if (oid_object_info_extended(the_repository, &obj->oid, &oi, 0) < 0) + if (oid_object_info_extended(bitmap_repo(bitmap_git), &obj->oid, + &oi, 0) < 0) die(_("unable to get size of %s"), oid_to_hex(&obj->oid)); } @@ -1889,7 +1904,8 @@ static void filter_packed_objects_from_bitmap(struct bitmap_index *bitmap_git, bitmap_unset(result, i); for (i = 0; i < eindex->count; ++i) { - if (has_object_pack(the_repository, &eindex->objects[i]->oid)) + if (has_object_pack(bitmap_repo(bitmap_git), + &eindex->objects[i]->oid)) bitmap_unset(result, objects_nr + i); } } @@ -1907,6 +1923,7 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs, struct bitmap *haves_bitmap = NULL; struct bitmap_index *bitmap_git; + struct repository *repo; /* * We can't do pathspec limiting with bitmaps, because we don't know @@ -1980,18 +1997,20 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs, if (!use_boundary_traversal) object_array_clear(&revs->pending); + repo = bitmap_repo(bitmap_git); + if (haves) { if (use_boundary_traversal) { - trace2_region_enter("pack-bitmap", "haves/boundary", the_repository); + trace2_region_enter("pack-bitmap", "haves/boundary", repo); haves_bitmap = find_boundary_objects(bitmap_git, revs, haves); - trace2_region_leave("pack-bitmap", "haves/boundary", the_repository); + trace2_region_leave("pack-bitmap", "haves/boundary", repo); } else { - trace2_region_enter("pack-bitmap", "haves/classic", the_repository); + trace2_region_enter("pack-bitmap", "haves/classic", repo); revs->ignore_missing_links = 1; haves_bitmap = find_objects(bitmap_git, revs, haves, NULL); reset_revision_walk(); revs->ignore_missing_links = 0; - trace2_region_leave("pack-bitmap", "haves/classic", the_repository); + trace2_region_leave("pack-bitmap", "haves/classic", repo); } if (!haves_bitmap) @@ -2025,17 +2044,17 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs, object_list_free(&wants); object_list_free(&haves); - trace2_data_intmax("bitmap", the_repository, "pseudo_merges_satisfied", + trace2_data_intmax("bitmap", repo, "pseudo_merges_satisfied", pseudo_merges_satisfied_nr); - trace2_data_intmax("bitmap", the_repository, "pseudo_merges_cascades", + trace2_data_intmax("bitmap", repo, "pseudo_merges_cascades", pseudo_merges_cascades_nr); - trace2_data_intmax("bitmap", the_repository, "bitmap/hits", + trace2_data_intmax("bitmap", repo, "bitmap/hits", existing_bitmaps_hits_nr); - trace2_data_intmax("bitmap", the_repository, "bitmap/misses", + trace2_data_intmax("bitmap", repo, "bitmap/misses", existing_bitmaps_misses_nr); - trace2_data_intmax("bitmap", the_repository, "bitmap/roots_with_bitmap", + trace2_data_intmax("bitmap", repo, "bitmap/roots_with_bitmap", roots_with_bitmaps_nr); - trace2_data_intmax("bitmap", the_repository, "bitmap/roots_without_bitmap", + trace2_data_intmax("bitmap", repo, "bitmap/roots_without_bitmap", roots_without_bitmaps_nr); return bitmap_git; @@ -2256,7 +2275,7 @@ void reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git, struct bitmap **reuse_out, int multi_pack_reuse) { - struct repository *r = the_repository; + struct repository *r = bitmap_repo(bitmap_git); struct bitmapped_pack *packs = NULL; struct bitmap *result = bitmap_git->result; struct bitmap *reuse; @@ -2792,7 +2811,7 @@ int rebuild_bitmap(const uint32_t *reposition, uint32_t *create_bitmap_mapping(struct bitmap_index *bitmap_git, struct packing_data *mapping) { - struct repository *r = the_repository; + struct repository *r = bitmap_repo(bitmap_git); uint32_t i, num_objects; uint32_t *reposition; @@ -2948,7 +2967,8 @@ static off_t get_disk_usage_for_extended(struct bitmap_index *bitmap_git) st_add(bitmap_num_objects(bitmap_git), i))) continue; - if (oid_object_info_extended(the_repository, &obj->oid, &oi, 0) < 0) + if (oid_object_info_extended(bitmap_repo(bitmap_git), &obj->oid, + &oi, 0) < 0) die(_("unable to get disk usage of '%s'"), oid_to_hex(&obj->oid)); -- cgit v1.2.3 From 281164995159ed641f5e76f40515baf0b5811943 Mon Sep 17 00:00:00 2001 From: Taylor Blau Date: Tue, 3 Dec 2024 15:44:04 +0100 Subject: packfile.c: remove unnecessary prepare_packed_git() call In 454ea2e4d7 (treewide: use get_all_packs, 2018-08-20) we converted existing calls to both: - get_packed_git(), as well as - the_repository->objects->packed_git , to instead use the new get_all_packs() function. In the instance that this commit addresses, there was a preceding call to prepare_packed_git(), which dates all the way back to 660c889e46 (sha1_file: add for_each iterators for loose and packed objects, 2014-10-15) when its caller (for_each_packed_object()) was first introduced. This call could have been removed in 454ea2e4d7, since get_all_packs() itself calls prepare_packed_git(). But the translation in 454ea2e4d7 was (to the best of my knowledge) a find-and-replace rather than inspecting each individual caller. Having an extra prepare_packed_git() call here is harmless, since it will notice that we have already set the 'packed_git_initialized' field and the call will be a noop. So we're only talking about a few dozen CPU cycles to set up and tear down the stack frame. But having a lone prepare_packed_git() call immediately before a call to get_all_packs() confused me, so let's remove it as redundant to avoid more confusion in the future. Signed-off-by: Taylor Blau Signed-off-by: Junio C Hamano --- packfile.c | 1 - 1 file changed, 1 deletion(-) diff --git a/packfile.c b/packfile.c index 2e0e28c7de..9c4bd81a8c 100644 --- a/packfile.c +++ b/packfile.c @@ -2220,7 +2220,6 @@ int for_each_packed_object(struct repository *repo, each_packed_object_fn cb, int r = 0; int pack_errors = 0; - prepare_packed_git(repo); for (p = get_all_packs(repo); p; p = p->next) { if ((flags & FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local) continue; -- cgit v1.2.3 From bc1a980759bc61a426c26d3b47e2d77a708a038b Mon Sep 17 00:00:00 2001 From: Kai Koponen Date: Tue, 3 Dec 2024 12:14:34 -0500 Subject: doc: mention rev-list --ancestry-path restrictions The rev-list documentation doesn't mention that the given commit must be in the specified commit range, leading to unexpected results. Signed-off-by: Kai Koponen Signed-off-by: Junio C Hamano --- Documentation/rev-list-options.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index 0d90d5b154..9d5243e0aa 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -401,7 +401,8 @@ Default mode:: --ancestry-path[=]:: When given a range of commits to display (e.g. 'commit1..commit2' - or 'commit2 {caret}commit1'), only display commits in that range + or 'commit2 {caret}commit1'), and a commit in that range, + only display commits in that range that are ancestors of , descendants of , or itself. If no commit is specified, use 'commit1' (the excluded part of the range) as . Can be passed multiple -- cgit v1.2.3 From 8cb4c6e62f28ac9d9a04daf794ff6dbddf55e416 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Tue, 3 Dec 2024 16:06:52 -0500 Subject: t9300: test verification of renamed paths Commit da91a90c2f (fast-import: disallow more path components, 2024-11-30) added two separate verify_path() calls (one for added/modified files, and one for renames/copies). But our tests only exercise the first one. Let's protect ourselves against regressions by tweaking one of the tests to rename into the bad path. There are adjacent tests that will stay as additions, so now both calls are covered. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t9300-fast-import.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index e2b1db6bc2..fd01a2353c 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -553,9 +553,16 @@ test_expect_success 'B: fail on invalid file path of .' ' commit refs/heads/badpath committer Name $GIT_COMMITTER_DATE data < $GIT_COMMITTER_DATE + data < Date: Wed, 27 Nov 2024 17:28:26 +0100 Subject: midx-write: pass down repository to static functions In 'midx-write.c' there are a lot of static functions which use global variables `the_repository` or `the_hash_algo`. In a follow up commit, the repository variable will be added to `write_midx_context`, which some of the functions can use. But for functions which do not have access to this struct, pass down the required information from non-static functions `write_midx_file` and `write_midx_file_only`. This requires that the function `hash_to_hex` is also replaced with `hash_to_hex_algop` since the former internally accesses the `the_hash_algo` global variable. This ensures that the usage of global variables is limited to these non-static functions, which will be cleaned up in a follow up commit. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- midx-write.c | 57 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/midx-write.c b/midx-write.c index c57726ef94..22b5233f51 100644 --- a/midx-write.c +++ b/midx-write.c @@ -35,13 +35,13 @@ extern void clear_incremental_midx_files_ext(const char *object_dir, extern int cmp_idx_or_pack_name(const char *idx_or_pack_name, const char *idx_name); -static size_t write_midx_header(struct hashfile *f, - unsigned char num_chunks, +static size_t write_midx_header(const struct git_hash_algo *hash_algo, + struct hashfile *f, unsigned char num_chunks, uint32_t num_packs) { hashwrite_be32(f, MIDX_SIGNATURE); hashwrite_u8(f, MIDX_VERSION); - hashwrite_u8(f, oid_version(the_hash_algo)); + hashwrite_u8(f, oid_version(hash_algo)); hashwrite_u8(f, num_chunks); hashwrite_u8(f, 0); /* unused */ hashwrite_be32(f, num_packs); @@ -702,7 +702,7 @@ static int add_ref_to_pending(const char *refname, const char *referent UNUSED, return 0; } - if (!peel_iterated_oid(the_repository, oid, &peeled)) + if (!peel_iterated_oid(revs->repo, oid, &peeled)) oid = &peeled; object = parse_object_or_die(oid, refname); @@ -827,7 +827,7 @@ static struct commit **find_commits_for_midx_bitmap(uint32_t *indexed_commits_nr return cb.commits; } -static int write_midx_bitmap(const char *midx_name, +static int write_midx_bitmap(struct repository *r, const char *midx_name, const unsigned char *midx_hash, struct packing_data *pdata, struct commit **commits, @@ -840,9 +840,9 @@ static int write_midx_bitmap(const char *midx_name, struct bitmap_writer writer; struct pack_idx_entry **index; char *bitmap_name = xstrfmt("%s-%s.bitmap", midx_name, - hash_to_hex(midx_hash)); + hash_to_hex_algop(midx_hash, r->hash_algo)); - trace2_region_enter("midx", "write_midx_bitmap", the_repository); + trace2_region_enter("midx", "write_midx_bitmap", r); if (flags & MIDX_WRITE_BITMAP_HASH_CACHE) options |= BITMAP_OPT_HASH_CACHE; @@ -859,7 +859,7 @@ static int write_midx_bitmap(const char *midx_name, for (i = 0; i < pdata->nr_objects; i++) index[i] = &pdata->objects[i].idx; - bitmap_writer_init(&writer, the_repository, pdata); + bitmap_writer_init(&writer, r, pdata); bitmap_writer_show_progress(&writer, flags & MIDX_PROGRESS); bitmap_writer_build_type_index(&writer, index); @@ -892,7 +892,7 @@ cleanup: free(bitmap_name); bitmap_writer_free(&writer); - trace2_region_leave("midx", "write_midx_bitmap", the_repository); + trace2_region_leave("midx", "write_midx_bitmap", r); return ret; } @@ -1049,7 +1049,7 @@ static void clear_midx_files(const char *object_dir, strbuf_release(&buf); } -static int write_midx_internal(const char *object_dir, +static int write_midx_internal(struct repository *r, const char *object_dir, struct string_list *packs_to_include, struct string_list *packs_to_drop, const char *preferred_pack_name, @@ -1070,7 +1070,8 @@ static int write_midx_internal(const char *object_dir, const char **keep_hashes = NULL; struct chunkfile *cf; - trace2_region_enter("midx", "write_midx_internal", the_repository); + trace2_region_enter("midx", "write_midx_internal", r); + ctx.incremental = !!(flags & MIDX_WRITE_INCREMENTAL); if (ctx.incremental && (flags & MIDX_WRITE_BITMAP)) @@ -1087,8 +1088,7 @@ static int write_midx_internal(const char *object_dir, midx_name.buf); if (!packs_to_include || ctx.incremental) { - struct multi_pack_index *m = lookup_multi_pack_index(the_repository, - object_dir); + struct multi_pack_index *m = lookup_multi_pack_index(r, object_dir); if (m && !midx_checksum_valid(m)) { warning(_("ignoring existing multi-pack-index; checksum mismatch")); m = NULL; @@ -1351,7 +1351,7 @@ static int write_midx_internal(const char *object_dir, add_chunk(cf, MIDX_CHUNKID_OIDFANOUT, MIDX_CHUNK_FANOUT_SIZE, write_midx_oid_fanout); add_chunk(cf, MIDX_CHUNKID_OIDLOOKUP, - st_mult(ctx.entries_nr, the_hash_algo->rawsz), + st_mult(ctx.entries_nr, r->hash_algo->rawsz), write_midx_oid_lookup); add_chunk(cf, MIDX_CHUNKID_OBJECTOFFSETS, st_mult(ctx.entries_nr, MIDX_CHUNK_OFFSET_WIDTH), @@ -1373,7 +1373,8 @@ static int write_midx_internal(const char *object_dir, write_midx_bitmapped_packs); } - write_midx_header(f, get_num_chunks(cf), ctx.nr - dropped_packs); + write_midx_header(r->hash_algo, f, get_num_chunks(cf), + ctx.nr - dropped_packs); write_chunkfile(cf, &ctx); finalize_hashfile(f, midx_hash, FSYNC_COMPONENT_PACK_METADATA, @@ -1405,7 +1406,7 @@ static int write_midx_internal(const char *object_dir, FREE_AND_NULL(ctx.entries); ctx.entries_nr = 0; - if (write_midx_bitmap(midx_name.buf, midx_hash, &pdata, + if (write_midx_bitmap(r, midx_name.buf, midx_hash, &pdata, commits, commits_nr, ctx.pack_order, flags) < 0) { error(_("could not write multi-pack bitmap")); @@ -1449,12 +1450,13 @@ static int write_midx_internal(const char *object_dir, strbuf_release(&final_midx_name); keep_hashes[ctx.num_multi_pack_indexes_before] = - xstrdup(hash_to_hex(midx_hash)); + xstrdup(hash_to_hex_algop(midx_hash, r->hash_algo)); for (i = 0; i < ctx.num_multi_pack_indexes_before; i++) { uint32_t j = ctx.num_multi_pack_indexes_before - i - 1; - keep_hashes[j] = xstrdup(hash_to_hex(get_midx_checksum(m))); + keep_hashes[j] = xstrdup(hash_to_hex_algop(get_midx_checksum(m), + r->hash_algo)); m = m->base_midx; } @@ -1462,7 +1464,7 @@ static int write_midx_internal(const char *object_dir, fprintf(get_lock_file_fp(&lk), "%s\n", keep_hashes[i]); } else { keep_hashes[ctx.num_multi_pack_indexes_before] = - xstrdup(hash_to_hex(midx_hash)); + xstrdup(hash_to_hex_algop(midx_hash, r->hash_algo)); } if (ctx.m || ctx.base_midx) @@ -1495,7 +1497,7 @@ cleanup: } strbuf_release(&midx_name); - trace2_region_leave("midx", "write_midx_internal", the_repository); + trace2_region_leave("midx", "write_midx_internal", r); return result; } @@ -1505,8 +1507,8 @@ int write_midx_file(const char *object_dir, const char *refs_snapshot, unsigned flags) { - return write_midx_internal(object_dir, NULL, NULL, preferred_pack_name, - refs_snapshot, flags); + return write_midx_internal(the_repository, object_dir, NULL, NULL, + preferred_pack_name, refs_snapshot, flags); } int write_midx_file_only(const char *object_dir, @@ -1515,8 +1517,9 @@ int write_midx_file_only(const char *object_dir, const char *refs_snapshot, unsigned flags) { - return write_midx_internal(object_dir, packs_to_include, NULL, - preferred_pack_name, refs_snapshot, flags); + return write_midx_internal(the_repository, object_dir, packs_to_include, + NULL, preferred_pack_name, refs_snapshot, + flags); } int expire_midx_packs(struct repository *r, const char *object_dir, unsigned flags) @@ -1572,7 +1575,8 @@ int expire_midx_packs(struct repository *r, const char *object_dir, unsigned fla free(count); if (packs_to_drop.nr) - result = write_midx_internal(object_dir, NULL, &packs_to_drop, NULL, NULL, flags); + result = write_midx_internal(r, object_dir, NULL, + &packs_to_drop, NULL, NULL, flags); string_list_clear(&packs_to_drop, 0); @@ -1769,7 +1773,8 @@ int midx_repack(struct repository *r, const char *object_dir, size_t batch_size, goto cleanup; } - result = write_midx_internal(object_dir, NULL, NULL, NULL, NULL, flags); + result = write_midx_internal(r, object_dir, NULL, NULL, NULL, NULL, + flags); cleanup: free(include_pack); -- cgit v1.2.3 From 20df8141f5b7c015abb1090b19e4d24439e500c0 Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Wed, 27 Nov 2024 17:28:27 +0100 Subject: midx-write: use `revs->repo` inside `read_refs_snapshot` The function `read_refs_snapshot()` uses `parse_oid_hex()`, which relies on the global `the_hash_algo` variable. Let's instead use `parse_oid_hex_algop()` and provide the hash algo via `revs->repo`. Also, while here, fix a missing newline after the function's definition. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- midx-write.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/midx-write.c b/midx-write.c index 22b5233f51..564438f616 100644 --- a/midx-write.c +++ b/midx-write.c @@ -760,7 +760,7 @@ static int read_refs_snapshot(const char *refs_snapshot, hex = &buf.buf[1]; } - if (parse_oid_hex(hex, &oid, &end) < 0) + if (parse_oid_hex_algop(hex, &oid, &end, revs->repo->hash_algo) < 0) die(_("could not parse line: %s"), buf.buf); if (*end) die(_("malformed line: %s"), buf.buf); @@ -776,6 +776,7 @@ static int read_refs_snapshot(const char *refs_snapshot, strbuf_release(&buf); return 0; } + static struct commit **find_commits_for_midx_bitmap(uint32_t *indexed_commits_nr_p, const char *refs_snapshot, struct write_midx_context *ctx) -- cgit v1.2.3 From dfa7c68245bc01e7678d85520cbfbac042cb7c5c Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Wed, 27 Nov 2024 17:28:28 +0100 Subject: write-midx: add repository field to `write_midx_context` The struct `write_midx_context` is used to pass context for creating MIDX files. Add the repository field here to ensure that most functions within `midx-write.c` have access to the field and can use that instead of the global `the_repository` variable. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- midx-write.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/midx-write.c b/midx-write.c index 564438f616..1c355cdf8d 100644 --- a/midx-write.c +++ b/midx-write.c @@ -110,6 +110,8 @@ struct write_midx_context { uint32_t num_multi_pack_indexes_before; struct string_list *to_include; + + struct repository *repo; }; static int should_include_pack(const struct write_midx_context *ctx, @@ -154,7 +156,7 @@ static void add_pack_to_midx(const char *full_path, size_t full_path_len, return; ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc); - p = add_packed_git(the_repository, full_path, full_path_len, 0); + p = add_packed_git(ctx->repo, full_path, full_path_len, 0); if (!p) { warning(_("failed to add packfile '%s'"), full_path); @@ -480,7 +482,7 @@ static int write_midx_oid_lookup(struct hashfile *f, void *data) { struct write_midx_context *ctx = data; - unsigned char hash_len = the_hash_algo->rawsz; + unsigned char hash_len = ctx->repo->hash_algo->rawsz; struct pack_midx_entry *list = ctx->entries; uint32_t i; @@ -605,7 +607,7 @@ static uint32_t *midx_pack_order(struct write_midx_context *ctx) uint32_t *pack_order, base_objects = 0; uint32_t i; - trace2_region_enter("midx", "midx_pack_order", the_repository); + trace2_region_enter("midx", "midx_pack_order", ctx->repo); if (ctx->incremental && ctx->base_midx) base_objects = ctx->base_midx->num_objects + @@ -640,7 +642,7 @@ static uint32_t *midx_pack_order(struct write_midx_context *ctx) } free(data); - trace2_region_leave("midx", "midx_pack_order", the_repository); + trace2_region_leave("midx", "midx_pack_order", ctx->repo); return pack_order; } @@ -651,9 +653,10 @@ static void write_midx_reverse_index(char *midx_name, unsigned char *midx_hash, struct strbuf buf = STRBUF_INIT; char *tmp_file; - trace2_region_enter("midx", "write_midx_reverse_index", the_repository); + trace2_region_enter("midx", "write_midx_reverse_index", ctx->repo); - strbuf_addf(&buf, "%s-%s.rev", midx_name, hash_to_hex(midx_hash)); + strbuf_addf(&buf, "%s-%s.rev", midx_name, hash_to_hex_algop(midx_hash, + ctx->repo->hash_algo)); tmp_file = write_rev_file_order(NULL, ctx->pack_order, ctx->entries_nr, midx_hash, WRITE_REV); @@ -664,7 +667,7 @@ static void write_midx_reverse_index(char *midx_name, unsigned char *midx_hash, strbuf_release(&buf); free(tmp_file); - trace2_region_leave("midx", "write_midx_reverse_index", the_repository); + trace2_region_leave("midx", "write_midx_reverse_index", ctx->repo); } static void prepare_midx_packing_data(struct packing_data *pdata, @@ -672,10 +675,10 @@ static void prepare_midx_packing_data(struct packing_data *pdata, { uint32_t i; - trace2_region_enter("midx", "prepare_midx_packing_data", the_repository); + trace2_region_enter("midx", "prepare_midx_packing_data", ctx->repo); memset(pdata, 0, sizeof(struct packing_data)); - prepare_packing_data(the_repository, pdata); + prepare_packing_data(ctx->repo, pdata); for (i = 0; i < ctx->entries_nr; i++) { uint32_t pos = ctx->pack_order[i]; @@ -686,7 +689,7 @@ static void prepare_midx_packing_data(struct packing_data *pdata, ctx->info[ctx->pack_perm[from->pack_int_id]].p); } - trace2_region_leave("midx", "prepare_midx_packing_data", the_repository); + trace2_region_leave("midx", "prepare_midx_packing_data", ctx->repo); } static int add_ref_to_pending(const char *refname, const char *referent UNUSED, @@ -784,17 +787,16 @@ static struct commit **find_commits_for_midx_bitmap(uint32_t *indexed_commits_nr struct rev_info revs; struct bitmap_commit_cb cb = {0}; - trace2_region_enter("midx", "find_commits_for_midx_bitmap", - the_repository); + trace2_region_enter("midx", "find_commits_for_midx_bitmap", ctx->repo); cb.ctx = ctx; - repo_init_revisions(the_repository, &revs, NULL); + repo_init_revisions(ctx->repo, &revs, NULL); if (refs_snapshot) { read_refs_snapshot(refs_snapshot, &revs); } else { setup_revisions(0, NULL, &revs, NULL); - refs_for_each_ref(get_main_ref_store(the_repository), + refs_for_each_ref(get_main_ref_store(ctx->repo), add_ref_to_pending, &revs); } @@ -822,8 +824,7 @@ static struct commit **find_commits_for_midx_bitmap(uint32_t *indexed_commits_nr release_revisions(&revs); - trace2_region_leave("midx", "find_commits_for_midx_bitmap", - the_repository); + trace2_region_leave("midx", "find_commits_for_midx_bitmap", ctx->repo); return cb.commits; } @@ -945,7 +946,7 @@ static int fill_packs_from_midx(struct write_midx_context *ctx, */ if (flags & MIDX_WRITE_REV_INDEX || preferred_pack_name) { - if (prepare_midx_pack(the_repository, m, + if (prepare_midx_pack(ctx->repo, m, m->num_packs_in_base + i)) { error(_("could not load pack")); return 1; @@ -1073,6 +1074,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir, trace2_region_enter("midx", "write_midx_internal", r); + ctx.repo = r; ctx.incremental = !!(flags & MIDX_WRITE_INCREMENTAL); if (ctx.incremental && (flags & MIDX_WRITE_BITMAP)) @@ -1469,7 +1471,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir, } if (ctx.m || ctx.base_midx) - close_object_store(the_repository->objects); + close_object_store(ctx.repo->objects); if (commit_lock_file(&lk) < 0) die_errno(_("could not write multi-pack-index")); -- cgit v1.2.3 From 2fed09aa9b82e4710fb4049e18280df8270eb0b2 Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Wed, 27 Nov 2024 17:28:29 +0100 Subject: midx-write: pass down repository to `write_midx_file[_only]` In a previous commit, we passed the repository field to all subcommands in the `builtin/` directory. Utilize this to pass the repository field down to the `write_midx_file[_only]` functions to remove the usage of `the_repository` global variables. With this, all usage of global variables in `midx-write.c` is removed, hence, remove the `USE_THE_REPOSITORY_VARIABLE` guard from the file. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- builtin/multi-pack-index.c | 6 +++--- builtin/repack.c | 2 +- midx-write.c | 22 +++++++++------------- midx.h | 10 ++++------ 4 files changed, 17 insertions(+), 23 deletions(-) diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c index 85e40a4b6d..2a938466f5 100644 --- a/builtin/multi-pack-index.c +++ b/builtin/multi-pack-index.c @@ -120,7 +120,7 @@ static void read_packs_from_stdin(struct string_list *to) static int cmd_multi_pack_index_write(int argc, const char **argv, const char *prefix, - struct repository *repo UNUSED) + struct repository *repo) { struct option *options; static struct option builtin_multi_pack_index_write_options[] = { @@ -165,7 +165,7 @@ static int cmd_multi_pack_index_write(int argc, const char **argv, read_packs_from_stdin(&packs); - ret = write_midx_file_only(opts.object_dir, &packs, + ret = write_midx_file_only(repo, opts.object_dir, &packs, opts.preferred_pack, opts.refs_snapshot, opts.flags); @@ -176,7 +176,7 @@ static int cmd_multi_pack_index_write(int argc, const char **argv, } - ret = write_midx_file(opts.object_dir, opts.preferred_pack, + ret = write_midx_file(repo, opts.object_dir, opts.preferred_pack, opts.refs_snapshot, opts.flags); free(opts.refs_snapshot); diff --git a/builtin/repack.c b/builtin/repack.c index 96a4fa234b..9c21fc482d 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -1569,7 +1569,7 @@ int cmd_repack(int argc, unsigned flags = 0; if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL, 0)) flags |= MIDX_WRITE_INCREMENTAL; - write_midx_file(repo_get_object_directory(the_repository), + write_midx_file(the_repository, repo_get_object_directory(the_repository), NULL, NULL, flags); } diff --git a/midx-write.c b/midx-write.c index 1c355cdf8d..1bc2f52569 100644 --- a/midx-write.c +++ b/midx-write.c @@ -1,5 +1,3 @@ -#define USE_THE_REPOSITORY_VARIABLE - #include "git-compat-util.h" #include "abspath.h" #include "config.h" @@ -1505,24 +1503,22 @@ cleanup: return result; } -int write_midx_file(const char *object_dir, +int write_midx_file(struct repository *r, const char *object_dir, const char *preferred_pack_name, - const char *refs_snapshot, - unsigned flags) + const char *refs_snapshot, unsigned flags) { - return write_midx_internal(the_repository, object_dir, NULL, NULL, - preferred_pack_name, refs_snapshot, flags); + return write_midx_internal(r, object_dir, NULL, NULL, + preferred_pack_name, refs_snapshot, + flags); } -int write_midx_file_only(const char *object_dir, +int write_midx_file_only(struct repository *r, const char *object_dir, struct string_list *packs_to_include, const char *preferred_pack_name, - const char *refs_snapshot, - unsigned flags) + const char *refs_snapshot, unsigned flags) { - return write_midx_internal(the_repository, object_dir, packs_to_include, - NULL, preferred_pack_name, refs_snapshot, - flags); + return write_midx_internal(r, object_dir, packs_to_include, NULL, + preferred_pack_name, refs_snapshot, flags); } int expire_midx_packs(struct repository *r, const char *object_dir, unsigned flags) diff --git a/midx.h b/midx.h index 3b0ac4d878..c37ad5b524 100644 --- a/midx.h +++ b/midx.h @@ -123,15 +123,13 @@ int prepare_multi_pack_index_one(struct repository *r, const char *object_dir, i * Variant of write_midx_file which writes a MIDX containing only the packs * specified in packs_to_include. */ -int write_midx_file(const char *object_dir, - const char *preferred_pack_name, - const char *refs_snapshot, +int write_midx_file(struct repository *r, const char *object_dir, + const char *preferred_pack_name, const char *refs_snapshot, unsigned flags); -int write_midx_file_only(const char *object_dir, +int write_midx_file_only(struct repository *r, const char *object_dir, struct string_list *packs_to_include, const char *preferred_pack_name, - const char *refs_snapshot, - unsigned flags); + const char *refs_snapshot, unsigned flags); void clear_midx_file(struct repository *r); int verify_midx_file(struct repository *r, const char *object_dir, unsigned flags); int expire_midx_packs(struct repository *r, const char *object_dir, unsigned flags); -- cgit v1.2.3 From fae9bae7091958255fa7729f6cedb8cc4f9a3387 Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Wed, 27 Nov 2024 17:28:30 +0100 Subject: midx: cleanup internal usage of `the_repository` and `the_hash_algo` In the `midx.c` file, there are multiple usages of `the_repository` and `the_hash_algo` within static functions of the file. Some of the usages can be simply swapped out with the available `repository` struct. While some of them can be swapped out by passing the repository to the required functions. This leaves out only some other usages of `the_repository` and `the_hash_algo` in the file in non-static functions, which we'll tackle in upcoming commits. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- midx.c | 49 +++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/midx.c b/midx.c index 079c45a1aa..6f0fb8285a 100644 --- a/midx.c +++ b/midx.c @@ -25,7 +25,7 @@ int cmp_idx_or_pack_name(const char *idx_or_pack_name, const unsigned char *get_midx_checksum(struct multi_pack_index *m) { - return m->data + m->data_len - the_hash_algo->rawsz; + return m->data + m->data_len - m->repo->hash_algo->rawsz; } void get_midx_filename(struct strbuf *out, const char *object_dir) @@ -94,7 +94,8 @@ static int midx_read_object_offsets(const unsigned char *chunk_start, #define MIDX_MIN_SIZE (MIDX_HEADER_SIZE + the_hash_algo->rawsz) -static struct multi_pack_index *load_multi_pack_index_one(const char *object_dir, +static struct multi_pack_index *load_multi_pack_index_one(struct repository *r, + const char *object_dir, const char *midx_name, int local) { @@ -131,7 +132,7 @@ static struct multi_pack_index *load_multi_pack_index_one(const char *object_dir m->data = midx_map; m->data_len = midx_size; m->local = local; - m->repo = the_repository; + m->repo = r; m->signature = get_be32(m->data); if (m->signature != MIDX_SIGNATURE) @@ -144,12 +145,12 @@ static struct multi_pack_index *load_multi_pack_index_one(const char *object_dir m->version); hash_version = m->data[MIDX_BYTE_HASH_VERSION]; - if (hash_version != oid_version(the_hash_algo)) { + if (hash_version != oid_version(r->hash_algo)) { error(_("multi-pack-index hash version %u does not match version %u"), - hash_version, oid_version(the_hash_algo)); + hash_version, oid_version(r->hash_algo)); goto cleanup_fail; } - m->hash_len = the_hash_algo->rawsz; + m->hash_len = r->hash_algo->rawsz; m->num_chunks = m->data[MIDX_BYTE_NUM_CHUNKS]; @@ -206,8 +207,8 @@ static struct multi_pack_index *load_multi_pack_index_one(const char *object_dir m->pack_names[i]); } - trace2_data_intmax("midx", the_repository, "load/num_packs", m->num_packs); - trace2_data_intmax("midx", the_repository, "load/num_objects", m->num_objects); + trace2_data_intmax("midx", r, "load/num_packs", m->num_packs); + trace2_data_intmax("midx", r, "load/num_objects", m->num_objects); free_chunkfile(cf); return m; @@ -240,8 +241,9 @@ void get_split_midx_filename_ext(struct strbuf *buf, const char *object_dir, strbuf_addf(buf, "/multi-pack-index-%s.%s", hash_to_hex(hash), ext); } -static int open_multi_pack_index_chain(const char *chain_file, - int *fd, struct stat *st) +static int open_multi_pack_index_chain(const struct git_hash_algo *hash_algo, + const char *chain_file, int *fd, + struct stat *st) { *fd = git_open(chain_file); if (*fd < 0) @@ -250,7 +252,7 @@ static int open_multi_pack_index_chain(const char *chain_file, close(*fd); return 0; } - if (st->st_size < the_hash_algo->hexsz) { + if (st->st_size < hash_algo->hexsz) { close(*fd); if (!st->st_size) { /* treat empty files the same as missing */ @@ -292,7 +294,8 @@ static int add_midx_to_chain(struct multi_pack_index *midx, return 1; } -static struct multi_pack_index *load_midx_chain_fd_st(const char *object_dir, +static struct multi_pack_index *load_midx_chain_fd_st(struct repository *r, + const char *object_dir, int local, int fd, struct stat *st, int *incomplete_chain) @@ -303,7 +306,7 @@ static struct multi_pack_index *load_midx_chain_fd_st(const char *object_dir, uint32_t i, count; FILE *fp = xfdopen(fd, "r"); - count = st->st_size / (the_hash_algo->hexsz + 1); + count = st->st_size / (r->hash_algo->hexsz + 1); for (i = 0; i < count; i++) { struct multi_pack_index *m; @@ -312,7 +315,7 @@ static struct multi_pack_index *load_midx_chain_fd_st(const char *object_dir, if (strbuf_getline_lf(&buf, fp) == EOF) break; - if (get_oid_hex(buf.buf, &layer)) { + if (get_oid_hex_algop(buf.buf, &layer, r->hash_algo)) { warning(_("invalid multi-pack-index chain: line '%s' " "not a hash"), buf.buf); @@ -325,7 +328,7 @@ static struct multi_pack_index *load_midx_chain_fd_st(const char *object_dir, strbuf_reset(&buf); get_split_midx_filename_ext(&buf, object_dir, layer.hash, MIDX_EXT_MIDX); - m = load_multi_pack_index_one(object_dir, buf.buf, local); + m = load_multi_pack_index_one(r, object_dir, buf.buf, local); if (m) { if (add_midx_to_chain(m, midx_chain)) { @@ -348,7 +351,8 @@ static struct multi_pack_index *load_midx_chain_fd_st(const char *object_dir, return midx_chain; } -static struct multi_pack_index *load_multi_pack_index_chain(const char *object_dir, +static struct multi_pack_index *load_multi_pack_index_chain(struct repository *r, + const char *object_dir, int local) { struct strbuf chain_file = STRBUF_INIT; @@ -357,10 +361,10 @@ static struct multi_pack_index *load_multi_pack_index_chain(const char *object_d struct multi_pack_index *m = NULL; get_midx_chain_filename(&chain_file, object_dir); - if (open_multi_pack_index_chain(chain_file.buf, &fd, &st)) { + if (open_multi_pack_index_chain(r->hash_algo, chain_file.buf, &fd, &st)) { int incomplete; /* ownership of fd is taken over by load function */ - m = load_midx_chain_fd_st(object_dir, local, fd, &st, + m = load_midx_chain_fd_st(r, object_dir, local, fd, &st, &incomplete); } @@ -376,9 +380,10 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, get_midx_filename(&midx_name, object_dir); - m = load_multi_pack_index_one(object_dir, midx_name.buf, local); + m = load_multi_pack_index_one(the_repository, object_dir, + midx_name.buf, local); if (!m) - m = load_multi_pack_index_chain(object_dir, local); + m = load_multi_pack_index_chain(the_repository, object_dir, local); strbuf_release(&midx_name); @@ -520,7 +525,7 @@ int bsearch_one_midx(const struct object_id *oid, struct multi_pack_index *m, uint32_t *result) { int ret = bsearch_hash(oid->hash, m->chunk_oid_fanout, - m->chunk_oid_lookup, the_hash_algo->rawsz, + m->chunk_oid_lookup, m->repo->hash_algo->rawsz, result); if (result) *result += m->num_objects_in_base; @@ -551,7 +556,7 @@ struct object_id *nth_midxed_object_oid(struct object_id *oid, n = midx_for_object(&m, n); oidread(oid, m->chunk_oid_lookup + st_mult(m->hash_len, n), - the_repository->hash_algo); + m->repo->hash_algo); return oid; } -- cgit v1.2.3 From d5c2ca576a47480b03a83821041955a21a645d1a Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Wed, 27 Nov 2024 17:28:31 +0100 Subject: midx: pass `repository` to `load_multi_pack_index` The `load_multi_pack_index` function in midx uses `the_repository` variable to access the `repository` struct. Modify the function and its callee's to send the `repository` field. This moves usage of `the_repository` to the `test-read-midx.c` file. While that is not optimal, it is okay, since the upcoming commits will slowly move the usage of `the_repository` up the layers and remove it eventually. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- midx.c | 11 ++++++----- midx.h | 4 +++- t/helper/test-read-midx.c | 8 ++++---- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/midx.c b/midx.c index 6f0fb8285a..98ee84d4a8 100644 --- a/midx.c +++ b/midx.c @@ -372,7 +372,8 @@ static struct multi_pack_index *load_multi_pack_index_chain(struct repository *r return m; } -struct multi_pack_index *load_multi_pack_index(const char *object_dir, +struct multi_pack_index *load_multi_pack_index(struct repository *r, + const char *object_dir, int local) { struct strbuf midx_name = STRBUF_INIT; @@ -380,10 +381,10 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, get_midx_filename(&midx_name, object_dir); - m = load_multi_pack_index_one(the_repository, object_dir, + m = load_multi_pack_index_one(r, object_dir, midx_name.buf, local); if (!m) - m = load_multi_pack_index_chain(the_repository, object_dir, local); + m = load_multi_pack_index_chain(r, object_dir, local); strbuf_release(&midx_name); @@ -727,7 +728,7 @@ int prepare_multi_pack_index_one(struct repository *r, const char *object_dir, i if (!strcmp(object_dir, m_search->object_dir)) return 1; - m = load_multi_pack_index(object_dir, local); + m = load_multi_pack_index(r, object_dir, local); if (m) { struct multi_pack_index *mp = r->objects->multi_pack_index; @@ -881,7 +882,7 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag struct pair_pos_vs_id *pairs = NULL; uint32_t i; struct progress *progress = NULL; - struct multi_pack_index *m = load_multi_pack_index(object_dir, 1); + struct multi_pack_index *m = load_multi_pack_index(r, object_dir, 1); struct multi_pack_index *curr; verify_midx_error = 0; diff --git a/midx.h b/midx.h index c37ad5b524..78efa28d35 100644 --- a/midx.h +++ b/midx.h @@ -97,7 +97,9 @@ void get_midx_chain_filename(struct strbuf *buf, const char *object_dir); void get_split_midx_filename_ext(struct strbuf *buf, const char *object_dir, const unsigned char *hash, const char *ext); -struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local); +struct multi_pack_index *load_multi_pack_index(struct repository *r, + const char *object_dir, + int local); int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, uint32_t pack_int_id); struct packed_git *nth_midxed_pack(struct multi_pack_index *m, uint32_t pack_int_id); diff --git a/t/helper/test-read-midx.c b/t/helper/test-read-midx.c index 438fb9fc61..fc63236961 100644 --- a/t/helper/test-read-midx.c +++ b/t/helper/test-read-midx.c @@ -18,7 +18,7 @@ static int read_midx_file(const char *object_dir, const char *checksum, struct multi_pack_index *m; setup_git_directory(); - m = load_multi_pack_index(object_dir, 1); + m = load_multi_pack_index(the_repository, object_dir, 1); if (!m) return 1; @@ -82,7 +82,7 @@ static int read_midx_checksum(const char *object_dir) struct multi_pack_index *m; setup_git_directory(); - m = load_multi_pack_index(object_dir, 1); + m = load_multi_pack_index(the_repository, object_dir, 1); if (!m) return 1; printf("%s\n", hash_to_hex(get_midx_checksum(m))); @@ -98,7 +98,7 @@ static int read_midx_preferred_pack(const char *object_dir) setup_git_directory(); - midx = load_multi_pack_index(object_dir, 1); + midx = load_multi_pack_index(the_repository, object_dir, 1); if (!midx) return 1; @@ -121,7 +121,7 @@ static int read_midx_bitmapped_packs(const char *object_dir) setup_git_directory(); - midx = load_multi_pack_index(object_dir, 1); + midx = load_multi_pack_index(the_repository, object_dir, 1); if (!midx) return 1; -- cgit v1.2.3 From f59de71cf700f9f8da27023ec8b5df117f99d9c8 Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Wed, 27 Nov 2024 17:28:32 +0100 Subject: midx: pass down `hash_algo` to functions using global variables The functions `get_split_midx_filename_ext()`, `get_midx_filename()` and `get_midx_filename_ext()` use `hash_to_hex()` which internally uses the `the_hash_algo` global variable. Remove this dependency on global variables by passing down the `hash_algo` through to the functions mentioned and instead calling `hash_to_hex_algop()` along with the obtained `hash_algo`. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- midx-write.c | 22 +++++++++++----------- midx.c | 26 +++++++++++++++----------- midx.h | 10 +++++++--- pack-bitmap.c | 6 +++--- pack-revindex.c | 2 +- 5 files changed, 37 insertions(+), 29 deletions(-) diff --git a/midx-write.c b/midx-write.c index 1bc2f52569..bcd1d50eb0 100644 --- a/midx-write.c +++ b/midx-write.c @@ -991,9 +991,10 @@ static int link_midx_to_chain(struct multi_pack_index *m) for (i = 0; i < ARRAY_SIZE(midx_exts); i++) { const unsigned char *hash = get_midx_checksum(m); - get_midx_filename_ext(&from, m->object_dir, hash, - midx_exts[i].non_split); - get_split_midx_filename_ext(&to, m->object_dir, hash, + get_midx_filename_ext(m->repo->hash_algo, &from, m->object_dir, + hash, midx_exts[i].non_split); + get_split_midx_filename_ext(m->repo->hash_algo, &to, + m->object_dir, hash, midx_exts[i].split); if (link(from.buf, to.buf) < 0 && errno != ENOENT) { @@ -1012,9 +1013,8 @@ done: return ret; } -static void clear_midx_files(const char *object_dir, - const char **hashes, - uint32_t hashes_nr, +static void clear_midx_files(struct repository *r, const char *object_dir, + const char **hashes, uint32_t hashes_nr, unsigned incremental) { /* @@ -1039,7 +1039,7 @@ static void clear_midx_files(const char *object_dir, } if (incremental) - get_midx_filename(&buf, object_dir); + get_midx_filename(r->hash_algo, &buf, object_dir); else get_midx_chain_filename(&buf, object_dir); @@ -1083,7 +1083,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir, "%s/pack/multi-pack-index.d/tmp_midx_XXXXXX", object_dir); else - get_midx_filename(&midx_name, object_dir); + get_midx_filename(r->hash_algo, &midx_name, object_dir); if (safe_create_leading_directories(midx_name.buf)) die_errno(_("unable to create leading directories of %s"), midx_name.buf); @@ -1440,8 +1440,8 @@ static int write_midx_internal(struct repository *r, const char *object_dir, if (link_midx_to_chain(ctx.base_midx) < 0) return -1; - get_split_midx_filename_ext(&final_midx_name, object_dir, - midx_hash, MIDX_EXT_MIDX); + get_split_midx_filename_ext(r->hash_algo, &final_midx_name, + object_dir, midx_hash, MIDX_EXT_MIDX); if (rename_tempfile(&incr, final_midx_name.buf) < 0) { error_errno(_("unable to rename new multi-pack-index layer")); @@ -1474,7 +1474,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir, if (commit_lock_file(&lk) < 0) die_errno(_("could not write multi-pack-index")); - clear_midx_files(object_dir, keep_hashes, + clear_midx_files(r, object_dir, keep_hashes, ctx.num_multi_pack_indexes_before + 1, ctx.incremental); diff --git a/midx.c b/midx.c index 98ee84d4a8..f45ea842cd 100644 --- a/midx.c +++ b/midx.c @@ -28,17 +28,19 @@ const unsigned char *get_midx_checksum(struct multi_pack_index *m) return m->data + m->data_len - m->repo->hash_algo->rawsz; } -void get_midx_filename(struct strbuf *out, const char *object_dir) +void get_midx_filename(const struct git_hash_algo *hash_algo, + struct strbuf *out, const char *object_dir) { - get_midx_filename_ext(out, object_dir, NULL, NULL); + get_midx_filename_ext(hash_algo, out, object_dir, NULL, NULL); } -void get_midx_filename_ext(struct strbuf *out, const char *object_dir, +void get_midx_filename_ext(const struct git_hash_algo *hash_algo, + struct strbuf *out, const char *object_dir, const unsigned char *hash, const char *ext) { strbuf_addf(out, "%s/pack/multi-pack-index", object_dir); if (ext) - strbuf_addf(out, "-%s.%s", hash_to_hex(hash), ext); + strbuf_addf(out, "-%s.%s", hash_to_hex_algop(hash, hash_algo), ext); } static int midx_read_oid_fanout(const unsigned char *chunk_start, @@ -234,11 +236,13 @@ void get_midx_chain_filename(struct strbuf *buf, const char *object_dir) strbuf_addstr(buf, "/multi-pack-index-chain"); } -void get_split_midx_filename_ext(struct strbuf *buf, const char *object_dir, +void get_split_midx_filename_ext(const struct git_hash_algo *hash_algo, + struct strbuf *buf, const char *object_dir, const unsigned char *hash, const char *ext) { get_midx_chain_dirname(buf, object_dir); - strbuf_addf(buf, "/multi-pack-index-%s.%s", hash_to_hex(hash), ext); + strbuf_addf(buf, "/multi-pack-index-%s.%s", + hash_to_hex_algop(hash, hash_algo), ext); } static int open_multi_pack_index_chain(const struct git_hash_algo *hash_algo, @@ -326,8 +330,8 @@ static struct multi_pack_index *load_midx_chain_fd_st(struct repository *r, valid = 0; strbuf_reset(&buf); - get_split_midx_filename_ext(&buf, object_dir, layer.hash, - MIDX_EXT_MIDX); + get_split_midx_filename_ext(r->hash_algo, &buf, object_dir, + layer.hash, MIDX_EXT_MIDX); m = load_multi_pack_index_one(r, object_dir, buf.buf, local); if (m) { @@ -379,7 +383,7 @@ struct multi_pack_index *load_multi_pack_index(struct repository *r, struct strbuf midx_name = STRBUF_INIT; struct multi_pack_index *m; - get_midx_filename(&midx_name, object_dir); + get_midx_filename(r->hash_algo, &midx_name, object_dir); m = load_multi_pack_index_one(r, object_dir, midx_name.buf, local); @@ -822,7 +826,7 @@ void clear_midx_file(struct repository *r) { struct strbuf midx = STRBUF_INIT; - get_midx_filename(&midx, r->objects->odb->path); + get_midx_filename(r->hash_algo, &midx, r->objects->odb->path); if (r->objects && r->objects->multi_pack_index) { close_midx(r->objects->multi_pack_index); @@ -891,7 +895,7 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag struct stat sb; struct strbuf filename = STRBUF_INIT; - get_midx_filename(&filename, object_dir); + get_midx_filename(r->hash_algo, &filename, object_dir); if (!stat(filename.buf, &sb)) { error(_("multi-pack-index file exists, but failed to parse")); diff --git a/midx.h b/midx.h index 78efa28d35..9d1374cbd5 100644 --- a/midx.h +++ b/midx.h @@ -7,6 +7,7 @@ struct object_id; struct pack_entry; struct repository; struct bitmapped_pack; +struct git_hash_algo; #define MIDX_SIGNATURE 0x4d494458 /* "MIDX" */ #define MIDX_VERSION 1 @@ -89,12 +90,15 @@ struct multi_pack_index { #define MIDX_EXT_MIDX "midx" const unsigned char *get_midx_checksum(struct multi_pack_index *m); -void get_midx_filename(struct strbuf *out, const char *object_dir); -void get_midx_filename_ext(struct strbuf *out, const char *object_dir, +void get_midx_filename(const struct git_hash_algo *hash_algo, + struct strbuf *out, const char *object_dir); +void get_midx_filename_ext(const struct git_hash_algo *hash_algo, + struct strbuf *out, const char *object_dir, const unsigned char *hash, const char *ext); void get_midx_chain_dirname(struct strbuf *buf, const char *object_dir); void get_midx_chain_filename(struct strbuf *buf, const char *object_dir); -void get_split_midx_filename_ext(struct strbuf *buf, const char *object_dir, +void get_split_midx_filename_ext(const struct git_hash_algo *hash_algo, + struct strbuf *buf, const char *object_dir, const unsigned char *hash, const char *ext); struct multi_pack_index *load_multi_pack_index(struct repository *r, diff --git a/pack-bitmap.c b/pack-bitmap.c index 0cb1b56c9d..7b62d099ca 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -375,8 +375,8 @@ static int load_bitmap_entries_v1(struct bitmap_index *index) char *midx_bitmap_filename(struct multi_pack_index *midx) { struct strbuf buf = STRBUF_INIT; - get_midx_filename_ext(&buf, midx->object_dir, get_midx_checksum(midx), - MIDX_EXT_BITMAP); + get_midx_filename_ext(midx->repo->hash_algo, &buf, midx->object_dir, + get_midx_checksum(midx), MIDX_EXT_BITMAP); return strbuf_detach(&buf, NULL); } @@ -415,7 +415,7 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git, if (bitmap_git->pack || bitmap_git->midx) { struct strbuf buf = STRBUF_INIT; - get_midx_filename(&buf, midx->object_dir); + get_midx_filename(midx->repo->hash_algo, &buf, midx->object_dir); trace2_data_string("bitmap", bitmap_repo(bitmap_git), "ignoring extra midx bitmap file", buf.buf); close(fd); diff --git a/pack-revindex.c b/pack-revindex.c index 22d3c23464..d3832478d9 100644 --- a/pack-revindex.c +++ b/pack-revindex.c @@ -383,7 +383,7 @@ int load_midx_revindex(struct multi_pack_index *m) trace2_data_string("load_midx_revindex", the_repository, "source", "rev"); - get_midx_filename_ext(&revindex_name, m->object_dir, + get_midx_filename_ext(m->repo->hash_algo, &revindex_name, m->object_dir, get_midx_checksum(m), MIDX_EXT_REV); ret = load_revindex_from_disk(revindex_name.buf, -- cgit v1.2.3 From 24d3dd79e4810ae7bafb3180664ac435fecd567f Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Wed, 27 Nov 2024 17:28:33 +0100 Subject: midx: inline the `MIDX_MIN_SIZE` definition The `MIDX_MIN_SIZE` definition is used to check the midx_size in `local_multi_pack_index_one`. This definition relies on the `the_hash_algo` global variable. Inline this and remove the global variable usage. With this, remove `USE_THE_REPOSITORY_VARIABLE` usage from `midx.c`. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- midx.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/midx.c b/midx.c index f45ea842cd..e0eae1c25e 100644 --- a/midx.c +++ b/midx.c @@ -1,5 +1,3 @@ -#define USE_THE_REPOSITORY_VARIABLE - #include "git-compat-util.h" #include "config.h" #include "dir.h" @@ -94,8 +92,6 @@ static int midx_read_object_offsets(const unsigned char *chunk_start, return 0; } -#define MIDX_MIN_SIZE (MIDX_HEADER_SIZE + the_hash_algo->rawsz) - static struct multi_pack_index *load_multi_pack_index_one(struct repository *r, const char *object_dir, const char *midx_name, @@ -122,7 +118,7 @@ static struct multi_pack_index *load_multi_pack_index_one(struct repository *r, midx_size = xsize_t(st.st_size); - if (midx_size < MIDX_MIN_SIZE) { + if (midx_size < (MIDX_HEADER_SIZE + r->hash_algo->rawsz)) { error(_("multi-pack-index file %s is too small"), midx_name); goto cleanup_fail; } -- cgit v1.2.3 From ad739f525eec917198887055f1a815e78d7c66be Mon Sep 17 00:00:00 2001 From: Bence Ferdinandy Date: Thu, 5 Dec 2024 13:16:20 +0100 Subject: fetch set_head: move warn advice into advise_if_enabled Advice about what to do when getting a warning is typed out explicitly twice and is printed as regular output. The output is also tested for. Extract the advice message into a single place and use a wrapper function, so if later the advice is made more chatty the signature only needs to be changed in once place. Remove the testing for the advice output in the tests. Signed-off-by: Bence Ferdinandy Signed-off-by: Junio C Hamano --- advice.c | 1 + advice.h | 1 + builtin/fetch.c | 17 +++++++++++++---- t/t5510-fetch.sh | 2 -- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/advice.c b/advice.c index 6b879d805c..66461fdce9 100644 --- a/advice.c +++ b/advice.c @@ -53,6 +53,7 @@ static struct { [ADVICE_COMMIT_BEFORE_MERGE] = { "commitBeforeMerge" }, [ADVICE_DETACHED_HEAD] = { "detachedHead" }, [ADVICE_DIVERGING] = { "diverging" }, + [ADVICE_FETCH_SET_HEAD_WARN] = { "fetchRemoteHEADWarn" }, [ADVICE_FETCH_SHOW_FORCED_UPDATES] = { "fetchShowForcedUpdates" }, [ADVICE_FORCE_DELETE_BRANCH] = { "forceDeleteBranch" }, [ADVICE_GRAFT_FILE_DEPRECATED] = { "graftFileDeprecated" }, diff --git a/advice.h b/advice.h index d7466bc0ef..cf2284ec43 100644 --- a/advice.h +++ b/advice.h @@ -20,6 +20,7 @@ enum advice_type { ADVICE_COMMIT_BEFORE_MERGE, ADVICE_DETACHED_HEAD, ADVICE_DIVERGING, + ADVICE_FETCH_SET_HEAD_WARN, ADVICE_FETCH_SHOW_FORCED_UPDATES, ADVICE_FORCE_DELETE_BRANCH, ADVICE_GRAFT_FILE_DEPRECATED, diff --git a/builtin/fetch.c b/builtin/fetch.c index 88c5c5d781..897e71325f 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1579,6 +1579,17 @@ static const char *strip_refshead(const char *name){ return name; } +static void set_head_advice_msg(const char *remote, const char *head_name) +{ + const char message_advice_set_head[] = + N_("Run 'git remote set-head %s %s' to follow the change, or set\n" + "'remote.%s.followRemoteHEAD' configuration option to a different value\n" + "if you do not want to see this message."); + + advise_if_enabled(ADVICE_FETCH_SET_HEAD_WARN, _(message_advice_set_head), + remote, head_name, remote); +} + static void report_set_head(const char *remote, const char *head_name, struct strbuf *buf_prev, int updateres) { struct strbuf buf_prefix = STRBUF_INIT; @@ -1590,15 +1601,13 @@ static void report_set_head(const char *remote, const char *head_name, if (prev_head && strcmp(prev_head, head_name)) { printf("'HEAD' at '%s' is '%s', but we have '%s' locally.\n", remote, head_name, prev_head); - printf("Run 'git remote set-head %s %s' to follow the change.\n", - remote, head_name); + set_head_advice_msg(remote, head_name); } else if (updateres && buf_prev->len) { printf("'HEAD' at '%s' is '%s', " "but we have a detached HEAD pointing to '%s' locally.\n", remote, head_name, buf_prev->buf); - printf("Run 'git remote set-head %s %s' to follow the change.\n", - remote, head_name); + set_head_advice_msg(remote, head_name); } strbuf_release(&buf_prefix); } diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 2467027d34..5c96591b9e 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -124,7 +124,6 @@ test_expect_success "fetch test followRemoteHEAD warn no change" ' git fetch >output && echo "${SQ}HEAD${SQ} at ${SQ}origin${SQ} is ${SQ}main${SQ}," \ "but we have ${SQ}other${SQ} locally." >expect && - echo "Run ${SQ}git remote set-head origin main${SQ} to follow the change." >>expect && test_cmp expect output && head=$(git rev-parse refs/remotes/origin/HEAD) && branch=$(git rev-parse refs/remotes/origin/other) && @@ -161,7 +160,6 @@ test_expect_success "fetch test followRemoteHEAD warn detached" ' echo "${SQ}HEAD${SQ} at ${SQ}origin${SQ} is ${SQ}main${SQ}," \ "but we have a detached HEAD pointing to" \ "${SQ}${HEAD}${SQ} locally." >expect && - echo "Run ${SQ}git remote set-head origin main${SQ} to follow the change." >>expect && test_cmp expect output ) ' -- cgit v1.2.3 From 9e2b7005becaf730ff75f6efbef4542cc4454107 Mon Sep 17 00:00:00 2001 From: Bence Ferdinandy Date: Thu, 5 Dec 2024 13:16:21 +0100 Subject: fetch set_head: add warn-if-not-$branch option Currently if we want to have a remote/HEAD locally that is different from the one on the remote, but we still want to get a warning if remote changes HEAD, our only option is to have an indiscriminate warning with "follow_remote_head" set to "warn". Add a new option "warn-if-not-$branch", where $branch is a branch name we do not wish to get a warning about. If the remote HEAD is $branch do not warn, otherwise, behave as "warn". E.g. let's assume, that our remote origin has HEAD set to "master", but locally we have "git remote set-head origin seen". Setting 'remote.origin.followRemoteHEAD = "warn"' will always print a warning, even though the remote has not changed HEAD from "master". Setting 'remote.origin.followRemoteHEAD = "warn-if-not-master" will squelch the warning message, unless the remote changes HEAD from "master". Note, that should the remote change HEAD to "seen" (which we have locally), there will still be no warning. Improve the advice message in report_set_head to also include silencing the warning message with "warn-if-not-$branch". Signed-off-by: Bence Ferdinandy Signed-off-by: Junio C Hamano --- Documentation/config/remote.txt | 8 +++++--- builtin/fetch.c | 16 +++++++++++----- remote.c | 13 +++++++++++-- remote.h | 1 + t/t5510-fetch.sh | 38 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 66 insertions(+), 10 deletions(-) diff --git a/Documentation/config/remote.txt b/Documentation/config/remote.txt index 024f92befc..4118c219c1 100644 --- a/Documentation/config/remote.txt +++ b/Documentation/config/remote.txt @@ -106,10 +106,12 @@ remote..followRemoteHEAD:: How linkgit:git-fetch[1] should handle updates to `remotes//HEAD`. The default value is "create", which will create `remotes//HEAD` if it exists on the remote, but not locally, but will not touch an - already existing local reference. Setting to "warn" will print + already existing local reference. Setting to "warn" will print a message if the remote has a different value, than the local one and - in case there is no local reference, it behaves like "create". Setting - to "always" will silently update it to the value on the remote. + in case there is no local reference, it behaves like "create". + A variant on "warn" is "warn-if-not-$branch", which behaves like + "warn", but if `HEAD` on the remote is `$branch` it will be silent. + Setting to "always" will silently update it to the value on the remote. Finally, setting it to "never" will never change or create the local reference. + diff --git a/builtin/fetch.c b/builtin/fetch.c index 897e71325f..c4257a7ead 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1584,10 +1584,12 @@ static void set_head_advice_msg(const char *remote, const char *head_name) const char message_advice_set_head[] = N_("Run 'git remote set-head %s %s' to follow the change, or set\n" "'remote.%s.followRemoteHEAD' configuration option to a different value\n" - "if you do not want to see this message."); + "if you do not want to see this message. Specifically running\n" + "'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n" + "until the remote changes HEAD to something else."); advise_if_enabled(ADVICE_FETCH_SET_HEAD_WARN, _(message_advice_set_head), - remote, head_name, remote); + remote, head_name, remote, remote, head_name); } static void report_set_head(const char *remote, const char *head_name, @@ -1612,7 +1614,8 @@ static void report_set_head(const char *remote, const char *head_name, strbuf_release(&buf_prefix); } -static int set_head(const struct ref *remote_refs, int follow_remote_head) +static int set_head(const struct ref *remote_refs, int follow_remote_head, + const char *no_warn_branch) { int result = 0, create_only, is_bare, was_detached; struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT, @@ -1669,7 +1672,9 @@ static int set_head(const struct ref *remote_refs, int follow_remote_head) result = 1; goto cleanup; } - if (follow_remote_head == FOLLOW_REMOTE_WARN && verbosity >= 0) + if (verbosity >= 0 && + follow_remote_head == FOLLOW_REMOTE_WARN && + (!no_warn_branch || strcmp(no_warn_branch, head_name))) report_set_head(remote, head_name, &b_local_head, was_detached); cleanup: @@ -1898,7 +1903,8 @@ static int do_fetch(struct transport *transport, "you need to specify exactly one branch with the --set-upstream option")); } } - if (set_head(remote_refs, transport->remote->follow_remote_head)) + if (set_head(remote_refs, transport->remote->follow_remote_head, + transport->remote->no_warn_branch)) ; /* * Way too many cases where this can go wrong diff --git a/remote.c b/remote.c index 0b18840d43..4ec5d3f47b 100644 --- a/remote.c +++ b/remote.c @@ -515,14 +515,23 @@ static int handle_config(const char *key, const char *value, return parse_transport_option(key, value, &remote->server_options); } else if (!strcmp(subkey, "followremotehead")) { + const char *no_warn_branch; if (!strcmp(value, "never")) remote->follow_remote_head = FOLLOW_REMOTE_NEVER; else if (!strcmp(value, "create")) remote->follow_remote_head = FOLLOW_REMOTE_CREATE; - else if (!strcmp(value, "warn")) + else if (!strcmp(value, "warn")) { remote->follow_remote_head = FOLLOW_REMOTE_WARN; - else if (!strcmp(value, "always")) + remote->no_warn_branch = NULL; + } else if (skip_prefix(value, "warn-if-not-", &no_warn_branch)) { + remote->follow_remote_head = FOLLOW_REMOTE_WARN; + remote->no_warn_branch = no_warn_branch; + } else if (!strcmp(value, "always")) { remote->follow_remote_head = FOLLOW_REMOTE_ALWAYS; + } else { + warning(_("unrecognized followRemoteHEAD value '%s' ignored"), + value); + } } return 0; } diff --git a/remote.h b/remote.h index 184b35653d..bda10dd5c8 100644 --- a/remote.h +++ b/remote.h @@ -116,6 +116,7 @@ struct remote { struct string_list server_options; enum follow_remote_head_settings follow_remote_head; + const char *no_warn_branch; }; /** diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 5c96591b9e..13881603f6 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -182,6 +182,44 @@ test_expect_success "fetch test followRemoteHEAD warn quiet" ' ) ' +test_expect_success "fetch test followRemoteHEAD warn-if-not-branch branch is same" ' + test_when_finished "git config unset remote.origin.followRemoteHEAD" && + ( + cd "$D" && + cd two && + git rev-parse --verify refs/remotes/origin/other && + git remote set-head origin other && + git rev-parse --verify refs/remotes/origin/HEAD && + git rev-parse --verify refs/remotes/origin/main && + git config set remote.origin.followRemoteHEAD "warn-if-not-main" && + actual=$(git fetch) && + test "z" = "z$actual" && + head=$(git rev-parse refs/remotes/origin/HEAD) && + branch=$(git rev-parse refs/remotes/origin/other) && + test "z$head" = "z$branch" + ) +' + +test_expect_success "fetch test followRemoteHEAD warn-if-not-branch branch is different" ' + test_when_finished "git config unset remote.origin.followRemoteHEAD" && + ( + cd "$D" && + cd two && + git rev-parse --verify refs/remotes/origin/other && + git remote set-head origin other && + git rev-parse --verify refs/remotes/origin/HEAD && + git rev-parse --verify refs/remotes/origin/main && + git config set remote.origin.followRemoteHEAD "warn-if-not-some/different-branch" && + git fetch >actual && + echo "${SQ}HEAD${SQ} at ${SQ}origin${SQ} is ${SQ}main${SQ}," \ + "but we have ${SQ}other${SQ} locally." >expect && + test_cmp expect actual && + head=$(git rev-parse refs/remotes/origin/HEAD) && + branch=$(git rev-parse refs/remotes/origin/other) && + test "z$head" = "z$branch" + ) +' + test_expect_success "fetch test followRemoteHEAD always" ' test_when_finished "git config unset remote.origin.followRemoteHEAD" && ( -- cgit v1.2.3 From 012bc566bad79876f4809d1e730a348b419772d0 Mon Sep 17 00:00:00 2001 From: Bence Ferdinandy Date: Thu, 5 Dec 2024 13:16:22 +0100 Subject: remote set-head: set followRemoteHEAD to "warn" if "always" When running "remote set-head" manually it is unlikely, that the user would actually like to have "fetch" always update the remote/HEAD. On the contrary, it is more likely, that the user would expect remote/HEAD to stay the way they manually set it, and just forgot about having "followRemoteHEAD" set to "always". When "followRemoteHEAD" is set to "always" make running "remote set-head" change the config to "warn". Signed-off-by: Bence Ferdinandy Signed-off-by: Junio C Hamano --- builtin/remote.c | 12 +++++++++++- t/t5505-remote.sh | 11 +++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/builtin/remote.c b/builtin/remote.c index 4a8b2ef678..9a30c17724 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -1433,6 +1433,7 @@ static int set_head(int argc, const char **argv, const char *prefix) b_local_head = STRBUF_INIT; char *head_name = NULL; struct ref_store *refs = get_main_ref_store(the_repository); + struct remote *remote; struct option options[] = { OPT_BOOL('a', "auto", &opt_a, @@ -1443,8 +1444,10 @@ static int set_head(int argc, const char **argv, const char *prefix) }; argc = parse_options(argc, argv, prefix, options, builtin_remote_sethead_usage, 0); - if (argc) + if (argc) { strbuf_addf(&b_head, "refs/remotes/%s/HEAD", argv[0]); + remote = remote_get(argv[0]); + } if (!opt_a && !opt_d && argc == 2) { head_name = xstrdup(argv[1]); @@ -1483,6 +1486,13 @@ static int set_head(int argc, const char **argv, const char *prefix) } if (opt_a) report_set_head_auto(argv[0], head_name, &b_local_head, was_detached); + if (remote->follow_remote_head == FOLLOW_REMOTE_ALWAYS) { + struct strbuf config_name = STRBUF_INIT; + strbuf_addf(&config_name, + "remote.%s.followremotehead", remote->name); + git_config_set(config_name.buf, "warn"); + strbuf_release(&config_name); + } cleanup: free(head_name); diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 2600add82a..93240a3602 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -505,6 +505,17 @@ test_expect_success 'set-head --auto has no problem w/multiple HEADs' ' ) ' +test_expect_success 'set-head changes followRemoteHEAD always to warn' ' + ( + cd test && + git config set remote.origin.followRemoteHEAD "always" && + git remote set-head --auto origin && + git config get remote.origin.followRemoteHEAD >actual && + echo "warn" >expect && + test_cmp expect actual + ) +' + cat >test/expect <<\EOF refs/remotes/origin/side2 EOF -- cgit v1.2.3 From 6c397d01046251b4d26f2aded07a695ada196962 Mon Sep 17 00:00:00 2001 From: Bence Ferdinandy Date: Thu, 5 Dec 2024 13:21:58 +0100 Subject: advice: suggest using subcommand "git config set" The advice message currently suggests using "git config advice..." to disable advice messages, but since 00bbdde141 (builtin/config: introduce "set" subcommand, 2024-05-06) we have the "set" subcommand for config. Since using the subcommand is more in-line with the modern interface, any advice should be promoting its usage. Change the disable advice message to use the subcommand instead. Change all uses of "git config advice" in the tests to use the subcommand. Signed-off-by: Bence Ferdinandy Signed-off-by: Junio C Hamano --- advice.c | 2 +- commit.c | 2 +- hook.c | 2 +- object-name.c | 2 +- t/t0018-advice.sh | 2 +- t/t3200-branch.sh | 2 +- t/t3404-rebase-interactive.sh | 6 +++--- t/t3501-revert-cherry-pick.sh | 2 +- t/t3507-cherry-pick-conflict.sh | 6 +++--- t/t3510-cherry-pick-sequence.sh | 2 +- t/t3511-cherry-pick-x.sh | 2 +- t/t3602-rm-sparse-checkout.sh | 2 +- t/t3700-add.sh | 6 +++--- t/t3705-add-sparse-checkout.sh | 2 +- t/t7002-mv-sparse-checkout.sh | 4 ++-- t/t7004-tag.sh | 2 +- t/t7201-co.sh | 4 ++-- t/t7400-submodule-basic.sh | 2 +- t/t7508-status.sh | 2 +- 19 files changed, 27 insertions(+), 27 deletions(-) diff --git a/advice.c b/advice.c index 6b879d805c..f7a5130c2c 100644 --- a/advice.c +++ b/advice.c @@ -93,7 +93,7 @@ static struct { static const char turn_off_instructions[] = N_("\n" - "Disable this message with \"git config advice.%s false\""); + "Disable this message with \"git config set advice.%s false\""); static void vadvise(const char *advice, int display_instructions, const char *key, va_list params) diff --git a/commit.c b/commit.c index 087cb19f4f..4a6ae863bb 100644 --- a/commit.c +++ b/commit.c @@ -270,7 +270,7 @@ static int read_graft_file(struct repository *r, const char *graft_file) "to convert the grafts into replace refs.\n" "\n" "Turn this message off by running\n" - "\"git config advice.graftFileDeprecated false\"")); + "\"git config set advice.graftFileDeprecated false\"")); while (!strbuf_getwholeline(&buf, fp, '\n')) { /* The format is just "Commit Parent1 Parent2 ...\n" */ struct commit_graft *graft = read_graft_line(&buf); diff --git a/hook.c b/hook.c index 7e90787bca..faeb01d9ac 100644 --- a/hook.c +++ b/hook.c @@ -39,7 +39,7 @@ const char *find_hook(const char *name) advise(_("The '%s' hook was ignored because " "it's not set as executable.\n" "You can disable this warning with " - "`git config advice.ignoredHook false`."), + "`git config set advice.ignoredHook false`."), path.buf); } } diff --git a/object-name.c b/object-name.c index 527b853ac4..dc7155c488 100644 --- a/object-name.c +++ b/object-name.c @@ -943,7 +943,7 @@ static int get_oid_basic(struct repository *r, const char *str, int len, "\n" "where \"$br\" is somehow empty and a 40-hex ref is created. Please\n" "examine these refs and maybe delete them. Turn this message off by\n" - "running \"git config advice.objectNameWarning false\""); + "running \"git config set advice.objectNameWarning false\""); struct object_id tmp_oid; char *real_ref = NULL; int refs_found = 0; diff --git a/t/t0018-advice.sh b/t/t0018-advice.sh index fac52322a7..4334766e6d 100755 --- a/t/t0018-advice.sh +++ b/t/t0018-advice.sh @@ -11,7 +11,7 @@ TEST_PASSES_SANITIZE_LEAK=true test_expect_success 'advice should be printed when config variable is unset' ' cat >expect <<-\EOF && hint: This is a piece of advice - hint: Disable this message with "git config advice.nestedTag false" + hint: Disable this message with "git config set advice.nestedTag false" EOF test-tool advise "This is a piece of advice" 2>actual && test_cmp expect actual diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index ccfa6a720d..a2e9ce03a5 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -1697,7 +1697,7 @@ test_expect_success 'errors if given a bad branch name' ' cat <<-\EOF >expect && fatal: '\''foo..bar'\'' is not a valid branch name hint: See `man git check-ref-format` - hint: Disable this message with "git config advice.refSyntax false" + hint: Disable this message with "git config set advice.refSyntax false" EOF test_must_fail git branch foo..bar >actual 2>&1 && test_cmp expect actual diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index f92baad138..6c077f9e9b 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -2235,20 +2235,20 @@ test_expect_success 'non-merge commands reject merge commits' ' error: ${SQ}pick${SQ} does not accept merge commits hint: ${SQ}pick${SQ} does not take a merge commit. If you wanted to hint: replay the merge, use ${SQ}merge -C${SQ} on the commit. - hint: Disable this message with "git config advice.rebaseTodoError false" + hint: Disable this message with "git config set advice.rebaseTodoError false" error: invalid line 1: pick $oid error: ${SQ}reword${SQ} does not accept merge commits hint: ${SQ}reword${SQ} does not take a merge commit. If you wanted to hint: replay the merge and reword the commit message, use hint: ${SQ}merge -c${SQ} on the commit - hint: Disable this message with "git config advice.rebaseTodoError false" + hint: Disable this message with "git config set advice.rebaseTodoError false" error: invalid line 2: reword $oid error: ${SQ}edit${SQ} does not accept merge commits hint: ${SQ}edit${SQ} does not take a merge commit. If you wanted to hint: replay the merge, use ${SQ}merge -C${SQ} on the commit, and then hint: ${SQ}break${SQ} to give the control back to you so that you can hint: do ${SQ}git commit --amend && git rebase --continue${SQ}. - hint: Disable this message with "git config advice.rebaseTodoError false" + hint: Disable this message with "git config set advice.rebaseTodoError false" error: invalid line 3: edit $oid error: cannot squash merge commit into another commit error: invalid line 4: fixup $oid diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh index 411027fb58..6e829f13bf 100755 --- a/t/t3501-revert-cherry-pick.sh +++ b/t/t3501-revert-cherry-pick.sh @@ -178,7 +178,7 @@ test_expect_success 'advice from failed revert' ' hint: You can instead skip this commit with "git revert --skip". hint: To abort and get back to the state before "git revert", hint: run "git revert --abort". - hint: Disable this message with "git config advice.mergeConflict false" + hint: Disable this message with "git config set advice.mergeConflict false" EOF test_commit --append --no-tag "double-add dream" dream dream && test_must_fail git revert HEAD^ 2>actual && diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh index f3947b400a..44596cb1e8 100755 --- a/t/t3507-cherry-pick-conflict.sh +++ b/t/t3507-cherry-pick-conflict.sh @@ -34,7 +34,7 @@ test_expect_success setup ' git commit --allow-empty --allow-empty-message && git tag empty && git checkout main && - git config advice.detachedhead false + git config set advice.detachedhead false ' @@ -60,7 +60,7 @@ test_expect_success 'advice from failed cherry-pick' ' hint: You can instead skip this commit with "git cherry-pick --skip". hint: To abort and get back to the state before "git cherry-pick", hint: run "git cherry-pick --abort". - hint: Disable this message with "git config advice.mergeConflict false" + hint: Disable this message with "git config set advice.mergeConflict false" EOF test_must_fail git cherry-pick picked 2>actual && @@ -75,7 +75,7 @@ test_expect_success 'advice from failed cherry-pick --no-commit' " error: could not apply \$picked... picked hint: after resolving the conflicts, mark the corrected paths hint: with 'git add ' or 'git rm ' - hint: Disable this message with \"git config advice.mergeConflict false\" + hint: Disable this message with \"git config set advice.mergeConflict false\" EOF test_must_fail git cherry-pick --no-commit picked 2>actual && diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh index 7eb52b12ed..66ff9db270 100755 --- a/t/t3510-cherry-pick-sequence.sh +++ b/t/t3510-cherry-pick-sequence.sh @@ -25,7 +25,7 @@ pristine_detach () { } test_expect_success setup ' - git config advice.detachedhead false && + git config set advice.detachedhead false && echo unrelated >unrelated && git add unrelated && test_commit initial foo a && diff --git a/t/t3511-cherry-pick-x.sh b/t/t3511-cherry-pick-x.sh index dd5d92ef30..dff0b2df9e 100755 --- a/t/t3511-cherry-pick-x.sh +++ b/t/t3511-cherry-pick-x.sh @@ -52,7 +52,7 @@ trailing empty lines " test_expect_success setup ' - git config advice.detachedhead false && + git config set advice.detachedhead false && echo unrelated >unrelated && git add unrelated && test_commit initial foo a && diff --git a/t/t3602-rm-sparse-checkout.sh b/t/t3602-rm-sparse-checkout.sh index fcdefba48c..bab3b1c85d 100755 --- a/t/t3602-rm-sparse-checkout.sh +++ b/t/t3602-rm-sparse-checkout.sh @@ -21,7 +21,7 @@ test_expect_success 'setup' " hint: If you intend to update such entries, try one of the following: hint: * Use the --sparse option. hint: * Disable or modify the sparsity rules. - hint: Disable this message with \"git config advice.updateSparsePath false\" + hint: Disable this message with \"git config set advice.updateSparsePath false\" EOF echo b | cat sparse_error_header - >sparse_entry_b_error && diff --git a/t/t3700-add.sh b/t/t3700-add.sh index 839c904745..7090ed2ef1 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -32,7 +32,7 @@ test_expect_success 'Test with no pathspecs' ' cat >expect <<-EOF && Nothing specified, nothing added. hint: Maybe you wanted to say ${SQ}git add .${SQ}? - hint: Disable this message with "git config advice.addEmptyPathspec false" + hint: Disable this message with "git config set advice.addEmptyPathspec false" EOF git add 2>actual && test_cmp expect actual @@ -376,7 +376,7 @@ test_expect_success '"git add" a embedded repository' ' hint: git rm --cached inner1 hint: hint: See "git help submodule" for more information. - hint: Disable this message with "git config advice.addEmbeddedRepo false" + hint: Disable this message with "git config set advice.addEmbeddedRepo false" warning: adding embedded git repository: inner2 EOF test_cmp expect actual @@ -414,7 +414,7 @@ cat >expect.err <<\EOF The following paths are ignored by one of your .gitignore files: ignored-file hint: Use -f if you really want to add them. -hint: Disable this message with "git config advice.addIgnoredFile false" +hint: Disable this message with "git config set advice.addIgnoredFile false" EOF cat >expect.out <<\EOF add 'track-this' diff --git a/t/t3705-add-sparse-checkout.sh b/t/t3705-add-sparse-checkout.sh index 2bade9e804..53a4782267 100755 --- a/t/t3705-add-sparse-checkout.sh +++ b/t/t3705-add-sparse-checkout.sh @@ -54,7 +54,7 @@ test_expect_success 'setup' " hint: If you intend to update such entries, try one of the following: hint: * Use the --sparse option. hint: * Disable or modify the sparsity rules. - hint: Disable this message with \"git config advice.updateSparsePath false\" + hint: Disable this message with \"git config set advice.updateSparsePath false\" EOF echo sparse_entry | cat sparse_error_header - >sparse_entry_error && diff --git a/t/t7002-mv-sparse-checkout.sh b/t/t7002-mv-sparse-checkout.sh index 57969ce805..5235092c1d 100755 --- a/t/t7002-mv-sparse-checkout.sh +++ b/t/t7002-mv-sparse-checkout.sh @@ -33,7 +33,7 @@ test_expect_success 'setup' " hint: If you intend to update such entries, try one of the following: hint: * Use the --sparse option. hint: * Disable or modify the sparsity rules. - hint: Disable this message with \"git config advice.updateSparsePath false\" + hint: Disable this message with \"git config set advice.updateSparsePath false\" EOF cat >dirty_error_header <<-EOF && @@ -46,7 +46,7 @@ test_expect_success 'setup' " hint: To correct the sparsity of these paths, do the following: hint: * Use \"git add --sparse \" to update the index hint: * Use \"git sparse-checkout reapply\" to apply the sparsity rules - hint: Disable this message with \"git config advice.updateSparsePath false\" + hint: Disable this message with \"git config set advice.updateSparsePath false\" EOF " diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index fa6336edf9..0ff4956869 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -1896,7 +1896,7 @@ test_expect_success 'recursive tagging should give advice' ' hint: already a tag. If you meant to tag the object that it points to, use: hint: hint: git tag -f nested annotated-v4.0^{} - hint: Disable this message with "git config advice.nestedTag false" + hint: Disable this message with "git config set advice.nestedTag false" EOF git tag -m nested nested annotated-v4.0 2>actual && test_cmp expect actual diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 2d984eb4c6..d4cf269431 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -225,7 +225,7 @@ test_expect_success 'switch to another branch while carrying a deletion' ' ' test_expect_success 'checkout to detach HEAD (with advice declined)' ' - git config advice.detachedHead false && + git config set advice.detachedHead false && rev=$(git rev-parse --short renamer^) && git checkout -f renamer && git clean -f && @@ -245,7 +245,7 @@ test_expect_success 'checkout to detach HEAD (with advice declined)' ' ' test_expect_success 'checkout to detach HEAD' ' - git config advice.detachedHead true && + git config set advice.detachedHead true && rev=$(git rev-parse --short renamer^) && git checkout -f renamer && git clean -f && diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 981488885f..d6a501d453 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -212,7 +212,7 @@ test_expect_success 'submodule add to .gitignored path fails' ' The following paths are ignored by one of your .gitignore files: submod hint: Use -f if you really want to add them. - hint: Disable this message with "git config advice.addIgnoredFile false" + hint: Disable this message with "git config set advice.addIgnoredFile false" EOF # Does not use test_commit due to the ignore echo "*" > .gitignore && diff --git a/t/t7508-status.sh b/t/t7508-status.sh index 773383fefb..22e310e277 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -1700,7 +1700,7 @@ test_expect_success 'setup slow status advice' ' EOF git add .gitignore && git commit -m "Add .gitignore" && - git config advice.statusuoption true + git config set advice.statusuoption true ) ' -- cgit v1.2.3 From db162862b36f8c2de8e7020801870abf33b61a20 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 6 Dec 2024 00:42:18 -0500 Subject: describe: split "found all tags" and max_candidates logic Commit a30154187a (describe: stop traversing when we run out of names, 2024-10-31) taught git-describe to automatically reduce the max_candidates setting to match the total number of possible names. This lets us break out of the traversal rather than fruitlessly searching for more candidates when there are no more to be found. However, setting max_candidates to 0 (e.g., if the repo has no tags) overlaps with the --exact-match option, which explicitly uses the same value. And this causes a regression with --always, which is ignored in exact-match mode. We used to get this in a repo with no tags: $ git describe --always HEAD b2f0a7f and now we get: $ git describe --always HEAD fatal: no tag exactly matches 'b2f0a7f47f5f2aebe1e7fceff19a57de20a78c06' The reason is that we bail early in describe_commit() when max_candidates is set to 0. This logic goes all the way back to 2c33f75754 (Teach git-describe --exact-match to avoid expensive tag searches, 2008-02-24). We should obviously fix this regression, but there are two paths, depending on what you think: $ git describe --always --exact-match and $ git describe --always --candidates=0 should do. Since the "--always" option was added, it has always been ignored in --exact-match (or --candidates=0) mode. I.e., we treat --exact-match as a true exact match of a tag, and never fall back to using --always, even if it was requested. If we think that's a bug (or at least a misfeature), then the right solution is to fix it by removing the early bail-out from 2c33f75754, letting the noop algorithm run and then hitting the --always fallback output. And then our regression naturally goes away, because it follows the same path. If we think that the current "--exact-match --always" behavior is the right thing, then we have to differentiate the case where we automatically reduced max_candidates to 0 from the case where the user asked for it specifically. That's possible to do with a flag, but we can also just reimplement the logic from a30154187a to explicitly break out of the traversal when we run out of candidates (rather than relying on the existing max_candidates check). My gut feeling is along the lines of option 1 (it's a bug, and people would be happy for "--exact-match --always" to give the fallback rather than ignoring "--always"). But the documentation can be interpreted in the other direction, and we've certainly lived with the existing behavior for many years. So it's possible that changing it now is the wrong thing. So this patch fixes the regression by taking the second option, retaining the "--exact-match" behavior as-is. There are two new tests. The first shows that the regression is fixed (we don't even need a new repo without tags; a restrictive --match is enough to create the situation that there are no candidate names). The second test confirms that the "--exact-match --always" behavior remains unchanged and continues to die when there is no tag pointing at the specified commit. It's possible we may reconsider this in the future, but this shows that the approach described above is implemented faithfully. We can also run the perf tests in p6100 to see that we've retained the speedup that a30154187a was going for: Test HEAD^ HEAD -------------------------------------------------------------------------------------- 6100.2: describe HEAD 0.72(0.64+0.07) 0.72(0.66+0.06) +0.0% 6100.3: describe HEAD with one max candidate 0.01(0.00+0.00) 0.01(0.00+0.00) +0.0% 6100.4: describe HEAD with one tag 0.01(0.01+0.00) 0.01(0.01+0.00) +0.0% Reported-by: Josh Steadmon Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin/describe.c | 5 ++--- t/t6120-describe.sh | 10 ++++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/builtin/describe.c b/builtin/describe.c index 8ec3be87df..a6ef8af32a 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -367,7 +367,8 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst) seen_commits++; - if (match_cnt == max_candidates) { + if (match_cnt == max_candidates || + match_cnt == hashmap_get_size(&names)) { gave_up_on = c; break; } @@ -667,8 +668,6 @@ int cmd_describe(int argc, NULL); if (!hashmap_get_size(&names) && !always) die(_("No names found, cannot describe anything.")); - if (hashmap_get_size(&names) < max_candidates) - max_candidates = hashmap_get_size(&names); if (argc == 0) { if (broken) { diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh index 69689d2f36..8e8bfed05b 100755 --- a/t/t6120-describe.sh +++ b/t/t6120-describe.sh @@ -716,4 +716,14 @@ test_expect_success 'describe --broken --dirty with a file with changed stat' ' ) ' +test_expect_success '--always with no refs falls back to commit hash' ' + git rev-parse HEAD >expect && + git describe --no-abbrev --always --match=no-such-tag >actual && + test_cmp expect actual +' + +test_expect_success '--exact-match does not show --always fallback' ' + test_must_fail git describe --exact-match --always +' + test_done -- cgit v1.2.3 From 2121a76d71e6742fe9627289b45717663bcef832 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 11:27:16 +0100 Subject: git-compat-util: introduce macros to disable "-Wsign-compare" warnings When compiling with DEVELOPER=YesPlease, we explicitly disable the "-Wsign-compare" warning. This is mostly because our code base is full of cases where we don't bother at all whether something should be signed or unsigned, and enabling the warning would thus cause tons of warnings to pop up. Unfortunately, disabling this warning also masks real issues. There have been multiple CVEs in the Git project that would have been flagged by this warning (e.g. CVE-2022-39260, CVE-2022-41903 and several fixes in the vicinity of these CVEs). Furthermore, the final audit report by X41 D-Sec, who are the ones who have discovered some of the CVEs, hinted that it might be a good idea to become more strict in this context. Now simply enabling the warning globally does not fly due to the stated reason above that we simply have too many sites where we use the wrong integer types. Instead, introduce a new set of macros that allow us to mark a file as being free of warnings with "-Wsign-compare". The mechanism is similar to what we do with `USE_THE_REPOSITORY_VARIABLE`: every file that is not marked with `DISABLE_SIGN_COMPARE_WARNINGS` will be compiled with those warnings enabled. These new markings will be wired up in the subsequent commits. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- git-compat-util.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/git-compat-util.h b/git-compat-util.h index a06d4f3809..e283c46c6f 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -44,6 +44,16 @@ struct strbuf; #define GIT_GNUC_PREREQ(maj, min) 0 #endif +#if defined(__GNUC__) || defined(__clang__) +# define PRAGMA(pragma) _Pragma(#pragma) +# define DISABLE_WARNING(warning) PRAGMA(GCC diagnostic ignored #warning) +#else +# define DISABLE_WARNING(warning) +#endif + +#ifdef DISABLE_SIGN_COMPARE_WARNINGS +DISABLE_WARNING(-Wsign-compare) +#endif #ifndef FLEX_ARRAY /* -- cgit v1.2.3 From 6e1d0ce47014f2d8434c54ef70dc9b43602652a5 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 11:27:17 +0100 Subject: compat/regex: explicitly ignore "-Wsign-compare" warnings Explicitly ignore "-Wsign-compare" warnings in our bundled copy of the regcomp implementation. We don't use the macro introduced in the preceding commit because this code does not include "git-compat-util.h" in the first place. Note that we already directly use "#pragma GCC diagnostic ignored" in "regcomp.c", so it shouldn't be an issue to use it directly in the new spot, either. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- compat/regex/regex.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compat/regex/regex.c b/compat/regex/regex.c index e6f4a5d177..4b09cc4e14 100644 --- a/compat/regex/regex.c +++ b/compat/regex/regex.c @@ -17,6 +17,8 @@ License along with the GNU C Library; if not, see . */ +#pragma GCC diagnostic ignored "-Wsign-compare" + #ifdef HAVE_CONFIG_H #include "config.h" #endif -- cgit v1.2.3 From 709fdce0893f93464435841e0eb9f6df3fd73807 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 11:27:18 +0100 Subject: compat/win32: fix -Wsign-compare warning in "wWinMain()" GCC generates a warning in "headless.c" because we compare `slash` with `size`, where the former is an `int` and the latter is a `size_t`. Fix the warning by storing `slash` as a `size_t`, as well. This commit is being singled out because the file does not include the "git-compat-util.h" header, and consequently, we cannot easily mark it with the `DISABLE_SIGN_COMPARE_WARNING` macro. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- compat/win32/headless.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/compat/win32/headless.c b/compat/win32/headless.c index 11392a0b9a..a6eb116ddc 100644 --- a/compat/win32/headless.c +++ b/compat/win32/headless.c @@ -53,7 +53,8 @@ int WINAPI wWinMain(_In_ HINSTANCE instance, wchar_t git_command_line[32768]; size_t size = sizeof(git_command_line) / sizeof(wchar_t); const wchar_t *needs_quotes = L""; - int slash = 0, i; + size_t slash = 0; + int len; STARTUPINFO startup_info = { .cb = sizeof(STARTUPINFO), @@ -66,7 +67,7 @@ int WINAPI wWinMain(_In_ HINSTANCE instance, DWORD exit_code; /* First, determine the full path of argv[0] */ - for (i = 0; _wpgmptr[i]; i++) + for (size_t i = 0; _wpgmptr[i]; i++) if (_wpgmptr[i] == L' ') needs_quotes = L"\""; else if (_wpgmptr[i] == L'\\') @@ -79,16 +80,16 @@ int WINAPI wWinMain(_In_ HINSTANCE instance, extend_path(_wpgmptr, slash); /* Then, add the full path of `git.exe` as argv[0] */ - i = swprintf_s(git_command_line, size, L"%ls%.*ls\\git.exe%ls", - needs_quotes, slash, _wpgmptr, needs_quotes); - if (i < 0) + len = swprintf_s(git_command_line, size, L"%ls%.*ls\\git.exe%ls", + needs_quotes, (int) slash, _wpgmptr, needs_quotes); + if (len < 0) return 127; /* Too long path */ if (*command_line) { /* Now, append the command-line arguments */ - i = swprintf_s(git_command_line + i, size - i, - L" %ls", command_line); - if (i < 0) + len = swprintf_s(git_command_line + len, size - len, + L" %ls", command_line); + if (len < 0) return 127; } -- cgit v1.2.3 From 41f43b8243f42b9df2e98be8460646d4c0100ad3 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 11:27:19 +0100 Subject: global: mark code units that generate warnings with `-Wsign-compare` Mark code units that generate warnings with `-Wsign-compare`. This allows for a structured approach to get rid of all such warnings over time in a way that can be easily measured. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- add-interactive.c | 1 + add-patch.c | 1 + advice.c | 2 ++ apply.c | 1 + archive.c | 1 + attr.c | 1 + base85.c | 2 ++ bisect.c | 1 + blame.c | 1 + bloom.c | 2 ++ builtin/add.c | 3 +++ builtin/am.c | 2 ++ builtin/bisect.c | 2 ++ builtin/blame.c | 3 +++ builtin/branch.c | 3 +++ builtin/cat-file.c | 3 +++ builtin/checkout--worker.c | 2 ++ builtin/checkout-index.c | 3 +++ builtin/checkout.c | 2 ++ builtin/clean.c | 3 +++ builtin/clone.c | 3 +++ builtin/commit.c | 3 +++ builtin/describe.c | 2 ++ builtin/diff-files.c | 3 +++ builtin/diff-index.c | 2 ++ builtin/diff-tree.c | 2 ++ builtin/diff.c | 3 +++ builtin/difftool.c | 3 +++ builtin/fast-export.c | 3 +++ builtin/fast-import.c | 2 ++ builtin/fetch-pack.c | 2 ++ builtin/fetch.c | 3 +++ builtin/for-each-repo.c | 2 ++ builtin/fsmonitor--daemon.c | 2 ++ builtin/gc.c | 3 +++ builtin/grep.c | 3 +++ builtin/help.c | 4 +++- builtin/index-pack.c | 2 ++ builtin/log.c | 3 +++ builtin/ls-files.c | 3 +++ builtin/mailsplit.c | 3 +++ builtin/merge-file.c | 2 ++ builtin/merge-index.c | 2 ++ builtin/merge-ours.c | 3 +++ builtin/merge-tree.c | 2 ++ builtin/merge.c | 3 +++ builtin/mv.c | 2 ++ builtin/name-rev.c | 2 ++ builtin/pack-objects.c | 2 ++ builtin/pack-redundant.c | 2 ++ builtin/pack-refs.c | 2 ++ builtin/patch-id.c | 2 ++ builtin/prune.c | 2 ++ builtin/pull.c | 2 ++ builtin/push.c | 3 +++ builtin/range-diff.c | 2 ++ builtin/rebase.c | 3 +++ builtin/receive-pack.c | 2 ++ builtin/reflog.c | 2 ++ builtin/remote.c | 2 ++ builtin/repack.c | 2 ++ builtin/replay.c | 4 +++- builtin/rerere.c | 2 ++ builtin/reset.c | 3 +++ builtin/rev-list.c | 2 ++ builtin/rev-parse.c | 3 +++ builtin/revert.c | 2 ++ builtin/rm.c | 3 +++ builtin/shortlog.c | 2 ++ builtin/show-branch.c | 2 ++ builtin/show-index.c | 2 ++ builtin/sparse-checkout.c | 2 ++ builtin/stash.c | 2 ++ builtin/submodule--helper.c | 2 ++ builtin/tag.c | 3 +++ builtin/unpack-objects.c | 2 ++ builtin/update-index.c | 3 +++ builtin/update-ref.c | 2 ++ builtin/var.c | 3 +++ builtin/worktree.c | 2 ++ bulk-checkin.c | 1 + bundle-uri.c | 1 + bundle.c | 1 + cache-tree.c | 1 + chunk-format.c | 1 + color.c | 2 ++ column.c | 2 ++ combine-diff.c | 1 + commit-graph.c | 1 + commit-reach.c | 1 + commit.c | 1 + compat/fsmonitor/fsm-listen-darwin.c | 2 ++ compat/mingw.c | 1 + compat/poll/poll.c | 2 ++ compat/terminal.c | 2 ++ compat/win32mmap.c | 2 ++ compat/winansi.c | 2 ++ config.c | 1 + connect.c | 1 + convert.c | 1 + credential.c | 1 + csum-file.c | 1 + daemon.c | 1 + date.c | 2 ++ decorate.c | 3 +++ delta-islands.c | 1 + diagnose.c | 1 + diff-delta.c | 2 ++ diff-lib.c | 1 + diff-merges.c | 2 ++ diff-no-index.c | 2 ++ diff.c | 1 + diffcore-order.c | 3 +++ diffcore-pickaxe.c | 3 +++ diffcore-rename.c | 1 + diffcore-rotate.c | 3 +++ dir.c | 1 + entry.c | 1 + ewah/ewah_bitmap.c | 3 +++ ewah/ewah_io.c | 3 +++ ewah/ewah_rlw.c | 3 +++ fetch-pack.c | 1 + fmt-merge-msg.c | 1 + fsmonitor.c | 1 + gettext.c | 2 ++ git.c | 1 + gpg-interface.c | 1 + graph.c | 1 + grep.c | 2 ++ help.c | 1 + hex.c | 1 + http-backend.c | 1 + http-push.c | 1 + http-walker.c | 1 + http.c | 1 + imap-send.c | 1 + json-writer.c | 2 ++ kwset.c | 2 ++ line-log.c | 2 ++ list-objects-filter-options.c | 1 + list-objects-filter.c | 1 + list-objects.c | 1 + log-tree.c | 1 + ls-refs.c | 1 + mailinfo.c | 1 + mailmap.c | 1 + match-trees.c | 1 + mem-pool.c | 2 ++ merge-ll.c | 1 + merge-ort.c | 1 + merge-recursive.c | 1 + merge.c | 1 + midx-write.c | 1 + midx.c | 1 + name-hash.c | 1 + notes-merge.c | 1 + notes.c | 1 + object-file-convert.c | 1 + object-file.c | 1 + object-name.c | 1 + object.c | 1 + pack-bitmap-write.c | 1 + pack-bitmap.c | 1 + pack-check.c | 1 + packfile.c | 1 + parallel-checkout.c | 1 + patch-ids.c | 2 ++ path.c | 1 + pathspec.c | 1 + pkt-line.c | 2 ++ preload-index.c | 1 + pretty.c | 1 + progress.c | 1 + pseudo-merge.c | 1 + quote.c | 2 ++ range-diff.c | 1 + reachable.c | 1 + read-cache.c | 1 + ref-filter.c | 1 + reflog-walk.c | 1 + reflog.c | 1 + refs.c | 1 + refs/debug.c | 2 ++ refs/files-backend.c | 1 + refs/iterator.c | 2 ++ refs/packed-backend.c | 1 + refspec.c | 1 + reftable/system.h | 2 ++ remote-curl.c | 1 + remote.c | 1 + rerere.c | 1 + resolve-undo.c | 1 + revision.c | 1 + run-command.c | 1 + scalar.c | 1 + send-pack.c | 1 + sequencer.c | 1 + serve.c | 1 + server-info.c | 1 + setup.c | 1 + shallow.c | 1 + sideband.c | 1 + sparse-index.c | 1 + split-index.c | 1 + strbuf.c | 2 ++ string-list.c | 2 ++ strvec.c | 2 ++ submodule-config.c | 1 + submodule.c | 1 + symlinks.c | 2 ++ t/helper/test-bloom.c | 1 + t/helper/test-cache-tree.c | 1 + t/helper/test-config.c | 1 + t/helper/test-csprng.c | 2 ++ t/helper/test-drop-caches.c | 2 ++ t/helper/test-dump-fsmonitor.c | 1 + t/helper/test-dump-split-index.c | 1 + t/helper/test-dump-untracked-cache.c | 1 + t/helper/test-genrandom.c | 2 ++ t/helper/test-genzeros.c | 2 ++ t/helper/test-hash-speed.c | 2 ++ t/helper/test-mergesort.c | 2 ++ t/helper/test-parse-options.c | 2 ++ t/helper/test-path-utils.c | 1 + t/helper/test-reach.c | 1 + t/helper/test-ref-store.c | 1 + t/helper/test-revision-walking.c | 1 + t/helper/test-run-command.c | 2 ++ t/helper/test-string-list.c | 2 ++ t/helper/test-tool.c | 2 ++ t/helper/test-trace2.c | 1 + t/unit-tests/lib-reftable.c | 2 ++ t/unit-tests/t-example-decorate.c | 1 + t/unit-tests/t-prio-queue.c | 2 ++ t/unit-tests/t-reftable-readwrite.c | 2 ++ t/unit-tests/t-reftable-stack.c | 2 ++ t/unit-tests/t-trailer.c | 2 ++ t/unit-tests/test-lib.c | 2 ++ tag.c | 1 + tmp-objdir.c | 1 + trace.c | 1 + trace2.c | 2 ++ trace2/tr2_sysenv.c | 2 ++ trace2/tr2_tgt_event.c | 2 ++ trace2/tr2_tgt_perf.c | 2 ++ trailer.c | 1 + transport-helper.c | 1 + transport.c | 1 + tree-diff.c | 1 + unix-socket.c | 2 ++ unpack-trees.c | 1 + upload-pack.c | 1 + urlmatch.c | 2 ++ usage.c | 3 +++ userdiff.c | 1 + utf8.c | 2 ++ version.c | 1 + versioncmp.c | 1 + worktree.c | 1 + wrapper.c | 3 +++ ws.c | 3 +++ wt-status.c | 1 + xdiff-interface.c | 1 + xdiff/xdiffi.c | 1 + xdiff/xinclude.h | 2 ++ 265 files changed, 439 insertions(+), 2 deletions(-) diff --git a/add-interactive.c b/add-interactive.c index 49042b3026..d0f8c10e6f 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "add-interactive.h" diff --git a/add-patch.c b/add-patch.c index 557903310d..7b598e14df 100644 --- a/add-patch.c +++ b/add-patch.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "add-interactive.h" diff --git a/advice.c b/advice.c index 6b879d805c..c2da976543 100644 --- a/advice.c +++ b/advice.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "advice.h" #include "config.h" diff --git a/apply.c b/apply.c index a3fc2d5330..4a7b6120ac 100644 --- a/apply.c +++ b/apply.c @@ -8,6 +8,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" diff --git a/archive.c b/archive.c index a7a92ff839..b9c200cba6 100644 --- a/archive.c +++ b/archive.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" diff --git a/attr.c b/attr.c index c605d2c170..67f11c96a5 100644 --- a/attr.c +++ b/attr.c @@ -7,6 +7,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/base85.c b/base85.c index bbacdca31b..a6b8272039 100644 --- a/base85.c +++ b/base85.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "base85.h" diff --git a/bisect.c b/bisect.c index d71c4e4b44..1a9069c9ad 100644 --- a/bisect.c +++ b/bisect.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/blame.c b/blame.c index bf69768a7d..a15ddf9333 100644 --- a/blame.c +++ b/blame.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "refs.h" diff --git a/bloom.c b/bloom.c index c428634105..0c8d2cebf9 100644 --- a/bloom.c +++ b/bloom.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "bloom.h" #include "diff.h" diff --git a/builtin/add.c b/builtin/add.c index 7d35307792..ff6a7d7fd0 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -3,6 +3,9 @@ * * Copyright (C) 2006 Linus Torvalds */ + +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "advice.h" #include "config.h" diff --git a/builtin/am.c b/builtin/am.c index bfa95147cf..f3b6546b30 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -5,6 +5,8 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "abspath.h" #include "advice.h" diff --git a/builtin/bisect.c b/builtin/bisect.c index 8166d4abf5..8b8d870cd1 100644 --- a/builtin/bisect.c +++ b/builtin/bisect.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "copy.h" #include "environment.h" diff --git a/builtin/blame.c b/builtin/blame.c index 6a7bb3b072..b33b44c89a 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -4,7 +4,10 @@ * Copyright (c) 2006, 2014 by its authors * See COPYING for licensing conditions */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "color.h" diff --git a/builtin/branch.c b/builtin/branch.c index 05ba4cd7a6..349a6be6d6 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -4,7 +4,10 @@ * Copyright (c) 2006 Kristian Høgsberg * Based on git-branch.sh by Junio C Hamano. */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "color.h" diff --git a/builtin/cat-file.c b/builtin/cat-file.c index bfdfb51c7c..825d7d83b2 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -3,7 +3,10 @@ * * Copyright (C) Linus Torvalds, 2005 */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "convert.h" diff --git a/builtin/checkout--worker.c b/builtin/checkout--worker.c index ff6cdccc21..b81002a1df 100644 --- a/builtin/checkout--worker.c +++ b/builtin/checkout--worker.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "entry.h" diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c index 6dd38eb05d..a81501098d 100644 --- a/builtin/checkout-index.c +++ b/builtin/checkout-index.c @@ -4,7 +4,10 @@ * Copyright (C) 2005 Linus Torvalds * */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "gettext.h" diff --git a/builtin/checkout.c b/builtin/checkout.c index c449558e66..1f92e8297b 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "advice.h" #include "branch.h" diff --git a/builtin/clean.c b/builtin/clean.c index 9c48dd0271..053c94fc6b 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -5,7 +5,10 @@ * * Based on git-clean.sh by Pavel Roskin */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "abspath.h" #include "config.h" diff --git a/builtin/clone.c b/builtin/clone.c index 21721db28a..fd001d800c 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -7,7 +7,10 @@ * * Clone a repository into a different directory that does not yet exist. */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "abspath.h" diff --git a/builtin/commit.c b/builtin/commit.c index 71d674138c..ef5e622c07 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -4,7 +4,10 @@ * Copyright (c) 2007 Kristian Høgsberg * Based on git-commit.sh by Junio C Hamano and Linus Torvalds */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "advice.h" #include "config.h" diff --git a/builtin/describe.c b/builtin/describe.c index 7330a77b38..9045e583b7 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "environment.h" diff --git a/builtin/diff-files.c b/builtin/diff-files.c index e0e0ccec23..604b04bb2c 100644 --- a/builtin/diff-files.c +++ b/builtin/diff-files.c @@ -3,7 +3,10 @@ * * Copyright (C) Linus Torvalds, 2005 */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "diff.h" diff --git a/builtin/diff-index.c b/builtin/diff-index.c index ad503624c0..ebc824602e 100644 --- a/builtin/diff-index.c +++ b/builtin/diff-index.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "diff.h" diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c index 4b6656bb9f..a4df2d0c13 100644 --- a/builtin/diff-tree.c +++ b/builtin/diff-tree.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "diff.h" diff --git a/builtin/diff.c b/builtin/diff.c index 2fe92f373e..a4fffee42c 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -3,7 +3,10 @@ * * Copyright (c) 2006 Junio C Hamano */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "ewah/ewok.h" diff --git a/builtin/difftool.c b/builtin/difftool.c index 40e971e225..1914708a76 100644 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@ -11,7 +11,10 @@ * * Copyright (C) 2016 Johannes Schindelin */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "abspath.h" diff --git a/builtin/fast-export.c b/builtin/fast-export.c index e17f262e8e..a5c82eef1d 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -3,7 +3,10 @@ * * Copyright (C) 2007 Johannes E. Schindelin */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "gettext.h" diff --git a/builtin/fast-import.c b/builtin/fast-import.c index 457cdb40cc..1cc5911bb0 100644 --- a/builtin/fast-import.c +++ b/builtin/fast-import.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "abspath.h" #include "environment.h" diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c index 62e8c3aa6b..bed2816c2d 100644 --- a/builtin/fetch-pack.c +++ b/builtin/fetch-pack.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "gettext.h" #include "hex.h" diff --git a/builtin/fetch.c b/builtin/fetch.c index 335083eb10..b7457a7274 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1,7 +1,10 @@ /* * "git fetch" */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "advice.h" #include "config.h" diff --git a/builtin/for-each-repo.c b/builtin/for-each-repo.c index fae7f91cf1..7e36be9d8a 100644 --- a/builtin/for-each-repo.c +++ b/builtin/for-each-repo.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "gettext.h" diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c index f3f6bd330b..029dc64d6c 100644 --- a/builtin/fsmonitor--daemon.c +++ b/builtin/fsmonitor--daemon.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "abspath.h" #include "config.h" diff --git a/builtin/gc.c b/builtin/gc.c index 364cb0eacf..a5879d6b6b 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -9,7 +9,10 @@ * * Copyright (c) 2006 Shawn O. Pearce */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "abspath.h" #include "date.h" diff --git a/builtin/grep.c b/builtin/grep.c index 98b85c7fca..d00ee76f24 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -3,7 +3,10 @@ * * Copyright (c) 2006 Junio C Hamano */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "abspath.h" #include "gettext.h" diff --git a/builtin/help.c b/builtin/help.c index 6a72d991a8..aa6bd6e412 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -1,8 +1,10 @@ - /* * Builtin help command */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "exec-cmd.h" diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 95babdc5ea..54c7faf6ee 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "delta.h" diff --git a/builtin/log.c b/builtin/log.c index 368f6580a6..cb41a035c6 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -4,7 +4,10 @@ * (C) Copyright 2006 Linus Torvalds * 2006 Junio Hamano */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "abspath.h" #include "config.h" diff --git a/builtin/ls-files.c b/builtin/ls-files.c index e016b0415d..15499cd12b 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -5,7 +5,10 @@ * * Copyright (C) Linus Torvalds, 2005 */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "convert.h" diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c index b8f7150ce9..52481f7f2e 100644 --- a/builtin/mailsplit.c +++ b/builtin/mailsplit.c @@ -4,6 +4,9 @@ * It just splits a mbox into a list of files: "0001" "0002" .. * so you can process them further from there. */ + +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "gettext.h" #include "string-list.h" diff --git a/builtin/merge-file.c b/builtin/merge-file.c index cb42865eb5..7e315f374b 100644 --- a/builtin/merge-file.c +++ b/builtin/merge-file.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "abspath.h" #include "diff.h" diff --git a/builtin/merge-index.c b/builtin/merge-index.c index a5b87ee3c5..342699edb7 100644 --- a/builtin/merge-index.c +++ b/builtin/merge-index.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "hex.h" #include "read-cache-ll.h" diff --git a/builtin/merge-ours.c b/builtin/merge-ours.c index 1fcf53f005..3672c6353f 100644 --- a/builtin/merge-ours.c +++ b/builtin/merge-ours.c @@ -7,7 +7,10 @@ * * Pretend we resolved the heads, but declare our tree trumps everybody else. */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "builtin.h" #include "diff.h" diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index c5ed472967..3328144029 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "tree-walk.h" #include "xdiff-interface.h" diff --git a/builtin/merge.c b/builtin/merge.c index 51038eaca8..a2712a0bab 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -5,7 +5,10 @@ * * Based on git-merge.sh by Junio C Hamano. */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "abspath.h" diff --git a/builtin/mv.c b/builtin/mv.c index 472a278737..55a7d471dc 100644 --- a/builtin/mv.c +++ b/builtin/mv.c @@ -3,7 +3,9 @@ * * Copyright (C) 2006 Johannes Schindelin */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "abspath.h" diff --git a/builtin/name-rev.c b/builtin/name-rev.c index 765eb20a93..beac166b5c 100644 --- a/builtin/name-rev.c +++ b/builtin/name-rev.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "environment.h" #include "gettext.h" diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 676a586709..a5d6f8db60 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "environment.h" #include "gettext.h" diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c index d2c1c4e5ec..978c42aae7 100644 --- a/builtin/pack-redundant.c +++ b/builtin/pack-redundant.c @@ -5,7 +5,9 @@ * This file is licensed under the GPL v2. * */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "gettext.h" diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c index 2d83c1ed2a..71175a713a 100644 --- a/builtin/pack-refs.c +++ b/builtin/pack-refs.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "gettext.h" diff --git a/builtin/patch-id.c b/builtin/patch-id.c index 93b398e391..5658575747 100644 --- a/builtin/patch-id.c +++ b/builtin/patch-id.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "diff.h" diff --git a/builtin/prune.c b/builtin/prune.c index 2b1de01339..aeff9ca1b3 100644 --- a/builtin/prune.c +++ b/builtin/prune.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "commit.h" #include "diff.h" diff --git a/builtin/pull.c b/builtin/pull.c index edc56907aa..6f8a32620c 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -7,6 +7,8 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "advice.h" #include "config.h" diff --git a/builtin/push.c b/builtin/push.c index 51c609f208..7174efed6d 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -1,7 +1,10 @@ /* * "git push" */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "advice.h" #include "branch.h" diff --git a/builtin/range-diff.c b/builtin/range-diff.c index 1b33ab66a7..aa88a46d9e 100644 --- a/builtin/range-diff.c +++ b/builtin/range-diff.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "gettext.h" #include "object-name.h" diff --git a/builtin/rebase.c b/builtin/rebase.c index bbaca3c5d5..0498fff3c9 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -3,7 +3,10 @@ * * Copyright (c) 2018 Pratik Karki */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "abspath.h" diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 9d2c07f68d..c2e9103f11 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "abspath.h" diff --git a/builtin/reflog.c b/builtin/reflog.c index 5a0c22f2f7..08e99a22b0 100644 --- a/builtin/reflog.c +++ b/builtin/reflog.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "gettext.h" diff --git a/builtin/remote.c b/builtin/remote.c index 1ad3e70a6b..b2b13a7dd2 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "gettext.h" diff --git a/builtin/repack.c b/builtin/repack.c index d6bb37e84a..fd2ef166de 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "dir.h" diff --git a/builtin/replay.c b/builtin/replay.c index 2d12a4e403..1afc6d1ee0 100644 --- a/builtin/replay.c +++ b/builtin/replay.c @@ -2,9 +2,11 @@ * "git replay" builtin command */ +#define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" -#define USE_THE_REPOSITORY_VARIABLE #include "builtin.h" #include "environment.h" #include "hex.h" diff --git a/builtin/rerere.c b/builtin/rerere.c index f7143c3f5d..706a947213 100644 --- a/builtin/rerere.c +++ b/builtin/rerere.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "gettext.h" diff --git a/builtin/reset.c b/builtin/reset.c index 7154f88826..f34d22190f 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -7,7 +7,10 @@ * * Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "advice.h" #include "config.h" diff --git a/builtin/rev-list.c b/builtin/rev-list.c index 3078787115..9b41d0b62a 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "commit.h" diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 8401b4d7ab..949747a6b6 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -3,7 +3,10 @@ * * Copyright (C) Linus Torvalds, 2005 */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "abspath.h" diff --git a/builtin/revert.c b/builtin/revert.c index b7917dddd3..4b57c2c383 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "builtin.h" #include "parse-options.h" diff --git a/builtin/rm.c b/builtin/rm.c index eaff027258..12ae086a55 100644 --- a/builtin/rm.c +++ b/builtin/rm.c @@ -3,7 +3,10 @@ * * Copyright (C) Linus Torvalds 2006 */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "advice.h" #include "config.h" diff --git a/builtin/shortlog.c b/builtin/shortlog.c index c86b75d981..1c46f13a16 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "commit.h" diff --git a/builtin/show-branch.c b/builtin/show-branch.c index cd6bdf63bc..fce6b404e9 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "environment.h" diff --git a/builtin/show-index.c b/builtin/show-index.c index f164c01bbe..3152d3c74b 100644 --- a/builtin/show-index.c +++ b/builtin/show-index.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "gettext.h" #include "hash.h" diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c index 34af5b2590..14dcace5f8 100644 --- a/builtin/sparse-checkout.c +++ b/builtin/sparse-checkout.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "dir.h" diff --git a/builtin/stash.c b/builtin/stash.c index c212b1c0b2..a79d23f1a3 100644 --- a/builtin/stash.c +++ b/builtin/stash.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "abspath.h" #include "config.h" diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 19e5878381..cfcaffee0d 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "abspath.h" #include "environment.h" diff --git a/builtin/tag.c b/builtin/tag.c index 5e1f904d35..9d4dfe8ab0 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -5,7 +5,10 @@ * Carlos Rica * Based on git-tag.sh and mktag.c by Linus Torvalds. */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "advice.h" #include "config.h" diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c index 02b8d02f63..2197d6d933 100644 --- a/builtin/unpack-objects.c +++ b/builtin/unpack-objects.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "bulk-checkin.h" #include "config.h" diff --git a/builtin/update-index.c b/builtin/update-index.c index 45b4a8b555..74bbad9f87 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -3,7 +3,10 @@ * * Copyright (C) Linus Torvalds, 2005 */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "bulk-checkin.h" #include "config.h" diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 670e7812d6..4d35bdc4b4 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "config.h" #include "gettext.h" diff --git a/builtin/var.c b/builtin/var.c index 2ecaed51b4..74aa39dd6b 100644 --- a/builtin/var.c +++ b/builtin/var.c @@ -3,7 +3,10 @@ * * Copyright (C) Eric Biederman, 2005 */ + #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "attr.h" diff --git a/builtin/worktree.c b/builtin/worktree.c index 824dd71d64..7dd46e7fc9 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -1,4 +1,6 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "builtin.h" #include "abspath.h" #include "advice.h" diff --git a/bulk-checkin.c b/bulk-checkin.c index 2753d5bbe4..4a70a70a95 100644 --- a/bulk-checkin.c +++ b/bulk-checkin.c @@ -3,6 +3,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "bulk-checkin.h" diff --git a/bundle-uri.c b/bundle-uri.c index 0df66e2872..38e1d66d79 100644 --- a/bundle-uri.c +++ b/bundle-uri.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "bundle-uri.h" diff --git a/bundle.c b/bundle.c index 4773b51eb1..0501b74252 100644 --- a/bundle.c +++ b/bundle.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "lockfile.h" diff --git a/cache-tree.c b/cache-tree.c index c595e86120..bcbcad3d61 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "gettext.h" diff --git a/chunk-format.c b/chunk-format.c index 2dde24e6a3..51b5a2c959 100644 --- a/chunk-format.c +++ b/chunk-format.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "chunk-format.h" diff --git a/color.c b/color.c index 227a5ab2f4..7df8862c71 100644 --- a/color.c +++ b/color.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "config.h" #include "color.h" diff --git a/column.c b/column.c index 50bbccc92e..93fae316b4 100644 --- a/column.c +++ b/column.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "config.h" #include "column.h" diff --git a/combine-diff.c b/combine-diff.c index 33d0ed7097..641bc92dbd 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "object-store-ll.h" diff --git a/commit-graph.c b/commit-graph.c index 5bd89c0acd..7623a158c8 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/commit-reach.c b/commit-reach.c index c3518aa360..e3edd11995 100644 --- a/commit-reach.c +++ b/commit-reach.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "commit.h" diff --git a/commit.c b/commit.c index cc03a93036..9c1f9fa236 100644 --- a/commit.c +++ b/commit.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "tag.h" diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c index dfa551459d..58f3878a22 100644 --- a/compat/fsmonitor/fsm-listen-darwin.c +++ b/compat/fsmonitor/fsm-listen-darwin.c @@ -23,6 +23,8 @@ #endif #endif +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "fsmonitor-ll.h" #include "fsm-listen.h" diff --git a/compat/mingw.c b/compat/mingw.c index 63f36c893b..408b1a3102 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "../git-compat-util.h" #include "win32.h" diff --git a/compat/poll/poll.c b/compat/poll/poll.c index afa6d24584..a2becd16cd 100644 --- a/compat/poll/poll.c +++ b/compat/poll/poll.c @@ -18,6 +18,8 @@ You should have received a copy of the GNU General Public License along with this program; if not, see . */ +#define DISABLE_SIGN_COMPARE_WARNINGS + /* To bump the minimum Windows version to Windows Vista */ #include "git-compat-util.h" diff --git a/compat/terminal.c b/compat/terminal.c index d54efa1c5d..7fe515b9c8 100644 --- a/compat/terminal.c +++ b/compat/terminal.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "compat/terminal.h" #include "gettext.h" diff --git a/compat/win32mmap.c b/compat/win32mmap.c index a4ab4cb939..e951934316 100644 --- a/compat/win32mmap.c +++ b/compat/win32mmap.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "../git-compat-util.h" void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) diff --git a/compat/winansi.c b/compat/winansi.c index 1b3f916b9f..ac2ffb7869 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -4,6 +4,8 @@ #undef NOGDI +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "../git-compat-util.h" #include #include diff --git a/config.c b/config.c index a11bb85da3..969bd8630f 100644 --- a/config.c +++ b/config.c @@ -7,6 +7,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" diff --git a/connect.c b/connect.c index 58f53d8dcb..10fad43e98 100644 --- a/connect.c +++ b/connect.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/convert.c b/convert.c index c9a31eb4f0..9cc0ca20ca 100644 --- a/convert.c +++ b/convert.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "advice.h" diff --git a/credential.c b/credential.c index 6dea3859ec..a995031c5f 100644 --- a/credential.c +++ b/credential.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" diff --git a/csum-file.c b/csum-file.c index c203ebf11b..c14bacc7f9 100644 --- a/csum-file.c +++ b/csum-file.c @@ -9,6 +9,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "progress.h" diff --git a/daemon.c b/daemon.c index a40e435c63..68789ceb22 100644 --- a/daemon.c +++ b/daemon.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" diff --git a/date.c b/date.c index bee9fe8f10..a1b26a8dce 100644 --- a/date.c +++ b/date.c @@ -4,6 +4,8 @@ * Copyright (C) Linus Torvalds, 2005 */ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "date.h" #include "gettext.h" diff --git a/decorate.c b/decorate.c index 69aeb142b4..e161e13772 100644 --- a/decorate.c +++ b/decorate.c @@ -2,6 +2,9 @@ * decorate.c - decorate a git object with some arbitrary * data. */ + +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "object.h" #include "decorate.h" diff --git a/delta-islands.c b/delta-islands.c index 8443551259..1c465a6041 100644 --- a/delta-islands.c +++ b/delta-islands.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "object.h" diff --git a/diagnose.c b/diagnose.c index cc2d535b60..f340996e27 100644 --- a/diagnose.c +++ b/diagnose.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "diagnose.h" diff --git a/diff-delta.c b/diff-delta.c index 77fea08dfb..a4faf73829 100644 --- a/diff-delta.c +++ b/diff-delta.c @@ -11,6 +11,8 @@ * published by the Free Software Foundation. */ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "delta.h" diff --git a/diff-lib.c b/diff-lib.c index 3cf353946f..c6d3bc4d37 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -3,6 +3,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "commit.h" diff --git a/diff-merges.c b/diff-merges.c index 45507588a2..0adfe7f5c0 100644 --- a/diff-merges.c +++ b/diff-merges.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "diff-merges.h" diff --git a/diff-no-index.c b/diff-no-index.c index c5fb06e6d1..6f277892d3 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -4,6 +4,8 @@ * Copyright (c) 2008 by Junio C Hamano */ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "abspath.h" #include "color.h" diff --git a/diff.c b/diff.c index dceac20d18..97417cc2a1 100644 --- a/diff.c +++ b/diff.c @@ -3,6 +3,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" diff --git a/diffcore-order.c b/diffcore-order.c index 912513d3e6..ec59d3d9bc 100644 --- a/diffcore-order.c +++ b/diffcore-order.c @@ -1,6 +1,9 @@ /* * Copyright (C) 2005 Junio C Hamano */ + +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "gettext.h" #include "diff.h" diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c index 43fef8e8ba..a52d569911 100644 --- a/diffcore-pickaxe.c +++ b/diffcore-pickaxe.c @@ -2,6 +2,9 @@ * Copyright (C) 2005 Junio C Hamano * Copyright (C) 2010 Google Inc. */ + +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "diff.h" #include "diffcore.h" diff --git a/diffcore-rename.c b/diffcore-rename.c index 1b1c1a6a1f..08ebb1fc3d 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -4,6 +4,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "diff.h" diff --git a/diffcore-rotate.c b/diffcore-rotate.c index 73ca20b331..941a022d5e 100644 --- a/diffcore-rotate.c +++ b/diffcore-rotate.c @@ -2,6 +2,9 @@ * Copyright (C) 2021, Google LLC. * Based on diffcore-order.c, which is Copyright (C) 2005, Junio C Hamano */ + +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "gettext.h" #include "diff.h" diff --git a/dir.c b/dir.c index 7f35a3e317..5b2181e589 100644 --- a/dir.c +++ b/dir.c @@ -7,6 +7,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" diff --git a/entry.c b/entry.c index 3143b9996b..93bd6a78ff 100644 --- a/entry.c +++ b/entry.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "object-store-ll.h" diff --git a/ewah/ewah_bitmap.c b/ewah/ewah_bitmap.c index 8785cbc54a..9be9bb3758 100644 --- a/ewah/ewah_bitmap.c +++ b/ewah/ewah_bitmap.c @@ -16,6 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ + +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "ewok.h" #include "ewok_rlw.h" diff --git a/ewah/ewah_io.c b/ewah/ewah_io.c index 9035ee65ea..da005523b0 100644 --- a/ewah/ewah_io.c +++ b/ewah/ewah_io.c @@ -16,6 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ + +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "ewok.h" #include "strbuf.h" diff --git a/ewah/ewah_rlw.c b/ewah/ewah_rlw.c index 5093d43e2f..76b4c6c19e 100644 --- a/ewah/ewah_rlw.c +++ b/ewah/ewah_rlw.c @@ -16,6 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ + +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "ewok.h" #include "ewok_rlw.h" diff --git a/fetch-pack.c b/fetch-pack.c index fe1fb3c1b7..961cbe2fe3 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "repository.h" diff --git a/fmt-merge-msg.c b/fmt-merge-msg.c index 6acb37b480..5b63c3b088 100644 --- a/fmt-merge-msg.c +++ b/fmt-merge-msg.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/fsmonitor.c b/fsmonitor.c index 309a2541cb..98b2b476f0 100644 --- a/fsmonitor.c +++ b/fsmonitor.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/gettext.c b/gettext.c index 57facbc21e..8d08a61f84 100644 --- a/gettext.c +++ b/gettext.c @@ -2,6 +2,8 @@ * Copyright (c) 2010 Ævar Arnfjörð Bjarmason */ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "abspath.h" #include "environment.h" diff --git a/git.c b/git.c index 46b3c740c5..cd33b1f405 100644 --- a/git.c +++ b/git.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "config.h" diff --git a/gpg-interface.c b/gpg-interface.c index 07335987a6..a67d80475b 100644 --- a/gpg-interface.c +++ b/gpg-interface.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "commit.h" diff --git a/graph.c b/graph.c index bf000fdbe1..52205f75c3 100644 --- a/graph.c +++ b/graph.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "gettext.h" diff --git a/grep.c b/grep.c index e95cded414..4e155ee9e6 100644 --- a/grep.c +++ b/grep.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "config.h" #include "gettext.h" diff --git a/help.c b/help.c index 8a830ba35c..5483ea8fd2 100644 --- a/help.c +++ b/help.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/hex.c b/hex.c index 5ca78a7744..e62406c182 100644 --- a/hex.c +++ b/hex.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "hash.h" diff --git a/http-backend.c b/http-backend.c index 73eec4ea3d..33cf378282 100644 --- a/http-backend.c +++ b/http-backend.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/http-push.c b/http-push.c index 4d24e6b8d4..a5e8c3e900 100644 --- a/http-push.c +++ b/http-push.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "environment.h" diff --git a/http-walker.c b/http-walker.c index 43cde0ebe5..7918ddc096 100644 --- a/http-walker.c +++ b/http-walker.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "repository.h" diff --git a/http.c b/http.c index bc64e57799..88bf3ba0a3 100644 --- a/http.c +++ b/http.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "git-curl-compat.h" diff --git a/imap-send.c b/imap-send.c index 25c68fd90d..68ab1aea83 100644 --- a/imap-send.c +++ b/imap-send.c @@ -22,6 +22,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/json-writer.c b/json-writer.c index 25b9201f9c..8c5187e9fd 100644 --- a/json-writer.c +++ b/json-writer.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "json-writer.h" diff --git a/kwset.c b/kwset.c index 695e47b7cc..1714eada60 100644 --- a/kwset.c +++ b/kwset.c @@ -32,6 +32,8 @@ String Matching: An Aid to Bibliographic Search," CACM June 1975, Vol. 18, No. 6, which describes the failure function used below. */ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "kwset.h" diff --git a/line-log.c b/line-log.c index bc67b75d10..628e3fe3ae 100644 --- a/line-log.c +++ b/line-log.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "diffcore.h" #include "line-range.h" diff --git a/list-objects-filter-options.c b/list-objects-filter-options.c index fa72e81e4a..d1f7c56e6f 100644 --- a/list-objects-filter-options.c +++ b/list-objects-filter-options.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/list-objects-filter.c b/list-objects-filter.c index dc598a081b..4afa3029dc 100644 --- a/list-objects-filter.c +++ b/list-objects-filter.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "dir.h" diff --git a/list-objects.c b/list-objects.c index 985d008799..2075c69496 100644 --- a/list-objects.c +++ b/list-objects.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "tag.h" diff --git a/log-tree.c b/log-tree.c index 83cc4b1cfb..d08eb672a9 100644 --- a/log-tree.c +++ b/log-tree.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "commit-reach.h" diff --git a/ls-refs.c b/ls-refs.c index c824aea714..89a796a356 100644 --- a/ls-refs.c +++ b/ls-refs.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "environment.h" diff --git a/mailinfo.c b/mailinfo.c index d1f42bd7e3..aa263bf490 100644 --- a/mailinfo.c +++ b/mailinfo.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/mailmap.c b/mailmap.c index 9f9fa3199a..f35d20ed7f 100644 --- a/mailmap.c +++ b/mailmap.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "environment.h" diff --git a/match-trees.c b/match-trees.c index 147b03abf1..a1c8b91eae 100644 --- a/match-trees.c +++ b/match-trees.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "hex.h" diff --git a/mem-pool.c b/mem-pool.c index a3ba38831d..62441dcc71 100644 --- a/mem-pool.c +++ b/mem-pool.c @@ -2,6 +2,8 @@ * Memory Pool implementation logic. */ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "mem-pool.h" #include "gettext.h" diff --git a/merge-ll.c b/merge-ll.c index 62fc625552..b2dc26da4f 100644 --- a/merge-ll.c +++ b/merge-ll.c @@ -5,6 +5,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/merge-ort.c b/merge-ort.c index 11029c10be..46e78c3ffa 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -15,6 +15,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "merge-ort.h" diff --git a/merge-recursive.c b/merge-recursive.c index ed64a4c537..5dfaf32b2c 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -5,6 +5,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "merge-recursive.h" diff --git a/merge.c b/merge.c index fe3efa4b24..da04fff3ba 100644 --- a/merge.c +++ b/merge.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "gettext.h" diff --git a/midx-write.c b/midx-write.c index b3a5f6c516..f1a6f83bae 100644 --- a/midx-write.c +++ b/midx-write.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" diff --git a/midx.c b/midx.c index e82d4f2e65..504e03327a 100644 --- a/midx.c +++ b/midx.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/name-hash.c b/name-hash.c index 95528e3bcd..d66de1cdfd 100644 --- a/name-hash.c +++ b/name-hash.c @@ -7,6 +7,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "environment.h" diff --git a/notes-merge.c b/notes-merge.c index dadbbabf86..8d701ed428 100644 --- a/notes-merge.c +++ b/notes-merge.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "advice.h" diff --git a/notes.c b/notes.c index f4f18daf07..f534423050 100644 --- a/notes.c +++ b/notes.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/object-file-convert.c b/object-file-convert.c index 3887d6d57b..eba71955cf 100644 --- a/object-file-convert.c +++ b/object-file-convert.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "gettext.h" diff --git a/object-file.c b/object-file.c index 891eaa2b4b..5b792b3dd4 100644 --- a/object-file.c +++ b/object-file.c @@ -8,6 +8,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" diff --git a/object-name.c b/object-name.c index c892fbe80a..d396778efc 100644 --- a/object-name.c +++ b/object-name.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "object-name.h" diff --git a/object.c b/object.c index 94ea8fb8d2..100bf9b8d1 100644 --- a/object.c +++ b/object.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "gettext.h" diff --git a/pack-bitmap-write.c b/pack-bitmap-write.c index 49758e2525..4f8be53c2b 100644 --- a/pack-bitmap-write.c +++ b/pack-bitmap-write.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "environment.h" diff --git a/pack-bitmap.c b/pack-bitmap.c index 683f467051..bbcf7e9401 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "commit.h" diff --git a/pack-check.c b/pack-check.c index e883dae3f2..8d9f6da7ce 100644 --- a/pack-check.c +++ b/pack-check.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "environment.h" diff --git a/packfile.c b/packfile.c index 9560f0a33c..f38c207fb6 100644 --- a/packfile.c +++ b/packfile.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "environment.h" diff --git a/parallel-checkout.c b/parallel-checkout.c index 01736f1352..7cc6b30528 100644 --- a/parallel-checkout.c +++ b/parallel-checkout.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/patch-ids.c b/patch-ids.c index a5683b462c..8b89198073 100644 --- a/patch-ids.c +++ b/patch-ids.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "diff.h" #include "commit.h" diff --git a/path.c b/path.c index 93491bab14..1f21004804 100644 --- a/path.c +++ b/path.c @@ -3,6 +3,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" diff --git a/pathspec.c b/pathspec.c index 0fc6f84a6e..89663645e1 100644 --- a/pathspec.c +++ b/pathspec.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" diff --git a/pkt-line.c b/pkt-line.c index 24479eae4d..90ea2b6974 100644 --- a/pkt-line.c +++ b/pkt-line.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "copy.h" #include "pkt-line.h" diff --git a/preload-index.c b/preload-index.c index 7926eb09a6..ab94d6f399 100644 --- a/preload-index.c +++ b/preload-index.c @@ -3,6 +3,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "pathspec.h" diff --git a/pretty.c b/pretty.c index 098378720a..0bc8ad8a9a 100644 --- a/pretty.c +++ b/pretty.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/progress.c b/progress.c index 0d44c18edc..a8fdfceb5c 100644 --- a/progress.c +++ b/progress.c @@ -10,6 +10,7 @@ #define GIT_TEST_PROGRESS_ONLY #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "pager.h" diff --git a/pseudo-merge.c b/pseudo-merge.c index bb59965ed2..971f54cfe1 100644 --- a/pseudo-merge.c +++ b/pseudo-merge.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "pseudo-merge.h" diff --git a/quote.c b/quote.c index 3c05194496..b9f6bdc775 100644 --- a/quote.c +++ b/quote.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "path.h" #include "quote.h" diff --git a/range-diff.c b/range-diff.c index 10885ba301..eea172bcc9 100644 --- a/range-diff.c +++ b/range-diff.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "environment.h" diff --git a/reachable.c b/reachable.c index 3e9b3dd0a4..34079e1ae9 100644 --- a/reachable.c +++ b/reachable.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "gettext.h" diff --git a/read-cache.c b/read-cache.c index 01d0b3ad22..15d79839c2 100644 --- a/read-cache.c +++ b/read-cache.c @@ -5,6 +5,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "bulk-checkin.h" diff --git a/ref-filter.c b/ref-filter.c index 84c6036107..23054694c2 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "environment.h" diff --git a/reflog-walk.c b/reflog-walk.c index c7070b13b0..b53628ed53 100644 --- a/reflog-walk.c +++ b/reflog-walk.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "commit.h" diff --git a/reflog.c b/reflog.c index aeab78c9b7..1b5f031f6d 100644 --- a/reflog.c +++ b/reflog.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "gettext.h" diff --git a/refs.c b/refs.c index 762f3e324d..02fb4b7cb2 100644 --- a/refs.c +++ b/refs.c @@ -3,6 +3,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "advice.h" diff --git a/refs/debug.c b/refs/debug.c index a893ae0c90..89fbd59320 100644 --- a/refs/debug.c +++ b/refs/debug.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "hex.h" #include "refs-internal.h" diff --git a/refs/files-backend.c b/refs/files-backend.c index 64f51f0da9..14aaf8cffc 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "../git-compat-util.h" #include "../abspath.h" diff --git a/refs/iterator.c b/refs/iterator.c index 8e999d81fc..d25e568bf0 100644 --- a/refs/iterator.c +++ b/refs/iterator.c @@ -3,6 +3,8 @@ * documentation about the design and use of reference iterators. */ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "refs.h" #include "refs/refs-internal.h" diff --git a/refs/packed-backend.c b/refs/packed-backend.c index 3406f1e71d..a7b6f74b6e 100644 --- a/refs/packed-backend.c +++ b/refs/packed-backend.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "../git-compat-util.h" #include "../config.h" diff --git a/refspec.c b/refspec.c index 994901f55b..6d86e04442 100644 --- a/refspec.c +++ b/refspec.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "gettext.h" diff --git a/reftable/system.h b/reftable/system.h index 5ec8583343..d3b8a55f4b 100644 --- a/reftable/system.h +++ b/reftable/system.h @@ -11,6 +11,8 @@ https://developers.google.com/open-source/licenses/bsd /* This header glues the reftable library to the rest of Git */ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "lockfile.h" #include "tempfile.h" diff --git a/remote-curl.c b/remote-curl.c index 9a71e04301..a24e3a8b9a 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "git-curl-compat.h" diff --git a/remote.c b/remote.c index 10104d11e3..a6d8c15189 100644 --- a/remote.c +++ b/remote.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" diff --git a/rerere.c b/rerere.c index d01e98bf65..e7fa6426b3 100644 --- a/rerere.c +++ b/rerere.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" diff --git a/resolve-undo.c b/resolve-undo.c index 8c9911affb..b5a9dfb4ac 100644 --- a/resolve-undo.c +++ b/resolve-undo.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "dir.h" diff --git a/revision.c b/revision.c index 347dabf7f9..a152916861 100644 --- a/revision.c +++ b/revision.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/run-command.c b/run-command.c index 94f2f3079f..402138b8b5 100644 --- a/run-command.c +++ b/run-command.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "run-command.h" diff --git a/scalar.c b/scalar.c index ac0cb579d3..87bb30991b 100644 --- a/scalar.c +++ b/scalar.c @@ -3,6 +3,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" diff --git a/send-pack.c b/send-pack.c index 6677c44e8a..6e68074e50 100644 --- a/send-pack.c +++ b/send-pack.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/sequencer.c b/sequencer.c index 459066e43b..407ee4e90f 100644 --- a/sequencer.c +++ b/sequencer.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" diff --git a/serve.c b/serve.c index d674764a25..1e08fa9251 100644 --- a/serve.c +++ b/serve.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "repository.h" diff --git a/server-info.c b/server-info.c index c5af4cd98a..ef2f3f4b5c 100644 --- a/server-info.c +++ b/server-info.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "dir.h" diff --git a/setup.c b/setup.c index 7b648de027..8084465197 100644 --- a/setup.c +++ b/setup.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" diff --git a/shallow.c b/shallow.c index 4bb1518dbc..82a8da3d73 100644 --- a/shallow.c +++ b/shallow.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "hex.h" diff --git a/sideband.c b/sideband.c index 02805573fa..251e9615ed 100644 --- a/sideband.c +++ b/sideband.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "color.h" diff --git a/sparse-index.c b/sparse-index.c index 2107840bfc..5634abafaa 100644 --- a/sparse-index.c +++ b/sparse-index.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "environment.h" diff --git a/split-index.c b/split-index.c index cfbc773e6c..4c74c4adda 100644 --- a/split-index.c +++ b/split-index.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "gettext.h" diff --git a/strbuf.c b/strbuf.c index 3d2189a7f6..8ddd4b06c5 100644 --- a/strbuf.c +++ b/strbuf.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "gettext.h" #include "hex-ll.h" diff --git a/string-list.c b/string-list.c index 954569f381..bf061fec56 100644 --- a/string-list.c +++ b/string-list.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "string-list.h" diff --git a/strvec.c b/strvec.c index d1cf4e2496..e8f87ab3a6 100644 --- a/strvec.c +++ b/strvec.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "strvec.h" #include "strbuf.h" diff --git a/submodule-config.c b/submodule-config.c index 9c8c37b259..a25059ed7f 100644 --- a/submodule-config.c +++ b/submodule-config.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "dir.h" diff --git a/submodule.c b/submodule.c index 7ec564854d..ed1441923d 100644 --- a/submodule.c +++ b/submodule.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" diff --git a/symlinks.c b/symlinks.c index b29e340c2d..9cc090d42c 100644 --- a/symlinks.c +++ b/symlinks.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "gettext.h" #include "setup.h" diff --git a/t/helper/test-bloom.c b/t/helper/test-bloom.c index 97541daf71..8d4ef44131 100644 --- a/t/helper/test-bloom.c +++ b/t/helper/test-bloom.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "test-tool.h" #include "bloom.h" diff --git a/t/helper/test-cache-tree.c b/t/helper/test-cache-tree.c index 5cdef3ebef..3ae45cec3b 100644 --- a/t/helper/test-cache-tree.c +++ b/t/helper/test-cache-tree.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "test-tool.h" #include "gettext.h" diff --git a/t/helper/test-config.c b/t/helper/test-config.c index 33247f0e92..75e028ab2a 100644 --- a/t/helper/test-config.c +++ b/t/helper/test-config.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "test-tool.h" #include "config.h" diff --git a/t/helper/test-csprng.c b/t/helper/test-csprng.c index 65d14973c5..ea9b9b6563 100644 --- a/t/helper/test-csprng.c +++ b/t/helper/test-csprng.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "test-tool.h" #include "git-compat-util.h" diff --git a/t/helper/test-drop-caches.c b/t/helper/test-drop-caches.c index 73e551cfc2..7055d94354 100644 --- a/t/helper/test-drop-caches.c +++ b/t/helper/test-drop-caches.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "test-tool.h" #include "git-compat-util.h" diff --git a/t/helper/test-dump-fsmonitor.c b/t/helper/test-dump-fsmonitor.c index 1b7f37a84f..7b78f9d182 100644 --- a/t/helper/test-dump-fsmonitor.c +++ b/t/helper/test-dump-fsmonitor.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "test-tool.h" #include "read-cache-ll.h" diff --git a/t/helper/test-dump-split-index.c b/t/helper/test-dump-split-index.c index a6720faf9c..f31b44a767 100644 --- a/t/helper/test-dump-split-index.c +++ b/t/helper/test-dump-split-index.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "test-tool.h" #include "hex.h" diff --git a/t/helper/test-dump-untracked-cache.c b/t/helper/test-dump-untracked-cache.c index b2e70837a9..ae05795800 100644 --- a/t/helper/test-dump-untracked-cache.c +++ b/t/helper/test-dump-untracked-cache.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "test-tool.h" #include "dir.h" diff --git a/t/helper/test-genrandom.c b/t/helper/test-genrandom.c index 99b8dc1e2d..5b51e6648d 100644 --- a/t/helper/test-genrandom.c +++ b/t/helper/test-genrandom.c @@ -4,6 +4,8 @@ * Copyright (C) 2007 by Nicolas Pitre, licensed under the GPL version 2. */ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "test-tool.h" #include "git-compat-util.h" diff --git a/t/helper/test-genzeros.c b/t/helper/test-genzeros.c index 47af843b68..b895436a32 100644 --- a/t/helper/test-genzeros.c +++ b/t/helper/test-genzeros.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "test-tool.h" #include "git-compat-util.h" diff --git a/t/helper/test-hash-speed.c b/t/helper/test-hash-speed.c index 7de822af51..81a446dd64 100644 --- a/t/helper/test-hash-speed.c +++ b/t/helper/test-hash-speed.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "test-tool.h" #include "hash.h" diff --git a/t/helper/test-mergesort.c b/t/helper/test-mergesort.c index 328bfe2977..791e128793 100644 --- a/t/helper/test-mergesort.c +++ b/t/helper/test-mergesort.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "test-tool.h" #include "mem-pool.h" #include "mergesort.h" diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c index 5da359486c..25ba08a7c3 100644 --- a/t/helper/test-parse-options.c +++ b/t/helper/test-parse-options.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "test-tool.h" #include "parse-options.h" #include "strbuf.h" diff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c index 3129aa28fd..72ac8d1b1b 100644 --- a/t/helper/test-path-utils.c +++ b/t/helper/test-path-utils.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "test-tool.h" #include "abspath.h" diff --git a/t/helper/test-reach.c b/t/helper/test-reach.c index 84deee604a..25c232464d 100644 --- a/t/helper/test-reach.c +++ b/t/helper/test-reach.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "test-tool.h" #include "commit.h" diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c index 240f6fc29d..c5c4cb142d 100644 --- a/t/helper/test-ref-store.c +++ b/t/helper/test-ref-store.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "test-tool.h" #include "hex.h" diff --git a/t/helper/test-revision-walking.c b/t/helper/test-revision-walking.c index 071f5bd1e2..3b931a34a2 100644 --- a/t/helper/test-revision-walking.c +++ b/t/helper/test-revision-walking.c @@ -9,6 +9,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "test-tool.h" #include "commit.h" diff --git a/t/helper/test-run-command.c b/t/helper/test-run-command.c index 61eb1175fe..3719f23cc2 100644 --- a/t/helper/test-run-command.c +++ b/t/helper/test-run-command.c @@ -8,6 +8,8 @@ * published by the Free Software Foundation. */ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "test-tool.h" #include "run-command.h" #include "strvec.h" diff --git a/t/helper/test-string-list.c b/t/helper/test-string-list.c index e2aad611d1..6f10c5a435 100644 --- a/t/helper/test-string-list.c +++ b/t/helper/test-string-list.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "test-tool.h" #include "strbuf.h" #include "string-list.h" diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c index 1ebb69a5dc..b626f64eca 100644 --- a/t/helper/test-tool.c +++ b/t/helper/test-tool.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "test-tool.h" #include "test-tool-utils.h" diff --git a/t/helper/test-trace2.c b/t/helper/test-trace2.c index c588c273ce..415df078c1 100644 --- a/t/helper/test-trace2.c +++ b/t/helper/test-trace2.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "test-tool.h" #include "strvec.h" diff --git a/t/unit-tests/lib-reftable.c b/t/unit-tests/lib-reftable.c index 2ddf480588..7bc742e4f7 100644 --- a/t/unit-tests/lib-reftable.c +++ b/t/unit-tests/lib-reftable.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "lib-reftable.h" #include "test-lib.h" #include "reftable/constants.h" diff --git a/t/unit-tests/t-example-decorate.c b/t/unit-tests/t-example-decorate.c index 8bf0709c41..61da8e1c8b 100644 --- a/t/unit-tests/t-example-decorate.c +++ b/t/unit-tests/t-example-decorate.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "test-lib.h" #include "object.h" diff --git a/t/unit-tests/t-prio-queue.c b/t/unit-tests/t-prio-queue.c index fe6ae37935..a3d1aabab5 100644 --- a/t/unit-tests/t-prio-queue.c +++ b/t/unit-tests/t-prio-queue.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "test-lib.h" #include "prio-queue.h" diff --git a/t/unit-tests/t-reftable-readwrite.c b/t/unit-tests/t-reftable-readwrite.c index d279b86df0..d38092ff83 100644 --- a/t/unit-tests/t-reftable-readwrite.c +++ b/t/unit-tests/t-reftable-readwrite.c @@ -6,6 +6,8 @@ license that can be found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd */ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "test-lib.h" #include "lib-reftable.h" #include "reftable/basics.h" diff --git a/t/unit-tests/t-reftable-stack.c b/t/unit-tests/t-reftable-stack.c index 72f6747064..4377c0af1b 100644 --- a/t/unit-tests/t-reftable-stack.c +++ b/t/unit-tests/t-reftable-stack.c @@ -6,6 +6,8 @@ license that can be found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd */ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "test-lib.h" #include "lib-reftable.h" #include "reftable/merged.h" diff --git a/t/unit-tests/t-trailer.c b/t/unit-tests/t-trailer.c index e1c6ad7461..184593e73d 100644 --- a/t/unit-tests/t-trailer.c +++ b/t/unit-tests/t-trailer.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "test-lib.h" #include "trailer.h" diff --git a/t/unit-tests/test-lib.c b/t/unit-tests/test-lib.c index fa1f95965c..87e1f5c201 100644 --- a/t/unit-tests/test-lib.c +++ b/t/unit-tests/test-lib.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "test-lib.h" enum result { diff --git a/tag.c b/tag.c index d24170e340..332fc338e9 100644 --- a/tag.c +++ b/tag.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "environment.h" diff --git a/tmp-objdir.c b/tmp-objdir.c index 9da0071cba..b9084d0ac3 100644 --- a/tmp-objdir.c +++ b/tmp-objdir.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "tmp-objdir.h" diff --git a/trace.c b/trace.c index d8c43773ae..2cfd25942e 100644 --- a/trace.c +++ b/trace.c @@ -22,6 +22,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" diff --git a/trace2.c b/trace2.c index f894532d05..82d16e2783 100644 --- a/trace2.c +++ b/trace2.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "config.h" #include "repository.h" diff --git a/trace2/tr2_sysenv.c b/trace2/tr2_sysenv.c index 048cdd5438..01379c5cad 100644 --- a/trace2/tr2_sysenv.c +++ b/trace2/tr2_sysenv.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "config.h" #include "dir.h" diff --git a/trace2/tr2_tgt_event.c b/trace2/tr2_tgt_event.c index 45b0850a5e..69ee40449f 100644 --- a/trace2/tr2_tgt_event.c +++ b/trace2/tr2_tgt_event.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "config.h" #include "json-writer.h" diff --git a/trace2/tr2_tgt_perf.c b/trace2/tr2_tgt_perf.c index a6f9a8a193..298ae27f9d 100644 --- a/trace2/tr2_tgt_perf.c +++ b/trace2/tr2_tgt_perf.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "config.h" #include "repository.h" diff --git a/trailer.c b/trailer.c index 46f0e4610b..b7e4063285 100644 --- a/trailer.c +++ b/trailer.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/transport-helper.c b/transport-helper.c index bc27653cde..387c67d5bd 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "transport.h" diff --git a/transport.c b/transport.c index 47fda6a773..abf0ff5706 100644 --- a/transport.c +++ b/transport.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "advice.h" diff --git a/tree-diff.c b/tree-diff.c index 5eab8af631..d9237ffd9b 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -3,6 +3,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "diff.h" diff --git a/unix-socket.c b/unix-socket.c index 79800d8063..483c9c448c 100644 --- a/unix-socket.c +++ b/unix-socket.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "strbuf.h" #include "unix-socket.h" diff --git a/unpack-trees.c b/unpack-trees.c index e10a9d1209..b3be5d542f 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "advice.h" diff --git a/upload-pack.c b/upload-pack.c index 43006c0614..728b2477fc 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/urlmatch.c b/urlmatch.c index 1d0254abac..eea8300489 100644 --- a/urlmatch.c +++ b/urlmatch.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "gettext.h" #include "hex-ll.h" diff --git a/usage.c b/usage.c index 29a9725784..8c672a57f6 100644 --- a/usage.c +++ b/usage.c @@ -3,6 +3,9 @@ * * Copyright (C) Linus Torvalds, 2005 */ + +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "gettext.h" #include "trace2.h" diff --git a/userdiff.c b/userdiff.c index d43d8360d1..340c4eb4f7 100644 --- a/userdiff.c +++ b/userdiff.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/utf8.c b/utf8.c index 6bfaefa28e..35a0251939 100644 --- a/utf8.c +++ b/utf8.c @@ -1,3 +1,5 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "strbuf.h" #include "utf8.h" diff --git a/version.c b/version.c index 41b718c29e..d5aadab709 100644 --- a/version.c +++ b/version.c @@ -1,3 +1,4 @@ +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "version.h" #include "strbuf.h" diff --git a/versioncmp.c b/versioncmp.c index e3b2a6e330..71cef7e858 100644 --- a/versioncmp.c +++ b/versioncmp.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" diff --git a/worktree.c b/worktree.c index 77ff484d3e..86b36f5190 100644 --- a/worktree.c +++ b/worktree.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" diff --git a/wrapper.c b/wrapper.c index f87d90bf57..fa79fd6ec9 100644 --- a/wrapper.c +++ b/wrapper.c @@ -1,6 +1,9 @@ /* * Various trivial helper wrappers around standard functions */ + +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "abspath.h" #include "parse.h" diff --git a/ws.c b/ws.c index 9456e2fdbe..70acee3337 100644 --- a/ws.c +++ b/ws.c @@ -3,6 +3,9 @@ * * Copyright (c) 2007 Junio C Hamano */ + +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "attr.h" #include "strbuf.h" diff --git a/wt-status.c b/wt-status.c index 6a8c05d1cf..3ee9181764 100644 --- a/wt-status.c +++ b/wt-status.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "advice.h" diff --git a/xdiff-interface.c b/xdiff-interface.c index d5dc88661e..3bd61f26e9 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -1,4 +1,5 @@ #define USE_THE_REPOSITORY_VARIABLE +#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "gettext.h" diff --git a/xdiff/xdiffi.c b/xdiff/xdiffi.c index 344c2dfc3e..4685ba6137 100644 --- a/xdiff/xdiffi.c +++ b/xdiff/xdiffi.c @@ -19,6 +19,7 @@ * Davide Libenzi * */ +#define DISABLE_SIGN_COMPARE_WARNINGS #include "xinclude.h" diff --git a/xdiff/xinclude.h b/xdiff/xinclude.h index a4285ac0eb..7e56542526 100644 --- a/xdiff/xinclude.h +++ b/xdiff/xinclude.h @@ -23,6 +23,8 @@ #if !defined(XINCLUDE_H) #define XINCLUDE_H +#define DISABLE_SIGN_COMPARE_WARNINGS + #include "git-compat-util.h" #include "xmacros.h" #include "xdiff.h" -- cgit v1.2.3 From 4f9264b0cdf588745ebd71638a216e626b89df35 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 11:27:20 +0100 Subject: config.mak.dev: drop `-Wno-sign-compare` There is no need anymore to disable `-Wsign-compare` now that all files that cause warnings have been marked accordingly. Drop the option. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- config.mak.dev | 1 - 1 file changed, 1 deletion(-) diff --git a/config.mak.dev b/config.mak.dev index 8eca7fa228..0fd8cc4d35 100644 --- a/config.mak.dev +++ b/config.mak.dev @@ -53,7 +53,6 @@ ifeq ($(filter extra-all,$(DEVOPTS)),) # These are disabled because we have these all over the place. DEVELOPER_CFLAGS += -Wno-empty-body DEVELOPER_CFLAGS += -Wno-missing-field-initializers -DEVELOPER_CFLAGS += -Wno-sign-compare endif endif -- cgit v1.2.3 From 47d72a74a737f06791c282a75baf2c573cdf42f6 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 11:27:21 +0100 Subject: diff.h: fix index used to loop through unsigned integer The `struct diff_flags` structure is essentially an array of flags, all of which have the same type. We can thus use `sizeof()` to iterate through all of the flags, which we do in `diff_flags_or()`. But while the statement returns an unsigned integer, we used a signed integer to iterate through the flags, which generates a warning. Fix this by using `size_t` for the index instead. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/am.c | 1 - builtin/diff-tree.c | 1 - builtin/merge-ours.c | 1 - builtin/pack-refs.c | 1 - builtin/range-diff.c | 1 - builtin/reflog.c | 1 - builtin/reset.c | 1 - builtin/revert.c | 1 - builtin/shortlog.c | 1 - diff-merges.c | 2 -- diff.h | 3 +-- diffcore-order.c | 2 -- diffcore-rotate.c | 2 -- list-objects-filter.c | 1 - patch-ids.c | 2 -- reachable.c | 1 - reflog-walk.c | 1 - t/helper/test-revision-walking.c | 1 - 18 files changed, 1 insertion(+), 23 deletions(-) diff --git a/builtin/am.c b/builtin/am.c index f3b6546b30..1338b606fe 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -5,7 +5,6 @@ */ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "abspath.h" diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c index a4df2d0c13..40804e7b48 100644 --- a/builtin/diff-tree.c +++ b/builtin/diff-tree.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "config.h" diff --git a/builtin/merge-ours.c b/builtin/merge-ours.c index 3672c6353f..3ecd9172f1 100644 --- a/builtin/merge-ours.c +++ b/builtin/merge-ours.c @@ -9,7 +9,6 @@ */ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "builtin.h" diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c index 71175a713a..4fdd68880e 100644 --- a/builtin/pack-refs.c +++ b/builtin/pack-refs.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "config.h" diff --git a/builtin/range-diff.c b/builtin/range-diff.c index aa88a46d9e..433c305fc5 100644 --- a/builtin/range-diff.c +++ b/builtin/range-diff.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "gettext.h" diff --git a/builtin/reflog.c b/builtin/reflog.c index 08e99a22b0..95f264989b 100644 --- a/builtin/reflog.c +++ b/builtin/reflog.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "config.h" diff --git a/builtin/reset.c b/builtin/reset.c index f34d22190f..73b4537a9a 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -9,7 +9,6 @@ */ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "advice.h" diff --git a/builtin/revert.c b/builtin/revert.c index 4b57c2c383..aca6c293cd 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "builtin.h" diff --git a/builtin/shortlog.c b/builtin/shortlog.c index 1c46f13a16..30075b67be 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "config.h" diff --git a/diff-merges.c b/diff-merges.c index 0adfe7f5c0..45507588a2 100644 --- a/diff-merges.c +++ b/diff-merges.c @@ -1,5 +1,3 @@ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "git-compat-util.h" #include "diff-merges.h" diff --git a/diff.h b/diff.h index 5c8de79535..6e6007c17b 100644 --- a/diff.h +++ b/diff.h @@ -205,9 +205,8 @@ static inline void diff_flags_or(struct diff_flags *a, { char *tmp_a = (char *)a; const char *tmp_b = (const char *)b; - int i; - for (i = 0; i < sizeof(struct diff_flags); i++) + for (size_t i = 0; i < sizeof(struct diff_flags); i++) tmp_a[i] |= tmp_b[i]; } diff --git a/diffcore-order.c b/diffcore-order.c index ec59d3d9bc..f91ef22471 100644 --- a/diffcore-order.c +++ b/diffcore-order.c @@ -2,8 +2,6 @@ * Copyright (C) 2005 Junio C Hamano */ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "git-compat-util.h" #include "gettext.h" #include "diff.h" diff --git a/diffcore-rotate.c b/diffcore-rotate.c index 941a022d5e..67b591261a 100644 --- a/diffcore-rotate.c +++ b/diffcore-rotate.c @@ -3,8 +3,6 @@ * Based on diffcore-order.c, which is Copyright (C) 2005, Junio C Hamano */ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "git-compat-util.h" #include "gettext.h" #include "diff.h" diff --git a/list-objects-filter.c b/list-objects-filter.c index 4afa3029dc..dc598a081b 100644 --- a/list-objects-filter.c +++ b/list-objects-filter.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "dir.h" diff --git a/patch-ids.c b/patch-ids.c index 8b89198073..a5683b462c 100644 --- a/patch-ids.c +++ b/patch-ids.c @@ -1,5 +1,3 @@ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "git-compat-util.h" #include "diff.h" #include "commit.h" diff --git a/reachable.c b/reachable.c index 34079e1ae9..3e9b3dd0a4 100644 --- a/reachable.c +++ b/reachable.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "gettext.h" diff --git a/reflog-walk.c b/reflog-walk.c index b53628ed53..c7070b13b0 100644 --- a/reflog-walk.c +++ b/reflog-walk.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "commit.h" diff --git a/t/helper/test-revision-walking.c b/t/helper/test-revision-walking.c index 3b931a34a2..071f5bd1e2 100644 --- a/t/helper/test-revision-walking.c +++ b/t/helper/test-revision-walking.c @@ -9,7 +9,6 @@ */ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "test-tool.h" #include "commit.h" -- cgit v1.2.3 From ba8f6018b5bed4fc58f8dfe2f9714d22398b06fe Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 6 Dec 2024 11:27:22 +0100 Subject: csum-file: fix -Wsign-compare warning on 32-bit platform On 32-bit platforms, ssize_t may be "int" while size_t may be "unsigned int". At times we compare the number of bytes we read stored in a ssize_t variable with "unsigned int", but that is done after we check that we did not get an error return (which is negative---and that is the whole reason why we used ssize_t and not size_t), so these comparisons are safe. But compilers may not realize that. Cast these to size_t to work around the false positives. On platforms with size_t/ssize_t wider than a normal int, this won't be an issue. Signed-off-by: Junio C Hamano Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- csum-file.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/csum-file.c b/csum-file.c index c14bacc7f9..5716016e12 100644 --- a/csum-file.c +++ b/csum-file.c @@ -9,7 +9,6 @@ */ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "progress.h" @@ -24,7 +23,7 @@ static void verify_buffer_or_die(struct hashfile *f, if (ret < 0) die_errno("%s: sha1 file read error", f->name); - if (ret != count) + if ((size_t)ret != count) die("%s: sha1 file truncated", f->name); if (memcmp(buf, f->check_buffer, count)) die("sha1 file '%s' validation error", f->name); -- cgit v1.2.3 From 25435e4ad87aa484ce0d9d2adf3aa407f0241704 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 11:27:23 +0100 Subject: pkt-line: fix -Wsign-compare warning on 32 bit platform Similar to the preceding commit, we get a warning in `get_packet_data()` on 32 bit platforms due to our lenient use of `ssize_t`. This function is kind of curious though: we accept an `unsigned size` of bytes to read, then store the actual number of bytes read in an `ssize_t` and return it as an `int`. This is a whole lot of integer conversions, and in theory these can cause us to overflow when the passed-in size is larger than `ssize_t`, which on 32 bit platforms is implemented as an `int`. None of the callers of that function even care about the number of bytes we have read, so returning that number is moot anyway. Refactor the function such that it only returns an error code, which plugs the potential overflow. While at it, convert the passed-in size parameter to be of type `size_t`. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- pkt-line.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/pkt-line.c b/pkt-line.c index 90ea2b6974..2dc29d5b68 100644 --- a/pkt-line.c +++ b/pkt-line.c @@ -340,30 +340,32 @@ int write_packetized_from_buf_no_flush_count(const char *src_in, size_t len, } static int get_packet_data(int fd, char **src_buf, size_t *src_size, - void *dst, unsigned size, int options) + void *dst, size_t size, int options) { - ssize_t ret; + size_t bytes_read; if (fd >= 0 && src_buf && *src_buf) BUG("multiple sources given to packet_read"); /* Read up to "size" bytes from our source, whatever it is. */ if (src_buf && *src_buf) { - ret = size < *src_size ? size : *src_size; - memcpy(dst, *src_buf, ret); - *src_buf += ret; - *src_size -= ret; + bytes_read = size < *src_size ? size : *src_size; + memcpy(dst, *src_buf, bytes_read); + *src_buf += bytes_read; + *src_size -= bytes_read; } else { - ret = read_in_full(fd, dst, size); + ssize_t ret = read_in_full(fd, dst, size); if (ret < 0) { if (options & PACKET_READ_GENTLE_ON_READ_ERROR) return error_errno(_("read error")); die_errno(_("read error")); } + + bytes_read = (size_t) ret; } /* And complain if we didn't get enough bytes to satisfy the read. */ - if (ret != size) { + if (bytes_read != size) { if (options & PACKET_READ_GENTLE_ON_EOF) return -1; @@ -372,7 +374,7 @@ static int get_packet_data(int fd, char **src_buf, size_t *src_size, die(_("the remote end hung up unexpectedly")); } - return ret; + return 0; } int packet_length(const char lenbuf_hex[4], size_t size) -- cgit v1.2.3 From 80c9e70ebe871f0826bc101142c66ff783405100 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 11:27:24 +0100 Subject: global: trivial conversions to fix `-Wsign-compare` warnings We have a bunch of loops which iterate up to an unsigned boundary using a signed index, which generates warnigs because we compare a signed and unsigned value in the loop condition. Address these sites for trivial cases and enable `-Wsign-compare` warnings for these code units. This patch only adapts those code units where we can drop the `DISABLE_SIGN_COMPARE_WARNINGS` macro in the same step. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- advice.c | 9 ++------- base85.c | 5 +---- builtin/add.c | 10 ++++------ builtin/branch.c | 1 - builtin/difftool.c | 4 ++-- builtin/for-each-repo.c | 5 ++--- builtin/help.c | 4 +--- builtin/mailsplit.c | 3 +-- builtin/merge-tree.c | 6 ++---- builtin/pack-redundant.c | 4 +--- builtin/pull.c | 4 +--- builtin/push.c | 5 ++--- builtin/rerere.c | 9 ++++----- builtin/stash.c | 7 ++----- builtin/submodule--helper.c | 8 +++----- builtin/var.c | 4 +--- commit.c | 4 +--- compat/fsmonitor/fsm-listen-darwin.c | 5 +---- compat/terminal.c | 5 +---- diagnose.c | 8 +++----- diffcore-rename.c | 4 +--- entry.c | 5 ++--- ewah/ewah_bitmap.c | 6 +----- git.c | 33 +++++++++++++-------------------- help.h | 8 +++----- hex.c | 7 ++----- http-push.c | 4 +--- list-objects-filter-options.c | 5 +---- list-objects.c | 8 ++------ ls-refs.c | 5 +---- merge.c | 5 ++--- path.c | 5 ++--- pkt-line.c | 5 +---- refs/debug.c | 5 +---- send-pack.c | 6 ++---- serve.c | 8 ++------ strvec.c | 5 +---- t/helper/test-bloom.c | 10 ++-------- t/helper/test-dump-fsmonitor.c | 4 +--- t/helper/test-dump-split-index.c | 4 +--- t/helper/test-dump-untracked-cache.c | 7 +++---- t/helper/test-hash-speed.c | 7 ++----- t/helper/test-parse-options.c | 7 ++----- t/helper/test-reach.c | 4 +--- t/helper/test-ref-store.c | 4 +--- t/helper/test-tool.c | 5 +---- t/unit-tests/t-example-decorate.c | 5 ++--- t/unit-tests/t-prio-queue.c | 4 +--- tmp-objdir.c | 4 +--- trailer.c | 4 +--- transport-helper.c | 14 ++++++-------- transport.c | 14 ++++---------- usage.c | 4 +--- version.c | 4 +--- versioncmp.c | 4 +--- 55 files changed, 105 insertions(+), 238 deletions(-) diff --git a/advice.c b/advice.c index c2da976543..147b596d33 100644 --- a/advice.c +++ b/advice.c @@ -1,5 +1,3 @@ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "git-compat-util.h" #include "advice.h" #include "config.h" @@ -162,7 +160,6 @@ void advise_if_enabled(enum advice_type type, const char *advice, ...) int git_default_advice_config(const char *var, const char *value) { const char *k, *slot_name; - int i; if (!strcmp(var, "color.advice")) { advice_use_color = git_config_colorbool(var, value); @@ -181,7 +178,7 @@ int git_default_advice_config(const char *var, const char *value) if (!skip_prefix(var, "advice.", &k)) return 0; - for (i = 0; i < ARRAY_SIZE(advice_setting); i++) { + for (size_t i = 0; i < ARRAY_SIZE(advice_setting); i++) { if (strcasecmp(k, advice_setting[i].key)) continue; advice_setting[i].level = git_config_bool(var, value) @@ -195,9 +192,7 @@ int git_default_advice_config(const char *var, const char *value) void list_config_advices(struct string_list *list, const char *prefix) { - int i; - - for (i = 0; i < ARRAY_SIZE(advice_setting); i++) + for (size_t i = 0; i < ARRAY_SIZE(advice_setting); i++) list_config_item(list, prefix, advice_setting[i].key); } diff --git a/base85.c b/base85.c index a6b8272039..80e899a2b1 100644 --- a/base85.c +++ b/base85.c @@ -1,5 +1,3 @@ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "git-compat-util.h" #include "base85.h" @@ -31,10 +29,9 @@ static const char en85[] = { static char de85[256]; static void prep_base85(void) { - int i; if (de85['Z']) return; - for (i = 0; i < ARRAY_SIZE(en85); i++) { + for (size_t i = 0; i < ARRAY_SIZE(en85); i++) { int ch = en85[i]; de85[ch] = i + 1; } diff --git a/builtin/add.c b/builtin/add.c index ff6a7d7fd0..78dfb26577 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -4,8 +4,6 @@ * Copyright (C) 2006 Linus Torvalds */ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "builtin.h" #include "advice.h" #include "config.h" @@ -42,9 +40,9 @@ static int chmod_pathspec(struct repository *repo, char flip, int show_only) { - int i, ret = 0; + int ret = 0; - for (i = 0; i < repo->index->cache_nr; i++) { + for (size_t i = 0; i < repo->index->cache_nr; i++) { struct cache_entry *ce = repo->index->cache[i]; int err; @@ -72,9 +70,9 @@ static int renormalize_tracked_files(struct repository *repo, const struct pathspec *pathspec, int flags) { - int i, retval = 0; + int retval = 0; - for (i = 0; i < repo->index->cache_nr; i++) { + for (size_t i = 0; i < repo->index->cache_nr; i++) { struct cache_entry *ce = repo->index->cache[i]; if (!include_sparse && diff --git a/builtin/branch.c b/builtin/branch.c index 349a6be6d6..3737a11cbf 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -6,7 +6,6 @@ */ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "config.h" diff --git a/builtin/difftool.c b/builtin/difftool.c index 1914708a76..03a8bb92a9 100644 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@ -13,7 +13,6 @@ */ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" @@ -367,7 +366,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, char *lbase_dir = NULL, *rbase_dir = NULL; size_t ldir_len, rdir_len, wtdir_len; const char *workdir, *tmp; - int ret = 0, i; + int ret = 0; + size_t i; FILE *fp = NULL; struct hashmap working_tree_dups = HASHMAP_INIT(working_tree_entry_cmp, NULL); diff --git a/builtin/for-each-repo.c b/builtin/for-each-repo.c index 7e36be9d8a..325a7925f1 100644 --- a/builtin/for-each-repo.c +++ b/builtin/for-each-repo.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "config.h" @@ -38,7 +37,7 @@ int cmd_for_each_repo(int argc, { static const char *config_key = NULL; int keep_going = 0; - int i, result = 0; + int result = 0; const struct string_list *values; int err; @@ -63,7 +62,7 @@ int cmd_for_each_repo(int argc, else if (err) return 0; - for (i = 0; i < values->nr; i++) { + for (size_t i = 0; i < values->nr; i++) { int ret = run_command_on_repo(values->items[i].string, argc, argv); if (ret) { if (!keep_going) diff --git a/builtin/help.c b/builtin/help.c index aa6bd6e412..05136279cf 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -3,7 +3,6 @@ */ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "config.h" @@ -131,7 +130,6 @@ static void list_config_help(enum show_config_type type) struct string_list keys = STRING_LIST_INIT_DUP; struct string_list keys_uniq = STRING_LIST_INIT_DUP; struct string_list_item *item; - int i; for (p = config_name_list; *p; p++) { const char *var = *p; @@ -158,7 +156,7 @@ static void list_config_help(enum show_config_type type) e->prefix, e->placeholder); string_list_sort(&keys); - for (i = 0; i < keys.nr; i++) { + for (size_t i = 0; i < keys.nr; i++) { const char *var = keys.items[i].string; const char *wildcard, *tag, *cut; const char *dot = NULL; diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c index 52481f7f2e..41dd304731 100644 --- a/builtin/mailsplit.c +++ b/builtin/mailsplit.c @@ -175,7 +175,6 @@ static int split_maildir(const char *maildir, const char *dir, char *file = NULL; FILE *f = NULL; int ret = -1; - int i; struct string_list list = STRING_LIST_INIT_DUP; list.cmp = maildir_filename_cmp; @@ -183,7 +182,7 @@ static int split_maildir(const char *maildir, const char *dir, if (populate_maildir_list(&list, maildir) < 0) goto out; - for (i = 0; i < list.nr; i++) { + for (size_t i = 0; i < list.nr; i++) { char *name; free(file); diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index 3328144029..9a6c8b4e4c 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "tree-walk.h" @@ -499,10 +498,9 @@ static int real_merge(struct merge_tree_options *o, if (!result.clean) { struct string_list conflicted_files = STRING_LIST_INIT_NODUP; const char *last = NULL; - int i; merge_get_conflicted_files(&result, &conflicted_files); - for (i = 0; i < conflicted_files.nr; i++) { + for (size_t i = 0; i < conflicted_files.nr; i++) { const char *name = conflicted_files.items[i].string; struct stage_info *c = conflicted_files.items[i].util; if (!o->name_only) @@ -586,7 +584,7 @@ int cmd_merge_tree(int argc, if (xopts.nr && o.mode == MODE_TRIVIAL) die(_("--trivial-merge is incompatible with all other options")); - for (int x = 0; x < xopts.nr; x++) + for (size_t x = 0; x < xopts.nr; x++) if (parse_merge_opt(&o.merge_options, xopts.v[x])) die(_("unknown strategy option: -X%s"), xopts.v[x]); diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c index 978c42aae7..275333f543 100644 --- a/builtin/pack-redundant.c +++ b/builtin/pack-redundant.c @@ -7,7 +7,6 @@ */ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "gettext.h" @@ -391,7 +390,6 @@ static int cmp_remaining_objects(const void *a, const void *b) static void sort_pack_list(struct pack_list **pl) { struct pack_list **ary, *p; - int i; size_t n = pack_list_size(*pl); if (n < 2) @@ -405,7 +403,7 @@ static void sort_pack_list(struct pack_list **pl) QSORT(ary, n, cmp_remaining_objects); /* link them back again */ - for (i = 0; i < n - 1; i++) + for (size_t i = 0; i < n - 1; i++) ary[i]->next = ary[i + 1]; ary[n - 1]->next = NULL; *pl = ary[0]; diff --git a/builtin/pull.c b/builtin/pull.c index 6f8a32620c..9c4a00620a 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -7,7 +7,6 @@ */ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "advice.h" @@ -943,11 +942,10 @@ static int get_can_ff(struct object_id *orig_head, static int already_up_to_date(struct object_id *orig_head, struct oid_array *merge_heads) { - int i; struct commit *ours; ours = lookup_commit_reference(the_repository, orig_head); - for (i = 0; i < merge_heads->nr; i++) { + for (size_t i = 0; i < merge_heads->nr; i++) { struct commit_list *list = NULL; struct commit *theirs; int ok; diff --git a/builtin/push.c b/builtin/push.c index 7174efed6d..90de3746b5 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -3,7 +3,6 @@ */ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "advice.h" @@ -420,7 +419,7 @@ static int do_push(int flags, const struct string_list *push_options, struct remote *remote) { - int i, errs; + int errs; struct strvec *url; struct refspec *push_refspec = &rs; @@ -435,7 +434,7 @@ static int do_push(int flags, } errs = 0; url = push_url_of_remote(remote); - for (i = 0; i < url->nr; i++) { + for (size_t i = 0; i < url->nr; i++) { struct transport *transport = transport_get(remote, url->v[i]); if (flags & TRANSPORT_PUSH_OPTIONS) diff --git a/builtin/rerere.c b/builtin/rerere.c index 706a947213..41127e24e5 100644 --- a/builtin/rerere.c +++ b/builtin/rerere.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "config.h" @@ -57,7 +56,7 @@ int cmd_rerere(int argc, struct repository *repo UNUSED) { struct string_list merge_rr = STRING_LIST_INIT_DUP; - int i, autoupdate = -1, flags = 0; + int autoupdate = -1, flags = 0; struct option options[] = { OPT_SET_INT(0, "rerere-autoupdate", &autoupdate, @@ -100,11 +99,11 @@ int cmd_rerere(int argc, if (setup_rerere(the_repository, &merge_rr, flags | RERERE_READONLY) < 0) return 0; - for (i = 0; i < merge_rr.nr; i++) + for (size_t i = 0; i < merge_rr.nr; i++) printf("%s\n", merge_rr.items[i].string); } else if (!strcmp(argv[0], "remaining")) { rerere_remaining(the_repository, &merge_rr); - for (i = 0; i < merge_rr.nr; i++) { + for (size_t i = 0; i < merge_rr.nr; i++) { if (merge_rr.items[i].util != RERERE_RESOLVED) printf("%s\n", merge_rr.items[i].string); else @@ -116,7 +115,7 @@ int cmd_rerere(int argc, if (setup_rerere(the_repository, &merge_rr, flags | RERERE_READONLY) < 0) return 0; - for (i = 0; i < merge_rr.nr; i++) { + for (size_t i = 0; i < merge_rr.nr; i++) { const char *path = merge_rr.items[i].string; const struct rerere_id *id = merge_rr.items[i].util; if (diff_two(rerere_path(id, "preimage"), path, path, path)) diff --git a/builtin/stash.c b/builtin/stash.c index a79d23f1a3..dbaa999cf1 100644 --- a/builtin/stash.c +++ b/builtin/stash.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "abspath.h" @@ -875,9 +874,8 @@ static void diff_include_untracked(const struct stash_info *info, struct diff_op struct tree *tree[ARRAY_SIZE(oid)]; struct tree_desc tree_desc[ARRAY_SIZE(oid)]; struct unpack_trees_options unpack_tree_opt = { 0 }; - int i; - for (i = 0; i < ARRAY_SIZE(oid); i++) { + for (size_t i = 0; i < ARRAY_SIZE(oid); i++) { tree[i] = parse_tree_indirect(oid[i]); if (parse_tree(tree[i]) < 0) die(_("failed to parse tree")); @@ -1559,12 +1557,11 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q repo_read_index_preload(the_repository, NULL, 0); if (!include_untracked && ps->nr) { - int i; char *ps_matched = xcalloc(ps->nr, 1); /* TODO: audit for interaction with sparse-index. */ ensure_full_index(the_repository->index); - for (i = 0; i < the_repository->index->cache_nr; i++) + for (size_t i = 0; i < the_repository->index->cache_nr; i++) ce_path_match(the_repository->index, the_repository->index->cache[i], ps, ps_matched); diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index cfcaffee0d..f9b970f8a6 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "abspath.h" @@ -196,7 +195,7 @@ static int module_list_compute(const char **argv, struct pathspec *pathspec, struct module_list *list) { - int i, result = 0; + int result = 0; char *ps_matched = NULL; parse_pathspec(pathspec, 0, @@ -209,7 +208,7 @@ static int module_list_compute(const char **argv, if (repo_read_index(the_repository) < 0) die(_("index file corrupt")); - for (i = 0; i < the_repository->index->cache_nr; i++) { + for (size_t i = 0; i < the_repository->index->cache_nr; i++) { const struct cache_entry *ce = the_repository->index->cache[i]; if (!match_pathspec(the_repository->index, pathspec, ce->name, ce_namelen(ce), @@ -3398,7 +3397,6 @@ static void die_on_index_match(const char *path, int force) die(_("index file corrupt")); if (ps.nr) { - int i; char *ps_matched = xcalloc(ps.nr, 1); /* TODO: audit for interaction with sparse-index. */ @@ -3408,7 +3406,7 @@ static void die_on_index_match(const char *path, int force) * Since there is only one pathspec, we just need to * check ps_matched[0] to know if a cache entry matched. */ - for (i = 0; i < the_repository->index->cache_nr; i++) { + for (size_t i = 0; i < the_repository->index->cache_nr; i++) { ce_path_match(the_repository->index, the_repository->index->cache[i], &ps, ps_matched); diff --git a/builtin/var.c b/builtin/var.c index 74aa39dd6b..1449656cc9 100644 --- a/builtin/var.c +++ b/builtin/var.c @@ -5,7 +5,6 @@ */ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" @@ -181,10 +180,9 @@ static void list_vars(void) if ((val = ptr->read(0))) { if (ptr->multivalued && *val) { struct string_list list = STRING_LIST_INIT_DUP; - int i; string_list_split(&list, val, '\n', -1); - for (i = 0; i < list.nr; i++) + for (size_t i = 0; i < list.nr; i++) printf("%s=%s\n", ptr->name, list.items[i].string); string_list_clear(&list, 0); } else { diff --git a/commit.c b/commit.c index 9c1f9fa236..8f6045a6c3 100644 --- a/commit.c +++ b/commit.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "tag.h" @@ -1766,7 +1765,6 @@ int commit_tree_extended(const char *msg, size_t msg_len, { &compat_sig, r->compat_hash_algo }, { &sig, r->hash_algo }, }; - int i; /* * We write algorithms in the order they were implemented in @@ -1780,7 +1778,7 @@ int commit_tree_extended(const char *msg, size_t msg_len, * We traverse each algorithm in order, and apply the signature * to each buffer. */ - for (i = 0; i < ARRAY_SIZE(bufs); i++) { + for (size_t i = 0; i < ARRAY_SIZE(bufs); i++) { if (!bufs[i].algo) continue; add_header_signature(&buffer, bufs[i].sig, bufs[i].algo); diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c index 58f3878a22..43c3a915a0 100644 --- a/compat/fsmonitor/fsm-listen-darwin.c +++ b/compat/fsmonitor/fsm-listen-darwin.c @@ -23,8 +23,6 @@ #endif #endif -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "git-compat-util.h" #include "fsmonitor-ll.h" #include "fsm-listen.h" @@ -210,13 +208,12 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef UNUSED, const char *slash; char *resolved = NULL; struct strbuf tmp = STRBUF_INIT; - int k; /* * Build a list of all filesystem changes into a private/local * list and without holding any locks. */ - for (k = 0; k < num_of_events; k++) { + for (size_t k = 0; k < num_of_events; k++) { /* * On Mac, we receive an array of absolute paths. */ diff --git a/compat/terminal.c b/compat/terminal.c index 7fe515b9c8..584f27bf7e 100644 --- a/compat/terminal.c +++ b/compat/terminal.c @@ -1,5 +1,3 @@ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "git-compat-util.h" #include "compat/terminal.h" #include "gettext.h" @@ -261,14 +259,13 @@ static DWORD cmode_in, cmode_out; void restore_term(void) { if (use_stty) { - int i; struct child_process cp = CHILD_PROCESS_INIT; if (stty_restore.nr == 0) return; strvec_push(&cp.args, "stty"); - for (i = 0; i < stty_restore.nr; i++) + for (size_t i = 0; i < stty_restore.nr; i++) strvec_push(&cp.args, stty_restore.items[i].string); run_command(&cp); string_list_clear(&stty_restore, 0); diff --git a/diagnose.c b/diagnose.c index f340996e27..b11931df86 100644 --- a/diagnose.c +++ b/diagnose.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "diagnose.h" @@ -32,7 +31,6 @@ static struct diagnose_option diagnose_options[] = { int option_parse_diagnose(const struct option *opt, const char *arg, int unset) { - int i; enum diagnose_mode *diagnose = opt->value; if (!arg) { @@ -40,7 +38,7 @@ int option_parse_diagnose(const struct option *opt, const char *arg, int unset) return 0; } - for (i = 0; i < ARRAY_SIZE(diagnose_options); i++) { + for (size_t i = 0; i < ARRAY_SIZE(diagnose_options); i++) { if (!strcmp(arg, diagnose_options[i].option_name)) { *diagnose = diagnose_options[i].mode; return 0; @@ -187,7 +185,7 @@ int create_diagnostics_archive(struct strbuf *zip_path, enum diagnose_mode mode) char **argv_copy = NULL; int stdout_fd = -1, archiver_fd = -1; struct strbuf buf = STRBUF_INIT; - int res, i; + int res; struct archive_dir archive_dirs[] = { { ".git", 0 }, { ".git/hooks", 0 }, @@ -240,7 +238,7 @@ int create_diagnostics_archive(struct strbuf *zip_path, enum diagnose_mode mode) /* Only include this if explicitly requested */ if (mode == DIAGNOSE_ALL) { - for (i = 0; i < ARRAY_SIZE(archive_dirs); i++) { + for (size_t i = 0; i < ARRAY_SIZE(archive_dirs); i++) { if (add_directory_to_archiver(&archiver_args, archive_dirs[i].path, archive_dirs[i].recursive)) { diff --git a/diffcore-rename.c b/diffcore-rename.c index 08ebb1fc3d..10bb0321b1 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -4,7 +4,6 @@ */ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "diff.h" @@ -689,7 +688,6 @@ static void cleanup_dir_rename_info(struct dir_rename_info *info, struct hashmap_iter iter; struct strmap_entry *entry; struct string_list to_remove = STRING_LIST_INIT_NODUP; - int i; if (!info->setup) return; @@ -735,7 +733,7 @@ static void cleanup_dir_rename_info(struct dir_rename_info *info, if (strintmap_contains(counts, UNKNOWN_DIR)) strintmap_remove(counts, UNKNOWN_DIR); } - for (i = 0; i < to_remove.nr; ++i) + for (size_t i = 0; i < to_remove.nr; ++i) strmap_remove(info->dir_rename_count, to_remove.items[i].string, 1); string_list_clear(&to_remove, 0); diff --git a/entry.c b/entry.c index 93bd6a78ff..53a1c39358 100644 --- a/entry.c +++ b/entry.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "object-store-ll.h" @@ -442,7 +441,7 @@ static int check_path(const char *path, int len, struct stat *st, int skiplen) static void mark_colliding_entries(const struct checkout *state, struct cache_entry *ce, struct stat *st) { - int i, trust_ino = check_stat; + int trust_ino = check_stat; #if defined(GIT_WINDOWS_NATIVE) || defined(__CYGWIN__) trust_ino = 0; @@ -452,7 +451,7 @@ static void mark_colliding_entries(const struct checkout *state, /* TODO: audit for interaction with sparse-index. */ ensure_full_index(state->istate); - for (i = 0; i < state->istate->cache_nr; i++) { + for (size_t i = 0; i < state->istate->cache_nr; i++) { struct cache_entry *dup = state->istate->cache[i]; if (dup == ce) { diff --git a/ewah/ewah_bitmap.c b/ewah/ewah_bitmap.c index 9be9bb3758..67f8f588e0 100644 --- a/ewah/ewah_bitmap.c +++ b/ewah/ewah_bitmap.c @@ -17,8 +17,6 @@ * along with this program; if not, see . */ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "git-compat-util.h" #include "ewok.h" #include "ewok_rlw.h" @@ -258,10 +256,8 @@ void ewah_each_bit(struct ewah_bitmap *self, void (*callback)(size_t, void*), vo ++pointer; for (k = 0; k < rlw_get_literal_words(word); ++k) { - int c; - /* todo: zero count optimization */ - for (c = 0; c < BITS_IN_EWORD; ++c, ++pos) { + for (size_t c = 0; c < BITS_IN_EWORD; ++c, ++pos) { if ((self->buffer[pointer] & ((eword_t)1 << c)) != 0) callback(pos, payload); } diff --git a/git.c b/git.c index cd33b1f405..71d644dc1c 100644 --- a/git.c +++ b/git.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "config.h" @@ -56,7 +55,7 @@ static void list_builtins(struct string_list *list, unsigned int exclude_option) static void exclude_helpers_from_list(struct string_list *list) { - int i = 0; + size_t i = 0; while (i < list->nr) { if (strstr(list->items[i].string, "--")) @@ -76,7 +75,6 @@ static int match_token(const char *spec, int len, const char *token) static int list_cmds(const char *spec) { struct string_list list = STRING_LIST_INIT_DUP; - int i; int nongit; /* @@ -114,7 +112,7 @@ static int list_cmds(const char *spec) if (*spec == ',') spec++; } - for (i = 0; i < list.nr; i++) + for (size_t i = 0; i < list.nr; i++) puts(list.items[i].string); string_list_clear(&list, 0); return 0; @@ -323,10 +321,9 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) trace2_cmd_name("_query_"); if (!strcmp(cmd, "parseopt")) { struct string_list list = STRING_LIST_INIT_DUP; - int i; list_builtins(&list, NO_PARSEOPT); - for (i = 0; i < list.nr; i++) + for (size_t i = 0; i < list.nr; i++) printf("%s ", list.items[i].string); string_list_clear(&list, 0); exit(0); @@ -652,8 +649,7 @@ static struct cmd_struct commands[] = { static struct cmd_struct *get_builtin(const char *s) { - int i; - for (i = 0; i < ARRAY_SIZE(commands); i++) { + for (size_t i = 0; i < ARRAY_SIZE(commands); i++) { struct cmd_struct *p = commands + i; if (!strcmp(s, p->cmd)) return p; @@ -668,8 +664,7 @@ int is_builtin(const char *s) static void list_builtins(struct string_list *out, unsigned int exclude_option) { - int i; - for (i = 0; i < ARRAY_SIZE(commands); i++) { + for (size_t i = 0; i < ARRAY_SIZE(commands); i++) { if (exclude_option && (commands[i].option & exclude_option)) continue; @@ -680,7 +675,6 @@ static void list_builtins(struct string_list *out, unsigned int exclude_option) void load_builtin_commands(const char *prefix, struct cmdnames *cmds) { const char *name; - int i; /* * Callers can ask for a subset of the commands based on a certain @@ -691,7 +685,7 @@ void load_builtin_commands(const char *prefix, struct cmdnames *cmds) if (!skip_prefix(prefix, "git-", &prefix)) BUG("prefix '%s' must start with 'git-'", prefix); - for (i = 0; i < ARRAY_SIZE(commands); i++) + for (size_t i = 0; i < ARRAY_SIZE(commands); i++) if (skip_prefix(commands[i].cmd, prefix, &name)) add_cmdname(cmds, name, strlen(name)); } @@ -813,7 +807,7 @@ static int run_argv(struct strvec *args) handle_builtin(args); else if (get_builtin(args->v[0])) { struct child_process cmd = CHILD_PROCESS_INIT; - int i; + int err; /* * The current process is committed to launching a @@ -827,7 +821,7 @@ static int run_argv(struct strvec *args) commit_pager_choice(); strvec_push(&cmd.args, "git"); - for (i = 0; i < args->nr; i++) + for (size_t i = 0; i < args->nr; i++) strvec_push(&cmd.args, args->v[i]); trace_argv_printf(cmd.args.v, "trace: exec:"); @@ -840,9 +834,9 @@ static int run_argv(struct strvec *args) cmd.clean_on_exit = 1; cmd.wait_after_clean = 1; cmd.trace2_child_class = "git_alias"; - i = run_command(&cmd); - if (i >= 0 || errno != ENOENT) - exit(i); + err = run_command(&cmd); + if (err >= 0 || errno != ENOENT) + exit(err); die("could not execute builtin %s", args->v[0]); } @@ -851,9 +845,8 @@ static int run_argv(struct strvec *args) seen = unsorted_string_list_lookup(&cmd_list, args->v[0]); if (seen) { - int i; struct strbuf sb = STRBUF_INIT; - for (i = 0; i < cmd_list.nr; i++) { + for (size_t i = 0; i < cmd_list.nr; i++) { struct string_list_item *item = &cmd_list.items[i]; strbuf_addf(&sb, "\n %s", item->string); @@ -947,7 +940,7 @@ int cmd_main(int argc, const char **argv) */ setup_path(); - for (size_t i = 0; i < argc; i++) + for (int i = 0; i < argc; i++) strvec_push(&args, argv[i]); while (1) { diff --git a/help.h b/help.h index 67207b3073..c54bf0977d 100644 --- a/help.h +++ b/help.h @@ -60,8 +60,7 @@ static inline void list_config_item(struct string_list *list, #define define_list_config_array(array) \ void list_config_##array(struct string_list *list, const char *prefix) \ { \ - int i; \ - for (i = 0; i < ARRAY_SIZE(array); i++) \ + for (size_t i = 0; i < ARRAY_SIZE(array); i++) \ if (array[i]) \ list_config_item(list, prefix, array[i]); \ } \ @@ -70,11 +69,10 @@ struct string_list #define define_list_config_array_extra(array, values) \ void list_config_##array(struct string_list *list, const char *prefix) \ { \ - int i; \ static const char *extra[] = values; \ - for (i = 0; i < ARRAY_SIZE(extra); i++) \ + for (size_t i = 0; i < ARRAY_SIZE(extra); i++) \ list_config_item(list, prefix, extra[i]); \ - for (i = 0; i < ARRAY_SIZE(array); i++) \ + for (size_t i = 0; i < ARRAY_SIZE(array); i++) \ if (array[i]) \ list_config_item(list, prefix, array[i]); \ } \ diff --git a/hex.c b/hex.c index e62406c182..865a232167 100644 --- a/hex.c +++ b/hex.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "hash.h" @@ -8,8 +7,7 @@ static int get_hash_hex_algop(const char *hex, unsigned char *hash, const struct git_hash_algo *algop) { - int i; - for (i = 0; i < algop->rawsz; i++) { + for (size_t i = 0; i < algop->rawsz; i++) { int val = hex2chr(hex); if (val < 0) return -1; @@ -84,7 +82,6 @@ char *hash_to_hex_algop_r(char *buffer, const unsigned char *hash, { static const char hex[] = "0123456789abcdef"; char *buf = buffer; - int i; /* * Our struct object_id has been memset to 0, so default to printing @@ -93,7 +90,7 @@ char *hash_to_hex_algop_r(char *buffer, const unsigned char *hash, if (algop == &hash_algos[0]) algop = the_hash_algo; - for (i = 0; i < algop->rawsz; i++) { + for (size_t i = 0; i < algop->rawsz; i++) { unsigned int val = *hash++; *buf++ = hex[val >> 4]; *buf++ = hex[val & 0xf]; diff --git a/http-push.c b/http-push.c index a5e8c3e900..43da1c7cd3 100644 --- a/http-push.c +++ b/http-push.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "environment.h" @@ -1339,7 +1338,6 @@ static struct object_list **process_tree(struct tree *tree, static int get_delta(struct rev_info *revs, struct remote_lock *lock) { - int i; struct commit *commit; struct object_list **p = &objects; int count = 0; @@ -1352,7 +1350,7 @@ static int get_delta(struct rev_info *revs, struct remote_lock *lock) count += add_send_request(&commit->object, lock); } - for (i = 0; i < revs->pending.nr; i++) { + for (size_t i = 0; i < revs->pending.nr; i++) { struct object_array_entry *entry = revs->pending.objects + i; struct object *obj = entry->item; const char *name = entry->name; diff --git a/list-objects-filter-options.c b/list-objects-filter-options.c index d1f7c56e6f..948376d42d 100644 --- a/list-objects-filter-options.c +++ b/list-objects-filter-options.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" @@ -395,8 +394,6 @@ void list_objects_filter_copy( struct list_objects_filter_options *dest, const struct list_objects_filter_options *src) { - int i; - /* Copy everything. We will overwrite the pointers shortly. */ memcpy(dest, src, sizeof(struct list_objects_filter_options)); @@ -405,7 +402,7 @@ void list_objects_filter_copy( dest->sparse_oid_name = xstrdup_or_null(src->sparse_oid_name); ALLOC_ARRAY(dest->sub, dest->sub_alloc); - for (i = 0; i < src->sub_nr; i++) + for (size_t i = 0; i < src->sub_nr; i++) list_objects_filter_copy(&dest->sub[i], &src->sub[i]); } diff --git a/list-objects.c b/list-objects.c index 2075c69496..deacef98aa 100644 --- a/list-objects.c +++ b/list-objects.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "tag.h" @@ -284,7 +283,6 @@ void mark_edges_uninteresting(struct rev_info *revs, int sparse) { struct commit_list *list; - int i; if (sparse) { struct oidset set; @@ -321,7 +319,7 @@ void mark_edges_uninteresting(struct rev_info *revs, } if (revs->edge_hint_aggressive) { - for (i = 0; i < revs->cmdline.nr; i++) { + for (size_t i = 0; i < revs->cmdline.nr; i++) { struct object *obj = revs->cmdline.rev[i].item; struct commit *commit = (struct commit *)obj; if (obj->type != OBJ_COMMIT || !(obj->flags & UNINTERESTING)) @@ -344,11 +342,9 @@ static void add_pending_tree(struct rev_info *revs, struct tree *tree) static void traverse_non_commits(struct traversal_context *ctx, struct strbuf *base) { - int i; - assert(base->len == 0); - for (i = 0; i < ctx->revs->pending.nr; i++) { + for (size_t i = 0; i < ctx->revs->pending.nr; i++) { struct object_array_entry *pending = ctx->revs->pending.objects + i; struct object *obj = pending->item; const char *name = pending->name; diff --git a/ls-refs.c b/ls-refs.c index 89a796a356..e28c841375 100644 --- a/ls-refs.c +++ b/ls-refs.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "environment.h" @@ -54,12 +53,10 @@ static enum { */ static int ref_match(const struct strvec *prefixes, const char *refname) { - int i; - if (!prefixes->nr) return 1; /* no restriction */ - for (i = 0; i < prefixes->nr; i++) { + for (size_t i = 0; i < prefixes->nr; i++) { const char *prefix = prefixes->v[i]; if (starts_with(refname, prefix)) diff --git a/merge.c b/merge.c index da04fff3ba..5ecaf508e4 100644 --- a/merge.c +++ b/merge.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "gettext.h" @@ -26,11 +25,11 @@ int try_merge_command(struct repository *r, const char *head_arg, struct commit_list *remotes) { struct child_process cmd = CHILD_PROCESS_INIT; - int i, ret; + int ret; struct commit_list *j; strvec_pushf(&cmd.args, "merge-%s", strategy); - for (i = 0; i < xopts_nr; i++) + for (size_t i = 0; i < xopts_nr; i++) strvec_pushf(&cmd.args, "--%s", xopts[i]); for (j = common; j; j = j->next) strvec_push(&cmd.args, merge_argument(j->item)); diff --git a/path.c b/path.c index 1f21004804..b4be7581aa 100644 --- a/path.c +++ b/path.c @@ -3,7 +3,6 @@ */ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" @@ -1141,12 +1140,12 @@ int strbuf_normalize_path(struct strbuf *src) */ int longest_ancestor_length(const char *path, struct string_list *prefixes) { - int i, max_len = -1; + int max_len = -1; if (!strcmp(path, "/")) return -1; - for (i = 0; i < prefixes->nr; i++) { + for (size_t i = 0; i < prefixes->nr; i++) { const char *ceil = prefixes->items[i].string; int len = strlen(ceil); diff --git a/pkt-line.c b/pkt-line.c index 2dc29d5b68..a5bcbc96fb 100644 --- a/pkt-line.c +++ b/pkt-line.c @@ -1,5 +1,3 @@ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "git-compat-util.h" #include "copy.h" #include "pkt-line.h" @@ -41,7 +39,6 @@ static int packet_trace_pack(const char *buf, unsigned int len, int sideband) static void packet_trace(const char *buf, unsigned int len, int write) { - int i; struct strbuf out; static int in_pack, sideband; @@ -74,7 +71,7 @@ static void packet_trace(const char *buf, unsigned int len, int write) get_trace_prefix(), write ? '>' : '<'); /* XXX we should really handle printable utf8 */ - for (i = 0; i < len; i++) { + for (unsigned int i = 0; i < len; i++) { /* suppress newlines */ if (buf[i] == '\n') continue; diff --git a/refs/debug.c b/refs/debug.c index 89fbd59320..fbc4df08b4 100644 --- a/refs/debug.c +++ b/refs/debug.c @@ -1,5 +1,3 @@ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "git-compat-util.h" #include "hex.h" #include "refs-internal.h" @@ -85,9 +83,8 @@ static void print_update(int i, const char *refname, static void print_transaction(struct ref_transaction *transaction) { - int i; trace_printf_key(&trace_refs, "transaction {\n"); - for (i = 0; i < transaction->nr; i++) { + for (size_t i = 0; i < transaction->nr; i++) { struct ref_update *u = transaction->updates[i]; print_update(i, u->refname, &u->old_oid, &u->new_oid, u->flags, u->type, u->msg); diff --git a/send-pack.c b/send-pack.c index 6e68074e50..7e83213683 100644 --- a/send-pack.c +++ b/send-pack.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" @@ -73,7 +72,6 @@ static int pack_objects(int fd, struct ref *refs, struct oid_array *advertised, */ struct child_process po = CHILD_PROCESS_INIT; FILE *po_in; - int i; int rc; trace2_region_enter("send_pack", "pack_objects", the_repository); @@ -105,9 +103,9 @@ static int pack_objects(int fd, struct ref *refs, struct oid_array *advertised, * parameters by writing to the pipe. */ po_in = xfdopen(po.in, "w"); - for (i = 0; i < advertised->nr; i++) + for (size_t i = 0; i < advertised->nr; i++) feed_object(&advertised->oid[i], po_in, 1); - for (i = 0; i < negotiated->nr; i++) + for (size_t i = 0; i < negotiated->nr; i++) feed_object(&negotiated->oid[i], po_in, 1); while (refs) { diff --git a/serve.c b/serve.c index 1e08fa9251..c8694e3751 100644 --- a/serve.c +++ b/serve.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "repository.h" @@ -164,12 +163,11 @@ void protocol_v2_advertise_capabilities(void) { struct strbuf capability = STRBUF_INIT; struct strbuf value = STRBUF_INIT; - int i; /* serve by default supports v2 */ packet_write_fmt(1, "version 2\n"); - for (i = 0; i < ARRAY_SIZE(capabilities); i++) { + for (size_t i = 0; i < ARRAY_SIZE(capabilities); i++) { struct protocol_capability *c = &capabilities[i]; if (c->advertise(the_repository, &value)) { @@ -195,12 +193,10 @@ void protocol_v2_advertise_capabilities(void) static struct protocol_capability *get_capability(const char *key, const char **value) { - int i; - if (!key) return NULL; - for (i = 0; i < ARRAY_SIZE(capabilities); i++) { + for (size_t i = 0; i < ARRAY_SIZE(capabilities); i++) { struct protocol_capability *c = &capabilities[i]; const char *out; if (!skip_prefix(key, c->name, &out)) diff --git a/strvec.c b/strvec.c index e8f87ab3a6..5cead29ba1 100644 --- a/strvec.c +++ b/strvec.c @@ -1,5 +1,3 @@ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "git-compat-util.h" #include "strvec.h" #include "strbuf.h" @@ -129,8 +127,7 @@ void strvec_split(struct strvec *array, const char *to_split) void strvec_clear(struct strvec *array) { if (array->v != empty_strvec) { - int i; - for (i = 0; i < array->nr; i++) + for (size_t i = 0; i < array->nr; i++) free((char *)array->v[i]); free(array->v); } diff --git a/t/helper/test-bloom.c b/t/helper/test-bloom.c index 8d4ef44131..14e075c1a1 100644 --- a/t/helper/test-bloom.c +++ b/t/helper/test-bloom.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "test-tool.h" #include "bloom.h" @@ -12,30 +11,25 @@ static struct bloom_filter_settings settings = DEFAULT_BLOOM_FILTER_SETTINGS; static void add_string_to_filter(const char *data, struct bloom_filter *filter) { struct bloom_key key; - int i; fill_bloom_key(data, strlen(data), &key, &settings); printf("Hashes:"); - for (i = 0; i < settings.num_hashes; i++){ + for (size_t i = 0; i < settings.num_hashes; i++) printf("0x%08x|", key.hashes[i]); - } printf("\n"); add_key_to_filter(&key, filter, &settings); clear_bloom_key(&key); } static void print_bloom_filter(struct bloom_filter *filter) { - int i; - if (!filter) { printf("No filter.\n"); return; } printf("Filter_Length:%d\n", (int)filter->len); printf("Filter_Data:"); - for (i = 0; i < filter->len; i++) { + for (size_t i = 0; i < filter->len; i++) printf("%02x|", filter->data[i]); - } printf("\n"); } diff --git a/t/helper/test-dump-fsmonitor.c b/t/helper/test-dump-fsmonitor.c index 7b78f9d182..efd017ca35 100644 --- a/t/helper/test-dump-fsmonitor.c +++ b/t/helper/test-dump-fsmonitor.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "test-tool.h" #include "read-cache-ll.h" @@ -9,7 +8,6 @@ int cmd__dump_fsmonitor(int ac UNUSED, const char **av UNUSED) { struct index_state *istate = the_repository->index; - int i; setup_git_directory(); if (do_read_index(istate, the_repository->index_file, 0) < 0) @@ -20,7 +18,7 @@ int cmd__dump_fsmonitor(int ac UNUSED, const char **av UNUSED) } printf("fsmonitor last update %s\n", istate->fsmonitor_last_update); - for (i = 0; i < istate->cache_nr; i++) + for (size_t i = 0; i < istate->cache_nr; i++) printf((istate->cache[i]->ce_flags & CE_FSMONITOR_VALID) ? "+" : "-"); return 0; diff --git a/t/helper/test-dump-split-index.c b/t/helper/test-dump-split-index.c index f31b44a767..f855a3862c 100644 --- a/t/helper/test-dump-split-index.c +++ b/t/helper/test-dump-split-index.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "test-tool.h" #include "hex.h" @@ -17,7 +16,6 @@ static void show_bit(size_t pos, void *data UNUSED) int cmd__dump_split_index(int ac UNUSED, const char **av) { struct split_index *si; - int i; setup_git_directory(); @@ -29,7 +27,7 @@ int cmd__dump_split_index(int ac UNUSED, const char **av) return 0; } printf("base %s\n", oid_to_hex(&si->base_oid)); - for (i = 0; i < the_repository->index->cache_nr; i++) { + for (size_t i = 0; i < the_repository->index->cache_nr; i++) { struct cache_entry *ce = the_repository->index->cache[i]; printf("%06o %s %d\t%s\n", ce->ce_mode, oid_to_hex(&ce->oid), ce_stage(ce), ce->name); diff --git a/t/helper/test-dump-untracked-cache.c b/t/helper/test-dump-untracked-cache.c index ae05795800..01a109496b 100644 --- a/t/helper/test-dump-untracked-cache.c +++ b/t/helper/test-dump-untracked-cache.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "test-tool.h" #include "dir.h" @@ -24,7 +23,7 @@ static int compare_dir(const void *a_, const void *b_) static void dump(struct untracked_cache_dir *ucd, struct strbuf *base) { - int i, len; + int len; QSORT(ucd->untracked, ucd->untracked_nr, compare_untracked); QSORT(ucd->dirs, ucd->dirs_nr, compare_dir); len = base->len; @@ -38,9 +37,9 @@ static void dump(struct untracked_cache_dir *ucd, struct strbuf *base) if (ucd->valid) fputs(" valid", stdout); printf("\n"); - for (i = 0; i < ucd->untracked_nr; i++) + for (size_t i = 0; i < ucd->untracked_nr; i++) printf("%s\n", ucd->untracked[i]); - for (i = 0; i < ucd->dirs_nr; i++) + for (size_t i = 0; i < ucd->dirs_nr; i++) dump(ucd->dirs[i], base); strbuf_setlen(base, len); } diff --git a/t/helper/test-hash-speed.c b/t/helper/test-hash-speed.c index 81a446dd64..80df1aae66 100644 --- a/t/helper/test-hash-speed.c +++ b/t/helper/test-hash-speed.c @@ -1,5 +1,3 @@ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "test-tool.h" #include "hash.h" @@ -18,12 +16,11 @@ int cmd__hash_speed(int ac, const char **av) unsigned char hash[GIT_MAX_RAWSZ]; clock_t initial, start, end; unsigned bufsizes[] = { 64, 256, 1024, 8192, 16384 }; - int i; void *p; const struct git_hash_algo *algo = NULL; if (ac == 2) { - for (i = 1; i < GIT_HASH_NALGOS; i++) { + for (size_t i = 1; i < GIT_HASH_NALGOS; i++) { if (!strcmp(av[1], hash_algos[i].name)) { algo = &hash_algos[i]; break; @@ -38,7 +35,7 @@ int cmd__hash_speed(int ac, const char **av) printf("algo: %s\n", algo->name); - for (i = 0; i < ARRAY_SIZE(bufsizes); i++) { + for (size_t i = 0; i < ARRAY_SIZE(bufsizes); i++) { unsigned long j, kb; double kb_per_sec; p = xcalloc(1, bufsizes[i]); diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c index 25ba08a7c3..bfe45ec68b 100644 --- a/t/helper/test-parse-options.c +++ b/t/helper/test-parse-options.c @@ -1,5 +1,3 @@ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "test-tool.h" #include "parse-options.h" #include "strbuf.h" @@ -176,7 +174,6 @@ int cmd__parse_options(int argc, const char **argv) OPT_ALIAS('Z', "alias-target", "alias-source"), OPT_END(), }; - int i; int ret = 0; trace2_cmd_name("_parse_"); @@ -200,10 +197,10 @@ int cmd__parse_options(int argc, const char **argv) show(&expect, &ret, "dry run: %s", dry_run ? "yes" : "no"); show(&expect, &ret, "file: %s", file ? file : "(not set)"); - for (i = 0; i < list.nr; i++) + for (size_t i = 0; i < list.nr; i++) show(&expect, &ret, "list: %s", list.items[i].string); - for (i = 0; i < argc; i++) + for (int i = 0; i < argc; i++) show(&expect, &ret, "arg %02d: %s", i, argv[i]); expect.strdup_strings = 1; diff --git a/t/helper/test-reach.c b/t/helper/test-reach.c index 25c232464d..01cf77ae65 100644 --- a/t/helper/test-reach.c +++ b/t/helper/test-reach.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "test-tool.h" #include "commit.h" @@ -14,7 +13,6 @@ static void print_sorted_commit_ids(struct commit_list *list) { - int i; struct string_list s = STRING_LIST_INIT_DUP; while (list) { @@ -24,7 +22,7 @@ static void print_sorted_commit_ids(struct commit_list *list) string_list_sort(&s); - for (i = 0; i < s.nr; i++) + for (size_t i = 0; i < s.nr; i++) printf("%s\n", s.items[i].string); string_list_clear(&s, 0); diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c index c5c4cb142d..1cc05f043a 100644 --- a/t/helper/test-ref-store.c +++ b/t/helper/test-ref-store.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "test-tool.h" #include "hex.h" @@ -25,14 +24,13 @@ struct flag_definition { static unsigned int parse_flags(const char *str, struct flag_definition *defs) { struct string_list masks = STRING_LIST_INIT_DUP; - int i = 0; unsigned int result = 0; if (!strcmp(str, "0")) return 0; string_list_split(&masks, str, ',', 64); - for (; i < masks.nr; i++) { + for (size_t i = 0; i < masks.nr; i++) { const char *name = masks.items[i].string; struct flag_definition *def = defs; int found = 0; diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c index b626f64eca..4a7aa993ba 100644 --- a/t/helper/test-tool.c +++ b/t/helper/test-tool.c @@ -1,5 +1,3 @@ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "git-compat-util.h" #include "test-tool.h" #include "test-tool-utils.h" @@ -103,7 +101,6 @@ static NORETURN void die_usage(void) int cmd_main(int argc, const char **argv) { - int i; const char *working_directory = NULL; struct option options[] = { OPT_STRING('C', NULL, &working_directory, "directory", @@ -122,7 +119,7 @@ int cmd_main(int argc, const char **argv) if (working_directory && chdir(working_directory) < 0) die("Could not cd to '%s'", working_directory); - for (i = 0; i < ARRAY_SIZE(cmds); i++) { + for (size_t i = 0; i < ARRAY_SIZE(cmds); i++) { if (!strcmp(cmds[i].name, argv[1])) { argv++; argc--; diff --git a/t/unit-tests/t-example-decorate.c b/t/unit-tests/t-example-decorate.c index 61da8e1c8b..bfc776e223 100644 --- a/t/unit-tests/t-example-decorate.c +++ b/t/unit-tests/t-example-decorate.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "test-lib.h" #include "object.h" @@ -43,9 +42,9 @@ static void t_lookup(struct test_vars *vars) static void t_loop(struct test_vars *vars) { - int i, objects_noticed = 0; + int objects_noticed = 0; - for (i = 0; i < vars->n.size; i++) { + for (size_t i = 0; i < vars->n.size; i++) { if (vars->n.entries[i].base) objects_noticed++; } diff --git a/t/unit-tests/t-prio-queue.c b/t/unit-tests/t-prio-queue.c index a3d1aabab5..a053635000 100644 --- a/t/unit-tests/t-prio-queue.c +++ b/t/unit-tests/t-prio-queue.c @@ -1,5 +1,3 @@ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "test-lib.h" #include "prio-queue.h" @@ -27,7 +25,7 @@ static void test_prio_queue(int *input, size_t input_size, struct prio_queue pq = { intcmp }; int j = 0; - for (int i = 0; i < input_size; i++) { + for (size_t i = 0; i < input_size; i++) { void *peek, *get; switch(input[i]) { case GET: diff --git a/tmp-objdir.c b/tmp-objdir.c index b9084d0ac3..659fcdcc29 100644 --- a/tmp-objdir.c +++ b/tmp-objdir.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "tmp-objdir.h" @@ -238,7 +237,6 @@ static int migrate_paths(struct strbuf *src, struct strbuf *dst, { size_t src_len = src->len, dst_len = dst->len; struct string_list paths = STRING_LIST_INIT_DUP; - int i; int ret = 0; if (read_dir_paths(&paths, src->buf) < 0) @@ -246,7 +244,7 @@ static int migrate_paths(struct strbuf *src, struct strbuf *dst, paths.cmp = pack_copy_cmp; string_list_sort(&paths); - for (i = 0; i < paths.nr; i++) { + for (size_t i = 0; i < paths.nr; i++) { const char *name = paths.items[i].string; enum finalize_object_file_flags flags_copy = flags; diff --git a/trailer.c b/trailer.c index b7e4063285..310cf582dc 100644 --- a/trailer.c +++ b/trailer.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" @@ -523,7 +522,6 @@ static int git_trailer_config(const char *conf_key, const char *value, struct conf_info *conf; char *name = NULL; enum trailer_info_type type; - int i; if (!skip_prefix(conf_key, "trailer.", &trailer_item)) return 0; @@ -533,7 +531,7 @@ static int git_trailer_config(const char *conf_key, const char *value, return 0; variable_name++; - for (i = 0; i < ARRAY_SIZE(trailer_config_items); i++) { + for (size_t i = 0; i < ARRAY_SIZE(trailer_config_items); i++) { if (strcmp(trailer_config_items[i].name, variable_name)) continue; name = xstrndup(trailer_item, variable_name - trailer_item - 1); diff --git a/transport-helper.c b/transport-helper.c index 387c67d5bd..d457b42550 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "transport.h" @@ -314,9 +313,9 @@ static int string_list_set_helper_option(struct helper_data *data, struct string_list *list) { struct strbuf buf = STRBUF_INIT; - int i, ret = 0; + int ret = 0; - for (i = 0; i < list->nr; i++) { + for (size_t i = 0; i < list->nr; i++) { strbuf_addf(&buf, "option %s ", name); quote_c_style(list->items[i].string, &buf, NULL, 0); strbuf_addch(&buf, '\n'); @@ -334,7 +333,7 @@ static int set_helper_option(struct transport *transport, { struct helper_data *data = transport->data; struct strbuf buf = STRBUF_INIT; - int i, ret, is_bool = 0; + int ret, is_bool = 0; get_helper(transport); @@ -345,12 +344,12 @@ static int set_helper_option(struct transport *transport, return string_list_set_helper_option(data, name, (struct string_list *)value); - for (i = 0; i < ARRAY_SIZE(unsupported_options); i++) { + for (size_t i = 0; i < ARRAY_SIZE(unsupported_options); i++) { if (!strcmp(name, unsupported_options[i])) return 1; } - for (i = 0; i < ARRAY_SIZE(boolean_options); i++) { + for (size_t i = 0; i < ARRAY_SIZE(boolean_options); i++) { if (!strcmp(name, boolean_options[i])) { is_bool = 1; break; @@ -482,7 +481,6 @@ static int get_exporter(struct transport *transport, { struct helper_data *data = transport->data; struct child_process *helper = get_helper(transport); - int i; child_process_init(fastexport); @@ -498,7 +496,7 @@ static int get_exporter(struct transport *transport, if (data->import_marks) strvec_pushf(&fastexport->args, "--import-marks=%s", data->import_marks); - for (i = 0; i < revlist_args->nr; i++) + for (size_t i = 0; i < revlist_args->nr; i++) strvec_push(&fastexport->args, revlist_args->items[i].string); fastexport->git_cmd = 1; diff --git a/transport.c b/transport.c index abf0ff5706..d94ed4f98f 100644 --- a/transport.c +++ b/transport.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "advice.h" @@ -48,7 +47,6 @@ static int transport_color_config(void) "color.transport.rejected" }, *key = "color.transport"; char *value; - int i; static int initialized; if (initialized) @@ -61,7 +59,7 @@ static int transport_color_config(void) if (!want_color_stderr(transport_use_color)) return 0; - for (i = 0; i < ARRAY_SIZE(keys); i++) + for (size_t i = 0; i < ARRAY_SIZE(keys); i++) if (!git_config_get_string(keys[i], &value)) { if (!value) return config_error_nonbool(keys[i]); @@ -154,14 +152,13 @@ static struct ref *get_refs_from_bundle(struct transport *transport, { struct bundle_transport_data *data = transport->data; struct ref *result = NULL; - int i; if (for_push) return NULL; get_refs_from_bundle_inner(transport); - for (i = 0; i < data->header.references.nr; i++) { + for (size_t i = 0; i < data->header.references.nr; i++) { struct string_list_item *e = data->header.references.items + i; const char *name = e->string; struct ref *ref = alloc_ref(name); @@ -1282,11 +1279,9 @@ void transport_set_verbosity(struct transport *transport, int verbosity, static void die_with_unpushed_submodules(struct string_list *needs_pushing) { - int i; - fprintf(stderr, _("The following submodule paths contain changes that can\n" "not be found on any remote:\n")); - for (i = 0; i < needs_pushing->nr; i++) + for (size_t i = 0; i < needs_pushing->nr; i++) fprintf(stderr, " %s\n", needs_pushing->items[i].string); fprintf(stderr, _("\nPlease try\n\n" " git push --recurse-submodules=on-demand\n\n" @@ -1602,9 +1597,8 @@ int transport_get_remote_bundle_uri(struct transport *transport) void transport_unlock_pack(struct transport *transport, unsigned int flags) { int in_signal_handler = !!(flags & TRANSPORT_UNLOCK_PACK_IN_SIGNAL_HANDLER); - int i; - for (i = 0; i < transport->pack_lockfiles.nr; i++) + for (size_t i = 0; i < transport->pack_lockfiles.nr; i++) if (in_signal_handler) unlink(transport->pack_lockfiles.items[i].string); else diff --git a/usage.c b/usage.c index 8c672a57f6..47709006c1 100644 --- a/usage.c +++ b/usage.c @@ -4,8 +4,6 @@ * Copyright (C) Linus Torvalds, 2005 */ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "git-compat-util.h" #include "gettext.h" #include "trace2.h" @@ -192,7 +190,7 @@ void NORETURN die(const char *err, ...) static const char *fmt_with_err(char *buf, int n, const char *fmt) { char str_error[256], *err; - int i, j; + size_t i, j; err = strerror(errno); for (i = j = 0; err[i] && j < sizeof(str_error) - 1; ) { diff --git a/version.c b/version.c index d5aadab709..44cd39ae26 100644 --- a/version.c +++ b/version.c @@ -1,4 +1,3 @@ -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "version.h" #include "strbuf.h" @@ -25,11 +24,10 @@ const char *git_user_agent_sanitized(void) if (!agent) { struct strbuf buf = STRBUF_INIT; - int i; strbuf_addstr(&buf, git_user_agent()); strbuf_trim(&buf); - for (i = 0; i < buf.len; i++) { + for (size_t i = 0; i < buf.len; i++) { if (buf.buf[i] <= 32 || buf.buf[i] >= 127) buf.buf[i] = '.'; } diff --git a/versioncmp.c b/versioncmp.c index 71cef7e858..b6eebdb989 100644 --- a/versioncmp.c +++ b/versioncmp.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "config.h" @@ -78,11 +77,10 @@ static int swap_prereleases(const char *s1, int off, int *diff) { - int i; struct suffix_match match1 = { -1, off, -1 }; struct suffix_match match2 = { -1, off, -1 }; - for (i = 0; i < prereleases->nr; i++) { + for (size_t i = 0; i < prereleases->nr; i++) { const char *suffix = prereleases->items[i].string; int start, suffix_len = strlen(suffix); if (suffix_len < off) -- cgit v1.2.3 From 8108d1ac948c1029b29d8180dd5dbfdc5f2efb38 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 11:27:25 +0100 Subject: daemon: fix loops that have mismatching integer types We have several loops in "daemon.c" that use a signed integer to loop through a `size_t`. Adapt them to instead use a `size_t` as counter value. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- daemon.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/daemon.c b/daemon.c index 68789ceb22..bf313bc21a 100644 --- a/daemon.c +++ b/daemon.c @@ -503,8 +503,7 @@ static struct daemon_service daemon_service[] = { static void enable_service(const char *name, int ena) { - int i; - for (i = 0; i < ARRAY_SIZE(daemon_service); i++) { + for (size_t i = 0; i < ARRAY_SIZE(daemon_service); i++) { if (!strcmp(daemon_service[i].name, name)) { daemon_service[i].enabled = ena; return; @@ -515,8 +514,7 @@ static void enable_service(const char *name, int ena) static void make_service_overridable(const char *name, int ena) { - int i; - for (i = 0; i < ARRAY_SIZE(daemon_service); i++) { + for (size_t i = 0; i < ARRAY_SIZE(daemon_service); i++) { if (!strcmp(daemon_service[i].name, name)) { daemon_service[i].overridable = ena; return; @@ -737,7 +735,7 @@ static void set_keep_alive(int sockfd) static int execute(void) { char *line = packet_buffer; - int pktlen, len, i; + int pktlen, len; char *addr = getenv("REMOTE_ADDR"), *port = getenv("REMOTE_PORT"); struct hostinfo hi = HOSTINFO_INIT; struct strvec env = STRVEC_INIT; @@ -758,7 +756,7 @@ static int execute(void) if (len != pktlen) parse_extra_args(&hi, &env, line + len + 1, pktlen - len - 1); - for (i = 0; i < ARRAY_SIZE(daemon_service); i++) { + for (size_t i = 0; i < ARRAY_SIZE(daemon_service); i++) { struct daemon_service *s = &(daemon_service[i]); const char *arg; @@ -1108,8 +1106,8 @@ static void socksetup(struct string_list *listen_addr, int listen_port, struct s if (!listen_addr->nr) setup_named_sock(NULL, listen_port, socklist); else { - int i, socknum; - for (i = 0; i < listen_addr->nr; i++) { + int socknum; + for (size_t i = 0; i < listen_addr->nr; i++) { socknum = setup_named_sock(listen_addr->items[i].string, listen_port, socklist); @@ -1123,11 +1121,10 @@ static void socksetup(struct string_list *listen_addr, int listen_port, struct s static int service_loop(struct socketlist *socklist) { struct pollfd *pfd; - int i; CALLOC_ARRAY(pfd, socklist->nr); - for (i = 0; i < socklist->nr; i++) { + for (size_t i = 0; i < socklist->nr; i++) { pfd[i].fd = socklist->list[i]; pfd[i].events = POLLIN; } @@ -1135,8 +1132,6 @@ static int service_loop(struct socketlist *socklist) signal(SIGCHLD, child_handler); for (;;) { - int i; - check_dead_children(); if (poll(pfd, socklist->nr, -1) < 0) { @@ -1148,7 +1143,7 @@ static int service_loop(struct socketlist *socklist) continue; } - for (i = 0; i < socklist->nr; i++) { + for (size_t i = 0; i < socklist->nr; i++) { if (pfd[i].revents & POLLIN) { union { struct sockaddr sa; -- cgit v1.2.3 From 7d200af27f41b8732dcb1a6c01ff73b7b7b0ecc1 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 11:27:26 +0100 Subject: daemon: fix type of `max_connections` The `max_connections` type tracks how many children git-daemon(1) would spawn at the same time. This value can be controlled via a command line switch: if given a positive value we'll set that up as the limit. But when given either zero or a negative value we don't enforce any limit at all. But even when being passed a negative value we won't actually store it, but normalize it to 0. Still, the variable used to store the config is using a signed integer, which causes warnings when comparing the number of accepted connections (`max_connections`) with the number of current connections being handled (`live_children`). Adapt the type of `max_connections` such that the types of both variables match. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- daemon.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/daemon.c b/daemon.c index bf313bc21a..5ca70335fc 100644 --- a/daemon.c +++ b/daemon.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" @@ -801,8 +800,7 @@ static int addrcmp(const struct sockaddr_storage *s1, return 0; } -static int max_connections = 32; - +static unsigned int max_connections = 32; static unsigned int live_children; static struct child { @@ -1315,10 +1313,11 @@ int cmd_main(int argc, const char **argv) continue; } if (skip_prefix(arg, "--max-connections=", &v)) { - if (strtol_i(v, 10, &max_connections)) + int parsed_value; + if (strtol_i(v, 10, &parsed_value)) die(_("invalid max-connections '%s', expecting an integer"), v); - if (max_connections < 0) - max_connections = 0; /* unlimited */ + /* A negative value indicates unlimited children. */ + max_connections = parsed_value < 0 ? 0 : parsed_value; continue; } if (!strcmp(arg, "--strict-paths")) { -- cgit v1.2.3 From 87318f2b6ed371814cb53c91a458b336f175b325 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 11:27:27 +0100 Subject: gpg-interface: address -Wsign-comparison warnings There are a couple of -Wsign-comparison warnings in "gpg-interface.c". Most of them are trivial and simply using signed integers to loop towards an upper unsigned bound. But in `parse_signed_buffer()` we have one case where the different signedness of the two values of a ternary expression results in a warning. Given that: - `size` will always be bigger than `len` due to the loop condition. - `eol` will always be after `buf + len` because it is found via memchr(3p) starting from `buf + len`. We know that both values will always be natural integers. Squelch the warning by casting the left-hand side to `size_t`. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- gpg-interface.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/gpg-interface.c b/gpg-interface.c index a67d80475b..0896458de5 100644 --- a/gpg-interface.c +++ b/gpg-interface.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "commit.h" @@ -128,9 +127,7 @@ static struct gpg_format *use_format = &gpg_format[0]; static struct gpg_format *get_format_by_name(const char *str) { - int i; - - for (i = 0; i < ARRAY_SIZE(gpg_format); i++) + for (size_t i = 0; i < ARRAY_SIZE(gpg_format); i++) if (!strcmp(gpg_format[i].name, str)) return gpg_format + i; return NULL; @@ -138,9 +135,9 @@ static struct gpg_format *get_format_by_name(const char *str) static struct gpg_format *get_format_by_sig(const char *sig) { - int i, j; + int j; - for (i = 0; i < ARRAY_SIZE(gpg_format); i++) + for (size_t i = 0; i < ARRAY_SIZE(gpg_format); i++) for (j = 0; gpg_format[i].sigs[j]; j++) if (starts_with(sig, gpg_format[i].sigs[j])) return gpg_format + i; @@ -228,7 +225,7 @@ static void parse_gpg_output(struct signature_check *sigc) { const char *buf = sigc->gpg_status; const char *line, *next; - int i, j; + int j; int seen_exclusive_status = 0; /* Iterate over all lines */ @@ -243,7 +240,7 @@ static void parse_gpg_output(struct signature_check *sigc) continue; /* Iterate over all search strings */ - for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) { + for (size_t i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) { if (skip_prefix(line, sigcheck_gpg_status[i].check, &line)) { /* * GOODSIG, BADSIG etc. can occur only once for @@ -700,7 +697,7 @@ size_t parse_signed_buffer(const char *buf, size_t size) match = len; eol = memchr(buf + len, '\n', size - len); - len += eol ? eol - (buf + len) + 1 : size - len; + len += eol ? (size_t) (eol - (buf + len) + 1) : size - len; } return match; } -- cgit v1.2.3 From 6411a0a896d0ca00effa9b7a67ea0655257b9832 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 11:27:28 +0100 Subject: builtin/blame: fix type of `length` variable when emitting object ID The `length` variable is used to store how many bytes we wish to emit from an object ID. This value will either be the full hash algorithm's length, or the abbreviated hash that can be set via `--abbrev` or the "core.abbrev" option. The former is of type `size_t`, whereas the latter is of type `int`, which causes a warning with "-Wsign-compare". The reason why `abbrev` is using a signed type is mostly that it is initialized with `-1` to indicate that we have to compute the minimum abbreviation length. This length is computed via `find_alignment()`, which always gets called before `emit_other()`, and thus we can assume that the value would never be negative in `emit_other()`. In fact, we can even assume that the value will always be at least `MINIMUM_ABBREV`, which is enforced by both `git_default_core_config()` and `parse_opt_abbrev_cb()`. We implicitly rely on this by subtracting up to 3 without checking for whether the value becomes negative. We then pass the value to printf(3p) to print the prefix of our object's ID, so if that assumption was violated we may end up with undefined behaviour. Squelch the warning by asserting this invariant and casting the value of `abbrev` to `size_t`. This allows us to store the whole length as an unsigned integer, which we can then pass to `fwrite()`. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/blame.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/builtin/blame.c b/builtin/blame.c index b33b44c89a..867032e4c1 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -6,7 +6,6 @@ */ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "config.h" @@ -468,9 +467,14 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int reset = GIT_COLOR_RESET; } + if (abbrev < MINIMUM_ABBREV) + BUG("abbreviation is smaller than minimum length: %d < %d", + abbrev, MINIMUM_ABBREV); + for (cnt = 0; cnt < ent->num_lines; cnt++) { char ch; - int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? the_hash_algo->hexsz : abbrev; + size_t length = (opt & OUTPUT_LONG_OBJECT_NAME) ? + the_hash_algo->hexsz : (size_t) abbrev; if (opt & OUTPUT_COLOR_LINE) { if (cnt > 0) { @@ -501,7 +505,7 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int length--; putchar('?'); } - printf("%.*s", length, hex); + fwrite(hex, 1, length, stdout); if (opt & OUTPUT_ANNOTATE_COMPAT) { const char *name; if (opt & OUTPUT_SHOW_EMAIL) -- cgit v1.2.3 From efb38ad49fb2dd7bf6e732df0c59f3c1aeba2f76 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 11:27:29 +0100 Subject: builtin/patch-id: fix type of `get_one_patchid()` In `get_one_patchid()` we assign either the result of `strlen()` or `remove_space()` to `len`. But while the former correctly returns a `size_t`, the latter returns an `int` to indicate the length of the stripped string even though it cannot ever return a negative value. This causes a warning with "-Wsign-conversion". In fact, even `get_one_patchid()` itself is also using an integer as return value even though it always returns the length of the patch, and this bubbles up to other callers. Adapt the function and its helpers to use `size_t` for string lengths consistently. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/patch-id.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/builtin/patch-id.c b/builtin/patch-id.c index 5658575747..f540d8daa7 100644 --- a/builtin/patch-id.c +++ b/builtin/patch-id.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "config.h" @@ -10,13 +9,13 @@ #include "parse-options.h" #include "setup.h" -static void flush_current_id(int patchlen, struct object_id *id, struct object_id *result) +static void flush_current_id(size_t patchlen, struct object_id *id, struct object_id *result) { if (patchlen) printf("%s %s\n", oid_to_hex(result), oid_to_hex(id)); } -static int remove_space(char *line) +static size_t remove_space(char *line) { char *src = line; char *dst = line; @@ -63,10 +62,11 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after) return 1; } -static int get_one_patchid(struct object_id *next_oid, struct object_id *result, - struct strbuf *line_buf, int stable, int verbatim) +static size_t get_one_patchid(struct object_id *next_oid, struct object_id *result, + struct strbuf *line_buf, int stable, int verbatim) { - int patchlen = 0, found_next = 0; + size_t patchlen = 0; + int found_next = 0; int before = -1, after = -1; int diff_is_binary = 0; char pre_oid_str[GIT_MAX_HEXSZ + 1], post_oid_str[GIT_MAX_HEXSZ + 1]; @@ -78,7 +78,7 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result, while (strbuf_getwholeline(line_buf, stdin, '\n') != EOF) { char *line = line_buf->buf; const char *p = line; - int len; + size_t len; /* Possibly skip over the prefix added by "log" or "format-patch" */ if (!skip_prefix(line, "commit ", &p) && @@ -179,7 +179,7 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result, static void generate_id_list(int stable, int verbatim) { struct object_id oid, n, result; - int patchlen; + size_t patchlen; struct strbuf line_buf = STRBUF_INIT; oidclr(&oid, the_repository->hash_algo); -- cgit v1.2.3 From 89a0c5c024a53375a703a92dee11666d7ae11cd2 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 11:27:30 +0100 Subject: scalar: address -Wsign-compare warnings There are two -Wsign-compare warnings in "scalar.c", both of which are trivial: - We mistakenly use a signed integer to loop towards an upper unsigned bound in `cmd_reconfigure()`. - We subtract `path_sep - enlistment->buf`, which results in a signed integer, and use the value in a ternary expression where second value is unsigned. But as `path_sep` is being assigned the result of `find_last_dir_sep(enlistment->buf + offset)` we know that it must always be bigger than or equal to `enlistment->buf`, and thus the result will be positive. Address both of these warnings. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- scalar.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/scalar.c b/scalar.c index 87bb30991b..f24bcd0169 100644 --- a/scalar.c +++ b/scalar.c @@ -3,7 +3,6 @@ */ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "abspath.h" @@ -380,7 +379,7 @@ static int delete_enlistment(struct strbuf *enlistment) offset = offset_1st_component(enlistment->buf); path_sep = find_last_dir_sep(enlistment->buf + offset); strbuf_add(&parent, enlistment->buf, - path_sep ? path_sep - enlistment->buf : offset); + path_sep ? (size_t) (path_sep - enlistment->buf) : offset); if (chdir(parent.buf) < 0) { int res = error_errno(_("could not switch to '%s'"), parent.buf); strbuf_release(&parent); @@ -655,7 +654,7 @@ static int cmd_reconfigure(int argc, const char **argv) NULL }; struct string_list scalar_repos = STRING_LIST_INIT_DUP; - int i, res = 0; + int res = 0; struct strbuf commondir = STRBUF_INIT, gitdir = STRBUF_INIT; argc = parse_options(argc, argv, NULL, options, @@ -673,7 +672,7 @@ static int cmd_reconfigure(int argc, const char **argv) git_config(get_scalar_repos, &scalar_repos); - for (i = 0; i < scalar_repos.nr; i++) { + for (size_t i = 0; i < scalar_repos.nr; i++) { int succeeded = 0; struct repository *old_repo, r = { NULL }; const char *dir = scalar_repos.items[i].string; -- cgit v1.2.3 From e03d2a9ccb88c7ff42237f5890a05e071497f8ae Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 11:27:31 +0100 Subject: t/helper: don't depend on implicit wraparound In our test helpers we have two cases where we assign -1 to an `unsigned long`. The intent is to essentially mean "unbounded output", which is achieved via implicit wraparound of the value. This pattern causes warnings with -Wsign-compare though. Adapt it and instead use `ULONG_MAX` explicitly. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- t/helper/test-csprng.c | 5 +---- t/helper/test-genrandom.c | 4 +--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/t/helper/test-csprng.c b/t/helper/test-csprng.c index ea9b9b6563..a4a0aca617 100644 --- a/t/helper/test-csprng.c +++ b/t/helper/test-csprng.c @@ -1,9 +1,6 @@ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "test-tool.h" #include "git-compat-util.h" - int cmd__csprng(int argc, const char **argv) { unsigned long count; @@ -14,7 +11,7 @@ int cmd__csprng(int argc, const char **argv) return 2; } - count = (argc == 2) ? strtoul(argv[1], NULL, 0) : -1L; + count = (argc == 2) ? strtoul(argv[1], NULL, 0) : ULONG_MAX; while (count) { unsigned long chunk = count < sizeof(buf) ? count : sizeof(buf); diff --git a/t/helper/test-genrandom.c b/t/helper/test-genrandom.c index 5b51e6648d..51b67f2f87 100644 --- a/t/helper/test-genrandom.c +++ b/t/helper/test-genrandom.c @@ -4,8 +4,6 @@ * Copyright (C) 2007 by Nicolas Pitre, licensed under the GPL version 2. */ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "test-tool.h" #include "git-compat-util.h" @@ -24,7 +22,7 @@ int cmd__genrandom(int argc, const char **argv) next = next * 11 + *c; } while (*c++); - count = (argc == 3) ? strtoul(argv[2], NULL, 0) : -1L; + count = (argc == 3) ? strtoul(argv[2], NULL, 0) : ULONG_MAX; while (count--) { next = next * 1103515245 + 12345; -- cgit v1.2.3 From 4638e8806e3a1c5550b9ee3a1201e79cc519b85e Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:36 +0100 Subject: Makefile: use common template for GIT-BUILD-OPTIONS The "GIT-BUILD-OPTIONS" file is generated by our build systems to propagate built-in features and paths to our tests. The generation is done ad-hoc, where both our Makefile and the CMake build instructions simply echo a bunch of strings into the file. This makes it very hard to figure out what variables are expected to exist and what format they have, and the written variables can easily get out of sync between build systems. Introduce a new "GIT-BUILD-OPTIONS.in" template to address this issue. This has multiple advantages: - It demonstrates which built options exist in the first place. - It can serve as a spot to document the build options. - Some build systems complain when not all variables could be substituted, alerting us of mismatches. Others don't, but if we forgot to substitute such variables we now have a bogus string that will likely cause our tests to fail, if they have any meaning in the first place. Backfill values that we didn't yet set in our CMake build instructions. While at it, remove the `SUPPORTS_SIMPLE_IPC` variable that we only set up in CMake as it isn't used anywhere. This change requires us to adapt the setup of TEST_OUTPUT_DIRECTORY in "test-lib.sh" such that it does not get overwritten after sourcing when it has been set up via the environment. This is the only instance I could find where we rely on ordering on variables. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- GIT-BUILD-OPTIONS.in | 36 +++++++++++ Makefile | 115 ++++++++++++++---------------------- contrib/buildsystems/CMakeLists.txt | 58 ++++++++++++------ t/test-lib.sh | 22 +++++-- 4 files changed, 136 insertions(+), 95 deletions(-) create mode 100644 GIT-BUILD-OPTIONS.in diff --git a/GIT-BUILD-OPTIONS.in b/GIT-BUILD-OPTIONS.in new file mode 100644 index 0000000000..f0ca240493 --- /dev/null +++ b/GIT-BUILD-OPTIONS.in @@ -0,0 +1,36 @@ +SHELL_PATH=@SHELL_PATH@ +TEST_SHELL_PATH=@TEST_SHELL_PATH@ +PERL_PATH=@PERL_PATH@ +DIFF=@DIFF@ +PYTHON_PATH=@PYTHON_PATH@ +TAR=@TAR@ +NO_CURL=@NO_CURL@ +NO_ICONV=@NO_ICONV@ +NO_EXPAT=@NO_EXPAT@ +USE_LIBPCRE2=@USE_LIBPCRE2@ +NO_PERL=@NO_PERL@ +NO_PTHREADS=@NO_PTHREADS@ +NO_PYTHON=@NO_PYTHON@ +NO_REGEX=@NO_REGEX@ +NO_UNIX_SOCKETS=@NO_UNIX_SOCKETS@ +PAGER_ENV=@PAGER_ENV@ +SANITIZE_LEAK=@SANITIZE_LEAK@ +SANITIZE_ADDRESS=@SANITIZE_ADDRESS@ +X=@X@ +FSMONITOR_DAEMON_BACKEND=@FSMONITOR_DAEMON_BACKEND@ +FSMONITOR_OS_SETTINGS=@FSMONITOR_OS_SETTINGS@ +TEST_OUTPUT_DIRECTORY=@TEST_OUTPUT_DIRECTORY@ +GIT_TEST_OPTS=@GIT_TEST_OPTS@ +GIT_TEST_CMP=@GIT_TEST_CMP@ +GIT_TEST_CMP_USE_COPIED_CONTEXT=@GIT_TEST_CMP_USE_COPIED_CONTEXT@ +GIT_TEST_UTF8_LOCALE=@GIT_TEST_UTF8_LOCALE@ +NO_GETTEXT=@NO_GETTEXT@ +GIT_PERF_REPEAT_COUNT=@GIT_PERF_REPEAT_COUNT@ +GIT_PERF_REPO=@GIT_PERF_REPO@ +GIT_PERF_LARGE_REPO=@GIT_PERF_LARGE_REPO@ +GIT_PERF_MAKE_OPTS=@GIT_PERF_MAKE_OPTS@ +GIT_PERF_MAKE_COMMAND=@GIT_PERF_MAKE_COMMAND@ +GIT_INTEROP_MAKE_OPTS=@GIT_INTEROP_MAKE_OPTS@ +GIT_TEST_INDEX_VERSION=@GIT_TEST_INDEX_VERSION@ +GIT_TEST_PERL_FATAL_WARNINGS=@GIT_TEST_PERL_FATAL_WARNINGS@ +RUNTIME_PREFIX=@RUNTIME_PREFIX@ diff --git a/Makefile b/Makefile index 549b24e7fd..1f8434a902 100644 --- a/Makefile +++ b/Makefile @@ -3160,80 +3160,55 @@ GIT-LDFLAGS: FORCE echo "$$FLAGS" >GIT-LDFLAGS; \ fi +ifdef RUNTIME_PREFIX +RUNTIME_PREFIX_OPTION = true +else +RUNTIME_PREFIX_OPTION = false +endif + # We need to apply sq twice, once to protect from the shell # that runs GIT-BUILD-OPTIONS, and then again to protect it # and the first level quoting from the shell that runs "echo". GIT-BUILD-OPTIONS: FORCE - @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@+ - @echo TEST_SHELL_PATH=\''$(subst ','\'',$(TEST_SHELL_PATH_SQ))'\' >>$@+ - @echo PERL_PATH=\''$(subst ','\'',$(PERL_PATH_SQ))'\' >>$@+ - @echo DIFF=\''$(subst ','\'',$(subst ','\'',$(DIFF)))'\' >>$@+ - @echo PYTHON_PATH=\''$(subst ','\'',$(PYTHON_PATH_SQ))'\' >>$@+ - @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@+ - @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@+ - @echo NO_ICONV=\''$(subst ','\'',$(subst ','\'',$(NO_ICONV)))'\' >>$@+ - @echo NO_EXPAT=\''$(subst ','\'',$(subst ','\'',$(NO_EXPAT)))'\' >>$@+ - @echo USE_LIBPCRE2=\''$(subst ','\'',$(subst ','\'',$(USE_LIBPCRE2)))'\' >>$@+ - @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@+ - @echo NO_PTHREADS=\''$(subst ','\'',$(subst ','\'',$(NO_PTHREADS)))'\' >>$@+ - @echo NO_PYTHON=\''$(subst ','\'',$(subst ','\'',$(NO_PYTHON)))'\' >>$@+ - @echo NO_REGEX=\''$(subst ','\'',$(subst ','\'',$(NO_REGEX)))'\' >>$@+ - @echo NO_UNIX_SOCKETS=\''$(subst ','\'',$(subst ','\'',$(NO_UNIX_SOCKETS)))'\' >>$@+ - @echo PAGER_ENV=\''$(subst ','\'',$(subst ','\'',$(PAGER_ENV)))'\' >>$@+ - @echo SANITIZE_LEAK=\''$(subst ','\'',$(subst ','\'',$(SANITIZE_LEAK)))'\' >>$@+ - @echo SANITIZE_ADDRESS=\''$(subst ','\'',$(subst ','\'',$(SANITIZE_ADDRESS)))'\' >>$@+ - @echo X=\'$(X)\' >>$@+ -ifdef FSMONITOR_DAEMON_BACKEND - @echo FSMONITOR_DAEMON_BACKEND=\''$(subst ','\'',$(subst ','\'',$(FSMONITOR_DAEMON_BACKEND)))'\' >>$@+ -endif -ifdef FSMONITOR_OS_SETTINGS - @echo FSMONITOR_OS_SETTINGS=\''$(subst ','\'',$(subst ','\'',$(FSMONITOR_OS_SETTINGS)))'\' >>$@+ -endif -ifdef TEST_OUTPUT_DIRECTORY - @echo TEST_OUTPUT_DIRECTORY=\''$(subst ','\'',$(subst ','\'',$(TEST_OUTPUT_DIRECTORY)))'\' >>$@+ -endif -ifdef GIT_TEST_OPTS - @echo GIT_TEST_OPTS=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_OPTS)))'\' >>$@+ -endif -ifdef GIT_TEST_CMP - @echo GIT_TEST_CMP=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_CMP)))'\' >>$@+ -endif -ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT - @echo GIT_TEST_CMP_USE_COPIED_CONTEXT=YesPlease >>$@+ -endif -ifdef GIT_TEST_UTF8_LOCALE - @echo GIT_TEST_UTF8_LOCALE=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_UTF8_LOCALE)))'\' >>$@+ -endif - @echo NO_GETTEXT=\''$(subst ','\'',$(subst ','\'',$(NO_GETTEXT)))'\' >>$@+ -ifdef GIT_PERF_REPEAT_COUNT - @echo GIT_PERF_REPEAT_COUNT=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_REPEAT_COUNT)))'\' >>$@+ -endif -ifdef GIT_PERF_REPO - @echo GIT_PERF_REPO=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_REPO)))'\' >>$@+ -endif -ifdef GIT_PERF_LARGE_REPO - @echo GIT_PERF_LARGE_REPO=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_LARGE_REPO)))'\' >>$@+ -endif -ifdef GIT_PERF_MAKE_OPTS - @echo GIT_PERF_MAKE_OPTS=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_MAKE_OPTS)))'\' >>$@+ -endif -ifdef GIT_PERF_MAKE_COMMAND - @echo GIT_PERF_MAKE_COMMAND=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_MAKE_COMMAND)))'\' >>$@+ -endif -ifdef GIT_INTEROP_MAKE_OPTS - @echo GIT_INTEROP_MAKE_OPTS=\''$(subst ','\'',$(subst ','\'',$(GIT_INTEROP_MAKE_OPTS)))'\' >>$@+ -endif -ifdef GIT_TEST_INDEX_VERSION - @echo GIT_TEST_INDEX_VERSION=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_INDEX_VERSION)))'\' >>$@+ -endif -ifdef GIT_TEST_PERL_FATAL_WARNINGS - @echo GIT_TEST_PERL_FATAL_WARNINGS=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_PERL_FATAL_WARNINGS)))'\' >>$@+ -endif -ifdef RUNTIME_PREFIX - @echo RUNTIME_PREFIX=\'true\' >>$@+ -else - @echo RUNTIME_PREFIX=\'false\' >>$@+ -endif + @sed \ + -e "s|@SHELL_PATH@|\'$(SHELL_PATH_SQ)\'|" \ + -e "s|@TEST_SHELL_PATH@|\'$(TEST_SHELL_PATH_SQ)\'|" \ + -e "s|@PERL_PATH@|\'$(PERL_PATH_SQ)\'|" \ + -e "s|@DIFF@|\'$(DIFF)\'|" \ + -e "s|@PYTHON_PATH@|\'$(PYTHON_PATH_SQ)\'|" \ + -e "s|@TAR@|\'$(TAR)\'|" \ + -e "s|@NO_CURL@|\'$(NO_CURL)\'|" \ + -e "s|@NO_ICONV@|\'$(NO_ICONV)\'|" \ + -e "s|@NO_EXPAT@|\'$(NO_EXPAT)\'|" \ + -e "s|@USE_LIBPCRE2@|\'$(USE_LIBPCRE2)\'|" \ + -e "s|@NO_PERL@|\'$(NO_PERL)\'|" \ + -e "s|@NO_PTHREADS@|\'$(NO_PTHREADS)\'|" \ + -e "s|@NO_PYTHON@|\'$(NO_PYTHON)\'|" \ + -e "s|@NO_REGEX@|\'$(NO_REGEX)\'|" \ + -e "s|@NO_UNIX_SOCKETS@|\'$(NO_UNIX_SOCKETS)\'|" \ + -e "s|@PAGER_ENV@|\'$(PAGER_ENV)\'|" \ + -e "s|@SANITIZE_LEAK@|\'$(SANITIZE_LEAK)\'|" \ + -e "s|@SANITIZE_ADDRESS@|\'$(SANITIZE_ADDRESS)\'|" \ + -e "s|@X@|\'$(X)\'|" \ + -e "s|@FSMONITOR_DAEMON_BACKEND@|\'$(FSMONITOR_DAEMON_BACKEND)\'|" \ + -e "s|@FSMONITOR_OS_SETTINGS@|\'$(FSMONITOR_OS_SETTINGS)\'|" \ + -e "s|@TEST_OUTPUT_DIRECTORY@|\'$(TEST_OUTPUT_DIRECTORY)\'|" \ + -e "s|@GIT_TEST_OPTS@|\'$(GIT_TEST_OPTS)\'|" \ + -e "s|@GIT_TEST_CMP@|\'$(GIT_TEST_CMP)\'|" \ + -e "s|@GIT_TEST_CMP_USE_COPIED_CONTEXT@|\'$(GIT_TEST_CMP_USE_COPIED_CONTEXT)\'|" \ + -e "s|@GIT_TEST_UTF8_LOCALE@|\'$(GIT_TEST_UTF8_LOCALE)\'|" \ + -e "s|@NO_GETTEXT@|\'$(NO_GETTEXT)\'|" \ + -e "s|@GIT_PERF_REPEAT_COUNT@|\'$(GIT_PERF_REPEAT_COUNT)\'|" \ + -e "s|@GIT_PERF_REPO@|\'$(GIT_PERF_REPO)\'|" \ + -e "s|@GIT_PERF_LARGE_REPO@|\'$(GIT_PERF_LARGE_REPO)\'|" \ + -e "s|@GIT_PERF_MAKE_OPTS@|\'$(GIT_PERF_MAKE_OPTS)\'|" \ + -e "s|@GIT_PERF_MAKE_COMMAND@|\'$(GIT_PERF_MAKE_COMMAND)\'|" \ + -e "s|@GIT_INTEROP_MAKE_OPTS@|\'$(GIT_INTEROP_MAKE_OPTS)\'|" \ + -e "s|@GIT_TEST_INDEX_VERSION@|\'$(GIT_TEST_INDEX_VERSION)\'|" \ + -e "s|@GIT_TEST_PERL_FATAL_WARNINGS@|\'$(GIT_TEST_PERL_FATAL_WARNINGS)\'|" \ + -e "s|@RUNTIME_PREFIX@|\'$(RUNTIME_PREFIX_OPTION)\'|" \ + GIT-BUILD-OPTIONS.in >$@+ + @if grep -q '^[A-Z][A-Z_]*=@.*@$$' $@+; then echo "Unsubstituted build options in $@" >&2 && exit 1; fi @if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi @if test -f GIT-BUILD-DIR; then rm GIT-BUILD-DIR; fi diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 8c71f5a1d0..985004f594 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -1125,27 +1125,47 @@ if(NOT PYTHON_TESTS) set(NO_PYTHON 1) endif() -file(WRITE ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "SHELL_PATH='${SHELL_PATH}'\n") -file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "TEST_SHELL_PATH='${TEST_SHELL_PATH}'\n") -file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "PERL_PATH='${PERL_PATH}'\n") -file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "DIFF='${DIFF}'\n") -file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "PYTHON_PATH='${PYTHON_PATH}'\n") -file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "TAR='${TAR}'\n") -file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_CURL='${NO_CURL}'\n") -file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_ICONV='${NO_ICONV}'\n") -file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_EXPAT='${NO_EXPAT}'\n") -file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_PERL='${NO_PERL}'\n") -file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_PTHREADS='${NO_PTHREADS}'\n") -file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_UNIX_SOCKETS='${NO_UNIX_SOCKETS}'\n") -file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "PAGER_ENV='${PAGER_ENV}'\n") -file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "X='${EXE_EXTENSION}'\n") -file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_GETTEXT='${NO_GETTEXT}'\n") -file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "RUNTIME_PREFIX='${RUNTIME_PREFIX}'\n") -file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_PYTHON='${NO_PYTHON}'\n") -file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "SUPPORTS_SIMPLE_IPC='${SUPPORTS_SIMPLE_IPC}'\n") +file(STRINGS ${CMAKE_SOURCE_DIR}/GIT-BUILD-OPTIONS.in git_build_options NEWLINE_CONSUME) +string(REPLACE "@SHELL_PATH@" "'${SHELL_PATH}'" git_build_options "${git_build_options}") +string(REPLACE "@TEST_SHELL_PATH@" "'${TEST_SHELL_PATH}'" git_build_options "${git_build_options}") +string(REPLACE "@PERL_PATH@" "'${PERL_PATH}'" git_build_options "${git_build_options}") +string(REPLACE "@DIFF@" "'${DIFF}'" git_build_options "${git_build_options}") +string(REPLACE "@PYTHON_PATH@" "'${PYTHON_PATH}'" git_build_options "${git_build_options}") +string(REPLACE "@TAR@" "'${TAR}'" git_build_options "${git_build_options}") +string(REPLACE "@NO_CURL@" "${NO_CURL}" git_build_options "${git_build_options}") +string(REPLACE "@NO_ICONV@" "${NO_ICONV}" git_build_options "${git_build_options}") +string(REPLACE "@NO_EXPAT@" "${NO_EXPAT}" git_build_options "${git_build_options}") +string(REPLACE "@USE_LIBPCRE2@" "" git_build_options "${git_build_options}") +string(REPLACE "@NO_PERL@" "${NO_PERL}" git_build_options "${git_build_options}") +string(REPLACE "@NO_PTHREADS@" "${NO_PTHREADS}" git_build_options "${git_build_options}") +string(REPLACE "@NO_PYTHON@" "${NO_PYTHON}" git_build_options "${git_build_options}") +string(REPLACE "@NO_REGEX@" "" git_build_options "${git_build_options}") +string(REPLACE "@NO_UNIX_SOCKETS@" "${NO_UNIX_SOCKETS}" git_build_options "${git_build_options}") +string(REPLACE "@PAGER_ENV@" "'${PAGER_ENV}'" git_build_options "${git_build_options}") +string(REPLACE "@SANITIZE_LEAK@" "" git_build_options "${git_build_options}") +string(REPLACE "@SANITIZE_ADDRESS@" "" git_build_options "${git_build_options}") +string(REPLACE "@X@" "${EXE_EXTENSION}" git_build_options "${git_build_options}") +string(REPLACE "@FSMONITOR_DAEMON_BACKEND@" "win32" git_build_options "${git_build_options}") +string(REPLACE "@FSMONITOR_OS_SETTINGS@" "win32" git_build_options "${git_build_options}") +string(REPLACE "@TEST_OUTPUT_DIRECTORY@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_OPTS@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_CMP@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_CMP_USE_COPIED_CONTEXT@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_UTF8_LOCALE@" "" git_build_options "${git_build_options}") +string(REPLACE "@NO_GETTEXT@" "${NO_GETTEXT}" git_build_options "${git_build_options}") +string(REPLACE "@GIT_PERF_REPEAT_COUNT@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_PERF_REPO@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_PERF_LARGE_REPO@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_PERF_MAKE_OPTS@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_PERF_MAKE_COMMAND@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_INTEROP_MAKE_OPTS@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_INDEX_VERSION@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_PERL_FATAL_WARNINGS@" "" git_build_options "${git_build_options}") +string(REPLACE "@RUNTIME_PREFIX@" "'${RUNTIME_PREFIX}'" git_build_options "${git_build_options}") if(USE_VCPKG) - file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "PATH=\"$PATH:$TEST_DIRECTORY/../compat/vcbuild/vcpkg/installed/x64-windows/bin\"\n") + string(APPEND git_build_options "PATH=\"$PATH:$TEST_DIRECTORY/../compat/vcbuild/vcpkg/installed/x64-windows/bin\"\n") endif() +file(WRITE ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS ${git_build_options}) #Make the tests work when building out of the source tree get_filename_component(CACHE_PATH ${CMAKE_CURRENT_LIST_DIR}/../../CMakeCache.txt ABSOLUTE) diff --git a/t/test-lib.sh b/t/test-lib.sh index 426036b33a..20012f6f47 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -35,12 +35,6 @@ else # needing to exist. TEST_DIRECTORY=$(cd "$TEST_DIRECTORY" && pwd) || exit 1 fi -if test -z "$TEST_OUTPUT_DIRECTORY" -then - # Similarly, override this to store the test-results subdir - # elsewhere - TEST_OUTPUT_DIRECTORY=$TEST_DIRECTORY -fi GIT_BUILD_DIR="${TEST_DIRECTORY%/t}" if test "$TEST_DIRECTORY" = "$GIT_BUILD_DIR" then @@ -92,6 +86,15 @@ export LSAN_OPTIONS prepend_var UBSAN_OPTIONS : $GIT_SAN_OPTIONS export UBSAN_OPTIONS +# The TEST_OUTPUT_DIRECTORY will be overwritten via GIT-BUILD-OPTIONS. So in +# case the caller has manually set up this variable via the environment we must +# make sure to not overwrite that value, and thus we save it into +# TEST_OUTPUT_DIRECTORY_OVERRIDE here. +if test -n "$TEST_OUTPUT_DIRECTORY" && test -z "$TEST_OUTPUT_DIRECTORY_OVERRIDE" +then + TEST_OUTPUT_DIRECTORY_OVERRIDE=$TEST_OUTPUT_DIRECTORY +fi + if test ! -f "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS then echo >&2 'error: GIT-BUILD-OPTIONS missing (has Git been built?).' @@ -100,6 +103,13 @@ fi . "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS export PERL_PATH SHELL_PATH +if test -z "$TEST_OUTPUT_DIRECTORY" +then + # Similarly, override this to store the test-results subdir + # elsewhere + TEST_OUTPUT_DIRECTORY=$TEST_DIRECTORY +fi + # In t0000, we need to override test directories of nested testcases. In case # the developer has TEST_OUTPUT_DIRECTORY part of his build options, then we'd # reset this value to instead contain what the developer has specified. We thus -- cgit v1.2.3 From dbe46c0feb25417d01267bb97edb861694ed023d Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:37 +0100 Subject: Makefile: consistently use @PLACEHOLDER@ to substitute We have a bunch of placeholders in our scripts that we replace at build time, for example by using sed(1). These placeholders come in three different formats: @PLACEHOLDER@, @@PLACEHOLDER@@ and ++PLACEHOLDER++. Next to being inconsistent it also creates a bit of a problem with CMake, which only supports the first syntax in its `configure_file()` function. To work around that we instead manually replace placeholders via string operations, which is a hassle and removes safeguards that CMake has to verify that we didn't forget to replace any placeholders. Besides that, other build systems like Meson also support the CMake syntax. Unify our codebase to consistently use the syntax supported by such build systems. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Makefile | 44 ++++++++++++------------ configure.ac | 2 +- contrib/buildsystems/CMakeLists.txt | 34 +++++++++--------- git-cvsserver.perl | 2 +- git-instaweb.sh | 8 ++--- git-request-pull.sh | 2 +- git-send-email.perl | 2 +- git-sh-i18n.sh | 6 ++-- git-sh-setup.sh | 6 ++-- git-svn.perl | 2 +- gitweb/Makefile | 44 ++++++++++++------------ gitweb/gitweb.perl | 44 ++++++++++++------------ perl/Git/I18N.pm | 6 ++-- perl/Git/LoadCPAN.pm | 6 ++-- perl/header_templates/fixed_prefix.template.pl | 2 +- perl/header_templates/runtime_prefix.template.pl | 8 ++--- unimplemented.sh | 2 +- wrap-for-bin.sh | 18 +++++----- 18 files changed, 119 insertions(+), 119 deletions(-) diff --git a/Makefile b/Makefile index 1f8434a902..75e26d2e31 100644 --- a/Makefile +++ b/Makefile @@ -1555,10 +1555,10 @@ endif ifdef SANE_TOOL_PATH SANE_TOOL_PATH_SQ = $(subst ','\'',$(SANE_TOOL_PATH)) -BROKEN_PATH_FIX = 's|^\# @@BROKEN_PATH_FIX@@$$|git_broken_path_fix "$(SANE_TOOL_PATH_SQ)"|' +BROKEN_PATH_FIX = 's|^\# @BROKEN_PATH_FIX@$$|git_broken_path_fix "$(SANE_TOOL_PATH_SQ)"|' PATH := $(SANE_TOOL_PATH):${PATH} else -BROKEN_PATH_FIX = '/^\# @@BROKEN_PATH_FIX@@$$/d' +BROKEN_PATH_FIX = '/^\# @BROKEN_PATH_FIX@$$/d' endif ifeq (,$(HOST_CPU)) @@ -2548,13 +2548,13 @@ GIT-SCRIPT-DEFINES: FORCE define cmd_munge_script sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \ - -e 's|@@DIFF@@|$(DIFF_SQ)|' \ - -e 's|@@LOCALEDIR@@|$(localedir_SQ)|g' \ - -e 's/@@USE_GETTEXT_SCHEME@@/$(USE_GETTEXT_SCHEME)/g' \ + -e 's|@DIFF@|$(DIFF_SQ)|' \ + -e 's|@LOCALEDIR@|$(localedir_SQ)|g' \ + -e 's/@USE_GETTEXT_SCHEME@/$(USE_GETTEXT_SCHEME)/g' \ -e $(BROKEN_PATH_FIX) \ - -e 's|@@GITWEBDIR@@|$(gitwebdir_SQ)|g' \ - -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ - -e 's|@@PAGER_ENV@@|$(PAGER_ENV_SQ)|g' \ + -e 's|@GITWEBDIR@|$(gitwebdir_SQ)|g' \ + -e 's|@PERL@|$(PERL_PATH_SQ)|g' \ + -e 's|@PAGER_ENV@|$(PAGER_ENV_SQ)|g' \ $@.sh >$@+ endef @@ -2611,7 +2611,7 @@ $(SCRIPT_PERL_GEN): % : %.perl GIT-PERL-DEFINES GIT-PERL-HEADER GIT-VERSION-FILE -e ' r GIT-PERL-HEADER' \ -e ' G' \ -e '}' \ - -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ + -e 's/@GIT_VERSION@/$(GIT_VERSION)/g' \ $< >$@+ && \ chmod +x $@+ && \ mv $@+ $@ @@ -2629,11 +2629,11 @@ GIT-PERL-HEADER: $(PERL_HEADER_TEMPLATE) GIT-PERL-DEFINES Makefile INSTLIBDIR='$(perllibdir_SQ)' && \ INSTLIBDIR_EXTRA='$(PERLLIB_EXTRA_SQ)' && \ INSTLIBDIR="$$INSTLIBDIR$${INSTLIBDIR_EXTRA:+:$$INSTLIBDIR_EXTRA}" && \ - sed -e 's=@@PATHSEP@@=$(pathsep)=g' \ - -e "s=@@INSTLIBDIR@@=$$INSTLIBDIR=g" \ - -e 's=@@PERLLIBDIR_REL@@=$(perllibdir_relative_SQ)=g' \ - -e 's=@@GITEXECDIR_REL@@=$(gitexecdir_relative_SQ)=g' \ - -e 's=@@LOCALEDIR_REL@@=$(localedir_relative_SQ)=g' \ + sed -e 's=@PATHSEP@=$(pathsep)=g' \ + -e "s=@INSTLIBDIR@=$$INSTLIBDIR=g" \ + -e 's=@PERLLIBDIR_REL@=$(perllibdir_relative_SQ)=g' \ + -e 's=@GITEXECDIR_REL@=$(gitexecdir_relative_SQ)=g' \ + -e 's=@LOCALEDIR_REL@=$(localedir_relative_SQ)=g' \ $< >$@+ && \ mv $@+ $@ @@ -2649,7 +2649,7 @@ else # NO_PERL $(SCRIPT_PERL_GEN) git-instaweb: % : unimplemented.sh $(QUIET_GEN) \ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ - -e 's|@@REASON@@|NO_PERL=$(NO_PERL)|g' \ + -e 's|@REASON@|NO_PERL=$(NO_PERL)|g' \ unimplemented.sh >$@+ && \ chmod +x $@+ && \ mv $@+ $@ @@ -2670,13 +2670,13 @@ else # NO_PYTHON $(SCRIPT_PYTHON_GEN): % : unimplemented.sh $(QUIET_GEN) \ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ - -e 's|@@REASON@@|NO_PYTHON=$(NO_PYTHON)|g' \ + -e 's|@REASON@|NO_PYTHON=$(NO_PYTHON)|g' \ unimplemented.sh >$@+ && \ chmod +x $@+ && \ mv $@+ $@ endif # NO_PYTHON -CONFIGURE_RECIPE = sed -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ +CONFIGURE_RECIPE = sed -e 's/@GIT_VERSION@/$(GIT_VERSION)/g' \ configure.ac >configure.ac+ && \ autoconf -o configure configure.ac+ && \ $(RM) configure.ac+ @@ -3104,9 +3104,9 @@ endif perl/build/lib/%.pm: perl/%.pm GIT-PERL-DEFINES $(call mkdir_p_parent_template) $(QUIET_GEN) \ - sed -e 's|@@LOCALEDIR@@|$(perl_localedir_SQ)|g' \ - -e 's|@@NO_GETTEXT@@|$(NO_GETTEXT_SQ)|g' \ - -e 's|@@NO_PERL_CPAN_FALLBACKS@@|$(NO_PERL_CPAN_FALLBACKS_SQ)|g' \ + sed -e 's|@LOCALEDIR@|$(perl_localedir_SQ)|g' \ + -e 's|@NO_GETTEXT@|$(NO_GETTEXT_SQ)|g' \ + -e 's|@NO_PERL_CPAN_FALLBACKS@|$(NO_PERL_CPAN_FALLBACKS_SQ)|g' \ < $< > $@ perl/build/man/man3/Git.3pm: perl/Git.pm @@ -3231,8 +3231,8 @@ all:: $(TEST_PROGRAMS) $(test_bindir_programs) $(UNIT_TEST_PROGS) $(CLAR_TEST_PR bin-wrappers/%: wrap-for-bin.sh $(call mkdir_p_parent_template) $(QUIET_GEN)sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ - -e 's|@@BUILD_DIR@@|$(shell pwd)|' \ - -e 's|@@PROG@@|$(patsubst test-%,t/helper/test-%,$(@F))$(if $(filter-out $(BINDIR_PROGRAMS_NO_X),$(@F)),$(X),)|' < $< > $@ && \ + -e 's|@BUILD_DIR@|$(shell pwd)|' \ + -e 's|@PROG@|$(patsubst test-%,t/helper/test-%,$(@F))$(if $(filter-out $(BINDIR_PROGRAMS_NO_X),$(@F)),$(X),)|' < $< > $@ && \ chmod +x $@ # GNU make supports exporting all variables by "export" without parameters. diff --git a/configure.ac b/configure.ac index d1a96da14e..5923edc44a 100644 --- a/configure.ac +++ b/configure.ac @@ -142,7 +142,7 @@ fi ## Configure body starts here. AC_PREREQ(2.59) -AC_INIT([git], [@@GIT_VERSION@@], [git@vger.kernel.org]) +AC_INIT([git], [@GIT_VERSION@], [git@vger.kernel.org]) AC_CONFIG_SRCDIR([git.c]) diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 985004f594..1abf5f099c 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -836,14 +836,14 @@ set(git_shell_scripts foreach(script ${git_shell_scripts}) file(STRINGS ${CMAKE_SOURCE_DIR}/${script}.sh content NEWLINE_CONSUME) string(REPLACE "@SHELL_PATH@" "${SHELL_PATH}" content "${content}") - string(REPLACE "@@DIFF@@" "diff" content "${content}") + string(REPLACE "@DIFF@" "diff" content "${content}") string(REPLACE "@LOCALEDIR@" "${LOCALEDIR}" content "${content}") string(REPLACE "@GITWEBDIR@" "${GITWEBDIR}" content "${content}") - string(REPLACE "@@NO_CURL@@" "" content "${content}") - string(REPLACE "@@USE_GETTEXT_SCHEME@@" "" content "${content}") - string(REPLACE "# @@BROKEN_PATH_FIX@@" "" content "${content}") - string(REPLACE "@@PERL@@" "${PERL_PATH}" content "${content}") - string(REPLACE "@@PAGER_ENV@@" "LESS=FRX LV=-c" content "${content}") + string(REPLACE "@NO_CURL@" "" content "${content}") + string(REPLACE "@USE_GETTEXT_SCHEME@" "" content "${content}") + string(REPLACE "# @BROKEN_PATH_FIX@" "" content "${content}") + string(REPLACE "@PERL@" "${PERL_PATH}" content "${content}") + string(REPLACE "@PAGER_ENV@" "LESS=FRX LV=-c" content "${content}") file(WRITE ${CMAKE_BINARY_DIR}/${script} ${content}) endforeach() @@ -852,13 +852,13 @@ parse_makefile_for_scripts(git_perl_scripts "SCRIPT_PERL" ".perl") #create perl header file(STRINGS ${CMAKE_SOURCE_DIR}/perl/header_templates/fixed_prefix.template.pl perl_header ) -string(REPLACE "@@PATHSEP@@" ":" perl_header "${perl_header}") -string(REPLACE "@@INSTLIBDIR@@" "${INSTLIBDIR}" perl_header "${perl_header}") +string(REPLACE "@PATHSEP@" ":" perl_header "${perl_header}") +string(REPLACE "@INSTLIBDIR@" "${INSTLIBDIR}" perl_header "${perl_header}") foreach(script ${git_perl_scripts}) file(STRINGS ${CMAKE_SOURCE_DIR}/${script}.perl content NEWLINE_CONSUME) string(REPLACE "#!/usr/bin/perl" "#!/usr/bin/perl\n${perl_header}\n" content "${content}") - string(REPLACE "@@GIT_VERSION@@" "${PROJECT_VERSION}" content "${content}") + string(REPLACE "@GIT_VERSION@" "${PROJECT_VERSION}" content "${content}") file(WRITE ${CMAKE_BINARY_DIR}/${script} ${content}) endforeach() @@ -873,8 +873,8 @@ file(GLOB_RECURSE perl_modules "${CMAKE_SOURCE_DIR}/perl/*.pm") foreach(pm ${perl_modules}) string(REPLACE "${CMAKE_SOURCE_DIR}/perl/" "" file_path ${pm}) file(STRINGS ${pm} content NEWLINE_CONSUME) - string(REPLACE "@@LOCALEDIR@@" "${LOCALEDIR}" content "${content}") - string(REPLACE "@@NO_PERL_CPAN_FALLBACKS@@" "" content "${content}") + string(REPLACE "@LOCALEDIR@" "${LOCALEDIR}" content "${content}") + string(REPLACE "@NO_PERL_CPAN_FALLBACKS@" "" content "${content}") file(WRITE ${CMAKE_BINARY_DIR}/perl/build/lib/${file_path} ${content}) #test-lib.sh requires perl/build/lib to be the build directory of perl modules endforeach() @@ -1064,21 +1064,21 @@ set(wrapper_test_scripts foreach(script ${wrapper_scripts}) file(STRINGS ${CMAKE_SOURCE_DIR}/wrap-for-bin.sh content NEWLINE_CONSUME) - string(REPLACE "@@BUILD_DIR@@" "${CMAKE_BINARY_DIR}" content "${content}") - string(REPLACE "@@PROG@@" "${script}${EXE_EXTENSION}" content "${content}") + string(REPLACE "@BUILD_DIR@" "${CMAKE_BINARY_DIR}" content "${content}") + string(REPLACE "@PROG@" "${script}${EXE_EXTENSION}" content "${content}") file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/${script} ${content}) endforeach() foreach(script ${wrapper_test_scripts}) file(STRINGS ${CMAKE_SOURCE_DIR}/wrap-for-bin.sh content NEWLINE_CONSUME) - string(REPLACE "@@BUILD_DIR@@" "${CMAKE_BINARY_DIR}" content "${content}") - string(REPLACE "@@PROG@@" "t/helper/${script}${EXE_EXTENSION}" content "${content}") + string(REPLACE "@BUILD_DIR@" "${CMAKE_BINARY_DIR}" content "${content}") + string(REPLACE "@PROG@" "t/helper/${script}${EXE_EXTENSION}" content "${content}") file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/${script} ${content}) endforeach() file(STRINGS ${CMAKE_SOURCE_DIR}/wrap-for-bin.sh content NEWLINE_CONSUME) -string(REPLACE "@@BUILD_DIR@@" "${CMAKE_BINARY_DIR}" content "${content}") -string(REPLACE "@@PROG@@" "git-cvsserver" content "${content}") +string(REPLACE "@BUILD_DIR@" "${CMAKE_BINARY_DIR}" content "${content}") +string(REPLACE "@PROG@" "git-cvsserver" content "${content}") file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/git-cvsserver ${content}) #options for configuring test options diff --git a/git-cvsserver.perl b/git-cvsserver.perl index a4ad9a5d2d..a4e1bad33c 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -26,7 +26,7 @@ use File::Path qw/rmtree/; use File::Basename; use Getopt::Long qw(:config require_order no_ignore_case); -my $VERSION = '@@GIT_VERSION@@'; +my $VERSION = '@GIT_VERSION@'; my $log = GITCVS::log->new(); my $cfg; diff --git a/git-instaweb.sh b/git-instaweb.sh index 8dbe21d588..c8efb1205a 100755 --- a/git-instaweb.sh +++ b/git-instaweb.sh @@ -3,7 +3,7 @@ # Copyright (c) 2006 Eric Wong # -PERL='@@PERL@@' +PERL='@PERL@' OPTIONS_KEEPDASHDASH= OPTIONS_STUCKLONG= OPTIONS_SPEC="\ @@ -38,8 +38,8 @@ conf="$GIT_DIR/gitweb/httpd.conf" # if installed, it doesn't need further configuration (module_path) test -z "$httpd" && httpd='lighttpd -f' -# Default is @@GITWEBDIR@@ -test -z "$root" && root='@@GITWEBDIR@@' +# Default is @GITWEBDIR@ +test -z "$root" && root='@GITWEBDIR@' # any untaken local port will do... test -z "$port" && port=1234 @@ -716,7 +716,7 @@ EOF gitweb_conf() { cat > "$fqgitdir/gitweb/gitweb_config.perl" <compile() if $ENV{'MOD_PERL'}; } -our $version = "++GIT_VERSION++"; +our $version = "@GIT_VERSION@"; our ($my_url, $my_uri, $base_url, $path_info, $home_link); sub evaluate_uri { @@ -80,46 +80,46 @@ sub evaluate_uri { # core git executable to use # this can just be "git" if your webserver has a sensible PATH -our $GIT = "++GIT_BINDIR++/git"; +our $GIT = "@GIT_BINDIR@/git"; # absolute fs-path which will be prepended to the project path #our $projectroot = "/pub/scm"; -our $projectroot = "++GITWEB_PROJECTROOT++"; +our $projectroot = "@GITWEB_PROJECTROOT@"; # fs traversing limit for getting project list # the number is relative to the projectroot -our $project_maxdepth = "++GITWEB_PROJECT_MAXDEPTH++"; +our $project_maxdepth = "@GITWEB_PROJECT_MAXDEPTH@"; # string of the home link on top of all pages -our $home_link_str = "++GITWEB_HOME_LINK_STR++"; +our $home_link_str = "@GITWEB_HOME_LINK_STR@"; # extra breadcrumbs preceding the home link our @extra_breadcrumbs = (); # name of your site or organization to appear in page titles # replace this with something more descriptive for clearer bookmarks -our $site_name = "++GITWEB_SITENAME++" +our $site_name = "@GITWEB_SITENAME@" || ($ENV{'SERVER_NAME'} || "Untitled") . " Git"; # html snippet to include in the section of each page -our $site_html_head_string = "++GITWEB_SITE_HTML_HEAD_STRING++"; +our $site_html_head_string = "@GITWEB_SITE_HTML_HEAD_STRING@"; # filename of html text to include at top of each page -our $site_header = "++GITWEB_SITE_HEADER++"; +our $site_header = "@GITWEB_SITE_HEADER@"; # html text to include at home page -our $home_text = "++GITWEB_HOMETEXT++"; +our $home_text = "@GITWEB_HOMETEXT@"; # filename of html text to include at bottom of each page -our $site_footer = "++GITWEB_SITE_FOOTER++"; +our $site_footer = "@GITWEB_SITE_FOOTER@"; # URI of stylesheets -our @stylesheets = ("++GITWEB_CSS++"); +our @stylesheets = ("@GITWEB_CSS@"); # URI of a single stylesheet, which can be overridden in GITWEB_CONFIG. our $stylesheet = undef; # URI of GIT logo (72x27 size) -our $logo = "++GITWEB_LOGO++"; +our $logo = "@GITWEB_LOGO@"; # URI of GIT favicon, assumed to be image/png type -our $favicon = "++GITWEB_FAVICON++"; +our $favicon = "@GITWEB_FAVICON@"; # URI of gitweb.js (JavaScript code for gitweb) -our $javascript = "++GITWEB_JS++"; +our $javascript = "@GITWEB_JS@"; # URI and label (title) of GIT logo link #our $logo_url = "https://www.kernel.org/pub/software/scm/git/docs/"; @@ -128,7 +128,7 @@ our $logo_url = "https://git-scm.com/"; our $logo_label = "git homepage"; # source of projects list -our $projects_list = "++GITWEB_LIST++"; +our $projects_list = "@GITWEB_LIST@"; # the width (in characters) of the projects list "Description" column our $projects_list_description_width = 25; @@ -147,7 +147,7 @@ our $default_projects_order = "project"; # show repository only if this file exists # (only effective if this variable evaluates to true) -our $export_ok = "++GITWEB_EXPORT_OK++"; +our $export_ok = "@GITWEB_EXPORT_OK@"; # don't generate age column on the projects list page our $omit_age_column = 0; @@ -161,11 +161,11 @@ our $omit_owner=0; our $export_auth_hook = undef; # only allow viewing of repositories also shown on the overview page -our $strict_export = "++GITWEB_STRICT_EXPORT++"; +our $strict_export = "@GITWEB_STRICT_EXPORT@"; # list of git base URLs used for URL to where fetch project from, # i.e. full URL is "$git_base_url/$project" -our @git_base_url_list = grep { $_ ne '' } ("++GITWEB_BASE_URL++"); +our @git_base_url_list = grep { $_ ne '' } ("@GITWEB_BASE_URL@"); # default blob_plain mimetype and default charset for text/plain blob our $default_blob_plain_mimetype = 'text/plain'; @@ -200,7 +200,7 @@ our $prevent_xss = 0; # http://andre-simon.de/zip/download.php due to assumptions about parameters and output). # Useful if highlight is not installed on your webserver's PATH. # [Default: highlight] -our $highlight_bin = "++HIGHLIGHT_BIN++"; +our $highlight_bin = "@HIGHLIGHT_BIN@"; # information about snapshot formats that gitweb is capable of serving our %known_snapshot_formats = ( @@ -741,9 +741,9 @@ sub read_config_file { our ($GITWEB_CONFIG, $GITWEB_CONFIG_SYSTEM, $GITWEB_CONFIG_COMMON); sub evaluate_gitweb_config { - our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++"; - our $GITWEB_CONFIG_SYSTEM = $ENV{'GITWEB_CONFIG_SYSTEM'} || "++GITWEB_CONFIG_SYSTEM++"; - our $GITWEB_CONFIG_COMMON = $ENV{'GITWEB_CONFIG_COMMON'} || "++GITWEB_CONFIG_COMMON++"; + our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "@GITWEB_CONFIG@"; + our $GITWEB_CONFIG_SYSTEM = $ENV{'GITWEB_CONFIG_SYSTEM'} || "@GITWEB_CONFIG_SYSTEM@"; + our $GITWEB_CONFIG_COMMON = $ENV{'GITWEB_CONFIG_COMMON'} || "@GITWEB_CONFIG_COMMON@"; # Protect against duplications of file names, to not read config twice. # Only one of $GITWEB_CONFIG and $GITWEB_CONFIG_SYSTEM is used, so diff --git a/perl/Git/I18N.pm b/perl/Git/I18N.pm index ab46edb608..162230af81 100644 --- a/perl/Git/I18N.pm +++ b/perl/Git/I18N.pm @@ -20,14 +20,14 @@ our @EXPORT_OK = @EXPORT; # this "'@@' [...] '@@'" pattern. use constant NO_GETTEXT_STR => '@@' . 'NO_GETTEXT' . '@@'; use constant NO_GETTEXT => ( - q[@@NO_GETTEXT@@] ne '' + q[@NO_GETTEXT@] ne '' and - q[@@NO_GETTEXT@@] ne NO_GETTEXT_STR + q[@NO_GETTEXT@] ne NO_GETTEXT_STR ); sub __bootstrap_locale_messages { our $TEXTDOMAIN = 'git'; - our $TEXTDOMAINDIR ||= $ENV{GIT_TEXTDOMAINDIR} || '@@LOCALEDIR@@'; + our $TEXTDOMAINDIR ||= $ENV{GIT_TEXTDOMAINDIR} || '@LOCALEDIR@'; die "NO_GETTEXT=" . NO_GETTEXT_STR if NO_GETTEXT; require POSIX; diff --git a/perl/Git/LoadCPAN.pm b/perl/Git/LoadCPAN.pm index 61254fddbb..92d63c71d2 100644 --- a/perl/Git/LoadCPAN.pm +++ b/perl/Git/LoadCPAN.pm @@ -31,11 +31,11 @@ C repository. Use it for anything else at your peril! # Makefile, and allows for detecting whether the module is loaded from # perl/Git as opposed to perl/build/Git, which is useful for one-off # testing without having Error.pm et al installed. -use constant NO_PERL_CPAN_FALLBACKS_STR => '@@' . 'NO_PERL_CPAN_FALLBACKS' . '@@'; +use constant NO_PERL_CPAN_FALLBACKS_STR => '@' . 'NO_PERL_CPAN_FALLBACKS' . '@'; use constant NO_PERL_CPAN_FALLBACKS => ( - q[@@NO_PERL_CPAN_FALLBACKS@@] ne '' + q[@NO_PERL_CPAN_FALLBACKS@] ne '' and - q[@@NO_PERL_CPAN_FALLBACKS@@] ne NO_PERL_CPAN_FALLBACKS_STR + q[@NO_PERL_CPAN_FALLBACKS@] ne NO_PERL_CPAN_FALLBACKS_STR ); sub import { diff --git a/perl/header_templates/fixed_prefix.template.pl b/perl/header_templates/fixed_prefix.template.pl index 857b4391a4..d571ca5cde 100644 --- a/perl/header_templates/fixed_prefix.template.pl +++ b/perl/header_templates/fixed_prefix.template.pl @@ -1 +1 @@ -use lib (split(/@@PATHSEP@@/, $ENV{GITPERLLIB} || '@@INSTLIBDIR@@')); +use lib (split(/@PATHSEP@/, $ENV{GITPERLLIB} || '@INSTLIBDIR@')); diff --git a/perl/header_templates/runtime_prefix.template.pl b/perl/header_templates/runtime_prefix.template.pl index 9d28b3d863..e6f8e661a1 100644 --- a/perl/header_templates/runtime_prefix.template.pl +++ b/perl/header_templates/runtime_prefix.template.pl @@ -3,7 +3,7 @@ # This finds our Git::* libraries relative to the script's runtime path. sub __git_system_path { my ($relpath) = @_; - my $gitexecdir_relative = '@@GITEXECDIR_REL@@'; + my $gitexecdir_relative = '@GITEXECDIR_REL@'; # GIT_EXEC_PATH is supplied by `git` or the test suite. my $exec_path; @@ -24,11 +24,11 @@ sub __git_system_path { } BEGIN { - use lib split /@@PATHSEP@@/, + use lib split /@PATHSEP@/, ( $ENV{GITPERLLIB} || do { - my $perllibdir = __git_system_path('@@PERLLIBDIR_REL@@'); + my $perllibdir = __git_system_path('@PERLLIBDIR_REL@'); (-e $perllibdir) || die("Invalid system path ($relpath): $path"); $perllibdir; } @@ -36,7 +36,7 @@ BEGIN { # Export the system locale directory to the I18N module. The locale directory # is only installed if NO_GETTEXT is set. - $Git::I18N::TEXTDOMAINDIR = __git_system_path('@@LOCALEDIR_REL@@'); + $Git::I18N::TEXTDOMAINDIR = __git_system_path('@LOCALEDIR_REL@'); } # END RUNTIME_PREFIX generated code. diff --git a/unimplemented.sh b/unimplemented.sh index fee21d24e8..41776b279d 100644 --- a/unimplemented.sh +++ b/unimplemented.sh @@ -1,4 +1,4 @@ #!/bin/sh -echo >&2 "fatal: git was built without support for $(basename $0) (@@REASON@@)." +echo >&2 "fatal: git was built without support for $(basename $0) (@REASON@)." exit 128 diff --git a/wrap-for-bin.sh b/wrap-for-bin.sh index 95851b85b6..7898a1c238 100644 --- a/wrap-for-bin.sh +++ b/wrap-for-bin.sh @@ -4,33 +4,33 @@ # to run test suite against sandbox, but with only bindir-installed # executables in PATH. The Makefile copies this into various # files in bin-wrappers, substituting -# @@BUILD_DIR@@ and @@PROG@@. +# @BUILD_DIR@ and @PROG@. -GIT_EXEC_PATH='@@BUILD_DIR@@' +GIT_EXEC_PATH='@BUILD_DIR@' if test -n "$NO_SET_GIT_TEMPLATE_DIR" then unset GIT_TEMPLATE_DIR else - GIT_TEMPLATE_DIR='@@BUILD_DIR@@/templates/blt' + GIT_TEMPLATE_DIR='@BUILD_DIR@/templates/blt' export GIT_TEMPLATE_DIR fi -GITPERLLIB='@@BUILD_DIR@@/perl/build/lib'"${GITPERLLIB:+:$GITPERLLIB}" -GIT_TEXTDOMAINDIR='@@BUILD_DIR@@/po/build/locale' -PATH='@@BUILD_DIR@@/bin-wrappers:'"$PATH" +GITPERLLIB='@BUILD_DIR@/perl/build/lib'"${GITPERLLIB:+:$GITPERLLIB}" +GIT_TEXTDOMAINDIR='@BUILD_DIR@/po/build/locale' +PATH='@BUILD_DIR@/bin-wrappers:'"$PATH" export GIT_EXEC_PATH GITPERLLIB PATH GIT_TEXTDOMAINDIR case "$GIT_DEBUGGER" in '') - exec "${GIT_EXEC_PATH}/@@PROG@@" "$@" + exec "${GIT_EXEC_PATH}/@PROG@" "$@" ;; 1) unset GIT_DEBUGGER - exec gdb --args "${GIT_EXEC_PATH}/@@PROG@@" "$@" + exec gdb --args "${GIT_EXEC_PATH}/@PROG@" "$@" ;; *) GIT_DEBUGGER_ARGS="$GIT_DEBUGGER" unset GIT_DEBUGGER - exec ${GIT_DEBUGGER_ARGS} "${GIT_EXEC_PATH}/@@PROG@@" "$@" + exec ${GIT_DEBUGGER_ARGS} "${GIT_EXEC_PATH}/@PROG@" "$@" ;; esac -- cgit v1.2.3 From 4838deab65e71686353ad2e40cad679e26bfc0a4 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:38 +0100 Subject: Makefile: refactor GIT-VERSION-GEN to be reusable Our "GIT-VERSION-GEN" script always writes the "GIT-VERSION-FILE" into the current directory, where the expectation is that it should exist in the source directory. But other build systems that support out-of-tree builds may not want to do that to keep the source directory pristine, even though CMake currently doesn't care. Refactor the script such that it won't write the "GIT-VERSION-FILE" directly anymore, but instead knows to replace @PLACEHOLDERS@ in an arbitrary input file. This allows us to simplify the logic in CMake to determine the project version, but can also be reused later on in order to generate other files that need to contain version information like our "git.rc" file. While at it, change the format of the version file by removing the spaces around the equals sign. Like this we can continue to include the file in our Makefiles, but can also start to source it in shell scripts in subsequent steps. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- GIT-VERSION-FILE.in | 1 + GIT-VERSION-GEN | 61 ++++++++++++++++++++++++++++--------- Makefile | 5 ++- ci/test-documentation.sh | 2 +- contrib/buildsystems/CMakeLists.txt | 23 ++++---------- contrib/buildsystems/git-version.in | 1 + 6 files changed, 59 insertions(+), 34 deletions(-) create mode 100644 GIT-VERSION-FILE.in create mode 100644 contrib/buildsystems/git-version.in diff --git a/GIT-VERSION-FILE.in b/GIT-VERSION-FILE.in new file mode 100644 index 0000000000..3789a48a34 --- /dev/null +++ b/GIT-VERSION-FILE.in @@ -0,0 +1 @@ +GIT_VERSION=@GIT_VERSION@ diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 78e8631f67..7afc7aad14 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,23 +1,48 @@ #!/bin/sh -GVF=GIT-VERSION-FILE DEF_VER=v2.47.GIT LF=' ' +if test "$#" -ne 3 +then + echo >&2 "USAGE: $0 " + exit 1 +fi + +SOURCE_DIR="$1" +INPUT="$2" +OUTPUT="$3" + +if ! test -f "$INPUT" +then + echo >&2 "Input is not a file: $INPUT" + exit 1 +fi + +# Protect us from reading Git version information outside of the Git directory +# in case it is not a repository itself, but embedded in an unrelated +# repository. +GIT_CEILING_DIRECTORIES="$SOURCE_DIR/.." +export GIT_CEILING_DIRECTORIES + # First see if there is a version file (included in release tarballs), # then try git-describe, then default. -if test -f version +if test -f "$SOURCE_DIR"/version then - VN=$(cat version) || VN="$DEF_VER" -elif { test -d "${GIT_DIR:-.git}" || test -f .git; } && - VN=$(git describe --match "v[0-9]*" HEAD 2>/dev/null) && + VN=$(cat "$SOURCE_DIR"/version) || VN="$DEF_VER" +elif { + test -d "$SOURCE_DIR/.git" || + test -d "${GIT_DIR:-.git}" || + test -f "$SOURCE_DIR"/.git; + } && + VN=$(git -C "$SOURCE_DIR" describe --match "v[0-9]*" HEAD 2>/dev/null) && case "$VN" in *$LF*) (exit 1) ;; v[0-9]*) - git update-index -q --refresh - test -z "$(git diff-index --name-only HEAD --)" || + git -C "$SOURCE_DIR" update-index -q --refresh + test -z "$(git -C "$SOURCE_DIR" diff-index --name-only HEAD --)" || VN="$VN-dirty" ;; esac then @@ -26,15 +51,21 @@ else VN="$DEF_VER" fi -VN=$(expr "$VN" : v*'\(.*\)') +GIT_VERSION=$(expr "$VN" : v*'\(.*\)') + +read GIT_MAJOR_VERSION GIT_MINOR_VERSION GIT_MICRO_VERSION trailing <"$OUTPUT"+ -if test -r $GVF +if ! test -f "$OUTPUT" || ! cmp "$OUTPUT"+ "$OUTPUT" >/dev/null then - VC=$(sed -e 's/^GIT_VERSION = //' <$GVF) + mv "$OUTPUT"+ "$OUTPUT" else - VC=unset + rm "$OUTPUT"+ fi -test "$VN" = "$VC" || { - echo >&2 "GIT_VERSION = $VN" - echo "GIT_VERSION = $VN" >$GVF -} diff --git a/Makefile b/Makefile index 75e26d2e31..73510d6bcb 100644 --- a/Makefile +++ b/Makefile @@ -592,7 +592,10 @@ include shared.mak # Disable -pedantic compilation. GIT-VERSION-FILE: FORCE - @$(SHELL_PATH) ./GIT-VERSION-GEN + @OLD=$$(cat $@ 2>/dev/null || :) && \ + $(SHELL_PATH) ./GIT-VERSION-GEN "$(shell pwd)" GIT-VERSION-FILE.in $@ && \ + NEW=$$(cat $@ 2>/dev/null || :) && \ + if test "$$OLD" != "$$NEW"; then echo "$$NEW" >&2; fi -include GIT-VERSION-FILE # Set our default configuration. diff --git a/ci/test-documentation.sh b/ci/test-documentation.sh index 02b3af3941..6c018b673e 100755 --- a/ci/test-documentation.sh +++ b/ci/test-documentation.sh @@ -6,7 +6,7 @@ . ${0%/*}/lib.sh filter_log () { - sed -e '/^GIT_VERSION = /d' \ + sed -e '/^GIT_VERSION=/d' \ -e "/constant Gem::ConfigMap is deprecated/d" \ -e '/^ \* new asciidoc flags$/d' \ -e '/stripped namespace before processing/d' \ diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 1abf5f099c..376d748ce9 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -83,23 +83,12 @@ if(NOT SH_EXE) "On Windows, you can get it as part of 'Git for Windows' install at https://gitforwindows.org/") endif() -#Create GIT-VERSION-FILE using GIT-VERSION-GEN -if(NOT EXISTS ${CMAKE_SOURCE_DIR}/GIT-VERSION-FILE) - message("Generating GIT-VERSION-FILE") - execute_process(COMMAND ${SH_EXE} ${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) -endif() - -#Parse GIT-VERSION-FILE to get the version -file(STRINGS ${CMAKE_SOURCE_DIR}/GIT-VERSION-FILE git_version REGEX "GIT_VERSION = (.*)") -string(REPLACE "GIT_VERSION = " "" git_version ${git_version}) -string(FIND ${git_version} "GIT" location) -if(location EQUAL -1) - string(REGEX MATCH "[0-9]*\\.[0-9]*\\.[0-9]*" git_version ${git_version}) -else() - string(REGEX MATCH "[0-9]*\\.[0-9]*" git_version ${git_version}) - string(APPEND git_version ".0") #for building from a snapshot -endif() +message("Generating Git version") +execute_process(COMMAND ${SH_EXE} "${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN" + "${CMAKE_SOURCE_DIR}" + "${CMAKE_SOURCE_DIR}/contrib/buildsystems/git-version.in" + "${CMAKE_BINARY_DIR}/git-version") +file(STRINGS "${CMAKE_BINARY_DIR}/git-version" git_version) project(git VERSION ${git_version} diff --git a/contrib/buildsystems/git-version.in b/contrib/buildsystems/git-version.in new file mode 100644 index 0000000000..9750505ae7 --- /dev/null +++ b/contrib/buildsystems/git-version.in @@ -0,0 +1 @@ +@GIT_MAJOR_VERSION@.@GIT_MINOR_VERSION@.@GIT_MICRO_VERSION@ -- cgit v1.2.3 From 0c8d33951400f7d7175e1dad51e970fb70849f2b Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:39 +0100 Subject: Makefile: propagate Git version via generated header We set up a couple of preprocessor macros when compiling Git that propagate the version that Git was built from to `git version` et al. The way this is set up makes it harder than necessary to reuse the infrastructure across the different build systems. Refactor this such that we generate a "version-def.h" header via `GIT-VERSION-GEN` instead. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- .gitignore | 1 + GIT-VERSION-GEN | 7 +++++++ Makefile | 13 ++++++------- contrib/buildsystems/CMakeLists.txt | 16 ++++++++++++---- version-def.h.in | 8 ++++++++ version.c | 1 + 6 files changed, 35 insertions(+), 11 deletions(-) create mode 100644 version-def.h.in diff --git a/.gitignore b/.gitignore index 6687bd6db4..e17963e842 100644 --- a/.gitignore +++ b/.gitignore @@ -195,6 +195,7 @@ /config-list.h /command-list.h /hook-list.h +/version-def.h *.tar.gz *.dsc *.deb diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 7afc7aad14..c18f24e515 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -52,6 +52,11 @@ else fi GIT_VERSION=$(expr "$VN" : v*'\(.*\)') +GIT_BUILT_FROM_COMMIT=$(git -C "$SOURCE_DIR" rev-parse -q --verify HEAD 2>/dev/null) +if test -z "$GIT_USER_AGENT" +then + GIT_USER_AGENT="git/$GIT_VERSION" +fi read GIT_MAJOR_VERSION GIT_MINOR_VERSION GIT_MICRO_VERSION trailing <"$OUTPUT"+ if ! test -f "$OUTPUT" || ! cmp "$OUTPUT"+ "$OUTPUT" >/dev/null diff --git a/Makefile b/Makefile index 73510d6bcb..7150ffc39c 100644 --- a/Makefile +++ b/Makefile @@ -2508,13 +2508,11 @@ PAGER_ENV_CQ_SQ = $(subst ','\'',$(PAGER_ENV_CQ)) pager.sp pager.s pager.o: EXTRA_CPPFLAGS = \ -DPAGER_ENV='$(PAGER_ENV_CQ_SQ)' -version.sp version.s version.o: GIT-VERSION-FILE GIT-USER-AGENT -version.sp version.s version.o: EXTRA_CPPFLAGS = \ - '-DGIT_VERSION="$(GIT_VERSION)"' \ - '-DGIT_USER_AGENT=$(GIT_USER_AGENT_CQ_SQ)' \ - '-DGIT_BUILT_FROM_COMMIT="$(shell \ - GIT_CEILING_DIRECTORIES="$(CURDIR)/.." \ - git rev-parse -q --verify HEAD 2>/dev/null)"' +version-def.h: version-def.h.in GIT-VERSION-GEN GIT-VERSION-FILE GIT-USER-AGENT + $(QUIET_GEN)GIT_USER_AGENT="$(GIT_USER_AGENT)" $(SHELL_PATH) ./GIT-VERSION-GEN "$(shell pwd)" $< $@+ + @if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi + +version.sp version.s version.o: version-def.h $(BUILT_INS): git$X $(QUIET_BUILT_IN)$(RM) $@ && \ @@ -3728,6 +3726,7 @@ clean: profile-clean coverage-clean cocciclean $(RM) $(FUZZ_PROGRAMS) $(RM) $(SP_OBJ) $(RM) $(HCC) + $(RM) version-def.h $(RM) -r bin-wrappers $(dep_dirs) $(compdb_dir) compile_commands.json $(RM) -r po/build/ $(RM) *.pyc *.pyo */*.pyc */*.pyo $(GENERATED_H) $(ETAGS_TARGET) tags cscope* diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 376d748ce9..3cc5e31819 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -229,10 +229,7 @@ add_compile_definitions(PAGER_ENV="LESS=FRX LV=-c" GIT_HTML_PATH="share/doc/git-doc" DEFAULT_HELP_FORMAT="html" DEFAULT_GIT_TEMPLATE_DIR="share/git-core/templates" - GIT_VERSION="${PROJECT_VERSION}.GIT" - GIT_USER_AGENT="git/${PROJECT_VERSION}.GIT" - BINDIR="bin" - GIT_BUILT_FROM_COMMIT="") + BINDIR="bin") if(WIN32) set(FALLBACK_RUNTIME_PREFIX /mingw64) @@ -668,6 +665,17 @@ parse_makefile_for_sources(libgit_SOURCES "LIB_OBJS") list(TRANSFORM libgit_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/") list(TRANSFORM compat_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/") + +add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/version-def.h" + COMMAND "${SH_EXE}" "${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN" + "${CMAKE_SOURCE_DIR}" + "${CMAKE_SOURCE_DIR}/version-def.h.in" + "${CMAKE_BINARY_DIR}/version-def.h" + DEPENDS "${SH_EXE}" "${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN" + "${CMAKE_SOURCE_DIR}/version-def.h.in" + VERBATIM) +list(APPEND libgit_SOURCES "${CMAKE_BINARY_DIR}/version-def.h") + add_library(libgit ${libgit_SOURCES} ${compat_SOURCES}) #libxdiff diff --git a/version-def.h.in b/version-def.h.in new file mode 100644 index 0000000000..347995df06 --- /dev/null +++ b/version-def.h.in @@ -0,0 +1,8 @@ +#ifndef VERSION_DEF_H +#define VERSION_DEF_H + +#define GIT_VERSION "@GIT_VERSION@" +#define GIT_BUILT_FROM_COMMIT "@GIT_BUILT_FROM_COMMIT@" +#define GIT_USER_AGENT "@GIT_USER_AGENT@" + +#endif /* VERSION_DEF_H */ diff --git a/version.c b/version.c index 41b718c29e..7adc4d51ff 100644 --- a/version.c +++ b/version.c @@ -1,5 +1,6 @@ #include "git-compat-util.h" #include "version.h" +#include "version-def.h" #include "strbuf.h" const char git_version_string[] = GIT_VERSION; -- cgit v1.2.3 From c2a3b847eda3b51973998c1fa0a8749eb7e686b9 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:42 +0100 Subject: Makefile: consistently use PERL_PATH When injecting the Perl path into our scripts we sometimes use '@PERL@' while we othertimes use '@PERL_PATH@'. Refactor the code use the latter consistently, which makes it easier to reuse the same logic for multiple scripts. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Makefile | 2 +- contrib/buildsystems/CMakeLists.txt | 2 +- git-instaweb.sh | 4 ++-- git-request-pull.sh | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 1255d222c2..0e289d1dbc 100644 --- a/Makefile +++ b/Makefile @@ -2554,7 +2554,7 @@ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ -e 's/@USE_GETTEXT_SCHEME@/$(USE_GETTEXT_SCHEME)/g' \ -e $(BROKEN_PATH_FIX) \ -e 's|@GITWEBDIR@|$(gitwebdir_SQ)|g' \ - -e 's|@PERL@|$(PERL_PATH_SQ)|g' \ + -e 's|@PERL_PATH@|$(PERL_PATH_SQ)|g' \ -e 's|@PAGER_ENV@|$(PAGER_ENV_SQ)|g' \ $@.sh >$@+ endef diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 865b3af9fb..ecaae8965c 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -846,7 +846,7 @@ foreach(script ${git_shell_scripts}) string(REPLACE "@NO_CURL@" "" content "${content}") string(REPLACE "@USE_GETTEXT_SCHEME@" "" content "${content}") string(REPLACE "# @BROKEN_PATH_FIX@" "" content "${content}") - string(REPLACE "@PERL@" "${PERL_PATH}" content "${content}") + string(REPLACE "@PERL_PATH@" "${PERL_PATH}" content "${content}") string(REPLACE "@PAGER_ENV@" "LESS=FRX LV=-c" content "${content}") file(WRITE ${CMAKE_BINARY_DIR}/${script} ${content}) endforeach() diff --git a/git-instaweb.sh b/git-instaweb.sh index c8efb1205a..5ad50160bb 100755 --- a/git-instaweb.sh +++ b/git-instaweb.sh @@ -3,7 +3,7 @@ # Copyright (c) 2006 Eric Wong # -PERL='@PERL@' +PERL='@PERL_PATH@' OPTIONS_KEEPDASHDASH= OPTIONS_STUCKLONG= OPTIONS_SPEC="\ @@ -716,7 +716,7 @@ EOF gitweb_conf() { cat > "$fqgitdir/gitweb/gitweb_config.perl" < Date: Fri, 6 Dec 2024 14:24:40 +0100 Subject: Makefile: generate "git.rc" via GIT-VERSION-GEN The "git.rc" is used on Windows to embed information like the project name and version into the resulting executables. As such we need to inject the version information, which we do by using preprocessor defines. The logic to do so is non-trivial and needs to be kept in sync with the different build systems. Refactor the logic so that we generate "git.rc" via `GIT-VERSION-GEN`. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- .gitignore | 1 + GIT-VERSION-GEN | 8 ++++++-- Makefile | 13 +++++++------ contrib/buildsystems/CMakeLists.txt | 19 +++++++++++++------ git.rc | 24 ------------------------ git.rc.in | 24 ++++++++++++++++++++++++ 6 files changed, 51 insertions(+), 38 deletions(-) delete mode 100644 git.rc create mode 100644 git.rc.in diff --git a/.gitignore b/.gitignore index e17963e842..d3be460040 100644 --- a/.gitignore +++ b/.gitignore @@ -199,6 +199,7 @@ *.tar.gz *.dsc *.deb +/git.rc /git.spec *.exe *.[aos] diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index c18f24e515..a1c8146f05 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -58,14 +58,18 @@ then GIT_USER_AGENT="git/$GIT_VERSION" fi -read GIT_MAJOR_VERSION GIT_MINOR_VERSION GIT_MICRO_VERSION trailing <"$OUTPUT"+ diff --git a/Makefile b/Makefile index 7150ffc39c..1255d222c2 100644 --- a/Makefile +++ b/Makefile @@ -2568,11 +2568,12 @@ $(SCRIPT_LIB) : % : %.sh GIT-SCRIPT-DEFINES $(QUIET_GEN)$(cmd_munge_script) && \ mv $@+ $@ -git.res: git.rc GIT-VERSION-FILE GIT-PREFIX - $(QUIET_RC)$(RC) \ - $(join -DMAJOR= -DMINOR= -DMICRO= -DPATCHLEVEL=, $(wordlist 1, 4, \ - $(shell echo $(GIT_VERSION) 0 0 0 0 | tr '.a-zA-Z-' ' '))) \ - -DGIT_VERSION="\\\"$(GIT_VERSION)\\\"" -i $< -o $@ +git.rc: git.rc.in GIT-VERSION-GEN GIT-VERSION-FILE + $(QUIET_GEN)$(SHELL_PATH) ./GIT-VERSION-GEN "$(shell pwd)" $< $@+ + @if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi + +git.res: git.rc GIT-PREFIX + $(QUIET_RC)$(RC) -i $< -o $@ # This makes sure we depend on the NO_PERL setting itself. $(SCRIPT_PERL_GEN): GIT-BUILD-OPTIONS @@ -3717,7 +3718,7 @@ clean: profile-clean coverage-clean cocciclean $(RM) -r .build $(UNIT_TEST_BIN) $(RM) GIT-TEST-SUITES $(RM) po/git.pot po/git-core.pot - $(RM) git.res + $(RM) git.rc git.res $(RM) $(OBJECTS) $(RM) headless-git.o $(RM) $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 3cc5e31819..865b3af9fb 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -691,18 +691,25 @@ list(TRANSFORM reftable_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/") add_library(reftable STATIC ${reftable_SOURCES}) if(WIN32) + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/git.rc + COMMAND "${SH_EXE}" "${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN" + "${CMAKE_SOURCE_DIR}" + "${CMAKE_SOURCE_DIR}/git.rc.in" + "${CMAKE_BINARY_DIR}/git.rc" + DEPENDS "${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN" + "${CMAKE_SOURCE_DIR}/git.rc.in" + VERBATIM) + if(NOT MSVC)#use windres when compiling with gcc and clang add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/git.res - COMMAND ${WINDRES_EXE} -O coff -DMAJOR=${PROJECT_VERSION_MAJOR} -DMINOR=${PROJECT_VERSION_MINOR} - -DMICRO=${PROJECT_VERSION_PATCH} -DPATCHLEVEL=0 -DGIT_VERSION="\\\"${PROJECT_VERSION}.GIT\\\"" - -i ${CMAKE_SOURCE_DIR}/git.rc -o ${CMAKE_BINARY_DIR}/git.res + COMMAND ${WINDRES_EXE} -O coff -i ${CMAKE_BINARY_DIR}/git.rc -o ${CMAKE_BINARY_DIR}/git.res + DEPENDS "${CMAKE_BINARY_DIR}/git.rc" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} VERBATIM) else()#MSVC use rc add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/git.res - COMMAND ${CMAKE_RC_COMPILER} /d MAJOR=${PROJECT_VERSION_MAJOR} /d MINOR=${PROJECT_VERSION_MINOR} - /d MICRO=${PROJECT_VERSION_PATCH} /d PATCHLEVEL=0 /d GIT_VERSION="${PROJECT_VERSION}.GIT" - /fo ${CMAKE_BINARY_DIR}/git.res ${CMAKE_SOURCE_DIR}/git.rc + COMMAND ${CMAKE_RC_COMPILER} /fo ${CMAKE_BINARY_DIR}/git.res ${CMAKE_BINARY_DIR}/git.rc + DEPENDS "${CMAKE_BINARY_DIR}/git.rc" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} VERBATIM) endif() diff --git a/git.rc b/git.rc deleted file mode 100644 index cc3fdc6cc6..0000000000 --- a/git.rc +++ /dev/null @@ -1,24 +0,0 @@ -1 VERSIONINFO -FILEVERSION MAJOR,MINOR,MICRO,PATCHLEVEL -PRODUCTVERSION MAJOR,MINOR,MICRO,PATCHLEVEL -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP */ - BEGIN - VALUE "CompanyName", "The Git Development Community\0" - VALUE "FileDescription", "Git for Windows\0" - VALUE "InternalName", "git\0" - VALUE "OriginalFilename", "git.exe\0" - VALUE "ProductName", "Git\0" - VALUE "ProductVersion", GIT_VERSION "\0" - END - END - - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - -1 RT_MANIFEST "compat/win32/git.manifest" diff --git a/git.rc.in b/git.rc.in new file mode 100644 index 0000000000..e69444eef3 --- /dev/null +++ b/git.rc.in @@ -0,0 +1,24 @@ +1 VERSIONINFO +FILEVERSION @GIT_MAJOR_VERSION@,@GIT_MINOR_VERSION@,@GIT_MICRO_VERSION@,@GIT_PATCH_LEVEL@ +PRODUCTVERSION @GIT_MAJOR_VERSION@,@GIT_MINOR_VERSION@,@GIT_MICRO_VERSION@,@GIT_PATCH_LEVEL@ +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP */ + BEGIN + VALUE "CompanyName", "The Git Development Community\0" + VALUE "FileDescription", "Git for Windows\0" + VALUE "InternalName", "git\0" + VALUE "OriginalFilename", "git.exe\0" + VALUE "ProductName", "Git\0" + VALUE "ProductVersion", "@GIT_VERSION@\0" + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +1 RT_MANIFEST "compat/win32/git.manifest" -- cgit v1.2.3 From e4b488049a5faa9b8c7255f483a89cea414d5eb4 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:43 +0100 Subject: Makefile: extract script to massage Perl scripts Extract the script to inject various build-time parameters into our Perl scripts into a standalone script. This is done such that we can reuse it in other build systems. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Makefile | 12 ++---------- contrib/buildsystems/CMakeLists.txt | 32 +++++++++++++++++++++++++++----- generate-perl.sh | 27 +++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 15 deletions(-) create mode 100755 generate-perl.sh diff --git a/Makefile b/Makefile index 0e289d1dbc..e33c5b966c 100644 --- a/Makefile +++ b/Makefile @@ -2606,16 +2606,8 @@ endif PERL_DEFINES += $(gitexecdir) $(perllibdir) $(localedir) -$(SCRIPT_PERL_GEN): % : %.perl GIT-PERL-DEFINES GIT-PERL-HEADER GIT-VERSION-FILE - $(QUIET_GEN) \ - sed -e '1{' \ - -e ' s|#!.*perl|#!$(PERL_PATH_SQ)|' \ - -e ' r GIT-PERL-HEADER' \ - -e ' G' \ - -e '}' \ - -e 's/@GIT_VERSION@/$(GIT_VERSION)/g' \ - $< >$@+ && \ - chmod +x $@+ && \ +$(SCRIPT_PERL_GEN): % : %.perl generate-perl.sh GIT-PERL-DEFINES GIT-PERL-HEADER GIT-VERSION-FILE + $(QUIET_GEN)$(SHELL_PATH) generate-perl.sh ./GIT-BUILD-OPTIONS ./GIT-VERSION-FILE GIT-PERL-HEADER "$<" "$@+" && \ mv $@+ $@ PERL_DEFINES := $(subst $(space),:,$(PERL_DEFINES)) diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index ecaae8965c..5cb9a20936 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -852,19 +852,41 @@ foreach(script ${git_shell_scripts}) endforeach() #perl scripts -parse_makefile_for_scripts(git_perl_scripts "SCRIPT_PERL" ".perl") +parse_makefile_for_scripts(git_perl_scripts "SCRIPT_PERL" "") #create perl header file(STRINGS ${CMAKE_SOURCE_DIR}/perl/header_templates/fixed_prefix.template.pl perl_header ) string(REPLACE "@PATHSEP@" ":" perl_header "${perl_header}") string(REPLACE "@INSTLIBDIR@" "${INSTLIBDIR}" perl_header "${perl_header}") +file(WRITE ${CMAKE_BINARY_DIR}/PERL-HEADER ${perl_header}) + +add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/GIT-VERSION-FILE" + COMMAND "${SH_EXE}" "${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN" + "${CMAKE_SOURCE_DIR}" + "${CMAKE_SOURCE_DIR}/GIT-VERSION-FILE.in" + "${CMAKE_BINARY_DIR}/GIT-VERSION-FILE" + DEPENDS ${SH_EXE} "${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN" + "${CMAKE_SOURCE_DIR}/GIT-VERSION-FILE.in" + VERBATIM) foreach(script ${git_perl_scripts}) - file(STRINGS ${CMAKE_SOURCE_DIR}/${script}.perl content NEWLINE_CONSUME) - string(REPLACE "#!/usr/bin/perl" "#!/usr/bin/perl\n${perl_header}\n" content "${content}") - string(REPLACE "@GIT_VERSION@" "${PROJECT_VERSION}" content "${content}") - file(WRITE ${CMAKE_BINARY_DIR}/${script} ${content}) + string(REPLACE ".perl" "" perl_gen_path "${script}") + + add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/${perl_gen_path}" + COMMAND "${SH_EXE}" "${CMAKE_SOURCE_DIR}/generate-perl.sh" + "${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS" + "${CMAKE_BINARY_DIR}/GIT-VERSION-FILE" + "${CMAKE_BINARY_DIR}/PERL-HEADER" + "${CMAKE_SOURCE_DIR}/${script}" + "${CMAKE_BINARY_DIR}/${perl_gen_path}" + DEPENDS "${CMAKE_SOURCE_DIR}/generate-perl.sh" + "${CMAKE_SOURCE_DIR}/${script}" + "${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS" + "${CMAKE_BINARY_DIR}/GIT-VERSION-FILE" + VERBATIM) + list(APPEND perl_gen ${CMAKE_BINARY_DIR}/${perl_gen_path}) endforeach() +add_custom_target(perl-gen ALL DEPENDS ${perl_gen}) #python script file(STRINGS ${CMAKE_SOURCE_DIR}/git-p4.py content NEWLINE_CONSUME) diff --git a/generate-perl.sh b/generate-perl.sh new file mode 100755 index 0000000000..95072522da --- /dev/null +++ b/generate-perl.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +set -e + +if test $# -ne 5 +then + echo >&2 "USAGE: $0 " + exit 1 +fi + +GIT_BUILD_OPTIONS="$1" +GIT_VERSION_FILE="$2" +PERL_HEADER="$3" +INPUT="$4" +OUTPUT="$5" + +. "$GIT_BUILD_OPTIONS" +. "$GIT_VERSION_FILE" + +sed -e '1{' \ + -e " s|#!.*perl|#!$PERL_PATH|" \ + -e " r $PERL_HEADER" \ + -e ' G' \ + -e '}' \ + -e "s/@GIT_VERSION@/$GIT_VERSION/g" \ + "$INPUT" >"$OUTPUT" +chmod a+x "$OUTPUT" -- cgit v1.2.3 From a38edab7c88b5503bb2b5f5cbd49f6b97e9a6a4e Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:41 +0100 Subject: Makefile: generate doc versions via GIT-VERSION-GEN The documentation we generate embeds information for the exact Git version used as well as the date of the commit. This information is injected by injecting attributes into the build process via command line argument. Refactor the logic so that we write the information into "asciidoc.conf" and "asciidoctor-extensions.rb" via `GIT-VERSION-GEN` for AsciiDoc and AsciiDoctor, respectively. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/.gitignore | 2 + Documentation/Makefile | 25 ++++-- Documentation/asciidoc.conf | 79 ----------------- Documentation/asciidoc.conf.in | 82 ++++++++++++++++++ Documentation/asciidoctor-extensions.rb | 135 ----------------------------- Documentation/asciidoctor-extensions.rb.in | 131 ++++++++++++++++++++++++++++ GIT-VERSION-GEN | 2 + 7 files changed, 233 insertions(+), 223 deletions(-) delete mode 100644 Documentation/asciidoc.conf create mode 100644 Documentation/asciidoc.conf.in delete mode 100644 Documentation/asciidoctor-extensions.rb create mode 100644 Documentation/asciidoctor-extensions.rb.in diff --git a/Documentation/.gitignore b/Documentation/.gitignore index a48448de32..649df89474 100644 --- a/Documentation/.gitignore +++ b/Documentation/.gitignore @@ -15,3 +15,5 @@ tmp-doc-diff/ GIT-ASCIIDOCFLAGS /.build/ /GIT-EXCLUDED-PROGRAMS +/asciidoc.conf +/asciidoctor-extensions.rb diff --git a/Documentation/Makefile b/Documentation/Makefile index 0f55baa252..9371f29425 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1,6 +1,8 @@ # Import tree-wide shared Makefile behavior and libraries include ../shared.mak +.PHONY: FORCE + # Guard against environment variables MAN1_TXT = MAN5_TXT = @@ -148,16 +150,12 @@ man5dir = $(mandir)/man5 man7dir = $(mandir)/man7 # DESTDIR = -GIT_DATE := $(shell git show --quiet --pretty='%as') - ASCIIDOC = asciidoc ASCIIDOC_EXTRA = ASCIIDOC_HTML = xhtml11 ASCIIDOC_DOCBOOK = docbook ASCIIDOC_CONF = -f asciidoc.conf -ASCIIDOC_COMMON = $(ASCIIDOC) $(ASCIIDOC_EXTRA) $(ASCIIDOC_CONF) \ - -amanmanual='Git Manual' -amansource='Git $(GIT_VERSION)' \ - -arevdate='$(GIT_DATE)' +ASCIIDOC_COMMON = $(ASCIIDOC) $(ASCIIDOC_EXTRA) $(ASCIIDOC_CONF) ASCIIDOC_DEPS = asciidoc.conf GIT-ASCIIDOCFLAGS TXT_TO_HTML = $(ASCIIDOC_COMMON) -b $(ASCIIDOC_HTML) TXT_TO_XML = $(ASCIIDOC_COMMON) -b $(ASCIIDOC_DOCBOOK) @@ -210,6 +208,14 @@ ASCIIDOC_DEPS = asciidoctor-extensions.rb GIT-ASCIIDOCFLAGS DBLATEX_COMMON = XMLTO_EXTRA += --skip-validation XMLTO_EXTRA += -x manpage.xsl + +asciidoctor-extensions.rb: asciidoctor-extensions.rb.in FORCE + $(QUIET_GEN)GIT_USER_AGENT="$(GIT_USER_AGENT)" $(SHELL_PATH) ../GIT-VERSION-GEN "$(shell pwd)/.." $< $@+ + @if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi +else +asciidoc.conf: asciidoc.conf.in FORCE + $(QUIET_GEN)GIT_USER_AGENT="$(GIT_USER_AGENT)" $(SHELL_PATH) ../GIT-VERSION-GEN "$(shell pwd)/.." $< $@+ + @if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi endif ASCIIDOC_DEPS += docinfo.html @@ -341,6 +347,7 @@ clean: $(RM) SubmittingPatches.txt $(RM) $(cmds_txt) $(mergetools_txt) *.made $(RM) GIT-ASCIIDOCFLAGS + $(RM) asciidoc.conf asciidoctor-extensions.rb docinfo.html: docinfo-html.in $(QUIET_GEN)$(RM) $@ && cat $< >$@ @@ -364,7 +371,7 @@ manpage-cmd = $(QUIET_XMLTO)$(XMLTO) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $< %.xml : %.txt $(ASCIIDOC_DEPS) $(QUIET_ASCIIDOC)$(TXT_TO_XML) -d manpage -o $@ $< -user-manual.xml: user-manual.txt user-manual.conf asciidoctor-extensions.rb GIT-ASCIIDOCFLAGS +user-manual.xml: user-manual.txt user-manual.conf $(ASCIIDOC_DEPS) $(QUIET_ASCIIDOC)$(TXT_TO_XML) -d book -o $@ $< technical/api-index.txt: technical/api-index-skel.txt \ @@ -373,7 +380,7 @@ technical/api-index.txt: technical/api-index-skel.txt \ technical/%.html: ASCIIDOC_EXTRA += -a git-relative-html-prefix=../ $(patsubst %,%.html,$(API_DOCS) technical/api-index $(TECH_DOCS)): %.html : %.txt \ - asciidoc.conf GIT-ASCIIDOCFLAGS + $(ASCIIDOC_DEPS) $(QUIET_ASCIIDOC)$(TXT_TO_HTML) $*.txt SubmittingPatches.txt: SubmittingPatches @@ -416,13 +423,13 @@ $(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml howto-index.txt: howto-index.sh $(HOWTO_TXT) $(QUIET_GEN)'$(SHELL_PATH_SQ)' ./howto-index.sh $(sort $(HOWTO_TXT)) >$@ -$(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt +$(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt $(ASCIIDOC_DEPS) $(QUIET_ASCIIDOC)$(TXT_TO_HTML) $*.txt WEBDOC_DEST = /pub/software/scm/git/docs howto/%.html: ASCIIDOC_EXTRA += -a git-relative-html-prefix=../ -$(patsubst %.txt,%.html,$(HOWTO_TXT)): %.html : %.txt GIT-ASCIIDOCFLAGS +$(patsubst %.txt,%.html,$(HOWTO_TXT)): %.html : %.txt $(ASCIIDOC_DEPS) $(QUIET_ASCIIDOC) \ sed -e '1,/^$$/d' $< | \ $(TXT_TO_HTML) - >$@ diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf deleted file mode 100644 index f6da6d1fbd..0000000000 --- a/Documentation/asciidoc.conf +++ /dev/null @@ -1,79 +0,0 @@ -## linkgit: macro -# -# Usage: linkgit:command[manpage-section] -# -# Note, {0} is the manpage section, while {target} is the command. -# -# Show Git link as: (
); if section is defined, else just show -# the command. - -[macros] -(?su)[\\]?(?Plinkgit):(?P\S*?)\[(?P.*?)\]= - -[attributes] -asterisk=* -plus=+ -caret=^ -startsb=[ -endsb=] -backslash=\ -tilde=~ -apostrophe=' -backtick=` -litdd=-- - -ifdef::backend-docbook[] -[linkgit-inlinemacro] -{0%{target}} -{0#} -{0#{target}{0}} -{0#} - -[literal-inlinemacro] -{eval:re.sub(r'(<[-a-zA-Z0-9.]+>)', r'\1', re.sub(r'([\[\s|()>]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@,\/_^\$]+\.?)+)',r'\1\2', re.sub(r'(\.\.\.?)([^\]$.])', r'\1\2', macros.passthroughs[int(attrs['passtext'][1:-1])] if attrs['passtext'][1:-1].isnumeric() else attrs['passtext'][1:-1])))} - -endif::backend-docbook[] - -ifdef::backend-docbook[] -ifdef::doctype-manpage[] -# The following two small workarounds insert a simple paragraph after screen -[listingblock] -{title} - -| - -{title#} - -[verseblock] -{title} -{title%} -{title#} -| - -{title#} -{title%} -endif::doctype-manpage[] -endif::backend-docbook[] - -ifdef::backend-xhtml11[] -[attributes] -git-relative-html-prefix= -[linkgit-inlinemacro] -{target}{0?({0})} - -[literal-inlinemacro] -{eval:re.sub(r'(<[-a-zA-Z0-9.]+>)', r'\1', re.sub(r'([\[\s|()>]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@,\/_^\$]+\.?)+)',r'\1\2', re.sub(r'(\.\.\.?)([^\]$.])', r'\1\2', macros.passthroughs[int(attrs['passtext'][1:-1])] if attrs['passtext'][1:-1].isnumeric() else attrs['passtext'][1:-1])))} - -endif::backend-xhtml11[] - -ifdef::backend-docbook[] -ifdef::doctype-manpage[] -[paradef-default] -synopsis-style=template="verseparagraph",filter="sed 's!…\\(\\]\\|$\\)!\\0!g;s!\\([\\[ |()]\\|^\\|\\]\\|>\\)\\([-=a-zA-Z0-9:+@,\\/_^\\$.]\\+\\|…\\)!\\1\\2!g;s!<[-a-zA-Z0-9.]\\+>!\\0!g'" -endif::doctype-manpage[] -endif::backend-docbook[] - -ifdef::backend-xhtml11[] -[paradef-default] -synopsis-style=template="verseparagraph",filter="sed 's!…\\(\\]\\|$\\)!\\0!g;s!\\([\\[ |()]\\|^\\|\\]\\|>\\)\\([-=a-zA-Z0-9:+@,\\/_^\\$.]\\+\\|…\\)!\\1\\2!g;s!<[-a-zA-Z0-9.]\\+>!\\0!g'" -endif::backend-xhtml11[] diff --git a/Documentation/asciidoc.conf.in b/Documentation/asciidoc.conf.in new file mode 100644 index 0000000000..dbe36a52ea --- /dev/null +++ b/Documentation/asciidoc.conf.in @@ -0,0 +1,82 @@ +## linkgit: macro +# +# Usage: linkgit:command[manpage-section] +# +# Note, {0} is the manpage section, while {target} is the command. +# +# Show Git link as: (
); if section is defined, else just show +# the command. + +[macros] +(?su)[\\]?(?Plinkgit):(?P\S*?)\[(?P.*?)\]= + +[attributes] +asterisk=* +plus=+ +caret=^ +startsb=[ +endsb=] +backslash=\ +tilde=~ +apostrophe=' +backtick=` +litdd=-- +manmanual='Git Manual' +mansource='Git @GIT_VERSION@' +revdate='@GIT_DATE@' + +ifdef::backend-docbook[] +[linkgit-inlinemacro] +{0%{target}} +{0#} +{0#{target}{0}} +{0#} + +[literal-inlinemacro] +{eval:re.sub(r'(<[-a-zA-Z0-9.]+>)', r'\1', re.sub(r'([\[\s|()>]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@,\/_^\$]+\.?)+)',r'\1\2', re.sub(r'(\.\.\.?)([^\]$.])', r'\1\2', macros.passthroughs[int(attrs['passtext'][1:-1])] if attrs['passtext'][1:-1].isnumeric() else attrs['passtext'][1:-1])))} + +endif::backend-docbook[] + +ifdef::backend-docbook[] +ifdef::doctype-manpage[] +# The following two small workarounds insert a simple paragraph after screen +[listingblock] +{title} + +| + +{title#} + +[verseblock] +{title} +{title%} +{title#} +| + +{title#} +{title%} +endif::doctype-manpage[] +endif::backend-docbook[] + +ifdef::backend-xhtml11[] +[attributes] +git-relative-html-prefix= +[linkgit-inlinemacro] +{target}{0?({0})} + +[literal-inlinemacro] +{eval:re.sub(r'(<[-a-zA-Z0-9.]+>)', r'\1', re.sub(r'([\[\s|()>]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@,\/_^\$]+\.?)+)',r'\1\2', re.sub(r'(\.\.\.?)([^\]$.])', r'\1\2', macros.passthroughs[int(attrs['passtext'][1:-1])] if attrs['passtext'][1:-1].isnumeric() else attrs['passtext'][1:-1])))} + +endif::backend-xhtml11[] + +ifdef::backend-docbook[] +ifdef::doctype-manpage[] +[paradef-default] +synopsis-style=template="verseparagraph",filter="sed 's!…\\(\\]\\|$\\)!\\0!g;s!\\([\\[ |()]\\|^\\|\\]\\|>\\)\\([-=a-zA-Z0-9:+@,\\/_^\\$.]\\+\\|…\\)!\\1\\2!g;s!<[-a-zA-Z0-9.]\\+>!\\0!g'" +endif::doctype-manpage[] +endif::backend-docbook[] + +ifdef::backend-xhtml11[] +[paradef-default] +synopsis-style=template="verseparagraph",filter="sed 's!…\\(\\]\\|$\\)!\\0!g;s!\\([\\[ |()]\\|^\\|\\]\\|>\\)\\([-=a-zA-Z0-9:+@,\\/_^\\$.]\\+\\|…\\)!\\1\\2!g;s!<[-a-zA-Z0-9.]\\+>!\\0!g'" +endif::backend-xhtml11[] diff --git a/Documentation/asciidoctor-extensions.rb b/Documentation/asciidoctor-extensions.rb deleted file mode 100644 index cb24480b63..0000000000 --- a/Documentation/asciidoctor-extensions.rb +++ /dev/null @@ -1,135 +0,0 @@ -require 'asciidoctor' -require 'asciidoctor/extensions' -require 'asciidoctor/converter/docbook5' -require 'asciidoctor/converter/html5' - -module Git - module Documentation - class LinkGitProcessor < Asciidoctor::Extensions::InlineMacroProcessor - use_dsl - - named :chrome - - def process(parent, target, attrs) - prefix = parent.document.attr('git-relative-html-prefix') - if parent.document.doctype == 'book' - "" \ - "#{target}(#{attrs[1]})" - elsif parent.document.basebackend? 'html' - %(#{target}(#{attrs[1]})) - elsif parent.document.basebackend? 'docbook' - "\n" \ - "#{target}" \ - "#{attrs[1]}\n" \ - "" - end - end - end - - class DocumentPostProcessor < Asciidoctor::Extensions::Postprocessor - def process document, output - if document.basebackend? 'docbook' - mansource = document.attributes['mansource'] - manversion = document.attributes['manversion'] - manmanual = document.attributes['manmanual'] - new_tags = "" \ - "#{mansource}\n" \ - "#{manversion}\n" \ - "#{manmanual}\n" - output = output.sub(/<\/refmeta>/, new_tags + "") - end - output - end - end - - class SynopsisBlock < Asciidoctor::Extensions::BlockProcessor - - use_dsl - named :synopsis - parse_content_as :simple - - def process parent, reader, attrs - outlines = reader.lines.map do |l| - l.gsub(/(\.\.\.?)([^\]$.])/, '`\1`\2') - .gsub(%r{([\[\] |()>]|^)([-a-zA-Z0-9:+=~@,/_^\$]+)}, '\1{empty}`\2`{empty}') - .gsub(/(<[-a-zA-Z0-9.]+>)/, '__\\1__') - .gsub(']', ']{empty}') - end - create_block parent, :verse, outlines, attrs - end - end - - class GitDBConverter < Asciidoctor::Converter::DocBook5Converter - - extend Asciidoctor::Converter::Config - register_for 'docbook5' - - def convert_inline_quoted node - if (type = node.type) == :asciimath - # NOTE fop requires jeuclid to process mathml markup - asciimath_available? ? %(#{(::AsciiMath.parse node.text).to_mathml 'mml:', 'xmlns:mml' => 'http://www.w3.org/1998/Math/MathML'}) : %() - elsif type == :latexmath - # unhandled math; pass source to alt and required mathphrase element; dblatex will process alt as LaTeX math - %() - elsif type == :monospaced - node.text.gsub(/(\.\.\.?)([^\]$.])/, '\1\2') - .gsub(%r{([\[\s|()>.]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@,/_^\$]+\.{0,2})+)}, '\1\2') - .gsub(/(<[-a-zA-Z0-9.]+>)/, '\1') - else - open, close, supports_phrase = QUOTE_TAGS[type] - text = node.text - if node.role - if supports_phrase - quoted_text = %(#{open}#{text}#{close}) - else - quoted_text = %(#{open.chop} role="#{node.role}">#{text}#{close}) - end - else - quoted_text = %(#{open}#{text}#{close}) - end - node.id ? %(#{quoted_text}) : quoted_text - end - end - end - - # register a html5 converter that takes in charge to convert monospaced text into Git style synopsis - class GitHTMLConverter < Asciidoctor::Converter::Html5Converter - - extend Asciidoctor::Converter::Config - register_for 'html5' - - def convert_inline_quoted node - if node.type == :monospaced - node.text.gsub(/(\.\.\.?)([^\]$.])/, '\1\2') - .gsub(%r{([\[\s|()>.]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@,/_^\$]+\.{0,2})+)}, '\1\2') - .gsub(/(<[-a-zA-Z0-9.]+>)/, '\1') - - else - open, close, tag = QUOTE_TAGS[node.type] - if node.id - class_attr = node.role ? %( class="#{node.role}") : '' - if tag - %(#{open.chop} id="#{node.id}"#{class_attr}>#{node.text}#{close}) - else - %(#{open}#{node.text}#{close}) - end - elsif node.role - if tag - %(#{open.chop} class="#{node.role}">#{node.text}#{close}) - else - %(#{open}#{node.text}#{close}) - end - else - %(#{open}#{node.text}#{close}) - end - end - end - end - end -end - -Asciidoctor::Extensions.register do - inline_macro Git::Documentation::LinkGitProcessor, :linkgit - block Git::Documentation::SynopsisBlock - postprocessor Git::Documentation::DocumentPostProcessor -end diff --git a/Documentation/asciidoctor-extensions.rb.in b/Documentation/asciidoctor-extensions.rb.in new file mode 100644 index 0000000000..c4c200dace --- /dev/null +++ b/Documentation/asciidoctor-extensions.rb.in @@ -0,0 +1,131 @@ +require 'asciidoctor' +require 'asciidoctor/extensions' +require 'asciidoctor/converter/docbook5' +require 'asciidoctor/converter/html5' + +module Git + module Documentation + class LinkGitProcessor < Asciidoctor::Extensions::InlineMacroProcessor + use_dsl + + named :chrome + + def process(parent, target, attrs) + prefix = parent.document.attr('git-relative-html-prefix') + if parent.document.doctype == 'book' + "" \ + "#{target}(#{attrs[1]})" + elsif parent.document.basebackend? 'html' + %(#{target}(#{attrs[1]})) + elsif parent.document.basebackend? 'docbook' + "\n" \ + "#{target}" \ + "#{attrs[1]}\n" \ + "" + end + end + end + + class DocumentPostProcessor < Asciidoctor::Extensions::Postprocessor + def process document, output + if document.basebackend? 'docbook' + new_tags = "" \ + "@GIT_VERSION@\n" \ + "Git Manual\n" + output = output.sub(/<\/refmeta>/, new_tags + "") + end + output + end + end + + class SynopsisBlock < Asciidoctor::Extensions::BlockProcessor + + use_dsl + named :synopsis + parse_content_as :simple + + def process parent, reader, attrs + outlines = reader.lines.map do |l| + l.gsub(/(\.\.\.?)([^\]$.])/, '`\1`\2') + .gsub(%r{([\[\] |()>]|^)([-a-zA-Z0-9:+=~@,/_^\$]+)}, '\1{empty}`\2`{empty}') + .gsub(/(<[-a-zA-Z0-9.]+>)/, '__\\1__') + .gsub(']', ']{empty}') + end + create_block parent, :verse, outlines, attrs + end + end + + class GitDBConverter < Asciidoctor::Converter::DocBook5Converter + + extend Asciidoctor::Converter::Config + register_for 'docbook5' + + def convert_inline_quoted node + if (type = node.type) == :asciimath + # NOTE fop requires jeuclid to process mathml markup + asciimath_available? ? %(#{(::AsciiMath.parse node.text).to_mathml 'mml:', 'xmlns:mml' => 'http://www.w3.org/1998/Math/MathML'}) : %() + elsif type == :latexmath + # unhandled math; pass source to alt and required mathphrase element; dblatex will process alt as LaTeX math + %() + elsif type == :monospaced + node.text.gsub(/(\.\.\.?)([^\]$.])/, '\1\2') + .gsub(%r{([\[\s|()>.]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@,/_^\$]+\.{0,2})+)}, '\1\2') + .gsub(/(<[-a-zA-Z0-9.]+>)/, '\1') + else + open, close, supports_phrase = QUOTE_TAGS[type] + text = node.text + if node.role + if supports_phrase + quoted_text = %(#{open}#{text}#{close}) + else + quoted_text = %(#{open.chop} role="#{node.role}">#{text}#{close}) + end + else + quoted_text = %(#{open}#{text}#{close}) + end + node.id ? %(#{quoted_text}) : quoted_text + end + end + end + + # register a html5 converter that takes in charge to convert monospaced text into Git style synopsis + class GitHTMLConverter < Asciidoctor::Converter::Html5Converter + + extend Asciidoctor::Converter::Config + register_for 'html5' + + def convert_inline_quoted node + if node.type == :monospaced + node.text.gsub(/(\.\.\.?)([^\]$.])/, '\1\2') + .gsub(%r{([\[\s|()>.]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@,/_^\$]+\.{0,2})+)}, '\1\2') + .gsub(/(<[-a-zA-Z0-9.]+>)/, '\1') + + else + open, close, tag = QUOTE_TAGS[node.type] + if node.id + class_attr = node.role ? %( class="#{node.role}") : '' + if tag + %(#{open.chop} id="#{node.id}"#{class_attr}>#{node.text}#{close}) + else + %(#{open}#{node.text}#{close}) + end + elsif node.role + if tag + %(#{open.chop} class="#{node.role}">#{node.text}#{close}) + else + %(#{open}#{node.text}#{close}) + end + else + %(#{open}#{node.text}#{close}) + end + end + end + end + end +end + +Asciidoctor::Extensions.register do + inline_macro Git::Documentation::LinkGitProcessor, :linkgit + block Git::Documentation::SynopsisBlock + postprocessor Git::Documentation::DocumentPostProcessor +end diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index a1c8146f05..b4687784c1 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -53,6 +53,7 @@ fi GIT_VERSION=$(expr "$VN" : v*'\(.*\)') GIT_BUILT_FROM_COMMIT=$(git -C "$SOURCE_DIR" rev-parse -q --verify HEAD 2>/dev/null) +GIT_DATE=$(git -C "$SOURCE_DIR" show --quiet --format='%as' 2>/dev/null) if test -z "$GIT_USER_AGENT" then GIT_USER_AGENT="git/$GIT_VERSION" @@ -72,6 +73,7 @@ sed -e "s|@GIT_VERSION@|$GIT_VERSION|" \ -e "s|@GIT_PATCH_LEVEL@|$GIT_PATCH_LEVEL|" \ -e "s|@GIT_BUILT_FROM_COMMIT@|$GIT_BUILT_FROM_COMMIT|" \ -e "s|@GIT_USER_AGENT@|$GIT_USER_AGENT|" \ + -e "s|@GIT_DATE@|$GIT_DATE|" \ "$INPUT" >"$OUTPUT"+ if ! test -f "$OUTPUT" || ! cmp "$OUTPUT"+ "$OUTPUT" >/dev/null -- cgit v1.2.3 From ccfba9e0c45d85e980b3c83bf1e30bf4f1e25ccf Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:44 +0100 Subject: Makefile: use "generate-perl.sh" to massage Perl library Extend "generate-perl.sh" such that it knows to also massage the Perl library files. There are two major differences: - We do not read in the Perl header. This is handled by matching on whether or not we have a Perl shebang. - We substitute some more variables, which we read in via our GIT-BUILD-OPTIONS. Adapt both our Makefile and the CMake build instructions to use this. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- GIT-BUILD-OPTIONS.in | 2 ++ Makefile | 10 ++++------ contrib/buildsystems/CMakeLists.txt | 23 +++++++++-------------- generate-perl.sh | 14 ++++++++++++-- 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/GIT-BUILD-OPTIONS.in b/GIT-BUILD-OPTIONS.in index f0ca240493..050432f9fc 100644 --- a/GIT-BUILD-OPTIONS.in +++ b/GIT-BUILD-OPTIONS.in @@ -1,6 +1,8 @@ SHELL_PATH=@SHELL_PATH@ TEST_SHELL_PATH=@TEST_SHELL_PATH@ PERL_PATH=@PERL_PATH@ +PERL_LOCALEDIR=@PERL_LOCALEDIR@ +NO_PERL_CPAN_FALLBACKS=@NO_PERL_CPAN_FALLBACKS@ DIFF=@DIFF@ PYTHON_PATH=@PYTHON_PATH@ TAR=@TAR@ diff --git a/Makefile b/Makefile index e33c5b966c..b8f9658109 100644 --- a/Makefile +++ b/Makefile @@ -3095,13 +3095,9 @@ endif NO_PERL_CPAN_FALLBACKS_SQ = $(subst ','\'',$(NO_PERL_CPAN_FALLBACKS)) endif -perl/build/lib/%.pm: perl/%.pm GIT-PERL-DEFINES +perl/build/lib/%.pm: perl/%.pm generate-perl.sh GIT-BUILD-OPTIONS GIT-VERSION-FILE GIT-PERL-DEFINES $(call mkdir_p_parent_template) - $(QUIET_GEN) \ - sed -e 's|@LOCALEDIR@|$(perl_localedir_SQ)|g' \ - -e 's|@NO_GETTEXT@|$(NO_GETTEXT_SQ)|g' \ - -e 's|@NO_PERL_CPAN_FALLBACKS@|$(NO_PERL_CPAN_FALLBACKS_SQ)|g' \ - < $< > $@ + $(QUIET_GEN)$(SHELL_PATH) generate-perl.sh ./GIT-BUILD-OPTIONS ./GIT-VERSION-FILE GIT-PERL-HEADER "$<" "$@" perl/build/man/man3/Git.3pm: perl/Git.pm $(call mkdir_p_parent_template) @@ -3168,6 +3164,8 @@ GIT-BUILD-OPTIONS: FORCE -e "s|@SHELL_PATH@|\'$(SHELL_PATH_SQ)\'|" \ -e "s|@TEST_SHELL_PATH@|\'$(TEST_SHELL_PATH_SQ)\'|" \ -e "s|@PERL_PATH@|\'$(PERL_PATH_SQ)\'|" \ + -e "s|@PERL_LOCALEDIR@|\'$(perl_localedir_SQ)\'|" \ + -e "s|@NO_PERL_CPAN_FALLBACKS@|\'$(NO_PERL_CPAN_FALLBACKS_SQ)\'|" \ -e "s|@DIFF@|\'$(DIFF)\'|" \ -e "s|@PYTHON_PATH@|\'$(PYTHON_PATH_SQ)\'|" \ -e "s|@TAR@|\'$(TAR)\'|" \ diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 5cb9a20936..52b479e2e5 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -853,6 +853,9 @@ endforeach() #perl scripts parse_makefile_for_scripts(git_perl_scripts "SCRIPT_PERL" "") +#perl modules +file(GLOB_RECURSE perl_modules "${CMAKE_SOURCE_DIR}/perl/*.pm") +list(TRANSFORM perl_modules REPLACE "${CMAKE_SOURCE_DIR}/" "") #create perl header file(STRINGS ${CMAKE_SOURCE_DIR}/perl/header_templates/fixed_prefix.template.pl perl_header ) @@ -869,9 +872,12 @@ add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/GIT-VERSION-FILE" "${CMAKE_SOURCE_DIR}/GIT-VERSION-FILE.in" VERBATIM) -foreach(script ${git_perl_scripts}) +foreach(script ${git_perl_scripts} ${perl_modules}) string(REPLACE ".perl" "" perl_gen_path "${script}") + get_filename_component(perl_gen_dir "${perl_gen_path}" DIRECTORY) + file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/${perl_gen_dir}") + add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/${perl_gen_path}" COMMAND "${SH_EXE}" "${CMAKE_SOURCE_DIR}/generate-perl.sh" "${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS" @@ -893,19 +899,6 @@ file(STRINGS ${CMAKE_SOURCE_DIR}/git-p4.py content NEWLINE_CONSUME) string(REPLACE "#!/usr/bin/env python" "#!/usr/bin/python" content "${content}") file(WRITE ${CMAKE_BINARY_DIR}/git-p4 ${content}) -#perl modules -file(GLOB_RECURSE perl_modules "${CMAKE_SOURCE_DIR}/perl/*.pm") - -foreach(pm ${perl_modules}) - string(REPLACE "${CMAKE_SOURCE_DIR}/perl/" "" file_path ${pm}) - file(STRINGS ${pm} content NEWLINE_CONSUME) - string(REPLACE "@LOCALEDIR@" "${LOCALEDIR}" content "${content}") - string(REPLACE "@NO_PERL_CPAN_FALLBACKS@" "" content "${content}") - file(WRITE ${CMAKE_BINARY_DIR}/perl/build/lib/${file_path} ${content}) -#test-lib.sh requires perl/build/lib to be the build directory of perl modules -endforeach() - - #templates file(GLOB templates "${CMAKE_SOURCE_DIR}/templates/*") list(TRANSFORM templates REPLACE "${CMAKE_SOURCE_DIR}/templates/" "") @@ -1155,6 +1148,8 @@ file(STRINGS ${CMAKE_SOURCE_DIR}/GIT-BUILD-OPTIONS.in git_build_options NEWLINE_ string(REPLACE "@SHELL_PATH@" "'${SHELL_PATH}'" git_build_options "${git_build_options}") string(REPLACE "@TEST_SHELL_PATH@" "'${TEST_SHELL_PATH}'" git_build_options "${git_build_options}") string(REPLACE "@PERL_PATH@" "'${PERL_PATH}'" git_build_options "${git_build_options}") +string(REPLACE "@PERL_LOCALEDIR@" "'${LOCALEDIR}'" git_build_options "${git_build_options}") +string(REPLACE "@NO_PERL_CPAN_FALLBACKS@" "" git_build_options "${git_build_options}") string(REPLACE "@DIFF@" "'${DIFF}'" git_build_options "${git_build_options}") string(REPLACE "@PYTHON_PATH@" "'${PYTHON_PATH}'" git_build_options "${git_build_options}") string(REPLACE "@TAR@" "'${TAR}'" git_build_options "${git_build_options}") diff --git a/generate-perl.sh b/generate-perl.sh index 95072522da..65f122ebfc 100755 --- a/generate-perl.sh +++ b/generate-perl.sh @@ -18,10 +18,20 @@ OUTPUT="$5" . "$GIT_VERSION_FILE" sed -e '1{' \ + -e " /^#!.*perl/!b" \ -e " s|#!.*perl|#!$PERL_PATH|" \ -e " r $PERL_HEADER" \ -e ' G' \ -e '}' \ - -e "s/@GIT_VERSION@/$GIT_VERSION/g" \ + -e "s|@GIT_VERSION@|$GIT_VERSION|g" \ + -e "s|@LOCALEDIR@|$PERL_LOCALEDIR|g" \ + -e "s|@NO_GETTEXT@|$NO_GETTEXT|g" \ + -e "s|@NO_PERL_CPAN_FALLBACKS@|$NO_PERL_CPAN_FALLBACKS|g" \ "$INPUT" >"$OUTPUT" -chmod a+x "$OUTPUT" + +case "$INPUT" in +*.perl) + chmod a+x "$OUTPUT";; +*) + ;; +esac -- cgit v1.2.3 From eb98cb835c9faf4d675411b3314b7fc9820ab179 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:45 +0100 Subject: Makefile: extract script to massage Shell scripts Same as in the preceding commits, extract a script that allows us to unify how we massage shell scripts. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- GIT-BUILD-OPTIONS.in | 4 ++++ Makefile | 34 ++++++++++------------------------ contrib/buildsystems/CMakeLists.txt | 31 ++++++++++++++++++++----------- generate-script.sh | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 35 deletions(-) create mode 100755 generate-script.sh diff --git a/GIT-BUILD-OPTIONS.in b/GIT-BUILD-OPTIONS.in index 050432f9fc..9b95a6b3ee 100644 --- a/GIT-BUILD-OPTIONS.in +++ b/GIT-BUILD-OPTIONS.in @@ -36,3 +36,7 @@ GIT_INTEROP_MAKE_OPTS=@GIT_INTEROP_MAKE_OPTS@ GIT_TEST_INDEX_VERSION=@GIT_TEST_INDEX_VERSION@ GIT_TEST_PERL_FATAL_WARNINGS=@GIT_TEST_PERL_FATAL_WARNINGS@ RUNTIME_PREFIX=@RUNTIME_PREFIX@ +GITWEBDIR=@GITWEBDIR@ +USE_GETTEXT_SCHEME=@USE_GETTEXT_SCHEME@ +LOCALEDIR=@LOCALEDIR@ +BROKEN_PATH_FIX=@BROKEN_PATH_FIX@ diff --git a/Makefile b/Makefile index b8f9658109..c898720861 100644 --- a/Makefile +++ b/Makefile @@ -1558,10 +1558,10 @@ endif ifdef SANE_TOOL_PATH SANE_TOOL_PATH_SQ = $(subst ','\'',$(SANE_TOOL_PATH)) -BROKEN_PATH_FIX = 's|^\# @BROKEN_PATH_FIX@$$|git_broken_path_fix "$(SANE_TOOL_PATH_SQ)"|' +BROKEN_PATH_FIX = s|^\# @BROKEN_PATH_FIX@$$|git_broken_path_fix "$(SANE_TOOL_PATH_SQ)"| PATH := $(SANE_TOOL_PATH):${PATH} else -BROKEN_PATH_FIX = '/^\# @BROKEN_PATH_FIX@$$/d' +BROKEN_PATH_FIX = /^\# @BROKEN_PATH_FIX@$$/d endif ifeq (,$(HOST_CPU)) @@ -2546,26 +2546,8 @@ GIT-SCRIPT-DEFINES: FORCE echo "$$FLAGS" >$@; \ fi -define cmd_munge_script -sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ - -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \ - -e 's|@DIFF@|$(DIFF_SQ)|' \ - -e 's|@LOCALEDIR@|$(localedir_SQ)|g' \ - -e 's/@USE_GETTEXT_SCHEME@/$(USE_GETTEXT_SCHEME)/g' \ - -e $(BROKEN_PATH_FIX) \ - -e 's|@GITWEBDIR@|$(gitwebdir_SQ)|g' \ - -e 's|@PERL_PATH@|$(PERL_PATH_SQ)|g' \ - -e 's|@PAGER_ENV@|$(PAGER_ENV_SQ)|g' \ - $@.sh >$@+ -endef - -$(SCRIPT_SH_GEN) : % : %.sh GIT-SCRIPT-DEFINES - $(QUIET_GEN)$(cmd_munge_script) && \ - chmod +x $@+ && \ - mv $@+ $@ - -$(SCRIPT_LIB) : % : %.sh GIT-SCRIPT-DEFINES - $(QUIET_GEN)$(cmd_munge_script) && \ +$(SCRIPT_SH_GEN) $(SCRIPT_LIB) : % : %.sh generate-script.sh GIT-BUILD-OPTIONS GIT-SCRIPT-DEFINES + $(QUIET_GEN)./generate-script.sh "$<" "$@+" ./GIT-BUILD-OPTIONS && \ mv $@+ $@ git.rc: git.rc.in GIT-VERSION-GEN GIT-VERSION-FILE @@ -2635,8 +2617,8 @@ GIT-PERL-HEADER: $(PERL_HEADER_TEMPLATE) GIT-PERL-DEFINES Makefile perllibdir: @echo '$(perllibdir_SQ)' -git-instaweb: git-instaweb.sh GIT-SCRIPT-DEFINES - $(QUIET_GEN)$(cmd_munge_script) && \ +git-instaweb: git-instaweb.sh generate-script.sh GIT-BUILD-OPTIONS GIT-SCRIPT-DEFINES + $(QUIET_GEN)./generate-script.sh "$<" "$@+" ./GIT-BUILD-OPTIONS && \ chmod +x $@+ && \ mv $@+ $@ else # NO_PERL @@ -3199,6 +3181,10 @@ GIT-BUILD-OPTIONS: FORCE -e "s|@GIT_TEST_INDEX_VERSION@|\'$(GIT_TEST_INDEX_VERSION)\'|" \ -e "s|@GIT_TEST_PERL_FATAL_WARNINGS@|\'$(GIT_TEST_PERL_FATAL_WARNINGS)\'|" \ -e "s|@RUNTIME_PREFIX@|\'$(RUNTIME_PREFIX_OPTION)\'|" \ + -e "s|@GITWEBDIR@|\'$(gitwebdir_SQ)\'|" \ + -e "s|@USE_GETTEXT_SCHEME@|\'$(USE_GETTEXT_SCHEME)\'|" \ + -e "s|@LOCALEDIR@|\'$(localedir_SQ)\'|" \ + -e "s!@BROKEN_PATH_FIX@!\'$(BROKEN_PATH_FIX)\'!" \ GIT-BUILD-OPTIONS.in >$@+ @if grep -q '^[A-Z][A-Z_]*=@.*@$$' $@+; then echo "Unsubstituted build options in $@" >&2 && exit 1; fi @if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 52b479e2e5..defdd958bb 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -838,18 +838,23 @@ set(git_shell_scripts ${git_sh_scripts} ${git_shlib_scripts} git-instaweb) foreach(script ${git_shell_scripts}) - file(STRINGS ${CMAKE_SOURCE_DIR}/${script}.sh content NEWLINE_CONSUME) - string(REPLACE "@SHELL_PATH@" "${SHELL_PATH}" content "${content}") - string(REPLACE "@DIFF@" "diff" content "${content}") - string(REPLACE "@LOCALEDIR@" "${LOCALEDIR}" content "${content}") - string(REPLACE "@GITWEBDIR@" "${GITWEBDIR}" content "${content}") - string(REPLACE "@NO_CURL@" "" content "${content}") - string(REPLACE "@USE_GETTEXT_SCHEME@" "" content "${content}") - string(REPLACE "# @BROKEN_PATH_FIX@" "" content "${content}") - string(REPLACE "@PERL_PATH@" "${PERL_PATH}" content "${content}") - string(REPLACE "@PAGER_ENV@" "LESS=FRX LV=-c" content "${content}") - file(WRITE ${CMAKE_BINARY_DIR}/${script} ${content}) + if ("${script}" IN_LIST git_sh_scripts) + string(REPLACE ".sh" "" shell_gen_path "${script}") + else() + set(shell_gen_path "${script}") + endif() + + add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/${shell_gen_path}" + COMMAND "${SH_EXE}" "${CMAKE_SOURCE_DIR}/generate-script.sh" + "${CMAKE_SOURCE_DIR}/${script}.sh" + "${CMAKE_BINARY_DIR}/${shell_gen_path}" + "${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS" + DEPENDS "${CMAKE_SOURCE_DIR}/generate-script.sh" + "${CMAKE_SOURCE_DIR}/${script}.sh" + VERBATIM) + list(APPEND shell_gen ${CMAKE_BINARY_DIR}/${shell_gen_path}) endforeach() +add_custom_target(shell-gen ALL DEPENDS ${shell_gen}) #perl scripts parse_makefile_for_scripts(git_perl_scripts "SCRIPT_PERL" "") @@ -1183,6 +1188,10 @@ string(REPLACE "@GIT_INTEROP_MAKE_OPTS@" "" git_build_options "${git_build_optio string(REPLACE "@GIT_TEST_INDEX_VERSION@" "" git_build_options "${git_build_options}") string(REPLACE "@GIT_TEST_PERL_FATAL_WARNINGS@" "" git_build_options "${git_build_options}") string(REPLACE "@RUNTIME_PREFIX@" "'${RUNTIME_PREFIX}'" git_build_options "${git_build_options}") +string(REPLACE "@GITWEBDIR@" "'${GITWEBDIR}'" git_build_options "${git_build_options}") +string(REPLACE "@USE_GETTEXT_SCHEME@" "" git_build_options "${git_build_options}") +string(REPLACE "@LOCALEDIR@" "'${LOCALEDIR}'" git_build_options "${git_build_options}") +string(REPLACE "@BROKEN_PATH_FIX@" "" git_build_options "${git_build_options}") if(USE_VCPKG) string(APPEND git_build_options "PATH=\"$PATH:$TEST_DIRECTORY/../compat/vcbuild/vcpkg/installed/x64-windows/bin\"\n") endif() diff --git a/generate-script.sh b/generate-script.sh new file mode 100755 index 0000000000..a149e4f0ba --- /dev/null +++ b/generate-script.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +set -e + +if test $# -ne 3 +then + echo >&2 "USAGE: $0 " + exit 1 +fi + +INPUT="$1" +OUTPUT="$2" +BUILD_OPTIONS="$3" + +. "$BUILD_OPTIONS" + +sed -e "1s|#!.*/sh|#!$SHELL_PATH|" \ + -e "s|@SHELL_PATH@|$SHELL_PATH|" \ + -e "s|@DIFF@|$DIFF|" \ + -e "s|@LOCALEDIR@|$LOCALEDIR|g" \ + -e "s/@USE_GETTEXT_SCHEME@/$USE_GETTEXT_SCHEME/g" \ + -e "$BROKEN_PATH_FIX" \ + -e "s|@GITWEBDIR@|$GITWEBDIR|g" \ + -e "s|@PERL_PATH@|$PERL_PATH|g" \ + -e "s|@PAGER_ENV@|$PAGER_ENV|g" \ + "$INPUT" >"$OUTPUT" + +case "$(basename "$INPUT")" in +git-mergetool--lib.sh|git-sh-i18n.sh|git-sh-setup.sh) + ;; +*) + chmod a+x "$OUTPUT" + ;; +esac -- cgit v1.2.3 From b7835b941bd437aa770ab91d7323ce74d2bd81b7 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:46 +0100 Subject: Makefile: extract script to massage Python scripts Extract a script that massages Python scripts. This provides a couple of benefits: - The build logic is deduplicated across Make, CMake and Meson. - CMake learns to rewrite scripts as-needed at build time instead of only writing them at configure time. Furthermore, we will use this script when introducing Meson to deduplicate the logic across build systems. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Makefile | 8 ++------ contrib/buildsystems/CMakeLists.txt | 15 +++++++++++---- generate-python.sh | 20 ++++++++++++++++++++ 3 files changed, 33 insertions(+), 10 deletions(-) create mode 100755 generate-python.sh diff --git a/Makefile b/Makefile index c898720861..35352119a8 100644 --- a/Makefile +++ b/Makefile @@ -2635,13 +2635,9 @@ endif # NO_PERL $(SCRIPT_PYTHON_GEN): GIT-BUILD-OPTIONS ifndef NO_PYTHON -$(SCRIPT_PYTHON_GEN): GIT-CFLAGS GIT-PREFIX GIT-PYTHON-VARS +$(SCRIPT_PYTHON_GEN): generate-python.sh $(SCRIPT_PYTHON_GEN): % : %.py - $(QUIET_GEN) \ - sed -e '1s|#!.*python|#!$(PYTHON_PATH_SQ)|' \ - $< >$@+ && \ - chmod +x $@+ && \ - mv $@+ $@ + $(QUIET_GEN)$(SHELL_PATH) generate-python.sh ./GIT-BUILD-OPTIONS "$<" "$@" else # NO_PYTHON $(SCRIPT_PYTHON_GEN): % : unimplemented.sh $(QUIET_GEN) \ diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index defdd958bb..93c865ee2b 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -899,10 +899,17 @@ foreach(script ${git_perl_scripts} ${perl_modules}) endforeach() add_custom_target(perl-gen ALL DEPENDS ${perl_gen}) -#python script -file(STRINGS ${CMAKE_SOURCE_DIR}/git-p4.py content NEWLINE_CONSUME) -string(REPLACE "#!/usr/bin/env python" "#!/usr/bin/python" content "${content}") -file(WRITE ${CMAKE_BINARY_DIR}/git-p4 ${content}) +# Python script +add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/git-p4" + COMMAND "${SH_EXE}" "${CMAKE_SOURCE_DIR}/generate-python.sh" + "${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS" + "${CMAKE_SOURCE_DIR}/git-p4.py" + "${CMAKE_BINARY_DIR}/git-p4" + DEPENDS "${CMAKE_SOURCE_DIR}/generate-python.sh" + "${CMAKE_SOURCE_DIR}/git-p4.py" + "${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS" + VERBATIM) +add_custom_target(python-gen ALL DEPENDS "${CMAKE_BINARY_DIR}/git-p4") #templates file(GLOB templates "${CMAKE_SOURCE_DIR}/templates/*") diff --git a/generate-python.sh b/generate-python.sh new file mode 100755 index 0000000000..31ac115689 --- /dev/null +++ b/generate-python.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +set -e + +if test $# -ne 3 +then + echo >&2 "USAGE: $0 " + exit 1 +fi + +GIT_BUILD_OPTIONS="$1" +INPUT="$2" +OUTPUT="$3" + +. "$GIT_BUILD_OPTIONS" + +sed -e "1s|#!.*python|#!$PYTHON_PATH|" \ + "$INPUT" >"$OUTPUT+" +chmod a+x "$OUTPUT+" +mv "$OUTPUT+" "$OUTPUT" -- cgit v1.2.3 From d2507bbbf4cec59fc002ca8e59e03155836d5005 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:47 +0100 Subject: Makefile: extract script to generate gitweb.cgi In order to generate "gitweb.cgi" we have to replace various different placeholders. This is done ad-hoc and is thus not easily reusable across different build systems. Introduce a new GITWEB-BUILD-OPTIONS.in template that we populate at configuration time with the expected options. This script is then used as input for a new "generate-gitweb.sh" script that generates the final "gitweb.cgi" file. While this requires us to repeat the options multiple times, it is in line to how we generate other build options like our GIT-BUILD-OPTIONS file. While at it, refactor how we replace the GITWEB_PROJECT_MAXDEPTH. Even though this variable is supposed to be an integer, the source file has the value quoted. The quotes are eventually stripped via sed(1), which replaces `"@GITWEB_PROJECT_MAXDEPTH@"` with the actual value, which is rather nonsensical. This is made clearer by just dropping the quotes in the source file. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- gitweb/GITWEB-BUILD-OPTIONS.in | 24 +++++++++++++++++ gitweb/Makefile | 59 +++++++++++++++++++++--------------------- gitweb/generate-gitweb-cgi.sh | 47 +++++++++++++++++++++++++++++++++ gitweb/gitweb.perl | 2 +- 4 files changed, 101 insertions(+), 31 deletions(-) create mode 100644 gitweb/GITWEB-BUILD-OPTIONS.in create mode 100755 gitweb/generate-gitweb-cgi.sh diff --git a/gitweb/GITWEB-BUILD-OPTIONS.in b/gitweb/GITWEB-BUILD-OPTIONS.in new file mode 100644 index 0000000000..41ac20654c --- /dev/null +++ b/gitweb/GITWEB-BUILD-OPTIONS.in @@ -0,0 +1,24 @@ +PERL_PATH=@PERL_PATH@ +JSMIN=@JSMIN@ +CSSMIN=@CSSMIN@ +GIT_BINDIR=@GIT_BINDIR@ +GITWEB_CONFIG=@GITWEB_CONFIG@ +GITWEB_CONFIG_SYSTEM=@GITWEB_CONFIG_SYSTEM@ +GITWEB_CONFIG_COMMON=@GITWEB_CONFIG_COMMON@ +GITWEB_HOME_LINK_STR=@GITWEB_HOME_LINK_STR@ +GITWEB_SITENAME=@GITWEB_SITENAME@ +GITWEB_PROJECTROOT=@GITWEB_PROJECTROOT@ +GITWEB_PROJECT_MAXDEPTH=@GITWEB_PROJECT_MAXDEPTH@ +GITWEB_EXPORT_OK=@GITWEB_EXPORT_OK@ +GITWEB_STRICT_EXPORT=@GITWEB_STRICT_EXPORT@ +GITWEB_BASE_URL=@GITWEB_BASE_URL@ +GITWEB_LIST=@GITWEB_LIST@ +GITWEB_HOMETEXT=@GITWEB_HOMETEXT@ +GITWEB_CSS=@GITWEB_CSS@ +GITWEB_LOGO=@GITWEB_LOGO@ +GITWEB_FAVICON=@GITWEB_FAVICON@ +GITWEB_JS=@GITWEB_JS@ +GITWEB_SITE_HTML_HEAD_STRING=@GITWEB_SITE_HTML_HEAD_STRING@ +GITWEB_SITE_HEADER=@GITWEB_SITE_HEADER@ +GITWEB_SITE_FOOTER=@GITWEB_SITE_FOOTER@ +HIGHLIGHT_BIN=@HIGHLIGHT_BIN@ diff --git a/gitweb/Makefile b/gitweb/Makefile index 164c8d5375..16a2ef2d1e 100644 --- a/gitweb/Makefile +++ b/gitweb/Makefile @@ -77,43 +77,42 @@ GITWEB_JSLIB_FILES += static/js/javascript-detection.js GITWEB_JSLIB_FILES += static/js/adjust-timezone.js GITWEB_JSLIB_FILES += static/js/blame_incremental.js - -GITWEB_REPLACE = \ - -e 's|@GIT_VERSION@|$(GIT_VERSION)|g' \ - -e 's|@GIT_BINDIR@|$(bindir)|g' \ - -e 's|@GITWEB_CONFIG@|$(GITWEB_CONFIG)|g' \ - -e 's|@GITWEB_CONFIG_SYSTEM@|$(GITWEB_CONFIG_SYSTEM)|g' \ - -e 's|@GITWEB_CONFIG_COMMON@|$(GITWEB_CONFIG_COMMON)|g' \ - -e 's|@GITWEB_HOME_LINK_STR@|$(GITWEB_HOME_LINK_STR)|g' \ - -e 's|@GITWEB_SITENAME@|$(GITWEB_SITENAME)|g' \ - -e 's|@GITWEB_PROJECTROOT@|$(GITWEB_PROJECTROOT)|g' \ - -e 's|"@GITWEB_PROJECT_MAXDEPTH@"|$(GITWEB_PROJECT_MAXDEPTH)|g' \ - -e 's|@GITWEB_EXPORT_OK@|$(GITWEB_EXPORT_OK)|g' \ - -e 's|@GITWEB_STRICT_EXPORT@|$(GITWEB_STRICT_EXPORT)|g' \ - -e 's|@GITWEB_BASE_URL@|$(GITWEB_BASE_URL)|g' \ - -e 's|@GITWEB_LIST@|$(GITWEB_LIST)|g' \ - -e 's|@GITWEB_HOMETEXT@|$(GITWEB_HOMETEXT)|g' \ - -e 's|@GITWEB_CSS@|$(GITWEB_CSS)|g' \ - -e 's|@GITWEB_LOGO@|$(GITWEB_LOGO)|g' \ - -e 's|@GITWEB_FAVICON@|$(GITWEB_FAVICON)|g' \ - -e 's|@GITWEB_JS@|$(GITWEB_JS)|g' \ - -e 's|@GITWEB_SITE_HTML_HEAD_STRING@|$(GITWEB_SITE_HTML_HEAD_STRING)|g' \ - -e 's|@GITWEB_SITE_HEADER@|$(GITWEB_SITE_HEADER)|g' \ - -e 's|@GITWEB_SITE_FOOTER@|$(GITWEB_SITE_FOOTER)|g' \ - -e 's|@HIGHLIGHT_BIN@|$(HIGHLIGHT_BIN)|g' - .PHONY: FORCE $(MAK_DIR_GITWEB)GITWEB-BUILD-OPTIONS: FORCE - @rm -f $@+ - @echo "x" '$(PERL_PATH_SQ)' $(GITWEB_REPLACE) "$(JSMIN)|$(CSSMIN)" >$@+ + @sed -e 's|@PERL_PATH@|$(PERL_PATH_SQ)|' \ + -e 's|@JSMIN@|$(JSMIN)|' \ + -e 's|@CSSMIN@|$(CSSMIN)|' \ + -e 's|@GIT_VERSION@|$(GIT_VERSION)|' \ + -e 's|@GIT_BINDIR@|$(bindir)|' \ + -e 's|@GITWEB_CONFIG@|$(GITWEB_CONFIG)|' \ + -e 's|@GITWEB_CONFIG_SYSTEM@|$(GITWEB_CONFIG_SYSTEM)|' \ + -e 's|@GITWEB_CONFIG_COMMON@|$(GITWEB_CONFIG_COMMON)|' \ + -e 's|@GITWEB_HOME_LINK_STR@|$(GITWEB_HOME_LINK_STR)|' \ + -e 's|@GITWEB_SITENAME@|$(GITWEB_SITENAME)|' \ + -e 's|@GITWEB_PROJECTROOT@|$(GITWEB_PROJECTROOT)|' \ + -e 's|@GITWEB_PROJECT_MAXDEPTH@|$(GITWEB_PROJECT_MAXDEPTH)|' \ + -e 's|@GITWEB_EXPORT_OK@|$(GITWEB_EXPORT_OK)|' \ + -e 's|@GITWEB_STRICT_EXPORT@|$(GITWEB_STRICT_EXPORT)|' \ + -e 's|@GITWEB_BASE_URL@|$(GITWEB_BASE_URL)|' \ + -e 's|@GITWEB_LIST@|$(GITWEB_LIST)|' \ + -e 's|@GITWEB_HOMETEXT@|$(GITWEB_HOMETEXT)|' \ + -e 's|@GITWEB_CSS@|$(GITWEB_CSS)|' \ + -e 's|@GITWEB_LOGO@|$(GITWEB_LOGO)|' \ + -e 's|@GITWEB_FAVICON@|$(GITWEB_FAVICON)|' \ + -e 's|@GITWEB_JS@|$(GITWEB_JS)|' \ + -e 's|@GITWEB_SITE_HTML_HEAD_STRING@|$(GITWEB_SITE_HTML_HEAD_STRING)|' \ + -e 's|@GITWEB_SITE_HEADER@|$(GITWEB_SITE_HEADER)|' \ + -e 's|@GITWEB_SITE_FOOTER@|$(GITWEB_SITE_FOOTER)|' \ + -e 's|@HIGHLIGHT_BIN@|$(HIGHLIGHT_BIN)|' \ + $(MAK_DIR_GITWEB)GITWEB-BUILD-OPTIONS.in >"$@+" @cmp -s $@+ $@ && rm -f $@+ || mv -f $@+ $@ +$(MAK_DIR_GITWEB)gitweb.cgi: $(MAK_DIR_GITWEB)generate-gitweb-cgi.sh $(MAK_DIR_GITWEB)gitweb.cgi: $(MAK_DIR_GITWEB)GITWEB-BUILD-OPTIONS +$(MAK_DIR_GITWEB)gitweb.cgi: GIT-VERSION-FILE $(MAK_DIR_GITWEB)gitweb.cgi: $(MAK_DIR_GITWEB)gitweb.perl $(QUIET_GEN)$(RM) $@ $@+ && \ - sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \ - $(GITWEB_REPLACE) $< >$@+ && \ - chmod +x $@+ && \ + $(MAK_DIR_GITWEB)generate-gitweb-cgi.sh $(MAK_DIR_GITWEB)/GITWEB-BUILD-OPTIONS ./GIT-VERSION-FILE $< $@+ && \ mv $@+ $@ $(MAK_DIR_GITWEB)static/gitweb.js: $(addprefix $(MAK_DIR_GITWEB),$(GITWEB_JSLIB_FILES)) diff --git a/gitweb/generate-gitweb-cgi.sh b/gitweb/generate-gitweb-cgi.sh new file mode 100755 index 0000000000..ede9038c33 --- /dev/null +++ b/gitweb/generate-gitweb-cgi.sh @@ -0,0 +1,47 @@ +#!/bin/sh + +set -e + +if test $# -ne 4 +then + echo >&2 "USAGE: $0 " + exit 1 +fi + +GITWEB_BUILD_OPTIONS="$1" +GIT_VERSION_FILE="$2" +INPUT="$3" +OUTPUT="$4" + +. "$GITWEB_BUILD_OPTIONS" +. "$GIT_VERSION_FILE" + +sed -e "1s|#!/usr/bin/perl|#!$PERL_PATH|" \ + -e "s|@PERL_PATH@|$PERL_PATH|" \ + -e "s|@JSMIN@|$JSMIN|" \ + -e "s|@CSSMIN@|$CSSMIN|" \ + -e "s|@GIT_VERSION@|$GIT_VERSION|" \ + -e "s|@GIT_BINDIR@|$GIT_BINDIR|" \ + -e "s|@GITWEB_CONFIG@|$GITWEB_CONFIG|" \ + -e "s|@GITWEB_CONFIG_SYSTEM@|$GITWEB_CONFIG_SYSTEM|" \ + -e "s|@GITWEB_CONFIG_COMMON@|$GITWEB_CONFIG_COMMON|" \ + -e "s|@GITWEB_HOME_LINK_STR@|$GITWEB_HOME_LINK_STR|" \ + -e "s|@GITWEB_SITENAME@|$GITWEB_SITENAME|" \ + -e "s|@GITWEB_PROJECTROOT@|$GITWEB_PROJECTROOT|" \ + -e "s|@GITWEB_PROJECT_MAXDEPTH@|$GITWEB_PROJECT_MAXDEPTH|" \ + -e "s|@GITWEB_EXPORT_OK@|$GITWEB_EXPORT_OK|" \ + -e "s|@GITWEB_STRICT_EXPORT@|$GITWEB_STRICT_EXPORT|" \ + -e "s|@GITWEB_BASE_URL@|$GITWEB_BASE_URL|" \ + -e "s|@GITWEB_LIST@|$GITWEB_LIST|" \ + -e "s|@GITWEB_HOMETEXT@|$GITWEB_HOMETEXT|" \ + -e "s|@GITWEB_CSS@|$GITWEB_CSS|" \ + -e "s|@GITWEB_LOGO@|$GITWEB_LOGO|" \ + -e "s|@GITWEB_FAVICON@|$GITWEB_FAVICON|" \ + -e "s|@GITWEB_JS@|$GITWEB_JS|" \ + -e "s|@GITWEB_SITE_HTML_HEAD_STRING@|$GITWEB_SITE_HTML_HEAD_STRING|" \ + -e "s|@GITWEB_SITE_HEADER@|$GITWEB_SITE_HEADER|" \ + -e "s|@GITWEB_SITE_FOOTER@|$GITWEB_SITE_FOOTER|" \ + -e "s|@HIGHLIGHT_BIN@|$HIGHLIGHT_BIN|" \ + "$INPUT" >"$OUTPUT" + +chmod a+x "$OUTPUT" diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index dfb66fdd2a..1c0a0adce4 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -88,7 +88,7 @@ our $projectroot = "@GITWEB_PROJECTROOT@"; # fs traversing limit for getting project list # the number is relative to the projectroot -our $project_maxdepth = "@GITWEB_PROJECT_MAXDEPTH@"; +our $project_maxdepth = @GITWEB_PROJECT_MAXDEPTH@; # string of the home link on top of all pages our $home_link_str = "@GITWEB_HOME_LINK_STR@"; -- cgit v1.2.3 From 19d8fe7da650970e5c18681f98d258fd924ecf9b Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:48 +0100 Subject: Makefile: extract script to generate gitweb.js Similar to the preceding commit, also extract the script to generate the "gitweb.js" file. While the logic itself is trivial, it helps us avoid duplication of logic across build systems and ensures that the build systems will remain in sync with each other in case the logic ever needs to change. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- gitweb/Makefile | 3 ++- gitweb/generate-gitweb-js.sh | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100755 gitweb/generate-gitweb-js.sh diff --git a/gitweb/Makefile b/gitweb/Makefile index 16a2ef2d1e..d5748e9359 100644 --- a/gitweb/Makefile +++ b/gitweb/Makefile @@ -115,9 +115,10 @@ $(MAK_DIR_GITWEB)gitweb.cgi: $(MAK_DIR_GITWEB)gitweb.perl $(MAK_DIR_GITWEB)generate-gitweb-cgi.sh $(MAK_DIR_GITWEB)/GITWEB-BUILD-OPTIONS ./GIT-VERSION-FILE $< $@+ && \ mv $@+ $@ +$(MAK_DIR_GITWEB)static/gitweb.js: $(MAK_DIR_GITWEB)generate-gitweb-js.sh $(MAK_DIR_GITWEB)static/gitweb.js: $(addprefix $(MAK_DIR_GITWEB),$(GITWEB_JSLIB_FILES)) $(QUIET_GEN)$(RM) $@ $@+ && \ - cat $^ >$@+ && \ + $(MAK_DIR_GITWEB)generate-gitweb-js.sh $@+ $^ && \ mv $@+ $@ ### Installation rules diff --git a/gitweb/generate-gitweb-js.sh b/gitweb/generate-gitweb-js.sh new file mode 100755 index 0000000000..01bb22b04b --- /dev/null +++ b/gitweb/generate-gitweb-js.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +if test "$#" -lt 2 +then + echo >&2 "USAGE: $0 ..." + exit 1 +fi + +OUTPUT="$1" +shift + +cat "$@" >"$OUTPUT" -- cgit v1.2.3 From 3f145a4fe37099c55c7596e93a4cfd850662f88a Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:49 +0100 Subject: Makefile: refactor generators to be PWD-independent We have multiple scripts that generate headers from other data. All of these scripts have the assumption built-in that they are executed in the current source directory, which makes them a bit unwieldy to use during out-of-tree builds. Refactor them to instead take the source directory as well as the output file as arguments. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Makefile | 6 +++--- contrib/buildsystems/CMakeLists.txt | 19 +++++++++-------- generate-cmdlist.sh | 42 +++++++++++++++++++++++-------------- generate-configlist.sh | 20 +++++++++++++----- generate-hooklist.sh | 15 ++++++++++++- 5 files changed, 68 insertions(+), 34 deletions(-) diff --git a/Makefile b/Makefile index 35352119a8..009e7d8e95 100644 --- a/Makefile +++ b/Makefile @@ -2523,17 +2523,17 @@ $(BUILT_INS): git$X config-list.h: generate-configlist.sh config-list.h: Documentation/*config.txt Documentation/config/*.txt - $(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh >$@ + $(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh . $@ command-list.h: generate-cmdlist.sh command-list.txt command-list.h: $(wildcard Documentation/git*.txt) $(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh \ $(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \ - command-list.txt >$@ + . $@ hook-list.h: generate-hooklist.sh Documentation/githooks.txt - $(QUIET_GEN)$(SHELL_PATH) ./generate-hooklist.sh >$@ + $(QUIET_GEN)$(SHELL_PATH) ./generate-hooklist.sh . $@ SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):\ $(localedir_SQ):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\ diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 93c865ee2b..e7bd45cbb6 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -638,23 +638,24 @@ set(EXCLUSION_PROGS_CACHE ${EXCLUSION_PROGS} CACHE STRING "Programs not built" F if(NOT EXISTS ${CMAKE_BINARY_DIR}/command-list.h OR NOT EXCLUSION_PROGS_CACHE STREQUAL EXCLUSION_PROGS) list(REMOVE_ITEM EXCLUSION_PROGS empty) message("Generating command-list.h") - execute_process(COMMAND ${SH_EXE} ${CMAKE_SOURCE_DIR}/generate-cmdlist.sh ${EXCLUSION_PROGS} command-list.txt - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_FILE ${CMAKE_BINARY_DIR}/command-list.h) + execute_process(COMMAND "${SH_EXE}" "${CMAKE_SOURCE_DIR}/generate-cmdlist.sh" + ${EXCLUSION_PROGS} + "${CMAKE_SOURCE_DIR}" + "${CMAKE_BINARY_DIR}/command-list.h") endif() if(NOT EXISTS ${CMAKE_BINARY_DIR}/config-list.h) message("Generating config-list.h") - execute_process(COMMAND ${SH_EXE} ${CMAKE_SOURCE_DIR}/generate-configlist.sh - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_FILE ${CMAKE_BINARY_DIR}/config-list.h) + execute_process(COMMAND "${SH_EXE}" "${CMAKE_SOURCE_DIR}/generate-configlist.sh" + "${CMAKE_SOURCE_DIR}" + "${CMAKE_BINARY_DIR}/config-list.h") endif() if(NOT EXISTS ${CMAKE_BINARY_DIR}/hook-list.h) message("Generating hook-list.h") - execute_process(COMMAND ${SH_EXE} ${CMAKE_SOURCE_DIR}/generate-hooklist.sh - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_FILE ${CMAKE_BINARY_DIR}/hook-list.h) + execute_process(COMMAND "${SH_EXE}" ${CMAKE_SOURCE_DIR}/generate-hooklist.sh + "${CMAKE_SOURCE_DIR}" + "${CMAKE_BINARY_DIR}/hook-list.h") endif() include_directories(${CMAKE_BINARY_DIR}) diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh index 205541e0f7..b923a5aab8 100755 --- a/generate-cmdlist.sh +++ b/generate-cmdlist.sh @@ -64,7 +64,7 @@ define_category_names () { print_command_list () { echo "static struct cmdname_help command_list[] = {" - echo "$1" | + echo "$2" | while read cmd rest do synopsis= @@ -76,7 +76,7 @@ print_command_list () { break ;; esac - done <"Documentation/$cmd.txt" + done <"$1/Documentation/$cmd.txt" printf '\t{ "%s", N_("%s"), 0' "$cmd" "$synopsis" printf " | CAT_%s" $rest @@ -93,18 +93,28 @@ do shift done -commands="$(command_list "$1")" -categories="$(category_list "$commands")" +if test "$#" -ne 2 +then + die "USAGE: $0 " +fi + +SOURCE_DIR="$1" +OUTPUT="$2" + +{ + commands="$(command_list "$SOURCE_DIR"/command-list.txt)" + categories="$(category_list "$commands")" -echo "/* Automatically generated by generate-cmdlist.sh */ -struct cmdname_help { - const char *name; - const char *help; - uint32_t category; -}; -" -define_categories "$categories" -echo -define_category_names "$categories" -echo -print_command_list "$commands" + echo "/* Automatically generated by generate-cmdlist.sh */ + struct cmdname_help { + const char *name; + const char *help; + uint32_t category; + }; + " + define_categories "$categories" + echo + define_category_names "$categories" + echo + print_command_list "$SOURCE_DIR" "$commands" +} >"$OUTPUT" diff --git a/generate-configlist.sh b/generate-configlist.sh index 8692fe5cf4..579422619c 100755 --- a/generate-configlist.sh +++ b/generate-configlist.sh @@ -1,13 +1,19 @@ #!/bin/sh -echo "/* Automatically generated by generate-configlist.sh */" -echo +SOURCE_DIR="$1" +OUTPUT="$2" + +if test -z "$SOURCE_DIR" || ! test -d "$SOURCE_DIR" || test -z "$OUTPUT" +then + echo >&2 "USAGE: $0 " + exit 1 +fi print_config_list () { cat <"$OUTPUT" diff --git a/generate-hooklist.sh b/generate-hooklist.sh index 2f9f54eb54..e22068c2fa 100755 --- a/generate-hooklist.sh +++ b/generate-hooklist.sh @@ -2,6 +2,17 @@ # # Usage: ./generate-hooklist.sh >hook-list.h +SOURCE_DIR="$1" +OUTPUT="$2" + +if test -z "$SOURCE_DIR" || ! test -d "$SOURCE_DIR" || test -z "$OUTPUT" +then + echo >&2 "USAGE: $0 " + exit 1 +fi + +{ + cat <"$OUTPUT" -- cgit v1.2.3 From 95bcd6f0b709ec6e761270732946651757cc11c3 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:50 +0100 Subject: Makefile: allow "bin-wrappers/" directory to exist The "bin-wrappers/" directory gets created by our build system and is populated with one script for each of our binaries. There isn't anything inherently wrong with the current layout, but it is somewhat hard to adapt for out-of-tree build systems. Adapt the layout such that our "bin-wrappers/" directory always exists and contains our "wrap-for-bin.sh" script to make things a little bit easier for subsequent steps. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- .gitignore | 1 - Documentation/CodingGuidelines | 2 +- Makefile | 6 +++--- bin-wrappers/.gitignore | 9 +++++++++ bin-wrappers/wrap-for-bin.sh | 36 ++++++++++++++++++++++++++++++++++++ contrib/buildsystems/CMakeLists.txt | 6 +++--- wrap-for-bin.sh | 36 ------------------------------------ 7 files changed, 52 insertions(+), 44 deletions(-) create mode 100644 bin-wrappers/.gitignore create mode 100755 bin-wrappers/wrap-for-bin.sh delete mode 100644 wrap-for-bin.sh diff --git a/.gitignore b/.gitignore index d3be460040..e82aa19df0 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,6 @@ /GIT-TEST-SUITES /GIT-USER-AGENT /GIT-VERSION-FILE -/bin-wrappers/ /git /git-add /git-am diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines index 87904791cb..1df9d0c42f 100644 --- a/Documentation/CodingGuidelines +++ b/Documentation/CodingGuidelines @@ -583,7 +583,7 @@ For C programs: Run `GIT_DEBUGGER=1 ./bin-wrappers/git foo` to simply use gdb as is, or run `GIT_DEBUGGER=" " ./bin-wrappers/git foo` to use your own debugger and arguments. Example: `GIT_DEBUGGER="ddd --gdb" - ./bin-wrappers/git log` (See `wrap-for-bin.sh`.) + ./bin-wrappers/git log` (See `bin-wrappers/wrap-for-bin.sh`.) - The primary data structure that a subsystem 'S' deals with is called `struct S`. Functions that operate on `struct S` are named diff --git a/Makefile b/Makefile index 009e7d8e95..6e93319bed 100644 --- a/Makefile +++ b/Makefile @@ -3202,8 +3202,7 @@ test_bindir_programs := $(patsubst %,bin-wrappers/%,$(BINDIR_PROGRAMS_NEED_X) $( all:: $(TEST_PROGRAMS) $(test_bindir_programs) $(UNIT_TEST_PROGS) $(CLAR_TEST_PROG) -bin-wrappers/%: wrap-for-bin.sh - $(call mkdir_p_parent_template) +$(test_bindir_programs): bin-wrappers/%: bin-wrappers/wrap-for-bin.sh $(QUIET_GEN)sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ -e 's|@BUILD_DIR@|$(shell pwd)|' \ -e 's|@PROG@|$(patsubst test-%,t/helper/test-%,$(@F))$(if $(filter-out $(BINDIR_PROGRAMS_NO_X),$(@F)),$(X),)|' < $< > $@ && \ @@ -3700,7 +3699,8 @@ clean: profile-clean coverage-clean cocciclean $(RM) $(SP_OBJ) $(RM) $(HCC) $(RM) version-def.h - $(RM) -r bin-wrappers $(dep_dirs) $(compdb_dir) compile_commands.json + $(RM) -r $(dep_dirs) $(compdb_dir) compile_commands.json + $(RM) $(test_bindir_programs) $(RM) -r po/build/ $(RM) *.pyc *.pyo */*.pyc */*.pyo $(GENERATED_H) $(ETAGS_TARGET) tags cscope* $(RM) -r .dist-tmp-dir .doc-tmp-dir diff --git a/bin-wrappers/.gitignore b/bin-wrappers/.gitignore new file mode 100644 index 0000000000..1c6c90458b --- /dev/null +++ b/bin-wrappers/.gitignore @@ -0,0 +1,9 @@ +/git +/git-cvsserver +/git-receive-pack +/git-shell +/git-upload-archive +/git-upload-pack +/scalar +/test-fake-ssh +/test-tool diff --git a/bin-wrappers/wrap-for-bin.sh b/bin-wrappers/wrap-for-bin.sh new file mode 100755 index 0000000000..7898a1c238 --- /dev/null +++ b/bin-wrappers/wrap-for-bin.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +# wrap-for-bin.sh: Template for git executable wrapper scripts +# to run test suite against sandbox, but with only bindir-installed +# executables in PATH. The Makefile copies this into various +# files in bin-wrappers, substituting +# @BUILD_DIR@ and @PROG@. + +GIT_EXEC_PATH='@BUILD_DIR@' +if test -n "$NO_SET_GIT_TEMPLATE_DIR" +then + unset GIT_TEMPLATE_DIR +else + GIT_TEMPLATE_DIR='@BUILD_DIR@/templates/blt' + export GIT_TEMPLATE_DIR +fi +GITPERLLIB='@BUILD_DIR@/perl/build/lib'"${GITPERLLIB:+:$GITPERLLIB}" +GIT_TEXTDOMAINDIR='@BUILD_DIR@/po/build/locale' +PATH='@BUILD_DIR@/bin-wrappers:'"$PATH" + +export GIT_EXEC_PATH GITPERLLIB PATH GIT_TEXTDOMAINDIR + +case "$GIT_DEBUGGER" in +'') + exec "${GIT_EXEC_PATH}/@PROG@" "$@" + ;; +1) + unset GIT_DEBUGGER + exec gdb --args "${GIT_EXEC_PATH}/@PROG@" "$@" + ;; +*) + GIT_DEBUGGER_ARGS="$GIT_DEBUGGER" + unset GIT_DEBUGGER + exec ${GIT_DEBUGGER_ARGS} "${GIT_EXEC_PATH}/@PROG@" "$@" + ;; +esac diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index e7bd45cbb6..9348665f22 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -1095,20 +1095,20 @@ set(wrapper_test_scripts foreach(script ${wrapper_scripts}) - file(STRINGS ${CMAKE_SOURCE_DIR}/wrap-for-bin.sh content NEWLINE_CONSUME) + file(STRINGS ${CMAKE_SOURCE_DIR}/bin-wrappers/wrap-for-bin.sh content NEWLINE_CONSUME) string(REPLACE "@BUILD_DIR@" "${CMAKE_BINARY_DIR}" content "${content}") string(REPLACE "@PROG@" "${script}${EXE_EXTENSION}" content "${content}") file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/${script} ${content}) endforeach() foreach(script ${wrapper_test_scripts}) - file(STRINGS ${CMAKE_SOURCE_DIR}/wrap-for-bin.sh content NEWLINE_CONSUME) + file(STRINGS ${CMAKE_SOURCE_DIR}/bin-wrappers/wrap-for-bin.sh content NEWLINE_CONSUME) string(REPLACE "@BUILD_DIR@" "${CMAKE_BINARY_DIR}" content "${content}") string(REPLACE "@PROG@" "t/helper/${script}${EXE_EXTENSION}" content "${content}") file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/${script} ${content}) endforeach() -file(STRINGS ${CMAKE_SOURCE_DIR}/wrap-for-bin.sh content NEWLINE_CONSUME) +file(STRINGS ${CMAKE_SOURCE_DIR}/bin-wrappers/wrap-for-bin.sh content NEWLINE_CONSUME) string(REPLACE "@BUILD_DIR@" "${CMAKE_BINARY_DIR}" content "${content}") string(REPLACE "@PROG@" "git-cvsserver" content "${content}") file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/git-cvsserver ${content}) diff --git a/wrap-for-bin.sh b/wrap-for-bin.sh deleted file mode 100644 index 7898a1c238..0000000000 --- a/wrap-for-bin.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh - -# wrap-for-bin.sh: Template for git executable wrapper scripts -# to run test suite against sandbox, but with only bindir-installed -# executables in PATH. The Makefile copies this into various -# files in bin-wrappers, substituting -# @BUILD_DIR@ and @PROG@. - -GIT_EXEC_PATH='@BUILD_DIR@' -if test -n "$NO_SET_GIT_TEMPLATE_DIR" -then - unset GIT_TEMPLATE_DIR -else - GIT_TEMPLATE_DIR='@BUILD_DIR@/templates/blt' - export GIT_TEMPLATE_DIR -fi -GITPERLLIB='@BUILD_DIR@/perl/build/lib'"${GITPERLLIB:+:$GITPERLLIB}" -GIT_TEXTDOMAINDIR='@BUILD_DIR@/po/build/locale' -PATH='@BUILD_DIR@/bin-wrappers:'"$PATH" - -export GIT_EXEC_PATH GITPERLLIB PATH GIT_TEXTDOMAINDIR - -case "$GIT_DEBUGGER" in -'') - exec "${GIT_EXEC_PATH}/@PROG@" "$@" - ;; -1) - unset GIT_DEBUGGER - exec gdb --args "${GIT_EXEC_PATH}/@PROG@" "$@" - ;; -*) - GIT_DEBUGGER_ARGS="$GIT_DEBUGGER" - unset GIT_DEBUGGER - exec ${GIT_DEBUGGER_ARGS} "${GIT_EXEC_PATH}/@PROG@" "$@" - ;; -esac -- cgit v1.2.3 From d2407bb8dc4bd7f0fb508e69d7ae49d0dfbf3b8b Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:51 +0100 Subject: Makefile: write absolute program path into bin-wrappers Write the absolute program path into our bin-wrappers. This allows us to simplify the Meson build instructions we are about to introduce a bit. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Makefile | 2 +- bin-wrappers/wrap-for-bin.sh | 6 +++--- contrib/buildsystems/CMakeLists.txt | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 6e93319bed..e1ae562760 100644 --- a/Makefile +++ b/Makefile @@ -3205,7 +3205,7 @@ all:: $(TEST_PROGRAMS) $(test_bindir_programs) $(UNIT_TEST_PROGS) $(CLAR_TEST_PR $(test_bindir_programs): bin-wrappers/%: bin-wrappers/wrap-for-bin.sh $(QUIET_GEN)sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ -e 's|@BUILD_DIR@|$(shell pwd)|' \ - -e 's|@PROG@|$(patsubst test-%,t/helper/test-%,$(@F))$(if $(filter-out $(BINDIR_PROGRAMS_NO_X),$(@F)),$(X),)|' < $< > $@ && \ + -e 's|@PROG@|$(shell pwd)/$(patsubst test-%,t/helper/test-%,$(@F))$(if $(filter-out $(BINDIR_PROGRAMS_NO_X),$(@F)),$(X),)|' < $< > $@ && \ chmod +x $@ # GNU make supports exporting all variables by "export" without parameters. diff --git a/bin-wrappers/wrap-for-bin.sh b/bin-wrappers/wrap-for-bin.sh index 7898a1c238..2feaec81f2 100755 --- a/bin-wrappers/wrap-for-bin.sh +++ b/bin-wrappers/wrap-for-bin.sh @@ -22,15 +22,15 @@ export GIT_EXEC_PATH GITPERLLIB PATH GIT_TEXTDOMAINDIR case "$GIT_DEBUGGER" in '') - exec "${GIT_EXEC_PATH}/@PROG@" "$@" + exec "@PROG@" "$@" ;; 1) unset GIT_DEBUGGER - exec gdb --args "${GIT_EXEC_PATH}/@PROG@" "$@" + exec gdb --args "@PROG@" "$@" ;; *) GIT_DEBUGGER_ARGS="$GIT_DEBUGGER" unset GIT_DEBUGGER - exec ${GIT_DEBUGGER_ARGS} "${GIT_EXEC_PATH}/@PROG@" "$@" + exec ${GIT_DEBUGGER_ARGS} "@PROG@" "$@" ;; esac diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 9348665f22..849d6b3765 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -1097,20 +1097,20 @@ set(wrapper_test_scripts foreach(script ${wrapper_scripts}) file(STRINGS ${CMAKE_SOURCE_DIR}/bin-wrappers/wrap-for-bin.sh content NEWLINE_CONSUME) string(REPLACE "@BUILD_DIR@" "${CMAKE_BINARY_DIR}" content "${content}") - string(REPLACE "@PROG@" "${script}${EXE_EXTENSION}" content "${content}") + string(REPLACE "@PROG@" "${CMAKE_BINARY_DIR}/${script}${EXE_EXTENSION}" content "${content}") file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/${script} ${content}) endforeach() foreach(script ${wrapper_test_scripts}) file(STRINGS ${CMAKE_SOURCE_DIR}/bin-wrappers/wrap-for-bin.sh content NEWLINE_CONSUME) string(REPLACE "@BUILD_DIR@" "${CMAKE_BINARY_DIR}" content "${content}") - string(REPLACE "@PROG@" "t/helper/${script}${EXE_EXTENSION}" content "${content}") + string(REPLACE "@PROG@" "${CMAKE_BINARY_DIR}/t/helper/${script}${EXE_EXTENSION}" content "${content}") file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/${script} ${content}) endforeach() file(STRINGS ${CMAKE_SOURCE_DIR}/bin-wrappers/wrap-for-bin.sh content NEWLINE_CONSUME) string(REPLACE "@BUILD_DIR@" "${CMAKE_BINARY_DIR}" content "${content}") -string(REPLACE "@PROG@" "git-cvsserver" content "${content}") +string(REPLACE "@PROG@" "${CMAKE_BINARY_DIR}/git-cvsserver" content "${content}") file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/git-cvsserver ${content}) #options for configuring test options -- cgit v1.2.3 From ed060aa0a35f5d0e201af45c6a32c405db4c2654 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:52 +0100 Subject: Makefile: simplify building of templates When we install Git we also install a set of default templates that both git-init(1) and git-clone(1) populate into our build directories. The way the pristine templates are laid out in our source directory is somewhat weird though: instead of reconstructing the actual directory hierarchy in "templates/", we represent directory separators with "--". The only reason I could come up with for why we have this is the "branches/" directory, which is supposed to be empty when installing it. And as Git famously doesn't store empty directories at all we have to work around this limitation. Now the thing is that the "branches/" directory is a leftover to how branches used to be stored in the dark ages. gitrepository-layout(5) lists this directory as "slightly deprecated", which I would claim is a strong understatement. I have never encountered anybody using it today and would be surprised if it even works as expected. So having the "--" hack in place for an item that is basically unused, unmaintained and deprecated doesn't only feel unreasonable, but installing that entry by default may also cause confusion for users that do not know what this is supposed to be in the first place. Remove this directory from our templates and, now that we do not require the workaround anymore, restructure the templates to form a proper hierarchy. This makes it way easier for build systems to install these templates into place. We should likely think about removing support for "branch/" altogether, but that is outside of the scope of this patch series. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- contrib/buildsystems/CMakeLists.txt | 34 ++---- templates/Makefile | 39 ++++--- templates/branches-- | 1 - templates/description | 1 + templates/hooks--applypatch-msg.sample | 15 --- templates/hooks--commit-msg.sample | 24 ---- templates/hooks--fsmonitor-watchman.sample | 174 ----------------------------- templates/hooks--post-update.sample | 8 -- templates/hooks--pre-applypatch.sample | 14 --- templates/hooks--pre-commit.sample | 49 -------- templates/hooks--pre-merge-commit.sample | 13 --- templates/hooks--pre-push.sample | 53 --------- templates/hooks--pre-rebase.sample | 169 ---------------------------- templates/hooks--pre-receive.sample | 24 ---- templates/hooks--prepare-commit-msg.sample | 42 ------- templates/hooks--push-to-checkout.sample | 78 ------------- templates/hooks--sendemail-validate.sample | 77 ------------- templates/hooks--update.sample | 128 --------------------- templates/hooks/applypatch-msg.sample | 15 +++ templates/hooks/commit-msg.sample | 24 ++++ templates/hooks/fsmonitor-watchman.sample | 174 +++++++++++++++++++++++++++++ templates/hooks/post-update.sample | 8 ++ templates/hooks/pre-applypatch.sample | 14 +++ templates/hooks/pre-commit.sample | 49 ++++++++ templates/hooks/pre-merge-commit.sample | 13 +++ templates/hooks/pre-push.sample | 53 +++++++++ templates/hooks/pre-rebase.sample | 169 ++++++++++++++++++++++++++++ templates/hooks/pre-receive.sample | 24 ++++ templates/hooks/prepare-commit-msg.sample | 42 +++++++ templates/hooks/push-to-checkout.sample | 78 +++++++++++++ templates/hooks/sendemail-validate.sample | 77 +++++++++++++ templates/hooks/update.sample | 128 +++++++++++++++++++++ templates/info--exclude | 6 - templates/info/exclude | 6 + templates/this--description | 1 - 35 files changed, 912 insertions(+), 912 deletions(-) delete mode 100644 templates/branches-- create mode 100644 templates/description delete mode 100755 templates/hooks--applypatch-msg.sample delete mode 100755 templates/hooks--commit-msg.sample delete mode 100755 templates/hooks--fsmonitor-watchman.sample delete mode 100755 templates/hooks--post-update.sample delete mode 100755 templates/hooks--pre-applypatch.sample delete mode 100755 templates/hooks--pre-commit.sample delete mode 100755 templates/hooks--pre-merge-commit.sample delete mode 100755 templates/hooks--pre-push.sample delete mode 100755 templates/hooks--pre-rebase.sample delete mode 100755 templates/hooks--pre-receive.sample delete mode 100755 templates/hooks--prepare-commit-msg.sample delete mode 100755 templates/hooks--push-to-checkout.sample delete mode 100755 templates/hooks--sendemail-validate.sample delete mode 100755 templates/hooks--update.sample create mode 100755 templates/hooks/applypatch-msg.sample create mode 100755 templates/hooks/commit-msg.sample create mode 100755 templates/hooks/fsmonitor-watchman.sample create mode 100755 templates/hooks/post-update.sample create mode 100755 templates/hooks/pre-applypatch.sample create mode 100755 templates/hooks/pre-commit.sample create mode 100755 templates/hooks/pre-merge-commit.sample create mode 100755 templates/hooks/pre-push.sample create mode 100755 templates/hooks/pre-rebase.sample create mode 100755 templates/hooks/pre-receive.sample create mode 100755 templates/hooks/prepare-commit-msg.sample create mode 100755 templates/hooks/push-to-checkout.sample create mode 100755 templates/hooks/sendemail-validate.sample create mode 100755 templates/hooks/update.sample delete mode 100644 templates/info--exclude create mode 100644 templates/info/exclude delete mode 100644 templates/this--description diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 849d6b3765..c643a44427 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -99,8 +99,8 @@ project(git #TODO Enable NLS on windows natively #macros for parsing the Makefile for sources and scripts -macro(parse_makefile_for_sources list_var regex) - file(STRINGS ${CMAKE_SOURCE_DIR}/Makefile ${list_var} REGEX "^${regex} \\+=(.*)") +macro(parse_makefile_for_sources list_var makefile regex) + file(STRINGS ${makefile} ${list_var} REGEX "^${regex} \\+=(.*)") string(REPLACE "${regex} +=" "" ${list_var} ${${list_var}}) string(REPLACE "$(COMPAT_OBJS)" "" ${list_var} ${${list_var}}) #remove "$(COMPAT_OBJS)" This is only for libgit. string(STRIP ${${list_var}} ${list_var}) #remove trailing/leading whitespaces @@ -662,7 +662,7 @@ include_directories(${CMAKE_BINARY_DIR}) #build #libgit -parse_makefile_for_sources(libgit_SOURCES "LIB_OBJS") +parse_makefile_for_sources(libgit_SOURCES ${CMAKE_SOURCE_DIR}/Makefile "LIB_OBJS") list(TRANSFORM libgit_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/") list(TRANSFORM compat_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/") @@ -680,13 +680,13 @@ list(APPEND libgit_SOURCES "${CMAKE_BINARY_DIR}/version-def.h") add_library(libgit ${libgit_SOURCES} ${compat_SOURCES}) #libxdiff -parse_makefile_for_sources(libxdiff_SOURCES "XDIFF_OBJS") +parse_makefile_for_sources(libxdiff_SOURCES ${CMAKE_SOURCE_DIR}/Makefile "XDIFF_OBJS") list(TRANSFORM libxdiff_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/") add_library(xdiff STATIC ${libxdiff_SOURCES}) #reftable -parse_makefile_for_sources(reftable_SOURCES "REFTABLE_OBJS") +parse_makefile_for_sources(reftable_SOURCES ${CMAKE_SOURCE_DIR}/Makefile "REFTABLE_OBJS") list(TRANSFORM reftable_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/") add_library(reftable STATIC ${reftable_SOURCES}) @@ -757,7 +757,7 @@ elseif(UNIX) endif() #git -parse_makefile_for_sources(git_SOURCES "BUILTIN_OBJS") +parse_makefile_for_sources(git_SOURCES ${CMAKE_SOURCE_DIR}/Makefile "BUILTIN_OBJS") list(TRANSFORM git_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/") add_executable(git ${CMAKE_SOURCE_DIR}/git.c ${git_SOURCES}) @@ -912,24 +912,14 @@ add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/git-p4" VERBATIM) add_custom_target(python-gen ALL DEPENDS "${CMAKE_BINARY_DIR}/git-p4") -#templates -file(GLOB templates "${CMAKE_SOURCE_DIR}/templates/*") -list(TRANSFORM templates REPLACE "${CMAKE_SOURCE_DIR}/templates/" "") -list(REMOVE_ITEM templates ".gitignore") -list(REMOVE_ITEM templates "Makefile") -list(REMOVE_ITEM templates "blt")# Prevents an error when reconfiguring for in source builds - -list(REMOVE_ITEM templates "branches--") -file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/templates/blt/branches) #create branches - +#${CMAKE_SOURCE_DIR}/Makefile templates +parse_makefile_for_sources(templates ${CMAKE_SOURCE_DIR}/templates/Makefile "TEMPLATES") +string(REPLACE " " ";" templates ${templates}) #templates have @.*@ replacement so use configure_file instead foreach(tm ${templates}) - string(REPLACE "--" "/" blt_tm ${tm}) - string(REPLACE "this" "" blt_tm ${blt_tm})# for this-- - configure_file(${CMAKE_SOURCE_DIR}/templates/${tm} ${CMAKE_BINARY_DIR}/templates/blt/${blt_tm} @ONLY) + configure_file(${CMAKE_SOURCE_DIR}/templates/${tm} ${CMAKE_BINARY_DIR}/templates/blt/${tm} @ONLY) endforeach() - #translations if(MSGFMT_EXE) file(GLOB po_files "${CMAKE_SOURCE_DIR}/po/*.po") @@ -1003,7 +993,7 @@ add_executable(test-fake-ssh ${CMAKE_SOURCE_DIR}/t/helper/test-fake-ssh.c) target_link_libraries(test-fake-ssh common-main) #unit-tests -parse_makefile_for_sources(unit-test_SOURCES "UNIT_TEST_OBJS") +parse_makefile_for_sources(unit-test_SOURCES ${CMAKE_SOURCE_DIR}/Makefile "UNIT_TEST_OBJS") list(TRANSFORM unit-test_SOURCES REPLACE "\\$\\(UNIT_TEST_DIR\\)/" "${CMAKE_SOURCE_DIR}/t/unit-tests/") add_library(unit-test-lib STATIC ${unit-test_SOURCES}) @@ -1069,7 +1059,7 @@ if(MSVC) endif() #test-tool -parse_makefile_for_sources(test-tool_SOURCES "TEST_BUILTINS_OBJS") +parse_makefile_for_sources(test-tool_SOURCES ${CMAKE_SOURCE_DIR}/Makefile "TEST_BUILTINS_OBJS") add_library(test-lib OBJECT ${CMAKE_SOURCE_DIR}/t/unit-tests/test-lib.c) list(TRANSFORM test-tool_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/t/helper/") diff --git a/templates/Makefile b/templates/Makefile index 367ad00c24..bd1e9e30c1 100644 --- a/templates/Makefile +++ b/templates/Makefile @@ -29,24 +29,35 @@ all: boilerplates.made custom # in a file direc--tory--file in the source. They will be # just copied to the destination. -bpsrc = $(filter-out %~,$(wildcard *--*)) -boilerplates.made : $(bpsrc) - $(QUIET)umask 022 && ls *--* 2>/dev/null | \ - while read boilerplate; \ +TEMPLATES = +TEMPLATES += description +TEMPLATES += hooks/applypatch-msg.sample +TEMPLATES += hooks/commit-msg.sample +TEMPLATES += hooks/fsmonitor-watchman.sample +TEMPLATES += hooks/post-update.sample +TEMPLATES += hooks/pre-applypatch.sample +TEMPLATES += hooks/pre-commit.sample +TEMPLATES += hooks/pre-merge-commit.sample +TEMPLATES += hooks/prepare-commit-msg.sample +TEMPLATES += hooks/pre-push.sample +TEMPLATES += hooks/pre-rebase.sample +TEMPLATES += hooks/pre-receive.sample +TEMPLATES += hooks/push-to-checkout.sample +TEMPLATES += hooks/sendemail-validate.sample +TEMPLATES += hooks/update.sample +TEMPLATES += info/exclude + +boilerplates.made: $(TEMPLATES) + $(QUIET)umask 022 && for template in $(TEMPLATES); \ do \ - case "$$boilerplate" in *~) continue ;; esac && \ - dst=`echo "$$boilerplate" | sed -e 's|^this|.|;s|--|/|g'` && \ - dir=`expr "$$dst" : '\(.*\)/'` && \ + dir=$$(dirname "$$template") && \ mkdir -p blt/$$dir && \ - case "$$boilerplate" in \ - *--) continue;; \ - esac && \ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \ - -e 's|@PERL_PATH@|$(PERL_PATH_SQ)|g' $$boilerplate > \ - blt/$$dst && \ - if test -x "$$boilerplate"; then rx=rx; else rx=r; fi && \ - chmod a+$$rx "blt/$$dst" || exit; \ + -e 's|@PERL_PATH@|$(PERL_PATH_SQ)|g' $$template > \ + blt/$$template && \ + if test -x "$$template"; then rx=rx; else rx=r; fi && \ + chmod a+$$rx "blt/$$template" || exit; \ done && \ date >$@ diff --git a/templates/branches-- b/templates/branches-- deleted file mode 100644 index fae88709a6..0000000000 --- a/templates/branches-- +++ /dev/null @@ -1 +0,0 @@ -: this is just to ensure the directory exists. diff --git a/templates/description b/templates/description new file mode 100644 index 0000000000..498b267a8c --- /dev/null +++ b/templates/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/templates/hooks--applypatch-msg.sample b/templates/hooks--applypatch-msg.sample deleted file mode 100755 index a5d7b84a67..0000000000 --- a/templates/hooks--applypatch-msg.sample +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh -# -# An example hook script to check the commit log message taken by -# applypatch from an e-mail message. -# -# The hook should exit with non-zero status after issuing an -# appropriate message if it wants to stop the commit. The hook is -# allowed to edit the commit message file. -# -# To enable this hook, rename this file to "applypatch-msg". - -. git-sh-setup -commitmsg="$(git rev-parse --git-path hooks/commit-msg)" -test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} -: diff --git a/templates/hooks--commit-msg.sample b/templates/hooks--commit-msg.sample deleted file mode 100755 index b58d1184a9..0000000000 --- a/templates/hooks--commit-msg.sample +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# -# An example hook script to check the commit log message. -# Called by "git commit" with one argument, the name of the file -# that has the commit message. The hook should exit with non-zero -# status after issuing an appropriate message if it wants to stop the -# commit. The hook is allowed to edit the commit message file. -# -# To enable this hook, rename this file to "commit-msg". - -# Uncomment the below to add a Signed-off-by line to the message. -# Doing this in a hook is a bad idea in general, but the prepare-commit-msg -# hook is more suited to it. -# -# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') -# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" - -# This example catches duplicate Signed-off-by lines. - -test "" = "$(grep '^Signed-off-by: ' "$1" | - sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { - echo >&2 Duplicate Signed-off-by lines. - exit 1 -} diff --git a/templates/hooks--fsmonitor-watchman.sample b/templates/hooks--fsmonitor-watchman.sample deleted file mode 100755 index 23e856f5de..0000000000 --- a/templates/hooks--fsmonitor-watchman.sample +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; -use IPC::Open2; - -# An example hook script to integrate Watchman -# (https://facebook.github.io/watchman/) with git to speed up detecting -# new and modified files. -# -# The hook is passed a version (currently 2) and last update token -# formatted as a string and outputs to stdout a new update token and -# all files that have been modified since the update token. Paths must -# be relative to the root of the working tree and separated by a single NUL. -# -# To enable this hook, rename this file to "query-watchman" and set -# 'git config core.fsmonitor .git/hooks/query-watchman' -# -my ($version, $last_update_token) = @ARGV; - -# Uncomment for debugging -# print STDERR "$0 $version $last_update_token\n"; - -# Check the hook interface version -if ($version ne 2) { - die "Unsupported query-fsmonitor hook version '$version'.\n" . - "Falling back to scanning...\n"; -} - -my $git_work_tree = get_working_dir(); - -my $retry = 1; - -my $json_pkg; -eval { - require JSON::XS; - $json_pkg = "JSON::XS"; - 1; -} or do { - require JSON::PP; - $json_pkg = "JSON::PP"; -}; - -launch_watchman(); - -sub launch_watchman { - my $o = watchman_query(); - if (is_work_tree_watched($o)) { - output_result($o->{clock}, @{$o->{files}}); - } -} - -sub output_result { - my ($clockid, @files) = @_; - - # Uncomment for debugging watchman output - # open (my $fh, ">", ".git/watchman-output.out"); - # binmode $fh, ":utf8"; - # print $fh "$clockid\n@files\n"; - # close $fh; - - binmode STDOUT, ":utf8"; - print $clockid; - print "\0"; - local $, = "\0"; - print @files; -} - -sub watchman_clock { - my $response = qx/watchman clock "$git_work_tree"/; - die "Failed to get clock id on '$git_work_tree'.\n" . - "Falling back to scanning...\n" if $? != 0; - - return $json_pkg->new->utf8->decode($response); -} - -sub watchman_query { - my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty') - or die "open2() failed: $!\n" . - "Falling back to scanning...\n"; - - # In the query expression below we're asking for names of files that - # changed since $last_update_token but not from the .git folder. - # - # To accomplish this, we're using the "since" generator to use the - # recency index to select candidate nodes and "fields" to limit the - # output to file names only. Then we're using the "expression" term to - # further constrain the results. - my $last_update_line = ""; - if (substr($last_update_token, 0, 1) eq "c") { - $last_update_token = "\"$last_update_token\""; - $last_update_line = qq[\n"since": $last_update_token,]; - } - my $query = <<" END"; - ["query", "$git_work_tree", {$last_update_line - "fields": ["name"], - "expression": ["not", ["dirname", ".git"]] - }] - END - - # Uncomment for debugging the watchman query - # open (my $fh, ">", ".git/watchman-query.json"); - # print $fh $query; - # close $fh; - - print CHLD_IN $query; - close CHLD_IN; - my $response = do {local $/; }; - - # Uncomment for debugging the watch response - # open ($fh, ">", ".git/watchman-response.json"); - # print $fh $response; - # close $fh; - - die "Watchman: command returned no output.\n" . - "Falling back to scanning...\n" if $response eq ""; - die "Watchman: command returned invalid output: $response\n" . - "Falling back to scanning...\n" unless $response =~ /^\{/; - - return $json_pkg->new->utf8->decode($response); -} - -sub is_work_tree_watched { - my ($output) = @_; - my $error = $output->{error}; - if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) { - $retry--; - my $response = qx/watchman watch "$git_work_tree"/; - die "Failed to make watchman watch '$git_work_tree'.\n" . - "Falling back to scanning...\n" if $? != 0; - $output = $json_pkg->new->utf8->decode($response); - $error = $output->{error}; - die "Watchman: $error.\n" . - "Falling back to scanning...\n" if $error; - - # Uncomment for debugging watchman output - # open (my $fh, ">", ".git/watchman-output.out"); - # close $fh; - - # Watchman will always return all files on the first query so - # return the fast "everything is dirty" flag to git and do the - # Watchman query just to get it over with now so we won't pay - # the cost in git to look up each individual file. - my $o = watchman_clock(); - $error = $output->{error}; - - die "Watchman: $error.\n" . - "Falling back to scanning...\n" if $error; - - output_result($o->{clock}, ("/")); - $last_update_token = $o->{clock}; - - eval { launch_watchman() }; - return 0; - } - - die "Watchman: $error.\n" . - "Falling back to scanning...\n" if $error; - - return 1; -} - -sub get_working_dir { - my $working_dir; - if ($^O =~ 'msys' || $^O =~ 'cygwin') { - $working_dir = Win32::GetCwd(); - $working_dir =~ tr/\\/\//; - } else { - require Cwd; - $working_dir = Cwd::cwd(); - } - - return $working_dir; -} diff --git a/templates/hooks--post-update.sample b/templates/hooks--post-update.sample deleted file mode 100755 index ec17ec1939..0000000000 --- a/templates/hooks--post-update.sample +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -# -# An example hook script to prepare a packed repository for use over -# dumb transports. -# -# To enable this hook, rename this file to "post-update". - -exec git update-server-info diff --git a/templates/hooks--pre-applypatch.sample b/templates/hooks--pre-applypatch.sample deleted file mode 100755 index 4142082bcb..0000000000 --- a/templates/hooks--pre-applypatch.sample +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh -# -# An example hook script to verify what is about to be committed -# by applypatch from an e-mail message. -# -# The hook should exit with non-zero status after issuing an -# appropriate message if it wants to stop the commit. -# -# To enable this hook, rename this file to "pre-applypatch". - -. git-sh-setup -precommit="$(git rev-parse --git-path hooks/pre-commit)" -test -x "$precommit" && exec "$precommit" ${1+"$@"} -: diff --git a/templates/hooks--pre-commit.sample b/templates/hooks--pre-commit.sample deleted file mode 100755 index 29ed5ee486..0000000000 --- a/templates/hooks--pre-commit.sample +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh -# -# An example hook script to verify what is about to be committed. -# Called by "git commit" with no arguments. The hook should -# exit with non-zero status after issuing an appropriate message if -# it wants to stop the commit. -# -# To enable this hook, rename this file to "pre-commit". - -if git rev-parse --verify HEAD >/dev/null 2>&1 -then - against=HEAD -else - # Initial commit: diff against an empty tree object - against=$(git hash-object -t tree /dev/null) -fi - -# If you want to allow non-ASCII filenames set this variable to true. -allownonascii=$(git config --type=bool hooks.allownonascii) - -# Redirect output to stderr. -exec 1>&2 - -# Cross platform projects tend to avoid non-ASCII filenames; prevent -# them from being added to the repository. We exploit the fact that the -# printable range starts at the space character and ends with tilde. -if [ "$allownonascii" != "true" ] && - # Note that the use of brackets around a tr range is ok here, (it's - # even required, for portability to Solaris 10's /usr/bin/tr), since - # the square bracket bytes happen to fall in the designated range. - test $(git diff-index --cached --name-only --diff-filter=A -z $against | - LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 -then - cat <<\EOF -Error: Attempt to add a non-ASCII file name. - -This can cause problems if you want to work with people on other platforms. - -To be portable it is advisable to rename the file. - -If you know what you are doing you can disable this check using: - - git config hooks.allownonascii true -EOF - exit 1 -fi - -# If there are whitespace errors, print the offending file names and fail. -exec git diff-index --check --cached $against -- diff --git a/templates/hooks--pre-merge-commit.sample b/templates/hooks--pre-merge-commit.sample deleted file mode 100755 index 399eab1924..0000000000 --- a/templates/hooks--pre-merge-commit.sample +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -# -# An example hook script to verify what is about to be committed. -# Called by "git merge" with no arguments. The hook should -# exit with non-zero status after issuing an appropriate message to -# stderr if it wants to stop the merge commit. -# -# To enable this hook, rename this file to "pre-merge-commit". - -. git-sh-setup -test -x "$GIT_DIR/hooks/pre-commit" && - exec "$GIT_DIR/hooks/pre-commit" -: diff --git a/templates/hooks--pre-push.sample b/templates/hooks--pre-push.sample deleted file mode 100755 index 4ce688d32b..0000000000 --- a/templates/hooks--pre-push.sample +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh - -# An example hook script to verify what is about to be pushed. Called by "git -# push" after it has checked the remote status, but before anything has been -# pushed. If this script exits with a non-zero status nothing will be pushed. -# -# This hook is called with the following parameters: -# -# $1 -- Name of the remote to which the push is being done -# $2 -- URL to which the push is being done -# -# If pushing without using a named remote those arguments will be equal. -# -# Information about the commits which are being pushed is supplied as lines to -# the standard input in the form: -# -# -# -# This sample shows how to prevent push of commits where the log message starts -# with "WIP" (work in progress). - -remote="$1" -url="$2" - -zero=$(git hash-object --stdin &2 "Found WIP commit in $local_ref, not pushing" - exit 1 - fi - fi -done - -exit 0 diff --git a/templates/hooks--pre-rebase.sample b/templates/hooks--pre-rebase.sample deleted file mode 100755 index db5feab8a1..0000000000 --- a/templates/hooks--pre-rebase.sample +++ /dev/null @@ -1,169 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2006, 2008 Junio C Hamano -# -# The "pre-rebase" hook is run just before "git rebase" starts doing -# its job, and can prevent the command from running by exiting with -# non-zero status. -# -# The hook is called with the following parameters: -# -# $1 -- the upstream the series was forked from. -# $2 -- the branch being rebased (or empty when rebasing the current branch). -# -# This sample shows how to prevent topic branches that are already -# merged to 'next' branch from getting rebased, because allowing it -# would result in rebasing already published history. - -publish=next -basebranch="$1" -if test "$#" = 2 -then - topic="refs/heads/$2" -else - topic=`git symbolic-ref HEAD` || - exit 0 ;# we do not interrupt rebasing detached HEAD -fi - -case "$topic" in -refs/heads/??/*) - ;; -*) - exit 0 ;# we do not interrupt others. - ;; -esac - -# Now we are dealing with a topic branch being rebased -# on top of master. Is it OK to rebase it? - -# Does the topic really exist? -git show-ref -q "$topic" || { - echo >&2 "No such branch $topic" - exit 1 -} - -# Is topic fully merged to master? -not_in_master=`git rev-list --pretty=oneline ^master "$topic"` -if test -z "$not_in_master" -then - echo >&2 "$topic is fully merged to master; better remove it." - exit 1 ;# we could allow it, but there is no point. -fi - -# Is topic ever merged to next? If so you should not be rebasing it. -only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` -only_next_2=`git rev-list ^master ${publish} | sort` -if test "$only_next_1" = "$only_next_2" -then - not_in_topic=`git rev-list "^$topic" master` - if test -z "$not_in_topic" - then - echo >&2 "$topic is already up to date with master" - exit 1 ;# we could allow it, but there is no point. - else - exit 0 - fi -else - not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` - @PERL_PATH@ -e ' - my $topic = $ARGV[0]; - my $msg = "* $topic has commits already merged to public branch:\n"; - my (%not_in_next) = map { - /^([0-9a-f]+) /; - ($1 => 1); - } split(/\n/, $ARGV[1]); - for my $elem (map { - /^([0-9a-f]+) (.*)$/; - [$1 => $2]; - } split(/\n/, $ARGV[2])) { - if (!exists $not_in_next{$elem->[0]}) { - if ($msg) { - print STDERR $msg; - undef $msg; - } - print STDERR " $elem->[1]\n"; - } - } - ' "$topic" "$not_in_next" "$not_in_master" - exit 1 -fi - -<<\DOC_END - -This sample hook safeguards topic branches that have been -published from being rewound. - -The workflow assumed here is: - - * Once a topic branch forks from "master", "master" is never - merged into it again (either directly or indirectly). - - * Once a topic branch is fully cooked and merged into "master", - it is deleted. If you need to build on top of it to correct - earlier mistakes, a new topic branch is created by forking at - the tip of the "master". This is not strictly necessary, but - it makes it easier to keep your history simple. - - * Whenever you need to test or publish your changes to topic - branches, merge them into "next" branch. - -The script, being an example, hardcodes the publish branch name -to be "next", but it is trivial to make it configurable via -$GIT_DIR/config mechanism. - -With this workflow, you would want to know: - -(1) ... if a topic branch has ever been merged to "next". Young - topic branches can have stupid mistakes you would rather - clean up before publishing, and things that have not been - merged into other branches can be easily rebased without - affecting other people. But once it is published, you would - not want to rewind it. - -(2) ... if a topic branch has been fully merged to "master". - Then you can delete it. More importantly, you should not - build on top of it -- other people may already want to - change things related to the topic as patches against your - "master", so if you need further changes, it is better to - fork the topic (perhaps with the same name) afresh from the - tip of "master". - -Let's look at this example: - - o---o---o---o---o---o---o---o---o---o "next" - / / / / - / a---a---b A / / - / / / / - / / c---c---c---c B / - / / / \ / - / / / b---b C \ / - / / / / \ / - ---o---o---o---o---o---o---o---o---o---o---o "master" - - -A, B and C are topic branches. - - * A has one fix since it was merged up to "next". - - * B has finished. It has been fully merged up to "master" and "next", - and is ready to be deleted. - - * C has not merged to "next" at all. - -We would want to allow C to be rebased, refuse A, and encourage -B to be deleted. - -To compute (1): - - git rev-list ^master ^topic next - git rev-list ^master next - - if these match, topic has not merged in next at all. - -To compute (2): - - git rev-list master..topic - - if this is empty, it is fully merged to "master". - -DOC_END diff --git a/templates/hooks--pre-receive.sample b/templates/hooks--pre-receive.sample deleted file mode 100755 index a1fd29ec14..0000000000 --- a/templates/hooks--pre-receive.sample +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# -# An example hook script to make use of push options. -# The example simply echoes all push options that start with 'echoback=' -# and rejects all pushes when the "reject" push option is used. -# -# To enable this hook, rename this file to "pre-receive". - -if test -n "$GIT_PUSH_OPTION_COUNT" -then - i=0 - while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" - do - eval "value=\$GIT_PUSH_OPTION_$i" - case "$value" in - echoback=*) - echo "echo from the pre-receive-hook: ${value#*=}" >&2 - ;; - reject) - exit 1 - esac - i=$((i + 1)) - done -fi diff --git a/templates/hooks--prepare-commit-msg.sample b/templates/hooks--prepare-commit-msg.sample deleted file mode 100755 index 318afe3fd8..0000000000 --- a/templates/hooks--prepare-commit-msg.sample +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh -# -# An example hook script to prepare the commit log message. -# Called by "git commit" with the name of the file that has the -# commit message, followed by the description of the commit -# message's source. The hook's purpose is to edit the commit -# message file. If the hook fails with a non-zero status, -# the commit is aborted. -# -# To enable this hook, rename this file to "prepare-commit-msg". - -# This hook includes three examples. The first one removes the -# "# Please enter the commit message..." help message. -# -# The second includes the output of "git diff --name-status -r" -# into the message, just before the "git status" output. It is -# commented because it doesn't cope with --amend or with squashed -# commits. -# -# The third example adds a Signed-off-by line to the message, that can -# still be edited. This is rarely a good idea. - -COMMIT_MSG_FILE=$1 -COMMIT_SOURCE=$2 -SHA1=$3 - -@PERL_PATH@ -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE" - -# case "$COMMIT_SOURCE,$SHA1" in -# ,|template,) -# @PERL_PATH@ -i.bak -pe ' -# print "\n" . `git diff --cached --name-status -r` -# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;; -# *) ;; -# esac - -# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') -# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE" -# if test -z "$COMMIT_SOURCE" -# then -# @PERL_PATH@ -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE" -# fi diff --git a/templates/hooks--push-to-checkout.sample b/templates/hooks--push-to-checkout.sample deleted file mode 100755 index af5a0c0018..0000000000 --- a/templates/hooks--push-to-checkout.sample +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/sh - -# An example hook script to update a checked-out tree on a git push. -# -# This hook is invoked by git-receive-pack(1) when it reacts to git -# push and updates reference(s) in its repository, and when the push -# tries to update the branch that is currently checked out and the -# receive.denyCurrentBranch configuration variable is set to -# updateInstead. -# -# By default, such a push is refused if the working tree and the index -# of the remote repository has any difference from the currently -# checked out commit; when both the working tree and the index match -# the current commit, they are updated to match the newly pushed tip -# of the branch. This hook is to be used to override the default -# behaviour; however the code below reimplements the default behaviour -# as a starting point for convenient modification. -# -# The hook receives the commit with which the tip of the current -# branch is going to be updated: -commit=$1 - -# It can exit with a non-zero status to refuse the push (when it does -# so, it must not modify the index or the working tree). -die () { - echo >&2 "$*" - exit 1 -} - -# Or it can make any necessary changes to the working tree and to the -# index to bring them to the desired state when the tip of the current -# branch is updated to the new commit, and exit with a zero status. -# -# For example, the hook can simply run git read-tree -u -m HEAD "$1" -# in order to emulate git fetch that is run in the reverse direction -# with git push, as the two-tree form of git read-tree -u -m is -# essentially the same as git switch or git checkout that switches -# branches while keeping the local changes in the working tree that do -# not interfere with the difference between the branches. - -# The below is a more-or-less exact translation to shell of the C code -# for the default behaviour for git's push-to-checkout hook defined in -# the push_to_deploy() function in builtin/receive-pack.c. -# -# Note that the hook will be executed from the repository directory, -# not from the working tree, so if you want to perform operations on -# the working tree, you will have to adapt your code accordingly, e.g. -# by adding "cd .." or using relative paths. - -if ! git update-index -q --ignore-submodules --refresh -then - die "Up-to-date check failed" -fi - -if ! git diff-files --quiet --ignore-submodules -- -then - die "Working directory has unstaged changes" -fi - -# This is a rough translation of: -# -# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX -if git cat-file -e HEAD 2>/dev/null -then - head=HEAD -else - head=$(git hash-object -t tree --stdin &2 - exit 1 -} - -unset GIT_DIR GIT_WORK_TREE -cd "$worktree" && - -if grep -q "^diff --git " "$1" -then - validate_patch "$1" -else - validate_cover_letter "$1" -fi && - -if test "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL" -then - git config --unset-all sendemail.validateWorktree && - trap 'git worktree remove -ff "$worktree"' EXIT && - validate_series -fi diff --git a/templates/hooks--update.sample b/templates/hooks--update.sample deleted file mode 100755 index c4d426bc6e..0000000000 --- a/templates/hooks--update.sample +++ /dev/null @@ -1,128 +0,0 @@ -#!/bin/sh -# -# An example hook script to block unannotated tags from entering. -# Called by "git receive-pack" with arguments: refname sha1-old sha1-new -# -# To enable this hook, rename this file to "update". -# -# Config -# ------ -# hooks.allowunannotated -# This boolean sets whether unannotated tags will be allowed into the -# repository. By default they won't be. -# hooks.allowdeletetag -# This boolean sets whether deleting tags will be allowed in the -# repository. By default they won't be. -# hooks.allowmodifytag -# This boolean sets whether a tag may be modified after creation. By default -# it won't be. -# hooks.allowdeletebranch -# This boolean sets whether deleting branches will be allowed in the -# repository. By default they won't be. -# hooks.denycreatebranch -# This boolean sets whether remotely creating branches will be denied -# in the repository. By default this is allowed. -# - -# --- Command line -refname="$1" -oldrev="$2" -newrev="$3" - -# --- Safety check -if [ -z "$GIT_DIR" ]; then - echo "Don't run this script from the command line." >&2 - echo " (if you want, you could supply GIT_DIR then run" >&2 - echo " $0 )" >&2 - exit 1 -fi - -if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then - echo "usage: $0 " >&2 - exit 1 -fi - -# --- Config -allowunannotated=$(git config --type=bool hooks.allowunannotated) -allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch) -denycreatebranch=$(git config --type=bool hooks.denycreatebranch) -allowdeletetag=$(git config --type=bool hooks.allowdeletetag) -allowmodifytag=$(git config --type=bool hooks.allowmodifytag) - -# check for no description -projectdesc=$(sed -e '1q' "$GIT_DIR/description") -case "$projectdesc" in -"Unnamed repository"* | "") - echo "*** Project description file hasn't been set" >&2 - exit 1 - ;; -esac - -# --- Check types -# if $newrev is 0000...0000, it's a commit to delete a ref. -zero=$(git hash-object --stdin &2 - echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 - exit 1 - fi - ;; - refs/tags/*,delete) - # delete tag - if [ "$allowdeletetag" != "true" ]; then - echo "*** Deleting a tag is not allowed in this repository" >&2 - exit 1 - fi - ;; - refs/tags/*,tag) - # annotated tag - if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 - then - echo "*** Tag '$refname' already exists." >&2 - echo "*** Modifying a tag is not allowed in this repository." >&2 - exit 1 - fi - ;; - refs/heads/*,commit) - # branch - if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then - echo "*** Creating a branch is not allowed in this repository" >&2 - exit 1 - fi - ;; - refs/heads/*,delete) - # delete branch - if [ "$allowdeletebranch" != "true" ]; then - echo "*** Deleting a branch is not allowed in this repository" >&2 - exit 1 - fi - ;; - refs/remotes/*,commit) - # tracking branch - ;; - refs/remotes/*,delete) - # delete tracking branch - if [ "$allowdeletebranch" != "true" ]; then - echo "*** Deleting a tracking branch is not allowed in this repository" >&2 - exit 1 - fi - ;; - *) - # Anything else (is there anything else?) - echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 - exit 1 - ;; -esac - -# --- Finished -exit 0 diff --git a/templates/hooks/applypatch-msg.sample b/templates/hooks/applypatch-msg.sample new file mode 100755 index 0000000000..a5d7b84a67 --- /dev/null +++ b/templates/hooks/applypatch-msg.sample @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +commitmsg="$(git rev-parse --git-path hooks/commit-msg)" +test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} +: diff --git a/templates/hooks/commit-msg.sample b/templates/hooks/commit-msg.sample new file mode 100755 index 0000000000..b58d1184a9 --- /dev/null +++ b/templates/hooks/commit-msg.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} diff --git a/templates/hooks/fsmonitor-watchman.sample b/templates/hooks/fsmonitor-watchman.sample new file mode 100755 index 0000000000..23e856f5de --- /dev/null +++ b/templates/hooks/fsmonitor-watchman.sample @@ -0,0 +1,174 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use IPC::Open2; + +# An example hook script to integrate Watchman +# (https://facebook.github.io/watchman/) with git to speed up detecting +# new and modified files. +# +# The hook is passed a version (currently 2) and last update token +# formatted as a string and outputs to stdout a new update token and +# all files that have been modified since the update token. Paths must +# be relative to the root of the working tree and separated by a single NUL. +# +# To enable this hook, rename this file to "query-watchman" and set +# 'git config core.fsmonitor .git/hooks/query-watchman' +# +my ($version, $last_update_token) = @ARGV; + +# Uncomment for debugging +# print STDERR "$0 $version $last_update_token\n"; + +# Check the hook interface version +if ($version ne 2) { + die "Unsupported query-fsmonitor hook version '$version'.\n" . + "Falling back to scanning...\n"; +} + +my $git_work_tree = get_working_dir(); + +my $retry = 1; + +my $json_pkg; +eval { + require JSON::XS; + $json_pkg = "JSON::XS"; + 1; +} or do { + require JSON::PP; + $json_pkg = "JSON::PP"; +}; + +launch_watchman(); + +sub launch_watchman { + my $o = watchman_query(); + if (is_work_tree_watched($o)) { + output_result($o->{clock}, @{$o->{files}}); + } +} + +sub output_result { + my ($clockid, @files) = @_; + + # Uncomment for debugging watchman output + # open (my $fh, ">", ".git/watchman-output.out"); + # binmode $fh, ":utf8"; + # print $fh "$clockid\n@files\n"; + # close $fh; + + binmode STDOUT, ":utf8"; + print $clockid; + print "\0"; + local $, = "\0"; + print @files; +} + +sub watchman_clock { + my $response = qx/watchman clock "$git_work_tree"/; + die "Failed to get clock id on '$git_work_tree'.\n" . + "Falling back to scanning...\n" if $? != 0; + + return $json_pkg->new->utf8->decode($response); +} + +sub watchman_query { + my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty') + or die "open2() failed: $!\n" . + "Falling back to scanning...\n"; + + # In the query expression below we're asking for names of files that + # changed since $last_update_token but not from the .git folder. + # + # To accomplish this, we're using the "since" generator to use the + # recency index to select candidate nodes and "fields" to limit the + # output to file names only. Then we're using the "expression" term to + # further constrain the results. + my $last_update_line = ""; + if (substr($last_update_token, 0, 1) eq "c") { + $last_update_token = "\"$last_update_token\""; + $last_update_line = qq[\n"since": $last_update_token,]; + } + my $query = <<" END"; + ["query", "$git_work_tree", {$last_update_line + "fields": ["name"], + "expression": ["not", ["dirname", ".git"]] + }] + END + + # Uncomment for debugging the watchman query + # open (my $fh, ">", ".git/watchman-query.json"); + # print $fh $query; + # close $fh; + + print CHLD_IN $query; + close CHLD_IN; + my $response = do {local $/; }; + + # Uncomment for debugging the watch response + # open ($fh, ">", ".git/watchman-response.json"); + # print $fh $response; + # close $fh; + + die "Watchman: command returned no output.\n" . + "Falling back to scanning...\n" if $response eq ""; + die "Watchman: command returned invalid output: $response\n" . + "Falling back to scanning...\n" unless $response =~ /^\{/; + + return $json_pkg->new->utf8->decode($response); +} + +sub is_work_tree_watched { + my ($output) = @_; + my $error = $output->{error}; + if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) { + $retry--; + my $response = qx/watchman watch "$git_work_tree"/; + die "Failed to make watchman watch '$git_work_tree'.\n" . + "Falling back to scanning...\n" if $? != 0; + $output = $json_pkg->new->utf8->decode($response); + $error = $output->{error}; + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + # Uncomment for debugging watchman output + # open (my $fh, ">", ".git/watchman-output.out"); + # close $fh; + + # Watchman will always return all files on the first query so + # return the fast "everything is dirty" flag to git and do the + # Watchman query just to get it over with now so we won't pay + # the cost in git to look up each individual file. + my $o = watchman_clock(); + $error = $output->{error}; + + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + output_result($o->{clock}, ("/")); + $last_update_token = $o->{clock}; + + eval { launch_watchman() }; + return 0; + } + + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + return 1; +} + +sub get_working_dir { + my $working_dir; + if ($^O =~ 'msys' || $^O =~ 'cygwin') { + $working_dir = Win32::GetCwd(); + $working_dir =~ tr/\\/\//; + } else { + require Cwd; + $working_dir = Cwd::cwd(); + } + + return $working_dir; +} diff --git a/templates/hooks/post-update.sample b/templates/hooks/post-update.sample new file mode 100755 index 0000000000..ec17ec1939 --- /dev/null +++ b/templates/hooks/post-update.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info diff --git a/templates/hooks/pre-applypatch.sample b/templates/hooks/pre-applypatch.sample new file mode 100755 index 0000000000..4142082bcb --- /dev/null +++ b/templates/hooks/pre-applypatch.sample @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +precommit="$(git rev-parse --git-path hooks/pre-commit)" +test -x "$precommit" && exec "$precommit" ${1+"$@"} +: diff --git a/templates/hooks/pre-commit.sample b/templates/hooks/pre-commit.sample new file mode 100755 index 0000000000..29ed5ee486 --- /dev/null +++ b/templates/hooks/pre-commit.sample @@ -0,0 +1,49 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=$(git hash-object -t tree /dev/null) +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --type=bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff-index --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- diff --git a/templates/hooks/pre-merge-commit.sample b/templates/hooks/pre-merge-commit.sample new file mode 100755 index 0000000000..399eab1924 --- /dev/null +++ b/templates/hooks/pre-merge-commit.sample @@ -0,0 +1,13 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git merge" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message to +# stderr if it wants to stop the merge commit. +# +# To enable this hook, rename this file to "pre-merge-commit". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" +: diff --git a/templates/hooks/pre-push.sample b/templates/hooks/pre-push.sample new file mode 100755 index 0000000000..4ce688d32b --- /dev/null +++ b/templates/hooks/pre-push.sample @@ -0,0 +1,53 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +zero=$(git hash-object --stdin &2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + +exit 0 diff --git a/templates/hooks/pre-rebase.sample b/templates/hooks/pre-rebase.sample new file mode 100755 index 0000000000..db5feab8a1 --- /dev/null +++ b/templates/hooks/pre-rebase.sample @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up to date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + @PERL_PATH@ -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END diff --git a/templates/hooks/pre-receive.sample b/templates/hooks/pre-receive.sample new file mode 100755 index 0000000000..a1fd29ec14 --- /dev/null +++ b/templates/hooks/pre-receive.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to make use of push options. +# The example simply echoes all push options that start with 'echoback=' +# and rejects all pushes when the "reject" push option is used. +# +# To enable this hook, rename this file to "pre-receive". + +if test -n "$GIT_PUSH_OPTION_COUNT" +then + i=0 + while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" + do + eval "value=\$GIT_PUSH_OPTION_$i" + case "$value" in + echoback=*) + echo "echo from the pre-receive-hook: ${value#*=}" >&2 + ;; + reject) + exit 1 + esac + i=$((i + 1)) + done +fi diff --git a/templates/hooks/prepare-commit-msg.sample b/templates/hooks/prepare-commit-msg.sample new file mode 100755 index 0000000000..318afe3fd8 --- /dev/null +++ b/templates/hooks/prepare-commit-msg.sample @@ -0,0 +1,42 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first one removes the +# "# Please enter the commit message..." help message. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +COMMIT_MSG_FILE=$1 +COMMIT_SOURCE=$2 +SHA1=$3 + +@PERL_PATH@ -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE" + +# case "$COMMIT_SOURCE,$SHA1" in +# ,|template,) +# @PERL_PATH@ -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;; +# *) ;; +# esac + +# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE" +# if test -z "$COMMIT_SOURCE" +# then +# @PERL_PATH@ -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE" +# fi diff --git a/templates/hooks/push-to-checkout.sample b/templates/hooks/push-to-checkout.sample new file mode 100755 index 0000000000..af5a0c0018 --- /dev/null +++ b/templates/hooks/push-to-checkout.sample @@ -0,0 +1,78 @@ +#!/bin/sh + +# An example hook script to update a checked-out tree on a git push. +# +# This hook is invoked by git-receive-pack(1) when it reacts to git +# push and updates reference(s) in its repository, and when the push +# tries to update the branch that is currently checked out and the +# receive.denyCurrentBranch configuration variable is set to +# updateInstead. +# +# By default, such a push is refused if the working tree and the index +# of the remote repository has any difference from the currently +# checked out commit; when both the working tree and the index match +# the current commit, they are updated to match the newly pushed tip +# of the branch. This hook is to be used to override the default +# behaviour; however the code below reimplements the default behaviour +# as a starting point for convenient modification. +# +# The hook receives the commit with which the tip of the current +# branch is going to be updated: +commit=$1 + +# It can exit with a non-zero status to refuse the push (when it does +# so, it must not modify the index or the working tree). +die () { + echo >&2 "$*" + exit 1 +} + +# Or it can make any necessary changes to the working tree and to the +# index to bring them to the desired state when the tip of the current +# branch is updated to the new commit, and exit with a zero status. +# +# For example, the hook can simply run git read-tree -u -m HEAD "$1" +# in order to emulate git fetch that is run in the reverse direction +# with git push, as the two-tree form of git read-tree -u -m is +# essentially the same as git switch or git checkout that switches +# branches while keeping the local changes in the working tree that do +# not interfere with the difference between the branches. + +# The below is a more-or-less exact translation to shell of the C code +# for the default behaviour for git's push-to-checkout hook defined in +# the push_to_deploy() function in builtin/receive-pack.c. +# +# Note that the hook will be executed from the repository directory, +# not from the working tree, so if you want to perform operations on +# the working tree, you will have to adapt your code accordingly, e.g. +# by adding "cd .." or using relative paths. + +if ! git update-index -q --ignore-submodules --refresh +then + die "Up-to-date check failed" +fi + +if ! git diff-files --quiet --ignore-submodules -- +then + die "Working directory has unstaged changes" +fi + +# This is a rough translation of: +# +# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX +if git cat-file -e HEAD 2>/dev/null +then + head=HEAD +else + head=$(git hash-object -t tree --stdin &2 + exit 1 +} + +unset GIT_DIR GIT_WORK_TREE +cd "$worktree" && + +if grep -q "^diff --git " "$1" +then + validate_patch "$1" +else + validate_cover_letter "$1" +fi && + +if test "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL" +then + git config --unset-all sendemail.validateWorktree && + trap 'git worktree remove -ff "$worktree"' EXIT && + validate_series +fi diff --git a/templates/hooks/update.sample b/templates/hooks/update.sample new file mode 100755 index 0000000000..c4d426bc6e --- /dev/null +++ b/templates/hooks/update.sample @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to block unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 )" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --type=bool hooks.allowunannotated) +allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch) +denycreatebranch=$(git config --type=bool hooks.denycreatebranch) +allowdeletetag=$(git config --type=bool hooks.allowdeletetag) +allowmodifytag=$(git config --type=bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero=$(git hash-object --stdin &2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0 diff --git a/templates/info--exclude b/templates/info--exclude deleted file mode 100644 index a5196d1be8..0000000000 --- a/templates/info--exclude +++ /dev/null @@ -1,6 +0,0 @@ -# git ls-files --others --exclude-from=.git/info/exclude -# Lines that start with '#' are comments. -# For a project mostly in C, the following would be a good set of -# exclude patterns (uncomment them if you want to use them): -# *.[oa] -# *~ diff --git a/templates/info/exclude b/templates/info/exclude new file mode 100644 index 0000000000..a5196d1be8 --- /dev/null +++ b/templates/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/templates/this--description b/templates/this--description deleted file mode 100644 index 498b267a8c..0000000000 --- a/templates/this--description +++ /dev/null @@ -1 +0,0 @@ -Unnamed repository; edit this file 'description' to name the repository. -- cgit v1.2.3 From 9219325be74c35c493a61ab3107d215cad91cf38 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:53 +0100 Subject: Documentation: allow sourcing generated includes from separate dir Our documentation uses "include::" directives to include parts that are either reused across multiple documents or parts that we generate at build time. Unfortunately, top-level includes are only ever resolved relative to the base directory, which is typically the directory of the including document. Most importantly, it is not possible to have either asciidoc or asciidoctor search multiple directories. It follows that both kinds of includes must live in the same directory. This is of course a bummer for out-of-tree builds, because here the dynamically-built includes live in the build directory whereas the static includes live in the source directory. Introduce a `build_dir` attribute and prepend it to all of our includes for dynamically-built files. This attribute gets set to the build directory and thus converts the include path to an absolute path, which asciidoc and asciidoctor know how to resolve. Note that this change also requires us to update "build-docdep.perl", which tries to figure out included files such our Makefile can set up proper build-time dependencies. This script simply scans through the source files for any lines that match "^include::" and treats the remainder of the line as included file path. But given that those may now contain the "{build_dir}" variable we have to teach the script to replace that attribute with the actual build directory. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/Makefile | 3 ++- Documentation/build-docdep.perl | 2 ++ Documentation/config/diff.txt | 2 +- Documentation/config/merge.txt | 2 +- Documentation/git.txt | 24 ++++++++++++------------ 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/Documentation/Makefile b/Documentation/Makefile index 9371f29425..a74fc0ff3d 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -224,6 +224,7 @@ SHELL_PATH ?= $(SHELL) # Shell quote; SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) +ASCIIDOC_EXTRA += -abuild_dir='$(shell pwd)' ifdef DEFAULT_PAGER DEFAULT_PAGER_SQ = $(subst ','\'',$(DEFAULT_PAGER)) ASCIIDOC_EXTRA += -a 'git-default-pager=$(DEFAULT_PAGER_SQ)' @@ -289,7 +290,7 @@ docdep_prereqs = \ cmd-list.made $(cmds_txt) doc.dep : $(docdep_prereqs) $(DOC_DEP_TXT) build-docdep.perl - $(QUIET_GEN)$(PERL_PATH) ./build-docdep.perl >$@ $(QUIET_STDERR) + $(QUIET_GEN)$(PERL_PATH) ./build-docdep.perl "$(shell pwd)" >$@ $(QUIET_STDERR) ifneq ($(MAKECMDGOALS),clean) -include doc.dep diff --git a/Documentation/build-docdep.perl b/Documentation/build-docdep.perl index 1b3ac8fdd9..315efaa2fa 100755 --- a/Documentation/build-docdep.perl +++ b/Documentation/build-docdep.perl @@ -1,5 +1,6 @@ #!/usr/bin/perl +my ($build_dir) = @ARGV; my %include = (); my %included = (); @@ -10,6 +11,7 @@ for my $text (<*.txt>) { chomp; s/^include::\s*//; s/\[\]//; + s/{build_dir}/${build_dir}/; $include{$text}{$_} = 1; $included{$_} = 1; } diff --git a/Documentation/config/diff.txt b/Documentation/config/diff.txt index 45f3fe855c..fdae13a212 100644 --- a/Documentation/config/diff.txt +++ b/Documentation/config/diff.txt @@ -218,7 +218,7 @@ endif::git-diff[] Set this option to `true` to make the diff driver cache the text conversion outputs. See linkgit:gitattributes[5] for details. -include::../mergetools-diff.txt[] +include::{build_dir}/mergetools-diff.txt[] `diff.indentHeuristic`:: Set this option to `false` to disable the default heuristics diff --git a/Documentation/config/merge.txt b/Documentation/config/merge.txt index 8851b6cede..82554d65a0 100644 --- a/Documentation/config/merge.txt +++ b/Documentation/config/merge.txt @@ -101,7 +101,7 @@ merge.guitool:: Any other value is treated as a custom merge tool and requires that a corresponding mergetool..cmd variable is defined. -include::../mergetools-merge.txt[] +include::{build_dir}/mergetools-merge.txt[] merge.verbosity:: Controls the amount of output shown by the recursive merge diff --git a/Documentation/git.txt b/Documentation/git.txt index d15a869762..44f0797ccf 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -245,17 +245,17 @@ ancillary user utilities. Main porcelain commands ~~~~~~~~~~~~~~~~~~~~~~~ -include::cmds-mainporcelain.txt[] +include::{build_dir}/cmds-mainporcelain.txt[] Ancillary Commands ~~~~~~~~~~~~~~~~~~ Manipulators: -include::cmds-ancillarymanipulators.txt[] +include::{build_dir}/cmds-ancillarymanipulators.txt[] Interrogators: -include::cmds-ancillaryinterrogators.txt[] +include::{build_dir}/cmds-ancillaryinterrogators.txt[] Interacting with Others @@ -264,7 +264,7 @@ Interacting with Others These commands are to interact with foreign SCM and with other people via patch over e-mail. -include::cmds-foreignscminterface.txt[] +include::{build_dir}/cmds-foreignscminterface.txt[] Reset, restore and revert ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -313,13 +313,13 @@ repositories. Manipulation commands ~~~~~~~~~~~~~~~~~~~~~ -include::cmds-plumbingmanipulators.txt[] +include::{build_dir}/cmds-plumbingmanipulators.txt[] Interrogation commands ~~~~~~~~~~~~~~~~~~~~~~ -include::cmds-plumbinginterrogators.txt[] +include::{build_dir}/cmds-plumbinginterrogators.txt[] In general, the interrogate commands do not touch the files in the working tree. @@ -328,12 +328,12 @@ the working tree. Syncing repositories ~~~~~~~~~~~~~~~~~~~~ -include::cmds-synchingrepositories.txt[] +include::{build_dir}/cmds-synchingrepositories.txt[] The following are helper commands used by the above; end users typically do not use them directly. -include::cmds-synchelpers.txt[] +include::{build_dir}/cmds-synchelpers.txt[] Internal helper commands @@ -342,14 +342,14 @@ Internal helper commands These are internal helper commands used by other commands; end users typically do not use them directly. -include::cmds-purehelpers.txt[] +include::{build_dir}/cmds-purehelpers.txt[] Guides ------ The following documentation pages are guides about Git concepts. -include::cmds-guide.txt[] +include::{build_dir}/cmds-guide.txt[] Repository, command and file interfaces --------------------------------------- @@ -358,7 +358,7 @@ This documentation discusses repository and command interfaces which users are expected to interact with directly. See `--user-formats` in linkgit:git-help[1] for more details on the criteria. -include::cmds-userinterfaces.txt[] +include::{build_dir}/cmds-userinterfaces.txt[] File formats, protocols and other developer interfaces ------------------------------------------------------ @@ -367,7 +367,7 @@ This documentation discusses file formats, over-the-wire protocols and other git developer interfaces. See `--developer-interfaces` in linkgit:git-help[1]. -include::cmds-developerinterfaces.txt[] +include::{build_dir}/cmds-developerinterfaces.txt[] Configuration Mechanism ----------------------- -- cgit v1.2.3 From 628d49f6e595694afc657fd80c1a12bb09c693b7 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:54 +0100 Subject: Documentation: teach "cmd-list.perl" about out-of-tree builds The "cmd-list.perl" script generates a list of commands that can be included into our manpages. The script doesn't know about out-of-tree builds and instead writes resulting files into the source directory. Adapt it such that we can read data from the source directory and write data into the build directory. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/Makefile | 2 +- Documentation/cmd-list.perl | 23 ++++++++++++----------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Documentation/Makefile b/Documentation/Makefile index a74fc0ff3d..e853d89eb5 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -312,7 +312,7 @@ cmds_txt = cmds-ancillaryinterrogators.txt \ $(cmds_txt): cmd-list.made cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT) - $(QUIET_GEN)$(PERL_PATH) ./cmd-list.perl ../command-list.txt $(cmds_txt) $(QUIET_STDERR) && \ + $(QUIET_GEN)$(PERL_PATH) ./cmd-list.perl .. . $(cmds_txt) && \ date >$@ mergetools_txt = mergetools-diff.txt mergetools-merge.txt diff --git a/Documentation/cmd-list.perl b/Documentation/cmd-list.perl index 755a110bc4..e260a98977 100755 --- a/Documentation/cmd-list.perl +++ b/Documentation/cmd-list.perl @@ -3,12 +3,13 @@ use File::Compare qw(compare); sub format_one { - my ($out, $nameattr) = @_; + my ($source_dir, $out, $nameattr) = @_; my ($name, $attr) = @$nameattr; + my ($path) = "$source_dir/Documentation/$name.txt"; my ($state, $description); my $mansection; $state = 0; - open I, '<', "$name.txt" or die "No such file $name.txt"; + open I, '<', "$path" or die "No such file $path.txt"; while () { if (/^(?:git|scalar)[a-z0-9-]*\(([0-9])\)$/) { $mansection = $1; @@ -29,7 +30,7 @@ sub format_one { } close I; if (!defined $description) { - die "No description found in $name.txt"; + die "No description found in $path.txt"; } if (my ($verify_name, $text) = ($description =~ /^($name) - (.*)/)) { print $out "linkgit:$name\[$mansection\]::\n\t"; @@ -43,9 +44,9 @@ sub format_one { } } -my ($input, @categories) = @ARGV; +my ($source_dir, $build_dir, @categories) = @ARGV; -open IN, "<$input"; +open IN, "<$source_dir/command-list.txt"; while () { last if /^### command list/; } @@ -63,17 +64,17 @@ close IN; for my $out (@categories) { my ($cat) = $out =~ /^cmds-(.*)\.txt$/; - open O, '>', "$out+" or die "Cannot open output file $out+"; + my ($path) = "$build_dir/$out"; + open O, '>', "$path+" or die "Cannot open output file $out+"; for (@{$cmds{$cat}}) { - format_one(\*O, $_); + format_one($source_dir, \*O, $_); } close O; - if (-f "$out" && compare("$out", "$out+") == 0) { - unlink "$out+"; + if (-f "$path" && compare("$path", "$path+") == 0) { + unlink "$path+"; } else { - print STDERR "$out\n"; - rename "$out+", "$out"; + rename "$path+", "$path"; } } -- cgit v1.2.3 From 023c3370ac330760aaf399cf6f6d9dbd7350e8e5 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:55 +0100 Subject: Documentation: extract script to generate a list of mergetools We include the list of available mergetools into our manpages. Extract the script that performs this logic such that we can reuse it in other build systems. While at it, refactor the Makefile targets such that we don't create "mergetools-list.made" anymore. It shouldn't be necessary, as we can instead have other targets depend on "mergetools-{diff,merge}.txt" directly. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/Makefile | 22 ++++++++-------------- Documentation/generate-mergetool-list.sh | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 14 deletions(-) create mode 100755 Documentation/generate-mergetool-list.sh diff --git a/Documentation/Makefile b/Documentation/Makefile index e853d89eb5..f0e5bc9c0c 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -282,11 +282,13 @@ ifneq ($(filter-out lint-docs clean,$(MAKECMDGOALS)),) -include ../GIT-VERSION-FILE endif +mergetools_txt = mergetools-diff.txt mergetools-merge.txt + # # Determine "include::" file references in asciidoc files. # docdep_prereqs = \ - mergetools-list.made $(mergetools_txt) \ + $(mergetools_txt) \ cmd-list.made $(cmds_txt) doc.dep : $(docdep_prereqs) $(DOC_DEP_TXT) build-docdep.perl @@ -315,19 +317,11 @@ cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT) $(QUIET_GEN)$(PERL_PATH) ./cmd-list.perl .. . $(cmds_txt) && \ date >$@ -mergetools_txt = mergetools-diff.txt mergetools-merge.txt - -$(mergetools_txt): mergetools-list.made - -mergetools-list.made: ../git-mergetool--lib.sh $(wildcard ../mergetools/*) - $(QUIET_GEN) \ - $(SHELL_PATH) -c 'MERGE_TOOLS_DIR=../mergetools && TOOL_MODE=diff && \ - . ../git-mergetool--lib.sh && \ - show_tool_names can_diff' | sed -e "s/\([a-z0-9]*\)/\`\1\`;;/" >mergetools-diff.txt && \ - $(SHELL_PATH) -c 'MERGE_TOOLS_DIR=../mergetools && TOOL_MODE=merge && \ - . ../git-mergetool--lib.sh && \ - show_tool_names can_merge' | sed -e "s/\([a-z0-9]*\)/\`\1\`;;/" >mergetools-merge.txt && \ - date >$@ +mergetools-%.txt: generate-mergetool-list.sh ../git-mergetool--lib.sh $(wildcard ../mergetools/*) +mergetools-diff.txt: + $(QUIET_GEN)$(SHELL_PATH) ./generate-mergetool-list.sh .. diff $@ +mergetools-merge.txt: + $(QUIET_GEN)$(SHELL_PATH) ./generate-mergetool-list.sh .. merge $@ TRACK_ASCIIDOCFLAGS = $(subst ','\'',$(ASCIIDOC_COMMON):$(ASCIIDOC_HTML):$(ASCIIDOC_DOCBOOK)) diff --git a/Documentation/generate-mergetool-list.sh b/Documentation/generate-mergetool-list.sh new file mode 100755 index 0000000000..6700498b93 --- /dev/null +++ b/Documentation/generate-mergetool-list.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +if test "$#" -ne 3 +then + echo >&2 "USAGE: $0 " + exit 1 +fi + +SOURCE_DIR="$1" +TOOL_MODE="$2" +OUTPUT="$3" +MERGE_TOOLS_DIR="$SOURCE_DIR/mergetools" + +( + . "$SOURCE_DIR"/git-mergetool--lib.sh && + show_tool_names can_$TOOL_MODE +) | sed -e "s/\([a-z0-9]*\)/\`\1\`;;/" >"$OUTPUT" -- cgit v1.2.3 From 7e0730c8baaac43fcf0366e686066ec2c1fc2f31 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:56 +0100 Subject: t: better support for out-of-tree builds Our in-tree builds used by the Makefile use various different build directories scattered around different locations. The paths to those build directories have to be propagated to our tests such that they can find the contained files. This is done via a mixture of hardcoded paths in our test library and injected variables in our bin-wrappers or "GIT-BUILD-OPTIONS". The latter two mechanisms are preferable over using hardcoded paths. For one, we have all paths which are subject to change stored in a small set of central files instead of having the knowledge of build paths in many files. And second, it allows build systems which build files elsewhere to adapt those paths based on their own needs. This is especially nice in the context of build systems that use out-of-tree builds like CMake or Meson. Remove hardcoded knowledge of build paths from our test library and move it into our bin-wrappers and "GIT-BUILD-OPTIONS". Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- GIT-BUILD-OPTIONS.in | 5 +++++ Makefile | 9 +++++++++ bin-wrappers/wrap-for-bin.sh | 11 ++++++----- contrib/buildsystems/CMakeLists.txt | 8 ++++++++ t/lib-gettext.sh | 4 ++-- t/t7609-mergetool--lib.sh | 2 +- t/test-lib.sh | 6 +++--- 7 files changed, 34 insertions(+), 11 deletions(-) diff --git a/GIT-BUILD-OPTIONS.in b/GIT-BUILD-OPTIONS.in index 9b95a6b3ee..f651116102 100644 --- a/GIT-BUILD-OPTIONS.in +++ b/GIT-BUILD-OPTIONS.in @@ -35,6 +35,11 @@ GIT_PERF_MAKE_COMMAND=@GIT_PERF_MAKE_COMMAND@ GIT_INTEROP_MAKE_OPTS=@GIT_INTEROP_MAKE_OPTS@ GIT_TEST_INDEX_VERSION=@GIT_TEST_INDEX_VERSION@ GIT_TEST_PERL_FATAL_WARNINGS=@GIT_TEST_PERL_FATAL_WARNINGS@ +GIT_TEST_TEXTDOMAINDIR=@GIT_TEST_TEXTDOMAINDIR@ +GIT_TEST_POPATH=@GIT_TEST_POPATH@ +GIT_TEST_TEMPLATE_DIR=@GIT_TEST_TEMPLATE_DIR@ +GIT_TEST_GITPERLLIB=@GIT_TEST_GITPERLLIB@ +GIT_TEST_MERGE_TOOLS_DIR=@GIT_TEST_MERGE_TOOLS_DIR@ RUNTIME_PREFIX=@RUNTIME_PREFIX@ GITWEBDIR=@GITWEBDIR@ USE_GETTEXT_SCHEME=@USE_GETTEXT_SCHEME@ diff --git a/Makefile b/Makefile index e1ae562760..c4b9d2801a 100644 --- a/Makefile +++ b/Makefile @@ -3176,6 +3176,11 @@ GIT-BUILD-OPTIONS: FORCE -e "s|@GIT_INTEROP_MAKE_OPTS@|\'$(GIT_INTEROP_MAKE_OPTS)\'|" \ -e "s|@GIT_TEST_INDEX_VERSION@|\'$(GIT_TEST_INDEX_VERSION)\'|" \ -e "s|@GIT_TEST_PERL_FATAL_WARNINGS@|\'$(GIT_TEST_PERL_FATAL_WARNINGS)\'|" \ + -e "s|@GIT_TEST_TEXTDOMAINDIR@|\'$(shell pwd)/po/build/locale\'|" \ + -e "s|@GIT_TEST_POPATH@|\'$(shell pwd)/po\'|" \ + -e "s|@GIT_TEST_TEMPLATE_DIR@|\'$(shell pwd)/templates/blt\'|" \ + -e "s|@GIT_TEST_GITPERLLIB@|\'$(shell pwd)/perl/build/lib\'|" \ + -e "s|@GIT_TEST_MERGE_TOOLS_DIR@|\'$(shell pwd)/mergetools\'|" \ -e "s|@RUNTIME_PREFIX@|\'$(RUNTIME_PREFIX_OPTION)\'|" \ -e "s|@GITWEBDIR@|\'$(gitwebdir_SQ)\'|" \ -e "s|@USE_GETTEXT_SCHEME@|\'$(USE_GETTEXT_SCHEME)\'|" \ @@ -3205,6 +3210,10 @@ all:: $(TEST_PROGRAMS) $(test_bindir_programs) $(UNIT_TEST_PROGS) $(CLAR_TEST_PR $(test_bindir_programs): bin-wrappers/%: bin-wrappers/wrap-for-bin.sh $(QUIET_GEN)sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ -e 's|@BUILD_DIR@|$(shell pwd)|' \ + -e 's|@GIT_TEXTDOMAINDIR@|$(shell pwd)/po/build/locale|' \ + -e 's|@GITPERLLIB@|$(shell pwd)/perl/build/lib|' \ + -e 's|@MERGE_TOOLS_DIR@|$(shell pwd)/mergetools|' \ + -e 's|@TEMPLATE_DIR@|$(shell pwd)/templates/blt|' \ -e 's|@PROG@|$(shell pwd)/$(patsubst test-%,t/helper/test-%,$(@F))$(if $(filter-out $(BINDIR_PROGRAMS_NO_X),$(@F)),$(X),)|' < $< > $@ && \ chmod +x $@ diff --git a/bin-wrappers/wrap-for-bin.sh b/bin-wrappers/wrap-for-bin.sh index 2feaec81f2..4b658ffd2d 100755 --- a/bin-wrappers/wrap-for-bin.sh +++ b/bin-wrappers/wrap-for-bin.sh @@ -4,21 +4,22 @@ # to run test suite against sandbox, but with only bindir-installed # executables in PATH. The Makefile copies this into various # files in bin-wrappers, substituting -# @BUILD_DIR@ and @PROG@. +# @BUILD_DIR@, @TEMPLATE_DIR@ and @PROG@. GIT_EXEC_PATH='@BUILD_DIR@' if test -n "$NO_SET_GIT_TEMPLATE_DIR" then unset GIT_TEMPLATE_DIR else - GIT_TEMPLATE_DIR='@BUILD_DIR@/templates/blt' + GIT_TEMPLATE_DIR='@TEMPLATE_DIR@' export GIT_TEMPLATE_DIR fi -GITPERLLIB='@BUILD_DIR@/perl/build/lib'"${GITPERLLIB:+:$GITPERLLIB}" -GIT_TEXTDOMAINDIR='@BUILD_DIR@/po/build/locale' +MERGE_TOOLS_DIR='@MERGE_TOOLS_DIR@' +GITPERLLIB='@GITPERLLIB@'"${GITPERLLIB:+:$GITPERLLIB}" +GIT_TEXTDOMAINDIR='@GIT_TEXTDOMAINDIR@' PATH='@BUILD_DIR@/bin-wrappers:'"$PATH" -export GIT_EXEC_PATH GITPERLLIB PATH GIT_TEXTDOMAINDIR +export MERGE_TOOLS_DIR GIT_EXEC_PATH GITPERLLIB PATH GIT_TEXTDOMAINDIR case "$GIT_DEBUGGER" in '') diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index c643a44427..49904ca8a9 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -1100,6 +1100,9 @@ endforeach() file(STRINGS ${CMAKE_SOURCE_DIR}/bin-wrappers/wrap-for-bin.sh content NEWLINE_CONSUME) string(REPLACE "@BUILD_DIR@" "${CMAKE_BINARY_DIR}" content "${content}") +string(REPLACE "@GIT_TEXTDOMAINDIR@" "${CMAKE_BINARY_DIR}/po/build/locale" content "${content}") +string(REPLACE "@GITPERLLIB@" "${CMAKE_BINARY_DIR}/perl/build/lib" content "${content}") +string(REPLACE "@MERGE_TOOLS_DIR@" "${CMAKE_SOURCE_DIR}/mergetools" content "${content}") string(REPLACE "@PROG@" "${CMAKE_BINARY_DIR}/git-cvsserver" content "${content}") file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/git-cvsserver ${content}) @@ -1185,6 +1188,11 @@ string(REPLACE "@GIT_PERF_MAKE_COMMAND@" "" git_build_options "${git_build_optio string(REPLACE "@GIT_INTEROP_MAKE_OPTS@" "" git_build_options "${git_build_options}") string(REPLACE "@GIT_TEST_INDEX_VERSION@" "" git_build_options "${git_build_options}") string(REPLACE "@GIT_TEST_PERL_FATAL_WARNINGS@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_TEXTDOMAINDIR@" "'${CMAKE_BINARY_DIR}/po/build/locale'" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_POPATH@" "'${CMAKE_BINARY_DIR}/po'" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_TEMPLATE_DIR@" "'${CMAKE_BINARY_DIR}/templates/blt'" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_GITPERLLIB@" "'${CMAKE_BINARY_DIR}/perl/build/lib'" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_MERGE_TOOLS_DIR@" "'${RUNTIME_PREFIX}'" git_build_options "${git_build_options}") string(REPLACE "@RUNTIME_PREFIX@" "'${RUNTIME_PREFIX}'" git_build_options "${git_build_options}") string(REPLACE "@GITWEBDIR@" "'${GITWEBDIR}'" git_build_options "${git_build_options}") string(REPLACE "@USE_GETTEXT_SCHEME@" "" git_build_options "${git_build_options}") diff --git a/t/lib-gettext.sh b/t/lib-gettext.sh index cc6bb2cdea..7a734c6973 100644 --- a/t/lib-gettext.sh +++ b/t/lib-gettext.sh @@ -6,8 +6,8 @@ . ./test-lib.sh -GIT_TEXTDOMAINDIR="$GIT_BUILD_DIR/po/build/locale" -GIT_PO_PATH="$GIT_BUILD_DIR/po" +GIT_TEXTDOMAINDIR="$GIT_TEST_TEXTDOMAINDIR" +GIT_PO_PATH="$GIT_TEST_POPATH" export GIT_TEXTDOMAINDIR GIT_PO_PATH if test -n "$GIT_TEST_INSTALLED" diff --git a/t/t7609-mergetool--lib.sh b/t/t7609-mergetool--lib.sh index 330d6d603d..e8e205707e 100755 --- a/t/t7609-mergetool--lib.sh +++ b/t/t7609-mergetool--lib.sh @@ -7,7 +7,7 @@ Testing basic merge tools options' . ./test-lib.sh test_expect_success 'mergetool --tool=vimdiff creates the expected layout' ' - . "$GIT_BUILD_DIR"/mergetools/vimdiff && + . "$GIT_TEST_MERGE_TOOLS_DIR"/vimdiff && run_unit_tests ' diff --git a/t/test-lib.sh b/t/test-lib.sh index 20012f6f47..fe688a3fce 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -1419,7 +1419,7 @@ else # normal case, use ../bin-wrappers only unless $with_dashes: PATH="$GIT_BUILD_DIR:$GIT_BUILD_DIR/t/helper:$PATH" fi fi -GIT_TEMPLATE_DIR="$GIT_BUILD_DIR"/templates/blt +GIT_TEMPLATE_DIR="$GIT_TEST_TEMPLATE_DIR" GIT_CONFIG_NOSYSTEM=1 GIT_ATTR_NOSYSTEM=1 GIT_CEILING_DIRECTORIES="$TRASH_DIRECTORY/.." @@ -1485,9 +1485,9 @@ then fi fi -GITPERLLIB="$GIT_BUILD_DIR"/perl/build/lib +GITPERLLIB="$GIT_TEST_GITPERLLIB" export GITPERLLIB -test -d "$GIT_BUILD_DIR"/templates/blt || { +test -d "$GIT_TEMPLATE_DIR" || { BAIL_OUT "You haven't built things yet, have you?" } -- cgit v1.2.3 From 5ee8927824fe5308bc9a1b7c7a1283e79eb135d5 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:57 +0100 Subject: t: allow overriding build dir Our "test-lib.sh" assumes that our build directory is the parent directory of "t/". While true when using our Makefile, it's not when using build systems that support out-of-tree builds. In commit ee9e66e4e7 (cmake: avoid editing t/test-lib.sh, 2022-10-18), we have introduce support for overriding the GIT_BUILD_DIR by creating the file "$GIT_BUILD_DIR/GIT-BUILD-DIR" with its contents pointing to the location of the build directory. The intent was to stop modifying "t/test-lib.sh" with the CMake build systems while allowing out-of-tree builds. But "$GIT_BUILD_DIR" is somewhat misleadingly named, as it in fact points to the _source_ directory. So while that commit solved part of the problem for out-of-tree builds, CMake still has to write files into the source tree. Solve the second part of the problem, namely not having to write any data into the source directory at all, by also supporting an environment variable that allows us to point to a different build directory. This allows us to perform properly self-contained out-of-tree builds. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- t/test-lib.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/t/test-lib.sh b/t/test-lib.sh index fe688a3fce..62dfcc4aaf 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -35,7 +35,7 @@ else # needing to exist. TEST_DIRECTORY=$(cd "$TEST_DIRECTORY" && pwd) || exit 1 fi -GIT_BUILD_DIR="${TEST_DIRECTORY%/t}" +GIT_BUILD_DIR="${GIT_BUILD_DIR:-${TEST_DIRECTORY%/t}}" if test "$TEST_DIRECTORY" = "$GIT_BUILD_DIR" then echo "PANIC: Running in a $TEST_DIRECTORY that doesn't end in '/t'?" >&2 @@ -522,6 +522,7 @@ unset VISUAL EMAIL LANGUAGE $("$PERL_PATH" -e ' PERF_ CURL_VERBOSE TRACE_CURL + BUILD_DIR )); my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env); print join("\n", @vars); -- cgit v1.2.3 From 00ab97b1bc07206be4d05547fe44bfd7afd607dc Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:58 +0100 Subject: Documentation: add comparison of build systems We're contemplating whether to eventually replace our build systems with a build system that is easier to use. Add a comparison of build systems to our technical documentation as a baseline for discussion. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/Makefile | 1 + Documentation/technical/build-systems.txt | 224 ++++++++++++++++++++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 Documentation/technical/build-systems.txt diff --git a/Documentation/Makefile b/Documentation/Makefile index f0e5bc9c0c..3392e1ce7e 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -113,6 +113,7 @@ TECH_DOCS += MyFirstObjectWalk TECH_DOCS += SubmittingPatches TECH_DOCS += ToolsForGit TECH_DOCS += technical/bitmap-format +TECH_DOCS += technical/build-systems TECH_DOCS += technical/bundle-uri TECH_DOCS += technical/hash-function-transition TECH_DOCS += technical/long-running-process-protocol diff --git a/Documentation/technical/build-systems.txt b/Documentation/technical/build-systems.txt new file mode 100644 index 0000000000..d9dafb407c --- /dev/null +++ b/Documentation/technical/build-systems.txt @@ -0,0 +1,224 @@ += Build Systems + +The build system is the primary way for both developers and system integrators +to interact with the Git project. As such, being easy to use and extend for +those who are not directly developing Git itself is just as important as other +requirements we have on any potential build system. + +This document outlines the different requirements that we have for the build +system and then compares available build systems using these criteria. + +== Requirements + +The following subsections present a list of requirements that we have for any +potential build system. Sections are sorted by decreasing priority. + +=== Platform support + +The build system must have support for all of our platforms that we continually +test against as outlined by our platform support policy. These platforms are: + + - Linux + - Windows + - macOS + +Furthermore, the build system should have support for the following platforms +that generally have somebody running test pipelines against regularly: + + - AIX + - FreeBSD + - NetBSD + - NonStop + - OpenBSD + +The platforms which must be supported by the tool should be aligned with our +[platform support policy](platform-support.txt). + +=== Auto-detection of supported features + +The build system must support auto-detection of features which are or aren't +available on the current platform. Platform maintainers should not be required +to manually configure the complete build. + +Auto-detection of the following items is considered to be important: + + - Check for the existence of headers. + - Check for the existence of libraries. + - Check for the existence of exectuables. + - Check for the runtime behavior of specific functions. + - Check for specific link order requirements when multiple libraries are + involved. + +=== Ease of use + +The build system should be both easy to use and easy to extend. While this is +naturally a subjective metric it is likely not controversial to say that some +build systems are considerably harder to use than others. + +=== IDE support + +The build system should integrate with well-known IDEs. Well-known IDEs include: + + - Microsoft Visual Studio + - Visual Studio Code + - Xcode + +There are four levels of support: + + - Native integration into the IDE. + - Integration into the IDE via a plugin. + - Integration into the IDE via generating a project description with the build + system. + - No integration. + +Native integration is preferable, but integration via either a plugin or by +generating a project description via the build system are considered feasible +alternatives. + +Another important distinction is the level of integration. There are two +features that one generally wants to have: + + - Integration of build targets. + - Automatic setup of features like code completion with detected build + dependencies. + +The first bullet point is the bare minimum, but is not sufficient to be +considered proper integration. + +=== Out-of-tree builds + +The build system should support out-of-tree builds. Out-of-tree builds allow a +developer to configure multiple different build directories with different +configuration, e.g. one "debug" build and one "release" build. + +=== Cross-platform builds + +The build system should support cross-platform builds, e.g. building for arm on +an x86-64 host. + +=== Language support + +The following languages and toolchains are of relevance and should be supported +by the build system: + + - C: the primary compiled language used by Git, must be supported. Relevant + toolchains are GCC, Clang and MSVC. + - Rust: candidate as a second compiled lanugage, should be supported. Relevant + toolchains is the LLVM-based rustc. + +Built-in support for the respective languages is preferred over support that +needs to be wired up manually to avoid unnecessary complexity. Native support +includes the following features: + + - Compiling objects. + - Dependency tracking. + - Detection of available features. + - Discovery of relevant toolchains. + - Linking libraries and executables. + - Templating placeholders in scripts. + +=== Test integration + +It should be possible to integrate tests into the build system such that it is +possible to build and test Git within the build system. Features which are nice +to have: + + - Track build-time dependencies for respective tests. Unit tests have + different requirements than integration tests. + - Allow filtering of which tests to run. + - Allow running tests such that utilities like `test_pause` or `debug` work. + +== Comparison + +The following list of build systems are considered: + +- GNU Make +- autoconf +- CMake +- Meson + +=== GNU Make + +- Platform support: ubitquitous on all platforms, but not well-integrated into Windows. +- Auto-detection: no built-in support for auto-detection of features. +- Ease of use: easy to use, but discovering available options is hard. Makefile + rules can quickly get out of hand once reaching a certain scope. +- IDE support: execution of Makefile targets is supported by many IDEs +- Out-of-tree builds: supported in theory, not wired up in practice. +- Cross-platform builds: supported in theory, not wired up in practice. +- Language support: + - C: Limited built-in support, many parts need to be wired up manually. + - Rust: No built-in support, needs to be wired up manually. +- Test integration: partially supported, many parts need to be wired up + manually. + +=== autoconf + +- Platform support: ubiquitous on all platforms, but not well-integrated into Windows. +- Auto-detection: supported. +- Ease of use: easy to use, discovering available options is comparatively + easy. The autoconf syntax is prohibitively hard to extend though due to its + complex set of interacting files and the hard-to-understand M4 language. +- IDE support: no integration into IDEs at generation time. The generated + Makefiles have the same level of support as GNU Make. +- Out-of-tree builds: supported in theory, not wired up in practice. +- Cross-platform builds: supported. +- Language support: + - C: Limited built-in support, many parts need to be wired up manually. + - Rust: No built-in support, needs to be wired up manually. +- Test integration: partially supported, many parts need to be wired up + manually. + +=== CMake + +- Platform support: not as extensive as GNU Make or autoconf, but all major + platforms are supported. + - AIX + - Cygwin + - FreeBSD + - Linux + - OpenBSD + - Solaris + - Windows + - macOS +- Ease of use: easy to use, discovering available options is not always + trivial. The scripting language used by CMake is somewhat cumbersome to use, + but extending CMake build instructions is doable. +- IDE support: natively integrated into Microsoft Visual Studio. Can generate + project descriptions for Xcode. An extension is available for Visual Studio + Code. Many other IDEs have plugins for CMake. +- Out-of-tree builds: supported. +- Cross-platform builds: supported. +- Language support: + - C: Supported for GCC, Clang, MSVC and other toolchains. + - Rust: No built-in support, needs to be wired up manually. +- Test integration: supported, even though test dependencies are a bit + cumbersome to use via "test fixtures". Interactive test runs are not + supported. + +=== Meson + +- Platform: not as extensive as GNU Make or autoconf, but all major platforms + and some smaller ones are supported. + - AIX + - Cygwin + - DragonflyBSD + - FreeBSD + - Haiku + - Linux + - NetBSD + - OpenBSD + - Solaris + - Windows + - macOS +- Ease of use: easy to use, discovering available options is easy. The + scripting language is straight-forward to use. +- IDE support: Supports generating build instructions for Xcode and Microsoft + Visual Studio, a plugin exists for Visual Studio Code. +- Out-of-tree builds: supported. +- Cross-platform builds: supported. +- Language support: + - C: Supported for GCC, Clang, MSVC and other toolchains. + - Rust: Supported for rustc. +- Test integration: supported. Interactive tests are supported starting with + Meson 1.5.0 via the `--interactive` flag. -- cgit v1.2.3 From 904339edbd80ec5676616af6e072b41804c1c8eb Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 14:24:59 +0100 Subject: Introduce support for the Meson build system Introduce support for the Meson build system, a "modern" meta build system that supports many different platforms, including Linux, macOS, Windows and BSDs. Meson supports different backends, including Ninja, Xcode and Microsoft Visual Studio. Several common IDEs provide an integration with it. The biggest contender compared to Meson is probably CMake as outlined in our "Documentation/technical/build-systems.txt" file. Based on my own personal experience from working with both build systems extensively I strongly favor Meson over CMake. In my opinion, it feels significantly easier to use with a syntax that feels more like a "real" programming language. The second big reason is that Meson supports Rust natively, which may prove to be important given that the project may pick up Rust as another language eventually. Using Meson is rather straight-forward. An example: ``` # Meson uses out-of-tree builds. You can set up multiple build # directories, how you name them is completely up to you. $ mkdir build $ cd build $ meson setup .. -Dprefix=/tmp/git-installation # Build the project. This also provides several other targets like e.g. `install` or `test`. $ ninja # Meson has been wired up to support execution of our test suites. # Both our unit tests and our integration tests are supported. # Running `meson test` without any arguments will execute all tests, # but the syntax supports globbing to select only some tests. $ meson test 't-*' # Execute single test interactively to allow for debugging. $ meson test 't0000-*' --interactive --test-args=-ix ``` The build instructions have been successfully tested on the following systems, tests are passing: - Apple macOS 10.15. - FreeBSD 14.1. - NixOS 24.11. - OpenBSD 7.6. - Ubuntu 24.04. - Windows 10 with Cygwin. - Windows 10 with MinGW64, except for t9700, which is also broken with our Makefile. - Windows 10 with Visual Studio 2022 toolchain, using the Native Tools Command Prompt with `meson setup --vsenv`. Tests pass, except for t9700. - Windows 10 with Visual Studio 2022 solution, using the Native Tools Command Prompt with `meson setup --backend vs2022`. Tests pass, except for t9700. - Windows 10 with VS Code, using the Meson plug-in. It is expected that there will still be rough edges in the current version. If this patch lands the expectation is that it will coexist with our other build systems for a while. Like this, distributions can slowly migrate over to Meson and report any findings they have to us such that we can continue to iterate. A potential cutoff date for other build systems may be Git 3.0. Some notes: - The installed distribution is structured somewhat differently than how it used to be the case. All of our binaries are installed into `$libexec/git-core`, while all binaries part of `$bindir` are now symbolic links pointing to the former. This rule is consistent in itself and thus easier to reason about. - We do not install dashed binaries into `$libexec/git-core` anymore, so there won't e.g. be a symlink for git-add(1). These are not required by modern Git and there isn't really much of a use case for those anymore. By not installing those symlinks we thus start the deprecation of this layout. - We're targeting Meson 1.3.0, which has been released relatively recently November 2023. The only feature we use from that version is `fs.relative_to()`, which we could replace if necessary. If so, we could start to target Meson 1.0.0 and newer, released in December 2022. - The whole build instructions count around 3300 lines, half of which is listing all of our code and test files. Our Makefiles are around 5000 lines, autoconf adds another 1300 lines. CMake in comparison has only 1200 linescode, but it avoids listing individual files and does not wire up auto-configuration as extensively as the Meson instructions do. - We bundle a set of subproject wrappers for curl, expat, openssl, pcre2 and zlib. This allows developers to build Git without these dependencies preinstalled, and Meson will fetch and build them automatically. This is especially helpful on Windows. Helped-by: Eli Schwartz Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/meson.build | 324 ++++++ bin-wrappers/meson.build | 28 + contrib/completion/meson.build | 16 + contrib/meson.build | 1 + gitweb/meson.build | 89 ++ meson.build | 1901 ++++++++++++++++++++++++++++++++++++ meson_options.txt | 81 ++ perl/FromCPAN/Mail/meson.build | 7 + perl/FromCPAN/meson.build | 9 + perl/Git/LoadCPAN/Mail/meson.build | 7 + perl/Git/LoadCPAN/meson.build | 9 + perl/Git/SVN/Memoize/meson.build | 7 + perl/Git/SVN/meson.build | 20 + perl/Git/meson.build | 18 + perl/meson.build | 12 + po/meson.build | 27 + subprojects/.gitignore | 1 + subprojects/curl.wrap | 13 + subprojects/expat.wrap | 13 + subprojects/openssl.wrap | 15 + subprojects/pcre2.wrap | 16 + subprojects/zlib.wrap | 13 + t/helper/meson.build | 91 ++ t/meson.build | 1114 +++++++++++++++++++++ templates/hooks/meson.build | 26 + templates/info/meson.build | 7 + templates/meson.build | 15 + 27 files changed, 3880 insertions(+) create mode 100644 Documentation/meson.build create mode 100644 bin-wrappers/meson.build create mode 100644 contrib/completion/meson.build create mode 100644 contrib/meson.build create mode 100644 gitweb/meson.build create mode 100644 meson.build create mode 100644 meson_options.txt create mode 100644 perl/FromCPAN/Mail/meson.build create mode 100644 perl/FromCPAN/meson.build create mode 100644 perl/Git/LoadCPAN/Mail/meson.build create mode 100644 perl/Git/LoadCPAN/meson.build create mode 100644 perl/Git/SVN/Memoize/meson.build create mode 100644 perl/Git/SVN/meson.build create mode 100644 perl/Git/meson.build create mode 100644 perl/meson.build create mode 100644 po/meson.build create mode 100644 subprojects/.gitignore create mode 100644 subprojects/curl.wrap create mode 100644 subprojects/expat.wrap create mode 100644 subprojects/openssl.wrap create mode 100644 subprojects/pcre2.wrap create mode 100644 subprojects/zlib.wrap create mode 100644 t/helper/meson.build create mode 100644 t/meson.build create mode 100644 templates/hooks/meson.build create mode 100644 templates/info/meson.build create mode 100644 templates/meson.build diff --git a/Documentation/meson.build b/Documentation/meson.build new file mode 100644 index 0000000000..f2426ccaa3 --- /dev/null +++ b/Documentation/meson.build @@ -0,0 +1,324 @@ +manpages = { + # Category 1. + 'git-add.txt' : 1, + 'git-am.txt' : 1, + 'git-annotate.txt' : 1, + 'git-apply.txt' : 1, + 'git-archimport.txt' : 1, + 'git-archive.txt' : 1, + 'git-bisect.txt' : 1, + 'git-blame.txt' : 1, + 'git-branch.txt' : 1, + 'git-bugreport.txt' : 1, + 'git-bundle.txt' : 1, + 'git-cat-file.txt' : 1, + 'git-check-attr.txt' : 1, + 'git-check-ignore.txt' : 1, + 'git-check-mailmap.txt' : 1, + 'git-checkout-index.txt' : 1, + 'git-checkout.txt' : 1, + 'git-check-ref-format.txt' : 1, + 'git-cherry-pick.txt' : 1, + 'git-cherry.txt' : 1, + 'git-citool.txt' : 1, + 'git-clean.txt' : 1, + 'git-clone.txt' : 1, + 'git-column.txt' : 1, + 'git-commit-graph.txt' : 1, + 'git-commit-tree.txt' : 1, + 'git-commit.txt' : 1, + 'git-config.txt' : 1, + 'git-count-objects.txt' : 1, + 'git-credential-cache--daemon.txt' : 1, + 'git-credential-cache.txt' : 1, + 'git-credential-store.txt' : 1, + 'git-credential.txt' : 1, + 'git-cvsexportcommit.txt' : 1, + 'git-cvsimport.txt' : 1, + 'git-cvsserver.txt' : 1, + 'git-daemon.txt' : 1, + 'git-describe.txt' : 1, + 'git-diagnose.txt' : 1, + 'git-diff-files.txt' : 1, + 'git-diff-index.txt' : 1, + 'git-difftool.txt' : 1, + 'git-diff-tree.txt' : 1, + 'git-diff.txt' : 1, + 'git-fast-export.txt' : 1, + 'git-fast-import.txt' : 1, + 'git-fetch-pack.txt' : 1, + 'git-fetch.txt' : 1, + 'git-filter-branch.txt' : 1, + 'git-fmt-merge-msg.txt' : 1, + 'git-for-each-ref.txt' : 1, + 'git-for-each-repo.txt' : 1, + 'git-format-patch.txt' : 1, + 'git-fsck-objects.txt' : 1, + 'git-fsck.txt' : 1, + 'git-fsmonitor--daemon.txt' : 1, + 'git-gc.txt' : 1, + 'git-get-tar-commit-id.txt' : 1, + 'git-grep.txt' : 1, + 'git-gui.txt' : 1, + 'git-hash-object.txt' : 1, + 'git-help.txt' : 1, + 'git-hook.txt' : 1, + 'git-http-backend.txt' : 1, + 'git-http-fetch.txt' : 1, + 'git-http-push.txt' : 1, + 'git-imap-send.txt' : 1, + 'git-index-pack.txt' : 1, + 'git-init-db.txt' : 1, + 'git-init.txt' : 1, + 'git-instaweb.txt' : 1, + 'git-interpret-trailers.txt' : 1, + 'git-log.txt' : 1, + 'git-ls-files.txt' : 1, + 'git-ls-remote.txt' : 1, + 'git-ls-tree.txt' : 1, + 'git-mailinfo.txt' : 1, + 'git-mailsplit.txt' : 1, + 'git-maintenance.txt' : 1, + 'git-merge-base.txt' : 1, + 'git-merge-file.txt' : 1, + 'git-merge-index.txt' : 1, + 'git-merge-one-file.txt' : 1, + 'git-mergetool--lib.txt' : 1, + 'git-mergetool.txt' : 1, + 'git-merge-tree.txt' : 1, + 'git-merge.txt' : 1, + 'git-mktag.txt' : 1, + 'git-mktree.txt' : 1, + 'git-multi-pack-index.txt' : 1, + 'git-mv.txt' : 1, + 'git-name-rev.txt' : 1, + 'git-notes.txt' : 1, + 'git-p4.txt' : 1, + 'git-pack-objects.txt' : 1, + 'git-pack-redundant.txt' : 1, + 'git-pack-refs.txt' : 1, + 'git-patch-id.txt' : 1, + 'git-prune-packed.txt' : 1, + 'git-prune.txt' : 1, + 'git-pull.txt' : 1, + 'git-push.txt' : 1, + 'git-quiltimport.txt' : 1, + 'git-range-diff.txt' : 1, + 'git-read-tree.txt' : 1, + 'git-rebase.txt' : 1, + 'git-receive-pack.txt' : 1, + 'git-reflog.txt' : 1, + 'git-refs.txt' : 1, + 'git-remote-ext.txt' : 1, + 'git-remote-fd.txt' : 1, + 'git-remote.txt' : 1, + 'git-repack.txt' : 1, + 'git-replace.txt' : 1, + 'git-replay.txt' : 1, + 'git-request-pull.txt' : 1, + 'git-rerere.txt' : 1, + 'git-reset.txt' : 1, + 'git-restore.txt' : 1, + 'git-revert.txt' : 1, + 'git-rev-list.txt' : 1, + 'git-rev-parse.txt' : 1, + 'git-rm.txt' : 1, + 'git-send-email.txt' : 1, + 'git-send-pack.txt' : 1, + 'git-shell.txt' : 1, + 'git-sh-i18n--envsubst.txt' : 1, + 'git-sh-i18n.txt' : 1, + 'git-shortlog.txt' : 1, + 'git-show-branch.txt' : 1, + 'git-show-index.txt' : 1, + 'git-show-ref.txt' : 1, + 'git-show.txt' : 1, + 'git-sh-setup.txt' : 1, + 'git-sparse-checkout.txt' : 1, + 'git-stage.txt' : 1, + 'git-stash.txt' : 1, + 'git-status.txt' : 1, + 'git-stripspace.txt' : 1, + 'git-submodule.txt' : 1, + 'git-svn.txt' : 1, + 'git-switch.txt' : 1, + 'git-symbolic-ref.txt' : 1, + 'git-tag.txt' : 1, + 'git-unpack-file.txt' : 1, + 'git-unpack-objects.txt' : 1, + 'git-update-index.txt' : 1, + 'git-update-ref.txt' : 1, + 'git-update-server-info.txt' : 1, + 'git-upload-archive.txt' : 1, + 'git-upload-pack.txt' : 1, + 'git-var.txt' : 1, + 'git-verify-commit.txt' : 1, + 'git-verify-pack.txt' : 1, + 'git-verify-tag.txt' : 1, + 'git-version.txt' : 1, + 'git-web--browse.txt' : 1, + 'git-whatchanged.txt' : 1, + 'git-worktree.txt' : 1, + 'git-write-tree.txt' : 1, + 'git.txt' : 1, + 'gitk.txt' : 1, + 'gitweb.txt' : 1, + 'scalar.txt' : 1, + + # Category 5. + 'gitattributes.txt' : 5, + 'gitformat-bundle.txt' : 5, + 'gitformat-chunk.txt' : 5, + 'gitformat-commit-graph.txt' : 5, + 'gitformat-index.txt' : 5, + 'gitformat-pack.txt' : 5, + 'gitformat-signature.txt' : 5, + 'githooks.txt' : 5, + 'gitignore.txt' : 5, + 'gitmailmap.txt' : 5, + 'gitmodules.txt' : 5, + 'gitprotocol-capabilities.txt' : 5, + 'gitprotocol-common.txt' : 5, + 'gitprotocol-http.txt' : 5, + 'gitprotocol-pack.txt' : 5, + 'gitprotocol-v2.txt' : 5, + 'gitrepository-layout.txt' : 5, + 'gitweb.conf.txt' : 5, + + # Category 7. + 'gitcli.txt' : 7, + 'gitcore-tutorial.txt' : 7, + 'gitcredentials.txt' : 7, + 'gitcvs-migration.txt' : 7, + 'gitdiffcore.txt' : 7, + 'giteveryday.txt' : 7, + 'gitfaq.txt' : 7, + 'gitglossary.txt' : 7, + 'gitpacking.txt' : 7, + 'gitnamespaces.txt' : 7, + 'gitremote-helpers.txt' : 7, + 'gitrevisions.txt' : 7, + 'gitsubmodules.txt' : 7, + 'gittutorial-2.txt' : 7, + 'gittutorial.txt' : 7, + 'gitworkflows.txt' : 7, +} + +asciidoc = find_program('asciidoc') +git = find_program('git', required: false) +xmlto = find_program('xmlto') + +asciidoc_conf = custom_target( + command: [ + shell, + meson.project_source_root() / 'GIT-VERSION-GEN', + meson.project_source_root(), + '@INPUT@', + '@OUTPUT@', + ], + input: meson.current_source_dir() / 'asciidoc.conf.in', + output: 'asciidoc.conf', + depends: [git_version_file], +) + +asciidoc_common_options = [ + asciidoc, + '--conf-file=' + asciidoc_conf.full_path(), + '--attribute=build_dir=' + meson.current_build_dir(), +] + +cmd_lists = [ + 'cmds-ancillaryinterrogators.txt', + 'cmds-ancillarymanipulators.txt', + 'cmds-mainporcelain.txt', + 'cmds-plumbinginterrogators.txt', + 'cmds-plumbingmanipulators.txt', + 'cmds-synchingrepositories.txt', + 'cmds-synchelpers.txt', + 'cmds-guide.txt', + 'cmds-developerinterfaces.txt', + 'cmds-userinterfaces.txt', + 'cmds-purehelpers.txt', + 'cmds-foreignscminterface.txt', +] + +documentation_deps = [ + asciidoc_conf, +] + +documentation_deps += custom_target( + command: [ + perl, + meson.current_source_dir() / 'cmd-list.perl', + meson.project_source_root(), + meson.current_build_dir(), + ] + cmd_lists, + output: cmd_lists +) + +foreach mode : [ 'diff', 'merge' ] + documentation_deps += custom_target( + command: [ + shell, + meson.current_source_dir() / 'generate-mergetool-list.sh', + '..', + 'diff', + '@OUTPUT@' + ], + env: [ + 'MERGE_TOOLS_DIR=' + meson.project_source_root() / 'mergetools', + 'TOOL_MODE=' + mode, + ], + output: 'mergetools-' + mode + '.txt', + ) +endforeach + +foreach manpage, category : manpages + if get_option('docs').contains('man') + manpage_xml_target = custom_target( + command: asciidoc_common_options + [ + '--backend=docbook', + '--doctype=manpage', + '--out-file=@OUTPUT@', + meson.current_source_dir() / manpage, + ], + depends: documentation_deps, + output: fs.stem(manpage) + '.xml', + ) + + manpage_path = fs.stem(manpage) + '.' + category.to_string() + manpage_target = custom_target( + command: [ + xmlto, + '-m', + meson.current_source_dir() / 'manpage-normal.xsl', + '-m', + meson.current_source_dir() / 'manpage-bold-literal.xsl', + '--stringparam', + 'man.base.url.for.relative.links=' + get_option('prefix') / get_option('mandir'), + 'man', + manpage_xml_target, + '-o', + meson.current_build_dir(), + ], + output: manpage_path, + install: true, + install_dir: get_option('mandir') / 'man' + category.to_string(), + ) + endif + + if get_option('docs').contains('html') and category == 1 + custom_target( + command: asciidoc_common_options + [ + '--backend=xhtml11', + '--doctype=manpage', + '--out-file=@OUTPUT@', + meson.current_source_dir() / manpage, + ], + depends: documentation_deps, + output: fs.stem(manpage) + '.html', + install: true, + install_dir: get_option('datadir') / 'doc/git-doc', + ) + endif +endforeach diff --git a/bin-wrappers/meson.build b/bin-wrappers/meson.build new file mode 100644 index 0000000000..8a4e910c9b --- /dev/null +++ b/bin-wrappers/meson.build @@ -0,0 +1,28 @@ +bin_wrappers_config = configuration_data() +foreach key, value : { + 'BUILD_DIR': meson.project_build_root(), + 'MERGE_TOOLS_DIR': meson.project_source_root() / 'mergetools', + 'TEMPLATE_DIR': meson.project_build_root() / 'templates', + 'GIT_TEXTDOMAINDIR': meson.project_build_root() / 'po', + 'GITPERLLIB': meson.project_build_root() / 'perl/lib', +} + # Paths need to be Unix-style without drive prefixes as they get added to the + # PATH variable. And given that drive prefixes contain a colon we'd otherwise + # end up with a broken PATH if we didn't convert them. + if cygpath.found() + value = run_command(cygpath, value, check: true).stdout().strip() + endif + bin_wrappers_config.set(key, value) +endforeach + +foreach executable : bin_wrappers + executable_config = configuration_data() + executable_config.merge_from(bin_wrappers_config) + executable_config.set('PROG', executable.full_path()) + + configure_file( + input: 'wrap-for-bin.sh', + output: fs.stem(executable.full_path()), + configuration: executable_config, + ) +endforeach diff --git a/contrib/completion/meson.build b/contrib/completion/meson.build new file mode 100644 index 0000000000..3a9ddab594 --- /dev/null +++ b/contrib/completion/meson.build @@ -0,0 +1,16 @@ +foreach script : [ + 'git-completion.bash', + 'git-completion.tcsh', + 'git-completion.zsh', + 'git-prompt.sh' +] + if meson.version().version_compare('>=1.3.0') + test_dependencies += fs.copyfile(script) + else + configure_file( + input: script, + output: script, + copy: true, + ) + endif +endforeach diff --git a/contrib/meson.build b/contrib/meson.build new file mode 100644 index 0000000000..a7b77b87c2 --- /dev/null +++ b/contrib/meson.build @@ -0,0 +1 @@ +subdir('completion') diff --git a/gitweb/meson.build b/gitweb/meson.build new file mode 100644 index 0000000000..89b403dc9d --- /dev/null +++ b/gitweb/meson.build @@ -0,0 +1,89 @@ +gitweb_config = configuration_data() +gitweb_config.set_quoted('PERL_PATH', perl.full_path()) +gitweb_config.set_quoted('CSSMIN', '') +gitweb_config.set_quoted('JSMIN', '') +gitweb_config.set_quoted('GIT_BINDIR', get_option('prefix') / get_option('bindir')) +gitweb_config.set_quoted('GITWEB_CONFIG', get_option('gitweb_config')) +gitweb_config.set_quoted('GITWEB_CONFIG_SYSTEM', get_option('gitweb_config_system')) +gitweb_config.set_quoted('GITWEB_CONFIG_COMMON', get_option('gitweb_config_common')) +gitweb_config.set_quoted('GITWEB_HOME_LINK_STR', get_option('gitweb_home_link_str')) +gitweb_config.set_quoted('GITWEB_SITENAME', get_option('gitweb_sitename')) +gitweb_config.set_quoted('GITWEB_PROJECTROOT', get_option('gitweb_projectroot')) +gitweb_config.set_quoted('GITWEB_PROJECT_MAXDEPTH', get_option('gitweb_project_maxdepth')) +gitweb_config.set_quoted('GITWEB_EXPORT_OK', get_option('gitweb_export_ok')) +gitweb_config.set_quoted('GITWEB_STRICT_EXPORT', get_option('gitweb_strict_export')) +gitweb_config.set_quoted('GITWEB_BASE_URL', get_option('gitweb_base_url')) +gitweb_config.set_quoted('GITWEB_LIST', get_option('gitweb_list')) +gitweb_config.set_quoted('GITWEB_HOMETEXT', get_option('gitweb_hometext')) +gitweb_config.set_quoted('GITWEB_CSS', get_option('gitweb_css')) +gitweb_config.set_quoted('GITWEB_LOGO', get_option('gitweb_logo')) +gitweb_config.set_quoted('GITWEB_FAVICON', get_option('gitweb_favicon')) +gitweb_config.set_quoted('GITWEB_JS', get_option('gitweb_js')) +gitweb_config.set_quoted('GITWEB_SITE_HTML_HEAD_STRING', get_option('gitweb_site_html_head_string')) +gitweb_config.set_quoted('GITWEB_SITE_HEADER', get_option('gitweb_site_header')) +gitweb_config.set_quoted('GITWEB_SITE_FOOTER', get_option('gitweb_site_footer')) +gitweb_config.set_quoted('HIGHLIGHT_BIN', get_option('highlight_bin')) + +configure_file( + input: 'GITWEB-BUILD-OPTIONS.in', + output: 'GITWEB-BUILD-OPTIONS', + configuration: gitweb_config, +) + +test_dependencies += custom_target( + input: 'gitweb.perl', + output: 'gitweb.cgi', + command: [ + shell, + meson.current_source_dir() / 'generate-gitweb-cgi.sh', + meson.current_build_dir() / 'GITWEB-BUILD-OPTIONS', + git_version_file.full_path(), + '@INPUT@', + '@OUTPUT@', + ], + install: true, + install_dir: get_option('datadir') / 'gitweb', + depends: [git_version_file], +) + +javascript_files = [ + meson.current_source_dir() / 'static/js/adjust-timezone.js', + meson.current_source_dir() / 'static/js/blame_incremental.js', + meson.current_source_dir() / 'static/js/javascript-detection.js', + meson.current_source_dir() / 'static/js/lib/common-lib.js', + meson.current_source_dir() / 'static/js/lib/cookies.js', + meson.current_source_dir() / 'static/js/lib/datetime.js', +] + +test_dependencies += custom_target( + input: javascript_files, + output: 'gitweb.js', + command: [ + shell, + meson.current_source_dir() / 'generate-gitweb-js.sh', + '@OUTPUT@', + ] + javascript_files, + install: true, + install_dir: get_option('datadir') / 'gitweb/static', +) + +foreach asset : [ + 'static/git-favicon.png', + 'static/git-logo.png', + 'static/gitweb.css', +] + if meson.version().version_compare('>=1.3.0') + fs.copyfile(asset, + install: true, + install_dir: get_option('datadir') / 'gitweb' / fs.parent(asset), + ) + else + configure_file( + input: asset, + output: fs.stem(asset), + copy: true, + install: true, + install_dir: get_option('datadir') / 'gitweb' / fs.parent(asset), + ) + endif +endforeach diff --git a/meson.build b/meson.build new file mode 100644 index 0000000000..0dccebcdf1 --- /dev/null +++ b/meson.build @@ -0,0 +1,1901 @@ +# Meson build system +# ================== +# +# The Meson build system is an alternative to our Makefile that you can use to +# build, test and install Git. Using Meson results in a couple of benefits: +# +# - Out-of-tree builds. +# - Better integration into IDEs. +# - Easy-to-use autoconfiguration of available features on your system. +# +# To use Meson from the command line you need to have both Meson and Ninja +# installed. Alternatively, if you do not have Python available on your system, +# you can also use Muon instead of Meson and Samurai instead of Ninja, both of +# which are drop-ins replacement that only depend on C. +# +# Basic usage +# =========== +# +# In the most trivial case, you can configure, build and install Git like this: +# +# 1. Set up the build directory. This only needs to happen once per build +# directory you want to have. You can also configure multiple different +# build directories with different configurations. +# +# $ meson setup build/ +# +# The build directory gets ignored by Git automatically as Meson will write +# a ".gitignore" file into it. From hereon, we will assume that you execute +# commands inside this build directory. +# +# 2. Compile Git. You can either use Meson, Ninja or Samurai to do this, so all +# of the following invocations are equivalent: +# +# $ meson compile +# $ ninja +# $ samu +# +# The different invocations should ultimately not make much of a difference. +# Using Meson also works with other generators though, like when the build +# directory has been set up for use with Microsoft Visual Studio. +# +# Ninja and Samurai use multiple jobs by default, scaling with the number of +# processor cores available. You can pass the `-jN` flag to change this. +# +# Meson automatically picks up ccache and sccache when these are installed +# when setting up the build directory. You can override this behaviour when +# setting up the build directory by setting the `CC` environment variable to +# your desired compiler. +# +# 3. Execute tests. Again, you can either use Meson, Ninja or Samurai to do this: +# +# $ meson test +# $ ninja test +# $ samu test +# +# It is recommended to use Meson in this case though as it also provides you +# additional features that the other build systems don't have available. +# You can e.g. pass additional arguments to the test executables or run +# individual tests: +# +# # Execute the t0000-basic integration test and t-reftable-stack unit test. +# $ meson test t0000-basic t-reftable-stack +# +# # Execute all reftable unit tests. +# $ meson test t-reftable-* +# +# # Execute all tests and stop with the first failure. +# $ meson test --maxfail 1 +# +# # Execute single test interactively such that features like `debug ()` work. +# $ meson test -i --test-args='-ix' t1400-update-ref +# +# Test execution is parallelized by default and scales with the number of +# processor cores available. You can change the number of processes by passing +# the `-jN` flag to `meson test`. +# +# 4. Install the Git distribution. Again, this can be done via Meson, Ninja or +# Samurai: +# +# $ meson install +# $ ninja install +# $ samu install +# +# The prefix into which Git shall be installed is defined when setting up +# the build directory. More on that in the "Configuration" section. +# +# Meson supports multiple backends. The default backend generates Ninja build +# instructions, but it also supports the generation of Microsoft Visual +# Studio solutions as well as Xcode projects by passing the `--backend` option +# to `meson setup`. IDEs like Eclipse and Visual Studio Code provide plugins to +# import Meson files directly. +# +# Configuration +# ============= +# +# The exact configuration of Git is determined when setting up the build +# directory via `meson setup`. Unless told otherwise, Meson will automatically +# detect the availability of various bits and pieces. There are two different +# kinds of options that can be used to further tweak the build: +# +# - Built-in options provided by Meson. +# +# - Options defined by the project in the "meson_options.txt" file. +# +# Both kinds of options can be inspected by running `meson configure` in the +# build directory, which will give you a list of the current value for all +# options. +# +# Options can be configured either when setting up the build directory or can +# be changed in preexisting build directories: +# +# # Set up a new build directory with optimized settings that will be +# # installed into an alternative prefix. +# $ meson setup --buildtype release --optimization 3 --strip --prefix=/home/$USER build +# +# # Set up a new build directory with a higher warning level. Level 2 is +# # mostly equivalent to setting DEVELOPER=1, level 3 and "everything" +# # will enable even more warnings. +# $ meson setup -Dwarning_level=2 build +# +# # Set up a new build directory with 'address' and 'undefined' sanitizers +# # using Clang. +# $ CC=clang meson setup -Db_sanitize=address,undefined build +# +# # Disable tests in a preexisting build directory. +# $ meson configure -Dtests=false +# +# # Disable features based on Python +# $ meson configure -Dpython=disabled +# +# Options have a type like booleans, choices, strings or features. Features are +# somewhat special as they can have one of three values: enabled, disabled or +# auto. While the first two values are self-explanatory, "auto" will enable or +# disable the feature based on the availability of prerequisites to support it. +# Python-based features for example will be enabled automatically when a Python +# interpreter could be found. The default value of such features can be changed +# via `meson setup --auto-features={enabled,disabled,auto}`, which will set the +# value of all features with a value of "auto" to the provided one by default. +# +# It is also possible to store a set of configuration options in machine files. +# This can be useful in case you regularly want to reuse the same set of options: +# +# [binaries] +# c = ['clang'] +# ar = ['ar'] +# +# [project options] +# gettext = 'disabled' +# default_editor = 'vim' +# +# [built-in options] +# b_lto = true +# b_sanitize = 'address,undefined' +# +# These machine files can be passed to `meson setup` via the `--native-file` +# option. +# +# Subproject wrappers +# =================== +# +# Subproject wrappers are a feature provided by Meson that allows the automatic +# fallback to a "wrapped" dependency in case the dependency is not provided by +# the system. For example if the system is lacking curl, then Meson will use +# "subprojects/curl.wrap" to set up curl as a subproject and compile and link +# the dependency into Git itself. This is especially helpful on systems like +# Windows, where you typically don't have such dependencies installed. +# +# The use of subproject wrappers can be disabled by executing `meson setup` +# with the `--wrap-mode nofallback` option. + +project('git', 'c', + meson_version: '>=0.61.0', + version: 'v2.47.GIT', +) + +fs = import('fs') + +program_path = [] +# Git for Windows provides all the tools we need to build Git. +if host_machine.system() == 'windows' + program_path += [ 'C:/Program Files/Git/bin', 'C:/Program Files/Git/usr/bin' ] +endif + +cygpath = find_program('cygpath', dirs: program_path, required: false) +diff = find_program('diff', dirs: program_path) +shell = find_program('sh', dirs: program_path) +tar = find_program('tar', dirs: program_path) + +script_environment = environment() +foreach tool : ['cat', 'cut', 'grep', 'sed', 'sort', 'tr', 'uname'] + program = find_program(tool, dirs: program_path) + script_environment.prepend('PATH', fs.parent(program.full_path())) +endforeach + +git = find_program('git', dirs: program_path, required: false) +if git.found() + script_environment.prepend('PATH', fs.parent(git.full_path())) +endif + +if get_option('sane_tool_path') != '' + script_environment.prepend('PATH', get_option('sane_tool_path')) +endif + +compiler = meson.get_compiler('c') + +libgit_sources = [ + 'abspath.c', + 'add-interactive.c', + 'add-patch.c', + 'advice.c', + 'alias.c', + 'alloc.c', + 'apply.c', + 'archive-tar.c', + 'archive-zip.c', + 'archive.c', + 'attr.c', + 'base85.c', + 'bisect.c', + 'blame.c', + 'blob.c', + 'bloom.c', + 'branch.c', + 'bulk-checkin.c', + 'bundle-uri.c', + 'bundle.c', + 'cache-tree.c', + 'cbtree.c', + 'chdir-notify.c', + 'checkout.c', + 'chunk-format.c', + 'color.c', + 'column.c', + 'combine-diff.c', + 'commit-graph.c', + 'commit-reach.c', + 'commit.c', + 'compat/nonblock.c', + 'compat/obstack.c', + 'compat/terminal.c', + 'compat/zlib-uncompress2.c', + 'config.c', + 'connect.c', + 'connected.c', + 'convert.c', + 'copy.c', + 'credential.c', + 'csum-file.c', + 'ctype.c', + 'date.c', + 'decorate.c', + 'delta-islands.c', + 'diagnose.c', + 'diff-delta.c', + 'diff-merges.c', + 'diff-lib.c', + 'diff-no-index.c', + 'diff.c', + 'diffcore-break.c', + 'diffcore-delta.c', + 'diffcore-order.c', + 'diffcore-pickaxe.c', + 'diffcore-rename.c', + 'diffcore-rotate.c', + 'dir-iterator.c', + 'dir.c', + 'editor.c', + 'entry.c', + 'environment.c', + 'ewah/bitmap.c', + 'ewah/ewah_bitmap.c', + 'ewah/ewah_io.c', + 'ewah/ewah_rlw.c', + 'exec-cmd.c', + 'fetch-negotiator.c', + 'fetch-pack.c', + 'fmt-merge-msg.c', + 'fsck.c', + 'fsmonitor.c', + 'fsmonitor-ipc.c', + 'fsmonitor-settings.c', + 'gettext.c', + 'git-zlib.c', + 'gpg-interface.c', + 'graph.c', + 'grep.c', + 'hash-lookup.c', + 'hashmap.c', + 'help.c', + 'hex.c', + 'hex-ll.c', + 'hook.c', + 'ident.c', + 'json-writer.c', + 'kwset.c', + 'levenshtein.c', + 'line-log.c', + 'line-range.c', + 'linear-assignment.c', + 'list-objects-filter-options.c', + 'list-objects-filter.c', + 'list-objects.c', + 'lockfile.c', + 'log-tree.c', + 'loose.c', + 'ls-refs.c', + 'mailinfo.c', + 'mailmap.c', + 'match-trees.c', + 'mem-pool.c', + 'merge-blobs.c', + 'merge-ll.c', + 'merge-ort.c', + 'merge-ort-wrappers.c', + 'merge-recursive.c', + 'merge.c', + 'midx.c', + 'midx-write.c', + 'name-hash.c', + 'negotiator/default.c', + 'negotiator/noop.c', + 'negotiator/skipping.c', + 'notes-cache.c', + 'notes-merge.c', + 'notes-utils.c', + 'notes.c', + 'object-file-convert.c', + 'object-file.c', + 'object-name.c', + 'object.c', + 'oid-array.c', + 'oidmap.c', + 'oidset.c', + 'oidtree.c', + 'pack-bitmap-write.c', + 'pack-bitmap.c', + 'pack-check.c', + 'pack-mtimes.c', + 'pack-objects.c', + 'pack-revindex.c', + 'pack-write.c', + 'packfile.c', + 'pager.c', + 'parallel-checkout.c', + 'parse.c', + 'parse-options-cb.c', + 'parse-options.c', + 'patch-delta.c', + 'patch-ids.c', + 'path.c', + 'pathspec.c', + 'pkt-line.c', + 'preload-index.c', + 'pretty.c', + 'prio-queue.c', + 'progress.c', + 'promisor-remote.c', + 'prompt.c', + 'protocol.c', + 'protocol-caps.c', + 'prune-packed.c', + 'pseudo-merge.c', + 'quote.c', + 'range-diff.c', + 'reachable.c', + 'read-cache.c', + 'rebase-interactive.c', + 'rebase.c', + 'ref-filter.c', + 'reflog-walk.c', + 'reflog.c', + 'refs.c', + 'refs/debug.c', + 'refs/files-backend.c', + 'refs/reftable-backend.c', + 'refs/iterator.c', + 'refs/packed-backend.c', + 'refs/ref-cache.c', + 'refspec.c', + 'reftable/basics.c', + 'reftable/error.c', + 'reftable/block.c', + 'reftable/blocksource.c', + 'reftable/iter.c', + 'reftable/merged.c', + 'reftable/pq.c', + 'reftable/reader.c', + 'reftable/record.c', + 'reftable/stack.c', + 'reftable/system.c', + 'reftable/tree.c', + 'reftable/writer.c', + 'remote.c', + 'replace-object.c', + 'repo-settings.c', + 'repository.c', + 'rerere.c', + 'reset.c', + 'resolve-undo.c', + 'revision.c', + 'run-command.c', + 'send-pack.c', + 'sequencer.c', + 'serve.c', + 'server-info.c', + 'setup.c', + 'shallow.c', + 'sideband.c', + 'sigchain.c', + 'sparse-index.c', + 'split-index.c', + 'stable-qsort.c', + 'statinfo.c', + 'strbuf.c', + 'streaming.c', + 'string-list.c', + 'strmap.c', + 'strvec.c', + 'sub-process.c', + 'submodule-config.c', + 'submodule.c', + 'symlinks.c', + 'tag.c', + 'tempfile.c', + 'thread-utils.c', + 'tmp-objdir.c', + 'trace.c', + 'trace2.c', + 'trace2/tr2_cfg.c', + 'trace2/tr2_cmd_name.c', + 'trace2/tr2_ctr.c', + 'trace2/tr2_dst.c', + 'trace2/tr2_sid.c', + 'trace2/tr2_sysenv.c', + 'trace2/tr2_tbuf.c', + 'trace2/tr2_tgt_event.c', + 'trace2/tr2_tgt_normal.c', + 'trace2/tr2_tgt_perf.c', + 'trace2/tr2_tls.c', + 'trace2/tr2_tmr.c', + 'trailer.c', + 'transport-helper.c', + 'transport.c', + 'tree-diff.c', + 'tree-walk.c', + 'tree.c', + 'unpack-trees.c', + 'upload-pack.c', + 'url.c', + 'urlmatch.c', + 'usage.c', + 'userdiff.c', + 'utf8.c', + 'varint.c', + 'versioncmp.c', + 'walker.c', + 'wildmatch.c', + 'worktree.c', + 'wrapper.c', + 'write-or-die.c', + 'ws.c', + 'wt-status.c', + 'xdiff-interface.c', + 'xdiff/xdiffi.c', + 'xdiff/xemit.c', + 'xdiff/xhistogram.c', + 'xdiff/xmerge.c', + 'xdiff/xpatience.c', + 'xdiff/xprepare.c', + 'xdiff/xutils.c', +] + +builtin_sources = [ + 'builtin/add.c', + 'builtin/am.c', + 'builtin/annotate.c', + 'builtin/apply.c', + 'builtin/archive.c', + 'builtin/bisect.c', + 'builtin/blame.c', + 'builtin/branch.c', + 'builtin/bugreport.c', + 'builtin/bundle.c', + 'builtin/cat-file.c', + 'builtin/check-attr.c', + 'builtin/check-ignore.c', + 'builtin/check-mailmap.c', + 'builtin/check-ref-format.c', + 'builtin/checkout--worker.c', + 'builtin/checkout-index.c', + 'builtin/checkout.c', + 'builtin/clean.c', + 'builtin/clone.c', + 'builtin/column.c', + 'builtin/commit-graph.c', + 'builtin/commit-tree.c', + 'builtin/commit.c', + 'builtin/config.c', + 'builtin/count-objects.c', + 'builtin/credential-cache--daemon.c', + 'builtin/credential-cache.c', + 'builtin/credential-store.c', + 'builtin/credential.c', + 'builtin/describe.c', + 'builtin/diagnose.c', + 'builtin/diff-files.c', + 'builtin/diff-index.c', + 'builtin/diff-tree.c', + 'builtin/diff.c', + 'builtin/difftool.c', + 'builtin/fast-export.c', + 'builtin/fast-import.c', + 'builtin/fetch-pack.c', + 'builtin/fetch.c', + 'builtin/fmt-merge-msg.c', + 'builtin/for-each-ref.c', + 'builtin/for-each-repo.c', + 'builtin/fsck.c', + 'builtin/fsmonitor--daemon.c', + 'builtin/gc.c', + 'builtin/get-tar-commit-id.c', + 'builtin/grep.c', + 'builtin/hash-object.c', + 'builtin/help.c', + 'builtin/hook.c', + 'builtin/index-pack.c', + 'builtin/init-db.c', + 'builtin/interpret-trailers.c', + 'builtin/log.c', + 'builtin/ls-files.c', + 'builtin/ls-remote.c', + 'builtin/ls-tree.c', + 'builtin/mailinfo.c', + 'builtin/mailsplit.c', + 'builtin/merge-base.c', + 'builtin/merge-file.c', + 'builtin/merge-index.c', + 'builtin/merge-ours.c', + 'builtin/merge-recursive.c', + 'builtin/merge-tree.c', + 'builtin/merge.c', + 'builtin/mktag.c', + 'builtin/mktree.c', + 'builtin/multi-pack-index.c', + 'builtin/mv.c', + 'builtin/name-rev.c', + 'builtin/notes.c', + 'builtin/pack-objects.c', + 'builtin/pack-redundant.c', + 'builtin/pack-refs.c', + 'builtin/patch-id.c', + 'builtin/prune-packed.c', + 'builtin/prune.c', + 'builtin/pull.c', + 'builtin/push.c', + 'builtin/range-diff.c', + 'builtin/read-tree.c', + 'builtin/rebase.c', + 'builtin/receive-pack.c', + 'builtin/reflog.c', + 'builtin/refs.c', + 'builtin/remote-ext.c', + 'builtin/remote-fd.c', + 'builtin/remote.c', + 'builtin/repack.c', + 'builtin/replace.c', + 'builtin/replay.c', + 'builtin/rerere.c', + 'builtin/reset.c', + 'builtin/rev-list.c', + 'builtin/rev-parse.c', + 'builtin/revert.c', + 'builtin/rm.c', + 'builtin/send-pack.c', + 'builtin/shortlog.c', + 'builtin/show-branch.c', + 'builtin/show-index.c', + 'builtin/show-ref.c', + 'builtin/sparse-checkout.c', + 'builtin/stash.c', + 'builtin/stripspace.c', + 'builtin/submodule--helper.c', + 'builtin/symbolic-ref.c', + 'builtin/tag.c', + 'builtin/unpack-file.c', + 'builtin/unpack-objects.c', + 'builtin/update-index.c', + 'builtin/update-ref.c', + 'builtin/update-server-info.c', + 'builtin/upload-archive.c', + 'builtin/upload-pack.c', + 'builtin/var.c', + 'builtin/verify-commit.c', + 'builtin/verify-pack.c', + 'builtin/verify-tag.c', + 'builtin/worktree.c', + 'builtin/write-tree.c', +] + +libgit_sources += custom_target( + input: 'command-list.txt', + output: 'command-list.h', + command: [shell, meson.current_source_dir() + '/generate-cmdlist.sh', meson.current_source_dir(), '@OUTPUT@'], + env: script_environment, +) + +libgit_sources += custom_target( + output: 'config-list.h', + command: [ + shell, + meson.current_source_dir() + '/generate-configlist.sh', + meson.current_source_dir(), + '@OUTPUT@', + ], + env: script_environment, +) + +libgit_sources += custom_target( + input: 'Documentation/githooks.txt', + output: 'hook-list.h', + command: [ + shell, + meson.current_source_dir() + '/generate-hooklist.sh', + meson.current_source_dir(), + '@OUTPUT@', + ], + env: script_environment, +) + +# This contains the variables for GIT-BUILD-OPTIONS, which we use to propagate +# build options to our tests. +build_options_config = configuration_data() +build_options_config.set('GIT_INTEROP_MAKE_OPTS', '') +build_options_config.set('GIT_PERF_LARGE_REPO', '') +build_options_config.set('GIT_PERF_MAKE_COMMAND', '') +build_options_config.set('GIT_PERF_MAKE_OPTS', '') +build_options_config.set('GIT_PERF_REPEAT_COUNT', '') +build_options_config.set('GIT_PERF_REPO', '') +build_options_config.set('GIT_TEST_CMP_USE_COPIED_CONTEXT', '') +build_options_config.set('GIT_TEST_INDEX_VERSION', '') +build_options_config.set('GIT_TEST_OPTS', '') +build_options_config.set('GIT_TEST_PERL_FATAL_WARNINGS', '') +build_options_config.set('GIT_TEST_UTF8_LOCALE', '') +build_options_config.set_quoted('LOCALEDIR', fs.as_posix(get_option('prefix') / get_option('localedir'))) +build_options_config.set('GITWEBDIR', fs.as_posix(get_option('prefix') / get_option('datadir') / 'gitweb')) + +if get_option('sane_tool_path') != '' + build_options_config.set_quoted('BROKEN_PATH_FIX', 's|^\# @BROKEN_PATH_FIX@$|git_broken_path_fix "' + get_option('sane_tool_path') + '"|') +else + build_options_config.set_quoted('BROKEN_PATH_FIX', '/^\# @BROKEN_PATH_FIX@$/d') +endif + +test_output_directory = get_option('test_output_directory') +if test_output_directory == '' + test_output_directory = meson.project_build_root() / 'test-output' +endif + +# These variables are used for building libgit.a. +libgit_c_args = [ + '-DBINDIR="' + get_option('bindir') + '"', + '-DDEFAULT_EDITOR="' + get_option('default_editor') + '"', + '-DDEFAULT_GIT_TEMPLATE_DIR="' + get_option('datadir') / 'git-core/templates' + '"', + '-DDEFAULT_HELP_FORMAT="' + get_option('default_help_format') + '"', + '-DDEFAULT_PAGER="' + get_option('default_pager') + '"', + '-DETC_GITATTRIBUTES="' + get_option('gitattributes') + '"', + '-DETC_GITCONFIG="' + get_option('gitconfig') + '"', + '-DFALLBACK_RUNTIME_PREFIX="' + get_option('prefix') + '"', + '-DGIT_EXEC_PATH="' + get_option('prefix') / get_option('libexecdir') / 'git-core"', + '-DGIT_HOST_CPU="' + host_machine.cpu_family() + '"', + '-DGIT_HTML_PATH="' + get_option('datadir') / 'doc/git-doc"', + '-DGIT_INFO_PATH="' + get_option('infodir') + '"', + '-DGIT_LOCALE_PATH="' + get_option('localedir') + '"', + '-DGIT_MAN_PATH="' + get_option('mandir') + '"', + '-DPAGER_ENV="' + get_option('pager_environment') + '"', + '-DSHELL_PATH="' + fs.as_posix(shell.full_path()) + '"', +] +libgit_include_directories = [ '.' ] +libgit_dependencies = [ ] + +# Treat any warning level above 1 the same as we treat DEVELOPER=1 in our +# Makefile. +if get_option('warning_level') in ['2','3', 'everything'] and compiler.get_argument_syntax() == 'gcc' + foreach cflag : [ + '-Wdeclaration-after-statement', + '-Wformat-security', + '-Wold-style-definition', + '-Woverflow', + '-Wpointer-arith', + '-Wstrict-prototypes', + '-Wunused', + '-Wvla', + '-Wwrite-strings', + '-fno-common', + '-Wtautological-constant-out-of-range-compare', + # If a function is public, there should be a prototype and the right + # header file should be included. If not, it should be static. + '-Wmissing-prototypes', + # These are disabled because we have these all over the place. + '-Wno-empty-body', + '-Wno-missing-field-initializers', + '-Wno-sign-compare', + ] + if compiler.has_argument(cflag) + libgit_c_args += cflag + endif + endforeach +endif + +if get_option('b_sanitize').contains('address') + build_options_config.set('SANITIZE_ADDRESS', 'YesCompiledWithIt') +else + build_options_config.set('SANITIZE_ADDRESS', '') +endif +if get_option('b_sanitize').contains('leak') + libgit_c_args += '-DSUPPRESS_ANNOTATED_LEAKS' + build_options_config.set('SANITIZE_LEAK', 'YesCompiledWithIt') +else + build_options_config.set('SANITIZE_LEAK', '') +endif +if get_option('b_sanitize').contains('undefined') + libgit_c_args += '-DSHA1DC_FORCE_ALIGNED_ACCESS' +endif + +executable_suffix = '' +if host_machine.system() == 'cygwin' or host_machine.system() == 'windows' + executable_suffix = '.exe' + libgit_c_args += '-DSTRIP_EXTENSION="' + executable_suffix + '"' +endif +build_options_config.set_quoted('X', executable_suffix) + +python = import('python').find_installation('python3', required: get_option('python')) +if python.found() + build_options_config.set('NO_PYTHON', '') +else + libgit_c_args += '-DNO_PYTHON' + build_options_config.set('NO_PYTHON', '1') +endif + +# Perl is used for two different things: our test harness and to provide some +# features. It is optional if you want to neither execute tests nor use any of +# these optional features. +perl_required = get_option('perl') +if get_option('tests') + perl_required = true +endif + +# Note that we only set NO_PERL if the Perl features were disabled by the user. +# It may not be set when we have found Perl, but only use it to run tests. +perl = find_program('perl', version: '>=5.8.1', dirs: program_path, required: perl_required) +perl_features_enabled = perl.found() and get_option('perl').allowed() +if perl_features_enabled + build_options_config.set('NO_PERL', '') + + if get_option('runtime_prefix') + build_options_config.set('PERL_LOCALEDIR', '') + else + build_options_config.set_quoted('PERL_LOCALEDIR', fs.as_posix(get_option('prefix') / get_option('localedir'))) + endif + + if get_option('perl_cpan_fallback') + build_options_config.set('NO_PERL_CPAN_FALLBACKS', '') + else + build_options_config.set_quoted('NO_PERL_CPAN_FALLBACKS', 'YesPlease') + endif +else + libgit_c_args += '-DNO_PERL' + build_options_config.set('NO_PERL', '1') + build_options_config.set('PERL_LOCALEDIR', '') + build_options_config.set('NO_PERL_CPAN_FALLBACKS', '') +endif + +zlib = dependency('zlib', default_options: ['default_library=static', 'tests=disabled']) +if zlib.version().version_compare('<1.2.0') + libgit_c_args += '-DNO_DEFLATE_BOUND' +endif +libgit_dependencies += zlib + +threads = dependency('threads', required: false) +if threads.found() + libgit_dependencies += threads + build_options_config.set('NO_PTHREADS', '') +else + libgit_c_args += '-DNO_PTHREADS' + build_options_config.set('NO_PTHREADS', '1') +endif + +msgfmt = find_program('msgfmt', dirs: program_path, required: false) +gettext_option = get_option('gettext').disable_auto_if(not msgfmt.found()) +if not msgfmt.found() and gettext_option.enabled() + error('Internationalization via libintl requires msgfmt') +endif + +if gettext_option.allowed() and host_machine.system() == 'darwin' and get_option('macos_use_homebrew_gettext') + if host_machine.cpu_family() == 'x86_64' + libintl_prefix = '/usr/local' + elif host_machine.cpu_family() == 'aarch64' + libintl_prefix = '/opt/homebrew' + else + error('Homebrew workaround not supported on current architecture') + endif + + intl = compiler.find_library('intl', dirs: libintl_prefix / 'lib', required: gettext_option) + if intl.found() + intl = declare_dependency( + dependencies: intl, + include_directories: libintl_prefix / 'include', + ) + endif +else + intl = dependency('intl', required: gettext_option) +endif +if intl.found() + libgit_dependencies += intl + build_options_config.set('NO_GETTEXT', '') + build_options_config.set('USE_GETTEXT_SCHEME', '') + + # POSIX nowadays requires `nl_langinfo()`, but some systems still don't have + # the function available. On such systems we instead fall back to libcharset. + # On native Windows systems we use our own emulation. + if host_machine.system() != 'windows' and not compiler.has_function('nl_langinfo') + libcharset = compiler.find_library('charset', required: true) + libgit_dependencies += libcharset + libgit_c_args += '-DHAVE_LIBCHARSET_H' + endif +else + libgit_c_args += '-DNO_GETTEXT' + build_options_config.set('NO_GETTEXT', '1') + build_options_config.set('USE_GETTEXT_SCHEME', 'fallthrough') +endif + +iconv = dependency('iconv', required: get_option('iconv')) +if iconv.found() + libgit_dependencies += iconv + build_options_config.set('NO_ICONV', '') + + have_old_iconv = false + if not compiler.compiles(''' + #include + + extern size_t iconv(iconv_t cd, + char **inbuf, size_t *inbytesleft, + char **outbuf, size_t *outbytesleft); + ''', name: 'old iconv interface', dependencies: [iconv]) + libgit_c_args += '-DOLD_ICONV' + have_old_iconv = true + endif + + iconv_omits_bom_source = '''# + #include + + int main(int argc, const char **argv) + { + ''' + if have_old_iconv + iconv_omits_bom_source += ''' + typedef const char *iconv_ibp; + ''' + else + iconv_omits_bom_source += ''' + typedef char *iconv_ibp; + ''' + endif + iconv_omits_bom_source += ''' + int v; + iconv_t conv; + char in[] = "a"; iconv_ibp pin = in; + char out[20] = ""; char *pout = out; + size_t isz = sizeof in; + size_t osz = sizeof out; + + conv = iconv_open("UTF-16", "UTF-8"); + iconv(conv, &pin, &isz, &pout, &osz); + iconv_close(conv); + v = (unsigned char)(out[0]) + (unsigned char)(out[1]); + return v != 0xfe + 0xff; + } + ''' + + if compiler.run(iconv_omits_bom_source, + dependencies: iconv, + name: 'iconv omits BOM', + ).returncode() != 0 + libgit_c_args += '-DICONV_OMITS_BOM' + endif +else + libgit_c_args += '-DNO_ICONV' + build_options_config.set('NO_ICONV', '1') +endif + +pcre2 = dependency('libpcre2-8', required: get_option('pcre2'), default_options: ['default_library=static', 'test=false']) +if pcre2.found() + libgit_dependencies += pcre2 + libgit_c_args += '-DUSE_LIBPCRE2' + build_options_config.set('USE_LIBPCRE2', '1') +else + build_options_config.set('USE_LIBPCRE2', '') +endif + +curl = dependency('libcurl', version: '>=7.21.3', required: get_option('curl'), default_options: ['default_library=static', 'tests=disabled', 'tool=disabled']) +use_curl_for_imap_send = false +if curl.found() + if curl.version().version_compare('>=7.34.0') + libgit_c_args += '-DUSE_CURL_FOR_IMAP_SEND' + use_curl_for_imap_send = true + endif + + libgit_dependencies += curl + libgit_c_args += '-DCURL_DISABLE_TYPECHECK' + build_options_config.set('NO_CURL', '') +else + libgit_c_args += '-DNO_CURL' + build_options_config.set('NO_CURL', '1') +endif + +expat = dependency('expat', required: get_option('expat'), default_options: ['default_library=static', 'build_tests=false']) +if expat.found() + libgit_dependencies += expat + + if expat.version().version_compare('<=1.2') + libgit_c_args += '-DEXPAT_NEEDS_XMLPARSE_H' + endif + build_options_config.set('NO_EXPAT', '') +else + libgit_c_args += '-DNO_EXPAT' + build_options_config.set('NO_EXPAT', '1') +endif + +if not compiler.has_header('sys/select.h') + libgit_c_args += '-DNO_SYS_SELECT_H' +endif + +has_poll_h = compiler.has_header('poll.h') +if not has_poll_h + libgit_c_args += '-DNO_POLL_H' +endif + +has_sys_poll_h = compiler.has_header('sys/poll.h') +if not has_sys_poll_h + libgit_c_args += '-DNO_SYS_POLL_H' +endif + +if not has_poll_h and not has_sys_poll_h + libgit_c_args += '-DNO_POLL' + libgit_sources += 'compat/poll/poll.c' + libgit_include_directories += 'compat/poll' +endif + +if not compiler.has_header('inttypes.h') + libgit_c_args += '-DNO_INTTYPES_H' +endif + +if compiler.has_header('alloca.h') + libgit_c_args += '-DHAVE_ALLOCA_H' +endif + +if compiler.has_header('sys/sysinfo.h') + libgit_c_args += '-DHAVE_SYSINFO' +endif + +# Windows has libgen.h and a basename implementation, but we still need our own +# implementation to threat things like drive prefixes specially. +if host_machine.system() == 'windows' or not compiler.has_header('libgen.h') + libgit_c_args += '-DNO_LIBGEN_H' + libgit_sources += 'compat/basename.c' +endif + +if compiler.has_header('paths.h') + libgit_c_args += '-DHAVE_PATHS_H' +endif + +if compiler.has_header('strings.h') + libgit_c_args += '-DHAVE_STRINGS_H' +endif + +networking_dependencies = [ ] +if host_machine.system() == 'windows' + winsock = compiler.find_library('ws2_32', required: false) + if winsock.found() + networking_dependencies += winsock + endif +else + libresolv = compiler.find_library('resolv', required: false) + if libresolv.found() + networking_dependencies += libresolv + endif +endif +libgit_dependencies += networking_dependencies + +foreach symbol : ['inet_ntop', 'inet_pton', 'strerror'] + if not compiler.has_function(symbol, dependencies: networking_dependencies) + libgit_c_args += '-DNO_' + symbol.to_upper() + endif +endforeach + +has_ipv6 = compiler.has_function('getaddrinfo', dependencies: networking_dependencies) +if not has_ipv6 + libgit_c_args += '-DNO_IPV6' +endif + +if not compiler.compiles(''' + #ifdef _WIN32 + # include + #else + # include + # include + #endif + + void func(void) + { + struct sockaddr_storage x; + } +''', name: 'struct sockaddr_storage') + if has_ipv6 + libgit_c_args += '-Dsockaddr_storage=sockaddr_in6' + else + libgit_c_args += '-Dsockaddr_storage=sockaddr_in' + endif +endif + +if compiler.has_function('socket', dependencies: networking_dependencies) + libgit_sources += [ + 'unix-socket.c', + 'unix-stream-server.c', + ] + build_options_config.set('NO_UNIX_SOCKETS', '') +else + libgit_c_args += '-DNO_UNIX_SOCKETS' + build_options_config.set('NO_UNIX_SOCKETS', '1') +endif + +if not compiler.has_function('pread') + libgit_c_args += '-DNO_PREAD' + libgit_sources += 'compat/pread.c' +endif + +if host_machine.system() == 'darwin' + libgit_sources += 'compat/precompose_utf8.c' + libgit_c_args += '-DPRECOMPOSE_UNICODE' + libgit_c_args += '-DPROTECT_HFS_DEFAULT' +endif + +# Configure general compatibility wrappers. +if host_machine.system() == 'cygwin' + libgit_sources += [ + 'compat/win32/path-utils.c', + ] +elif host_machine.system() == 'windows' + libgit_sources += [ + 'compat/mingw.c', + 'compat/winansi.c', + 'compat/win32/flush.c', + 'compat/win32/path-utils.c', + 'compat/win32/pthread.c', + 'compat/win32/syslog.c', + 'compat/win32/dirent.c', + 'compat/win32mmap.c', + 'compat/nedmalloc/nedmalloc.c', + ] + + libgit_c_args += [ + '-DDETECT_MSYS_TTY', + '-DENSURE_MSYSTEM_IS_SET', + '-DNATIVE_CRLF', + '-DNOGDI', + '-DNO_POSIX_GOODIES', + '-DWIN32', + '-D_CONSOLE', + '-D_CONSOLE_DETECT_MSYS_TTY', + '-D__USE_MINGW_ANSI_STDIO=0', + ] + + libgit_dependencies += compiler.find_library('ntdll') + libgit_include_directories += 'compat/win32' + if compiler.get_id() == 'msvc' + libgit_include_directories += 'compat/vcbuild/include' + endif +endif + +if host_machine.system() == 'linux' + libgit_sources += 'compat/linux/procinfo.c' +elif host_machine.system() == 'windows' + libgit_sources += 'compat/win32/trace2_win32_process_info.c' +else + libgit_sources += 'compat/stub/procinfo.c' +endif + +if host_machine.system() == 'cygwin' or host_machine.system() == 'windows' + libgit_c_args += [ + '-DUNRELIABLE_FSTAT', + '-DMMAP_PREVENTS_DELETE', + '-DOBJECT_CREATION_MODE=1', + ] +endif + +# Configure the simple-ipc subsystem required fro the fsmonitor. +if host_machine.system() == 'windows' + libgit_sources += [ + 'compat/simple-ipc/ipc-shared.c', + 'compat/simple-ipc/ipc-win32.c', + ] + libgit_c_args += '-DSUPPORTS_SIMPLE_IPC' +else + libgit_sources += [ + 'compat/simple-ipc/ipc-shared.c', + 'compat/simple-ipc/ipc-unix-socket.c', + ] + libgit_c_args += '-DSUPPORTS_SIMPLE_IPC' +endif + +fsmonitor_backend = '' +if host_machine.system() == 'windows' + fsmonitor_backend = 'win32' +elif host_machine.system() == 'darwin' + fsmonitor_backend = 'darwin' + libgit_dependencies += dependency('CoreServices') +endif +if fsmonitor_backend != '' + libgit_c_args += '-DHAVE_FSMONITOR_DAEMON_BACKEND' + libgit_c_args += '-DHAVE_FSMONITOR_OS_SETTINGS' + + libgit_sources += [ + 'compat/fsmonitor/fsm-health-' + fsmonitor_backend + '.c', + 'compat/fsmonitor/fsm-ipc-' + fsmonitor_backend + '.c', + 'compat/fsmonitor/fsm-listen-' + fsmonitor_backend + '.c', + 'compat/fsmonitor/fsm-path-utils-' + fsmonitor_backend + '.c', + 'compat/fsmonitor/fsm-settings-' + fsmonitor_backend + '.c', + ] +endif +build_options_config.set_quoted('FSMONITOR_DAEMON_BACKEND', fsmonitor_backend) +build_options_config.set_quoted('FSMONITOR_OS_SETTINGS', fsmonitor_backend) + +if not get_option('b_sanitize').contains('address') and get_option('regex').allowed() and compiler.has_header('regex.h') and compiler.get_define('REG_STARTEND', prefix: '#include ') != '' + build_options_config.set('NO_REGEX', '') + + if compiler.get_define('REG_ENHANCED', prefix: '#include ') != '' + libgit_c_args += '-DUSE_ENHANCED_BASIC_REGULAR_EXPRESSIONS' + libgit_sources += 'compat/regcomp_enhanced.c' + endif +elif not get_option('regex').enabled() + libgit_c_args += [ + '-DNO_REGEX', + '-DGAWK', + '-DNO_MBSUPPORT', + ] + build_options_config.set('NO_REGEX', '1') + libgit_sources += 'compat/regex/regex.c' + libgit_include_directories += 'compat/regex' +else + error('Native regex support requested but not found') +endif + +# setitimer and friends are provided by compat/mingw.c. +if host_machine.system() != 'windows' + if not compiler.compiles(''' + #include + void func(void) + { + struct itimerval value; + } + ''', name: 'struct itimerval') + libgit_c_args += '-DNO_STRUCT_ITIMERVAL' + libgit_c_args += '-DNO_SETITIMER' + elif not compiler.has_function('setitimer') + libgit_c_args += '-DNO_SETITIMER' + endif +endif + +if compiler.has_member('struct stat', 'st_mtimespec.tv_nsec', prefix: '#include ') + libgit_c_args += '-DUSE_ST_TIMESPEC' +elif not compiler.has_member('struct stat', 'st_mtim.tv_nsec', prefix: '#include ') + libgit_c_args += '-DNO_NSEC' +endif + +if not compiler.has_member('struct stat', 'st_blocks', prefix: '#include ') + libgit_c_args += '-DNO_ST_BLOCKS_IN_STRUCT_STAT' +endif + +if not compiler.has_member('struct dirent', 'd_type', prefix: '#include ') + libgit_c_args += '-DNO_D_TYPE_IN_DIRENT' +endif + +if not compiler.has_member('struct passwd', 'pw_gecos', prefix: '#include ') + libgit_c_args += '-DNO_GECOS_IN_PWENT' +endif + +if compiler.has_function('sync_file_range') + libgit_c_args += '-DHAVE_SYNC_FILE_RANGE' +endif + +if not compiler.has_function('strcasestr') + libgit_c_args += '-DNO_STRCASESTR' + libgit_sources += 'compat/strcasestr.c' +endif + +if not compiler.has_function('memmem') + libgit_c_args += '-DNO_MEMMEM' + libgit_sources += 'compat/memmem.c' +endif + +if not compiler.has_function('strlcpy') + libgit_c_args += '-DNO_STRLCPY' + libgit_sources += 'compat/strlcpy.c' +endif + +if not compiler.has_function('strdup') + libgit_c_args += '-DOVERRIDE_STRDUP' + libgit_sources += 'compat/strdup.c' +endif + +if not compiler.has_function('strtoumax') + libgit_c_args += '-DNO_STRTOUMAX' + libgit_sources += [ + 'compat/strtoumax.c', + 'compat/strtoimax.c', + ] +endif + +if not compiler.has_function('strtoull') + libgit_c_args += '-DNO_STRTOULL' +endif + +if not compiler.has_function('setenv') + libgit_c_args += '-DNO_SETENV' + libgit_sources += 'compat/setenv.c' +endif + +if not compiler.has_function('qsort') + libgit_c_args += '-DINTERNAL_QSORT' +endif +libgit_sources += 'compat/qsort_s.c' + +# unsetenv is provided by compat/mingw.c. +if host_machine.system() != 'windows' and not compiler.has_function('unsetenv') + libgit_c_args += '-DNO_UNSETENV' + libgit_sources += 'compat/unsetenv.c' +endif + +if not compiler.has_function('mkdtemp') + libgit_c_args += '-DNO_MKDTEMP' + libgit_sources += 'compat/mkdtemp.c' +endif + +if not compiler.has_function('initgroups') + libgit_c_args += '-DNO_INITGROUPS' +endif + +if compiler.has_function('getdelim') + libgit_c_args += '-DHAVE_GETDELIM' +endif + +if host_machine.system() == 'windows' + libgit_c_args += '-DUSE_WIN32_MMAP' +elif not compiler.has_function('mmap') + libgit_c_args += '-DNO_MMAP' + libgit_sources += 'compat/mmap.c' +endif + +if compiler.has_function('clock_gettime') + libgit_c_args += '-DHAVE_CLOCK_GETTIME' +endif + +if compiler.compiles(''' + #include + + void func(void) + { + clockid_t id = CLOCK_MONOTONIC; + } +''', name: 'monotonic clock') + libgit_c_args += '-DHAVE_CLOCK_MONOTONIC' +endif + +if not compiler.compiles(''' + #include + + void func(void) + { + uintmax_t x = 0; + } +''', name: 'uintmax_t') + libgit_c_args += '-DNO_UINTMAX_T' +endif + +has_bsd_sysctl = false +if compiler.has_header('sys/sysctl.h') + if compiler.compiles(''' + #include + #include + + void func(void) + { + int val, mib[2] = { 0 }; + size_t len = sizeof(val); + sysctl(mib, 2, &val, &len, NULL, 0); + } + ''', name: 'BSD sysctl') + libgit_c_args += '-DHAVE_BSD_SYSCTL' + has_bsd_sysctl = true + endif +endif + +if not meson.is_cross_build() and compiler.run(''' + #include + + int main(int argc, const char **argv) + { + FILE *f = fopen(".", "r"); + return f ? 0 : 1; + } +''', name: 'fread reads directories').returncode() == 0 + libgit_c_args += '-DFREAD_READS_DIRECTORIES' + libgit_sources += 'compat/fopen.c' +endif + +if not meson.is_cross_build() and fs.exists('/dev/tty') + libgit_c_args += '-DHAVE_DEV_TTY' +endif + +https_backend = get_option('https_backend') + +security_framework = dependency('Security', required: https_backend == 'CommonCrypto') +core_foundation_framework = dependency('CoreFoundation', required: security_framework.found()) +if https_backend == 'auto' and security_framework.found() + https_backend = 'CommonCrypto' +endif + +openssl_required = https_backend == 'openssl' or get_option('sha1_backend') == 'openssl' or get_option('sha256_backend') == 'openssl' +openssl = dependency('openssl', required: openssl_required, default_options: ['default_library=static']) +if https_backend == 'auto' and openssl.found() + https_backend = 'openssl' +endif + +if https_backend == 'CommonCrypto' + libgit_dependencies += security_framework + libgit_dependencies += core_foundation_framework + libgit_c_args += '-DAPPLE_COMMON_CRYPTO' +elif https_backend == 'openssl' + libgit_dependencies += openssl +else + # We either couldn't find any dependencies with 'auto' or the user requested + # 'none'. Both cases are benign. +endif + +if https_backend != 'openssl' + libgit_c_args += '-DNO_OPENSSL' +endif + +sha1_backend = get_option('sha1_backend') +if sha1_backend == 'sha1dc' + libgit_c_args += '-DSHA1_DC' + libgit_c_args += '-DSHA1DC_NO_STANDARD_INCLUDES=1' + libgit_c_args += '-DSHA1DC_INIT_SAFE_HASH_DEFAULT=0' + libgit_c_args += '-DSHA1DC_CUSTOM_INCLUDE_SHA1_C="git-compat-util.h"' + libgit_c_args += '-DSHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C="git-compat-util.h"' + + libgit_sources += [ + 'sha1dc_git.c', + 'sha1dc/sha1.c', + 'sha1dc/ubc_check.c', + ] +elif sha1_backend == 'common-crypto' + libgit_c_args += '-DCOMMON_DIGEST_FOR_OPENSSL' + libgit_c_args += '-DSHA1_APPLE' + # Apple CommonCrypto requires chunking + libgit_c_args += '-DSHA1_MAX_BLOCK_SIZE=1024L*1024L*1024L' +elif sha1_backend == 'openssl' + libgit_c_args += '-DSHA1_OPENSSL' + libgit_dependencies += openssl +elif sha1_backend == 'block' + libgit_c_args += '-DSHA1_BLK' + libgit_sources += 'block-sha1/sha1.c' +else + error('Unhandled SHA1 backend ' + sha1_backend) +endif + +sha256_backend = get_option('sha256_backend') +if sha256_backend == 'openssl' + libgit_c_args += '-DSHA256_OPENSSL' + libgit_dependencies += openssl +elif sha256_backend == 'nettle' + nettle = dependency('nettle') + libgit_dependencies += nettle + libgit_c_args += '-DSHA256_NETTLE' +elif sha256_backend == 'gcrypt' + gcrypt = dependency('gcrypt') + libgit_dependencies += gcrypt + libgit_c_args += '-DSHA256_GCRYPT' +elif sha256_backend == 'block' + libgit_c_args += '-DSHA256_BLK' + libgit_sources += 'sha256/block/sha256.c' +else + error('Unhandled SHA256 backend ' + sha256_backend) +endif + +if compiler.has_header_symbol('stdlib.h', 'arc4random_buf') + libgit_c_args += '-DHAVE_ARC4RANDOM' +elif compiler.has_header_symbol('bsd/stdlib.h', 'arc4random_buf') + libgit_c_args += '-DHAVE_ARC4RANDOM_BSD' +elif compiler.has_function('getrandom', prefix: '#include ') + libgit_c_args += '-DHAVE_GETRANDOM' +elif compiler.has_function('getentropy', prefix: '#include ') + libgit_c_args += '-DHAVE_GETENTROPY' +elif compiler.has_function('RtlGenRandom', prefix: '#include \n#include ') + libgit_c_args += '-DHAVE_RTLGENRANDOM' +elif openssl.found() + libgit_c_args += '-DHAVE_OPENSSL_CSPRNG' +endif + +if get_option('runtime_prefix') + libgit_c_args += '-DRUNTIME_PREFIX' + build_options_config.set('RUNTIME_PREFIX', 'true') + + if compiler.has_header('mach-o/dyld.h') + libgit_c_args += '-DHAVE_NS_GET_EXECUTABLE_PATH' + endif + + if has_bsd_sysctl and compiler.compiles(''' + #include + + void func(void) + { + KERN_PROC_PATHNAME; KERN_PROC; + } + ''', name: 'BSD KERN_PROC_PATHNAME') + libgit_c_args += '-DHAVE_NS_GET_EXECUTABLE_PATH' + endif + + if host_machine.system() == 'linux' + libgit_c_args += '-DPROCFS_EXECUTABLE_PATH="/proc/self/exe' + '"' + elif host_machine.system() == 'openbsd' + libgit_c_args += '-DPROCFS_EXECUTABLE_PATH="' + '/proc/curproc/file' + '"' + elif host_machine.system() == 'netbsd' + libgit_c_args += '-DPROCFS_EXECUTABLE_PATH="' + '/proc/curproc/exe' + '"' + endif + + if host_machine.system() == 'windows' and compiler.compiles(''' + #include + + void func(void) + { + _wpgmptr; + } + ''', name: 'Win32 _wpgmptr') + libgit_c_args += '-DHAVE_WPGMPTR' + endif +else + build_options_config.set('RUNTIME_PREFIX', 'false') +endif + +foreach key, value : { + 'DIFF': diff.full_path(), + 'GIT_TEST_CMP': diff.full_path() + ' -u', + 'GIT_TEST_GITPERLLIB': meson.project_build_root() / 'perl', + 'GIT_TEST_MERGE_TOOLS_DIR': meson.project_source_root() / 'mergetools', + 'GIT_TEST_POPATH': meson.project_source_root() / 'po', + 'GIT_TEST_TEMPLATE_DIR': meson.project_build_root() / 'templates', + 'GIT_TEST_TEXTDOMAINDIR': meson.project_build_root() / 'po', + 'PAGER_ENV': get_option('pager_environment'), + 'PERL_PATH': perl.found() ? perl.full_path() : '', + 'PYTHON_PATH': python.found () ? python.full_path() : '', + 'SHELL_PATH': shell.full_path(), + 'TAR': tar.full_path(), + 'TEST_OUTPUT_DIRECTORY': test_output_directory, + 'TEST_SHELL_PATH': shell.full_path(), +} + if value != '' and cygpath.found() + value = run_command(cygpath, value, check: true).stdout().strip() + endif + build_options_config.set_quoted(key, value) +endforeach + +configure_file( + input: 'GIT-BUILD-OPTIONS.in', + output: 'GIT-BUILD-OPTIONS', + configuration: build_options_config, +) + +git_version_file = custom_target( + command: [ + shell, + meson.current_source_dir() / 'GIT-VERSION-GEN', + meson.current_source_dir(), + '@INPUT@', + '@OUTPUT@', + ], + input: meson.current_source_dir() / 'GIT-VERSION-FILE.in', + output: 'GIT-VERSION-FILE', + build_always_stale: true, +) + +version_def_h = custom_target( + command: [ + shell, + meson.current_source_dir() / 'GIT-VERSION-GEN', + meson.current_source_dir(), + '@INPUT@', + '@OUTPUT@', + ], + input: meson.current_source_dir() / 'version-def.h.in', + output: 'version-def.h', + # Depend on GIT-VERSION-FILE so that we don't always try to rebuild this + # target for the same commit. + depends: [git_version_file], +) + +# Build a separate library for "version.c" so that we do not have to rebuild +# everything when the current Git commit changes. +libgit_version_library = static_library('git-version', + sources: [ + 'version.c', + version_def_h, + ], + c_args: libgit_c_args, + dependencies: libgit_dependencies, + include_directories: libgit_include_directories, +) + +libgit_library = static_library('git', + sources: libgit_sources, + c_args: libgit_c_args, + link_with: libgit_version_library, + dependencies: libgit_dependencies, + include_directories: libgit_include_directories, +) + +libgit = declare_dependency( + compile_args: libgit_c_args, + link_with: libgit_library, + dependencies: libgit_dependencies, + include_directories: libgit_include_directories, +) + +common_main_sources = ['common-main.c'] +common_main_link_args = [ ] +if host_machine.system() == 'windows' + git_rc = custom_target( + command: [ + shell, + meson.current_source_dir() / 'GIT-VERSION-GEN', + meson.current_source_dir(), + '@INPUT@', + '@OUTPUT@', + ], + input: meson.current_source_dir() / 'git.rc.in', + output: 'git.rc', + depends: [git_version_file], + ) + + common_main_sources += import('windows').compile_resources(git_rc, + include_directories: [meson.current_source_dir()], + ) + if compiler.get_argument_syntax() == 'gcc' + common_main_link_args += [ + '-municode', + '-Wl,-nxcompat', + '-Wl,-dynamicbase', + '-Wl,-pic-executable,-e,mainCRTStartup', + ] + elif compiler.get_argument_syntax() == 'msvc' + common_main_link_args += [ + '/ENTRY:wmainCRTStartup', + 'invalidcontinue.obj', + ] + else + error('Unsupported compiler ' + compiler.get_id()) + endif +endif +common_main_library = static_library('common-main', + sources: common_main_sources, + c_args: libgit_c_args, + dependencies: libgit_dependencies, + include_directories: libgit_include_directories, +) +common_main = declare_dependency( + link_with: common_main_library, + link_args: common_main_link_args, +) + +bin_wrappers = [ ] +test_dependencies = [ ] + +git = executable('git', + sources: builtin_sources + 'git.c', + dependencies: [libgit, common_main], + install: true, + install_dir: get_option('libexecdir') / 'git-core', +) +bin_wrappers += git + +test_dependencies += executable('git-daemon', + sources: 'daemon.c', + dependencies: [libgit, common_main], + install: true, + install_dir: get_option('libexecdir') / 'git-core', +) + +test_dependencies += executable('git-sh-i18n--envsubst', + sources: 'sh-i18n--envsubst.c', + dependencies: [libgit, common_main], + install: true, + install_dir: get_option('libexecdir') / 'git-core', +) + +bin_wrappers += executable('git-shell', + sources: 'shell.c', + dependencies: [libgit, common_main], + install: true, + install_dir: get_option('libexecdir') / 'git-core', +) + +test_dependencies += executable('git-http-backend', + sources: 'http-backend.c', + dependencies: [libgit, common_main], + install: true, + install_dir: get_option('libexecdir') / 'git-core', +) + +bin_wrappers += executable('scalar', + sources: 'scalar.c', + dependencies: [libgit, common_main], + install: true, + install_dir: get_option('libexecdir') / 'git-core', +) + +if get_option('curl').enabled() + curl_sources = [ + 'http.c', + 'http-walker.c', + ] + + git_remote_http = executable('git-remote-http', + sources: curl_sources + 'remote-curl.c', + dependencies: [libgit, common_main], + install: true, + install_dir: get_option('libexecdir') / 'git-core', + ) + test_dependencies += git_remote_http + + test_dependencies += executable('git-http-fetch', + sources: curl_sources + 'http-fetch.c', + dependencies: [libgit, common_main], + install: true, + install_dir: get_option('libexecdir') / 'git-core', + ) + + if expat.found() + test_dependencies += executable('git-http-push', + sources: curl_sources + 'http-push.c', + dependencies: [libgit, common_main], + install: true, + install_dir: get_option('libexecdir') / 'git-core', + ) + endif + + foreach alias : [ 'git-remote-https', 'git-remote-ftp', 'git-remote-ftps' ] + test_dependencies += executable(alias, + objects: git_remote_http.extract_all_objects(recursive: false), + dependencies: [libgit, common_main], + ) + + install_symlink(alias + executable_suffix, + install_dir: get_option('libexecdir') / 'git-core', + pointing_to: 'git-remote-http', + ) + endforeach +endif + +imap_send_sources = ['imap-send.c'] +if use_curl_for_imap_send + imap_send_sources += curl_sources +endif + +test_dependencies += executable('git-imap-send', + sources: imap_send_sources, + dependencies: [libgit, common_main], + install: true, + install_dir: get_option('libexecdir') / 'git-core', +) + +foreach alias : [ 'git-receive-pack', 'git-upload-archive', 'git-upload-pack' ] + bin_wrappers += executable(alias, + objects: git.extract_all_objects(recursive: false), + dependencies: [libgit, common_main], + ) + + install_symlink(alias + executable_suffix, + install_dir: get_option('libexecdir') / 'git-core', + pointing_to: 'git', + ) +endforeach + +foreach symlink : [ + 'git', + 'git-receive-pack', + 'git-shell', + 'git-upload-archive', + 'git-upload-pack', + 'scalar', +] + if meson.version().version_compare('>=1.3.0') + pointing_to = fs.relative_to(get_option('libexecdir') / 'git-core' / symlink, get_option('bindir')) + else + pointing_to = '../libexec/git-core' / symlink + endif + + install_symlink(symlink, + install_dir: get_option('bindir'), + pointing_to: pointing_to, + ) +endforeach + +scripts_sh = [ + 'git-difftool--helper.sh', + 'git-filter-branch.sh', + 'git-merge-octopus.sh', + 'git-merge-one-file.sh', + 'git-merge-resolve.sh', + 'git-mergetool--lib.sh', + 'git-mergetool.sh', + 'git-quiltimport.sh', + 'git-request-pull.sh', + 'git-sh-i18n.sh', + 'git-sh-setup.sh', + 'git-submodule.sh', + 'git-web--browse.sh', +] +if perl_features_enabled + scripts_sh += 'git-instaweb.sh' +endif + +foreach script : scripts_sh + test_dependencies += custom_target( + input: script, + output: fs.stem(script), + command: [ + shell, + meson.project_source_root() / 'generate-script.sh', + '@INPUT@', + '@OUTPUT@', + meson.project_build_root() / 'GIT-BUILD-OPTIONS', + ], + install: true, + install_dir: get_option('libexecdir') / 'git-core', + ) +endforeach + +if perl_features_enabled + scripts_perl = [ + 'git-archimport.perl', + 'git-cvsexportcommit.perl', + 'git-cvsimport.perl', + 'git-cvsserver.perl', + 'git-send-email.perl', + 'git-svn.perl', + ] + + pathsep = ':' + if host_machine.system() == 'windows' + pathsep = ';' + endif + + perl_header_template = 'perl/header_templates/fixed_prefix.template.pl' + if get_option('runtime_prefix') + perl_header_template = 'perl/header_templates/runtime_prefix.template.pl' + endif + + perl_header = configure_file( + input: perl_header_template, + output: 'GIT-PERL-HEADER', + configuration: { + 'GITEXECDIR_REL': get_option('libexecdir') / 'git-core', + 'PERLLIBDIR_REL': get_option('datadir') / 'perl5', + 'LOCALEDIR_REL': get_option('datadir') / 'locale', + 'INSTLIBDIR': get_option('datadir') / 'perl5', + 'PATHSEP': pathsep, + }, + ) + + generate_perl_command = [ + shell, + meson.project_source_root() / 'generate-perl.sh', + meson.project_build_root() / 'GIT-BUILD-OPTIONS', + git_version_file.full_path(), + perl_header, + '@INPUT@', + '@OUTPUT@', + ] + + foreach script : scripts_perl + generated_script = custom_target( + input: script, + output: fs.stem(script), + command: generate_perl_command, + install: true, + install_dir: get_option('libexecdir') / 'git-core', + depends: [git_version_file], + ) + test_dependencies += generated_script + + if script == 'git-cvsserver.perl' + bin_wrappers += generated_script + + if meson.version().version_compare('>=1.3.0') + pointing_to = fs.relative_to(get_option('libexecdir') / 'git-core' / fs.stem(script), get_option('bindir')) + else + pointing_to = '../libexec/git-core' / fs.stem(script) + endif + + install_symlink(fs.stem(script), + install_dir: get_option('bindir'), + pointing_to: pointing_to, + ) + endif + endforeach + + subdir('perl') +endif + +if python.found() + scripts_python = [ + 'git-p4.py' + ] + + foreach script : scripts_python + generated_python = custom_target( + input: script, + output: fs.stem(script), + command: [ + shell, + meson.project_source_root() / 'generate-python.sh', + meson.project_build_root() / 'GIT-BUILD-OPTIONS', + '@INPUT@', + '@OUTPUT@', + ], + install: true, + install_dir: get_option('libexecdir') / 'git-core', + ) + test_dependencies += generated_python + endforeach +endif + +mergetools = [ + 'mergetools/araxis', + 'mergetools/bc', + 'mergetools/codecompare', + 'mergetools/deltawalker', + 'mergetools/diffmerge', + 'mergetools/diffuse', + 'mergetools/ecmerge', + 'mergetools/emerge', + 'mergetools/examdiff', + 'mergetools/guiffy', + 'mergetools/gvimdiff', + 'mergetools/kdiff3', + 'mergetools/kompare', + 'mergetools/meld', + 'mergetools/nvimdiff', + 'mergetools/opendiff', + 'mergetools/p4merge', + 'mergetools/smerge', + 'mergetools/tkdiff', + 'mergetools/tortoisemerge', + 'mergetools/vimdiff', + 'mergetools/vscode', + 'mergetools/winmerge', + 'mergetools/xxdiff', +] + +foreach mergetool : mergetools + install_data(mergetool, install_dir: get_option('libexecdir') / 'git-core' / 'mergetools') +endforeach + +if intl.found() + subdir('po') +endif +subdir('contrib') +subdir('gitweb') +subdir('templates') + +# Everything but the bin-wrappers need to come before this target such that we +# can properly set up test dependencies. The bin-wrappers themselves are set up +# at configuration time, so these are fine. +if get_option('tests') + subdir('t') +endif + +subdir('bin-wrappers') +if get_option('docs') != [] + subdir('Documentation') +endif + +summary({ + 'curl': curl.found(), + 'expat': expat.found(), + 'gettext': intl.found(), + 'https': https_backend, + 'iconv': iconv.found(), + 'pcre2': pcre2.found(), + 'perl': perl_features_enabled, + 'python': python.found(), +}, section: 'Auto-detected features') diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000000..32a72139ba --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,81 @@ +# Configuration for how Git behaves at runtime. +option('default_pager', type: 'string', value: 'less', + description: 'Fall-back pager.') +option('default_editor', type: 'string', value: 'vi', + description: 'Fall-back editor.') +option('gitconfig', type: 'string', value: '/etc/gitconfig', + description: 'Path to the global git configuration file.') +option('gitattributes', type: 'string', value: '/etc/gitattributes', + description: 'Path to the global git attributes file.') +option('pager_environment', type: 'string', value: 'LESS=FRX LV=-c', + description: 'Environment used when spawning the pager') +option('perl_cpan_fallback', type: 'boolean', value: true, + description: 'Install bundled copies of CPAN modules that serve as a fallback in case the modules are not available on the system.') +option('runtime_prefix', type: 'boolean', value: false, + description: 'Resolve ancillary tooling and support files relative to the location of the runtime binary instead of hard-coding them into the binary.') +option('sane_tool_path', type: 'string', value: '', + description: 'A colon-separated list of paths to prepend to PATH if your tools in /usr/bin are broken.') + +# Features supported by Git. +option('curl', type: 'feature', value: 'enabled', + description: 'Build helpers used to access remotes with the HTTP transport.') +option('expat', type: 'feature', value: 'enabled', + description: 'Build helpers used to push to remotes with the HTTP transport.') +option('gettext', type: 'feature', value: 'auto', + description: 'Build translation files.') +option('iconv', type: 'feature', value: 'auto', + description: 'Support reencoding strings with different encodings.') +option('pcre2', type: 'feature', value: 'enabled', + description: 'Support Perl-compatible regular expressions in e.g. git-grep(1).') +option('perl', type: 'feature', value: 'auto', + description: 'Build tools written in Perl.') +option('python', type: 'feature', value: 'auto', + description: 'Build tools written in Python.') +option('regex', type: 'feature', value: 'auto', + description: 'Use the system-provided regex library instead of the bundled one.') + +# Backends. +option('https_backend', type: 'combo', value: 'auto', choices: ['auto', 'openssl', 'CommonCrypto', 'none'], + description: 'The HTTPS backend to use when connecting to remotes.') +option('sha1_backend', type: 'combo', choices: ['openssl', 'block', 'sha1dc', 'common-crypto'], value: 'sha1dc', + description: 'The backend used for hashing objects with the SHA1 object format') +option('sha256_backend', type: 'combo', choices: ['openssl', 'nettle', 'gcrypt', 'block'], value: 'block', + description: 'The backend used for hashing objects with the SHA256 object format') + +# Build tweaks. +option('macos_use_homebrew_gettext', type: 'boolean', value: true, + description: 'Use gettext from Homebrew instead of the slightly-broken system-provided one.') + +# gitweb configuration. +option('gitweb_config', type: 'string', value: 'gitweb_config.perl') +option('gitweb_config_system', type: 'string', value: '/etc/gitweb.conf') +option('gitweb_config_common', type: 'string', value: '/etc/gitweb-common.conf') +option('gitweb_home_link_str', type: 'string', value: 'projects') +option('gitweb_sitename', type: 'string', value: '') +option('gitweb_projectroot', type: 'string', value: '/pub/git') +option('gitweb_project_maxdepth', type: 'string', value: '2007') +option('gitweb_export_ok', type: 'string', value: '') +option('gitweb_strict_export', type: 'string', value: '') +option('gitweb_base_url', type: 'string', value: '') +option('gitweb_list', type: 'string', value: '') +option('gitweb_hometext', type: 'string', value: 'indextext.html') +option('gitweb_css', type: 'string', value: 'static/gitweb.css') +option('gitweb_logo', type: 'string', value: 'static/git-logo.png') +option('gitweb_favicon', type: 'string', value: 'static/git-favicon.png') +option('gitweb_js', type: 'string', value: 'static/gitweb.js') +option('gitweb_site_html_head_string', type: 'string', value: '') +option('gitweb_site_header', type: 'string', value: '') +option('gitweb_site_footer', type: 'string', value: '') +option('highlight_bin', type: 'string', value: 'highlight') + +# Documentation. +option('docs', type: 'array', choices: ['man', 'html'], value: [], + description: 'Which documenattion formats to build and install.') +option('default_help_format', type: 'combo', choices: ['man', 'html'], value: 'man', + description: 'Default format used when executing git-help(1).') + +# Testing. +option('tests', type: 'boolean', value: true, + description: 'Enable building tests. This requires Perl, but is separate from the "perl" option such that you can build tests without Perl features enabled.') +option('test_output_directory', type: 'string', + description: 'Path to the directory used to store test outputs') diff --git a/perl/FromCPAN/Mail/meson.build b/perl/FromCPAN/Mail/meson.build new file mode 100644 index 0000000000..129cff161c --- /dev/null +++ b/perl/FromCPAN/Mail/meson.build @@ -0,0 +1,7 @@ +test_dependencies += custom_target( + input: 'Address.pm', + output: 'Address.pm', + command: generate_perl_command, + install: true, + install_dir: get_option('datadir') / 'perl5/FromCPAN/Mail', +) diff --git a/perl/FromCPAN/meson.build b/perl/FromCPAN/meson.build new file mode 100644 index 0000000000..4e7ea909df --- /dev/null +++ b/perl/FromCPAN/meson.build @@ -0,0 +1,9 @@ +test_dependencies += custom_target( + input: 'Error.pm', + output: 'Error.pm', + command: generate_perl_command, + install: true, + install_dir: get_option('datadir') / 'perl5/FromCPAN', +) + +subdir('Mail') diff --git a/perl/Git/LoadCPAN/Mail/meson.build b/perl/Git/LoadCPAN/Mail/meson.build new file mode 100644 index 0000000000..7da5b37adb --- /dev/null +++ b/perl/Git/LoadCPAN/Mail/meson.build @@ -0,0 +1,7 @@ +test_dependencies += custom_target( + input: 'Address.pm', + output: 'Address.pm', + command: generate_perl_command, + install: true, + install_dir: get_option('datadir') / 'perl5/Git/LoadCPAN/Mail', +) diff --git a/perl/Git/LoadCPAN/meson.build b/perl/Git/LoadCPAN/meson.build new file mode 100644 index 0000000000..9468c073ae --- /dev/null +++ b/perl/Git/LoadCPAN/meson.build @@ -0,0 +1,9 @@ +test_dependencies += custom_target( + input: 'Error.pm', + output: 'Error.pm', + command: generate_perl_command, + install: true, + install_dir: get_option('datadir') / 'perl5/Git/LoadCPAN', +) + +subdir('Mail') diff --git a/perl/Git/SVN/Memoize/meson.build b/perl/Git/SVN/Memoize/meson.build new file mode 100644 index 0000000000..515ab3dd92 --- /dev/null +++ b/perl/Git/SVN/Memoize/meson.build @@ -0,0 +1,7 @@ +test_dependencies += custom_target( + input: 'YAML.pm', + output: 'YAML.pm', + command: generate_perl_command, + install: true, + install_dir: get_option('datadir') / 'perl5/Git/SVN', +) diff --git a/perl/Git/SVN/meson.build b/perl/Git/SVN/meson.build new file mode 100644 index 0000000000..8338531041 --- /dev/null +++ b/perl/Git/SVN/meson.build @@ -0,0 +1,20 @@ +foreach source : [ + 'Editor.pm', + 'Fetcher.pm', + 'GlobSpec.pm', + 'Log.pm', + 'Migration.pm', + 'Prompt.pm', + 'Ra.pm', + 'Utils.pm', +] + test_dependencies += custom_target( + input: source, + output: source, + command: generate_perl_command, + install: true, + install_dir: get_option('datadir') / 'perl5/Git/SVN', + ) +endforeach + +subdir('Memoize') diff --git a/perl/Git/meson.build b/perl/Git/meson.build new file mode 100644 index 0000000000..259209d730 --- /dev/null +++ b/perl/Git/meson.build @@ -0,0 +1,18 @@ +foreach source : [ + 'I18N.pm', + 'IndexInfo.pm', + 'LoadCPAN.pm', + 'Packet.pm', + 'SVN.pm', +] + test_dependencies += custom_target( + input: source, + output: source, + command: generate_perl_command, + install: true, + install_dir: get_option('datadir') / 'perl5/Git', + ) +endforeach + +subdir('LoadCPAN') +subdir('SVN') diff --git a/perl/meson.build b/perl/meson.build new file mode 100644 index 0000000000..c22d6f8a1a --- /dev/null +++ b/perl/meson.build @@ -0,0 +1,12 @@ +test_dependencies += custom_target( + input: 'Git.pm', + output: 'Git.pm', + command: generate_perl_command, + install: true, + install_dir: get_option('datadir') / 'perl5', +) + +subdir('Git') +if get_option('perl_cpan_fallback') + subdir('FromCPAN') +endif diff --git a/po/meson.build b/po/meson.build new file mode 100644 index 0000000000..d7154b6395 --- /dev/null +++ b/po/meson.build @@ -0,0 +1,27 @@ +i18n = import('i18n') + +translations = i18n.gettext('git', + languages: [ + 'bg', + 'ca', + 'de', + 'el', + 'es', + 'fr', + 'id', + 'is', + 'it', + 'ko', + 'pl', + 'pt_PT', + 'ru', + 'sv', + 'tr', + 'uk', + 'vi', + 'zh_CN', + 'zh_TW', + ], + install: true, +) +test_dependencies += translations[0] diff --git a/subprojects/.gitignore b/subprojects/.gitignore new file mode 100644 index 0000000000..63ea916ef5 --- /dev/null +++ b/subprojects/.gitignore @@ -0,0 +1 @@ +/*/ diff --git a/subprojects/curl.wrap b/subprojects/curl.wrap new file mode 100644 index 0000000000..f7e384b85c --- /dev/null +++ b/subprojects/curl.wrap @@ -0,0 +1,13 @@ +[wrap-file] +directory = curl-8.10.1 +source_url = https://github.com/curl/curl/releases/download/curl-8_10_1/curl-8.10.1.tar.xz +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/curl_8.10.1-1/curl-8.10.1.tar.xz +source_filename = curl-8.10.1.tar.xz +source_hash = 73a4b0e99596a09fa5924a4fb7e4b995a85fda0d18a2c02ab9cf134bebce04ee +patch_filename = curl_8.10.1-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/curl_8.10.1-1/get_patch +patch_hash = 707c28f35fc9b0e8d68c0c2800712007612f922a31da9637ce706a2159f3ddd8 +wrapdb_version = 8.10.1-1 + +[provide] +dependency_names = libcurl diff --git a/subprojects/expat.wrap b/subprojects/expat.wrap new file mode 100644 index 0000000000..2e0427dcfd --- /dev/null +++ b/subprojects/expat.wrap @@ -0,0 +1,13 @@ +[wrap-file] +directory = expat-2.6.3 +source_url = https://github.com/libexpat/libexpat/releases/download/R_2_6_3/expat-2.6.3.tar.xz +source_filename = expat-2.6.3.tar.bz2 +source_hash = 274db254a6979bde5aad404763a704956940e465843f2a9bd9ed7af22e2c0efc +patch_filename = expat_2.6.3-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/expat_2.6.3-1/get_patch +patch_hash = cf017fbe105e31428b2768360bd9be39094df4e948a1e8d1c54b6f7c76460cb1 +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/expat_2.6.3-1/expat-2.6.3.tar.bz2 +wrapdb_version = 2.6.3-1 + +[provide] +expat = expat_dep diff --git a/subprojects/openssl.wrap b/subprojects/openssl.wrap new file mode 100644 index 0000000000..873d55106e --- /dev/null +++ b/subprojects/openssl.wrap @@ -0,0 +1,15 @@ +[wrap-file] +directory = openssl-3.0.8 +source_url = https://www.openssl.org/source/openssl-3.0.8.tar.gz +source_filename = openssl-3.0.8.tar.gz +source_hash = 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e +patch_filename = openssl_3.0.8-3_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/openssl_3.0.8-3/get_patch +patch_hash = 300da189e106942347d61a4a4295aa2edbcf06184f8d13b4cee0bed9fb936963 +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/openssl_3.0.8-3/openssl-3.0.8.tar.gz +wrapdb_version = 3.0.8-3 + +[provide] +libcrypto = libcrypto_dep +libssl = libssl_dep +openssl = openssl_dep diff --git a/subprojects/pcre2.wrap b/subprojects/pcre2.wrap new file mode 100644 index 0000000000..7e18447254 --- /dev/null +++ b/subprojects/pcre2.wrap @@ -0,0 +1,16 @@ +[wrap-file] +directory = pcre2-10.44 +source_url = https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.44/pcre2-10.44.tar.bz2 +source_filename = pcre2-10.44.tar.bz2 +source_hash = d34f02e113cf7193a1ebf2770d3ac527088d485d4e047ed10e5d217c6ef5de96 +patch_filename = pcre2_10.44-2_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/pcre2_10.44-2/get_patch +patch_hash = 4336d422ee9043847e5e10dbbbd01940d4c9e5027f31ccdc33a7898a1ca94009 +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/pcre2_10.44-2/pcre2-10.44.tar.bz2 +wrapdb_version = 10.44-2 + +[provide] +libpcre2-8 = libpcre2_8 +libpcre2-16 = libpcre2_16 +libpcre2-32 = libpcre2_32 +libpcre2-posix = libpcre2_posix diff --git a/subprojects/zlib.wrap b/subprojects/zlib.wrap new file mode 100644 index 0000000000..aa14de1774 --- /dev/null +++ b/subprojects/zlib.wrap @@ -0,0 +1,13 @@ +[wrap-file] +directory = zlib-1.3.1 +source_url = http://zlib.net/fossils/zlib-1.3.1.tar.gz +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/zlib_1.3.1-1/zlib-1.3.1.tar.gz +source_filename = zlib-1.3.1.tar.gz +source_hash = 9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23 +patch_filename = zlib_1.3.1-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/zlib_1.3.1-1/get_patch +patch_hash = e79b98eb24a75392009cec6f99ca5cdca9881ff20bfa174e8b8926d5c7a47095 +wrapdb_version = 1.3.1-1 + +[provide] +zlib = zlib_dep diff --git a/t/helper/meson.build b/t/helper/meson.build new file mode 100644 index 0000000000..5e83884246 --- /dev/null +++ b/t/helper/meson.build @@ -0,0 +1,91 @@ +test_tool_sources = [ + '../unit-tests/test-lib.c', + 'test-advise.c', + 'test-bitmap.c', + 'test-bloom.c', + 'test-bundle-uri.c', + 'test-cache-tree.c', + 'test-chmtime.c', + 'test-config.c', + 'test-crontab.c', + 'test-csprng.c', + 'test-date.c', + 'test-delete-gpgsig.c', + 'test-delta.c', + 'test-dir-iterator.c', + 'test-drop-caches.c', + 'test-dump-cache-tree.c', + 'test-dump-fsmonitor.c', + 'test-dump-split-index.c', + 'test-dump-untracked-cache.c', + 'test-env-helper.c', + 'test-example-tap.c', + 'test-find-pack.c', + 'test-fsmonitor-client.c', + 'test-genrandom.c', + 'test-genzeros.c', + 'test-getcwd.c', + 'test-hash-speed.c', + 'test-hash.c', + 'test-hashmap.c', + 'test-hexdump.c', + 'test-json-writer.c', + 'test-lazy-init-name-hash.c', + 'test-match-trees.c', + 'test-mergesort.c', + 'test-mktemp.c', + 'test-online-cpus.c', + 'test-pack-mtimes.c', + 'test-parse-options.c', + 'test-parse-pathspec-file.c', + 'test-partial-clone.c', + 'test-path-utils.c', + 'test-pcre2-config.c', + 'test-pkt-line.c', + 'test-proc-receive.c', + 'test-progress.c', + 'test-reach.c', + 'test-read-cache.c', + 'test-read-graph.c', + 'test-read-midx.c', + 'test-ref-store.c', + 'test-reftable.c', + 'test-regex.c', + 'test-repository.c', + 'test-revision-walking.c', + 'test-rot13-filter.c', + 'test-run-command.c', + 'test-scrap-cache-tree.c', + 'test-serve-v2.c', + 'test-sha1.c', + 'test-sha256.c', + 'test-sigchain.c', + 'test-simple-ipc.c', + 'test-string-list.c', + 'test-submodule-config.c', + 'test-submodule-nested-repo-config.c', + 'test-submodule.c', + 'test-subprocess.c', + 'test-tool.c', + 'test-trace2.c', + 'test-truncate.c', + 'test-userdiff.c', + 'test-wildmatch.c', + 'test-windows-named-pipe.c', + 'test-write-cache.c', + 'test-xml-encode.c', +] + +test_tool = executable('test-tool', + sources: test_tool_sources, + dependencies: [libgit, common_main], +) +bin_wrappers += test_tool +test_dependencies += test_tool + +test_fake_ssh = executable('test-fake-ssh', + sources: 'test-fake-ssh.c', + dependencies: [libgit, common_main], +) +bin_wrappers += test_fake_ssh +test_dependencies += test_fake_ssh diff --git a/t/meson.build b/t/meson.build new file mode 100644 index 0000000000..13fe854ba0 --- /dev/null +++ b/t/meson.build @@ -0,0 +1,1114 @@ +clar_test_suites = [ + 'unit-tests/ctype.c', + 'unit-tests/strvec.c', +] + +clar_sources = [ + 'unit-tests/clar/clar.c', + 'unit-tests/unit-test.c', +] + +clar_decls_h = custom_target( + input: clar_test_suites, + output: 'clar-decls.h', + command : [ + shell, + meson.current_source_dir() + '/unit-tests/generate-clar-decls.sh', + '@OUTPUT@', + '@INPUT@', + ], + env: script_environment, +) +clar_sources += clar_decls_h + +clar_sources += custom_target( + input: clar_decls_h, + output: 'clar.suite', + command : [ + shell, + meson.current_source_dir() + '/unit-tests/generate-clar-suites.sh', + '@INPUT@', + '@OUTPUT@', + ], + env: script_environment, +) + +clar_unit_tests = executable('unit-tests', + sources: clar_sources + clar_test_suites, + dependencies: [libgit, common_main], +) +test('unit-tests', clar_unit_tests) + +unit_test_programs = [ + 'unit-tests/t-example-decorate.c', + 'unit-tests/t-hash.c', + 'unit-tests/t-hashmap.c', + 'unit-tests/t-mem-pool.c', + 'unit-tests/t-oid-array.c', + 'unit-tests/t-oidmap.c', + 'unit-tests/t-oidtree.c', + 'unit-tests/t-prio-queue.c', + 'unit-tests/t-reftable-basics.c', + 'unit-tests/t-reftable-block.c', + 'unit-tests/t-reftable-merged.c', + 'unit-tests/t-reftable-pq.c', + 'unit-tests/t-reftable-reader.c', + 'unit-tests/t-reftable-readwrite.c', + 'unit-tests/t-reftable-record.c', + 'unit-tests/t-reftable-stack.c', + 'unit-tests/t-reftable-tree.c', + 'unit-tests/t-strbuf.c', + 'unit-tests/t-strcmp-offset.c', + 'unit-tests/t-trailer.c', + 'unit-tests/t-urlmatch-normalization.c', +] + +foreach unit_test_program : unit_test_programs + unit_test_name = fs.stem(unit_test_program) + unit_test = executable(unit_test_name, + sources: [ + 'unit-tests/test-lib.c', + 'unit-tests/lib-oid.c', + 'unit-tests/lib-reftable.c', + unit_test_program, + ], + dependencies: [libgit, common_main], + ) + test(unit_test_name, unit_test, + workdir: meson.current_source_dir(), + timeout: 0, + ) +endforeach + +subdir('helper') + +integration_tests = [ + 't0000-basic.sh', + 't0001-init.sh', + 't0002-gitfile.sh', + 't0003-attributes.sh', + 't0004-unwritable.sh', + 't0005-signals.sh', + 't0006-date.sh', + 't0007-git-var.sh', + 't0008-ignores.sh', + 't0010-racy-git.sh', + 't0012-help.sh', + 't0013-sha1dc.sh', + 't0014-alias.sh', + 't0017-env-helper.sh', + 't0018-advice.sh', + 't0019-json-writer.sh', + 't0020-crlf.sh', + 't0021-conversion.sh', + 't0022-crlf-rename.sh', + 't0023-crlf-am.sh', + 't0024-crlf-archive.sh', + 't0025-crlf-renormalize.sh', + 't0026-eol-config.sh', + 't0027-auto-crlf.sh', + 't0028-working-tree-encoding.sh', + 't0029-core-unsetenvvars.sh', + 't0030-stripspace.sh', + 't0033-safe-directory.sh', + 't0034-root-safe-directory.sh', + 't0035-safe-bare-repository.sh', + 't0040-parse-options.sh', + 't0041-usage.sh', + 't0050-filesystem.sh', + 't0051-windows-named-pipe.sh', + 't0052-simple-ipc.sh', + 't0055-beyond-symlinks.sh', + 't0056-git-C.sh', + 't0060-path-utils.sh', + 't0061-run-command.sh', + 't0062-revision-walking.sh', + 't0063-string-list.sh', + 't0066-dir-iterator.sh', + 't0067-parse_pathspec_file.sh', + 't0068-for-each-repo.sh', + 't0070-fundamental.sh', + 't0071-sort.sh', + 't0080-unit-test-output.sh', + 't0081-find-pack.sh', + 't0090-cache-tree.sh', + 't0091-bugreport.sh', + 't0092-diagnose.sh', + 't0095-bloom.sh', + 't0100-previous.sh', + 't0101-at-syntax.sh', + 't0200-gettext-basic.sh', + 't0201-gettext-fallbacks.sh', + 't0202-gettext-perl.sh', + 't0203-gettext-setlocale-sanity.sh', + 't0204-gettext-reencode-sanity.sh', + 't0210-trace2-normal.sh', + 't0211-trace2-perf.sh', + 't0212-trace2-event.sh', + 't0300-credentials.sh', + 't0301-credential-cache.sh', + 't0302-credential-store.sh', + 't0303-credential-external.sh', + 't0410-partial-clone.sh', + 't0411-clone-from-partial.sh', + 't0450-txt-doc-vs-help.sh', + 't0500-progress-display.sh', + 't0600-reffiles-backend.sh', + 't0601-reffiles-pack-refs.sh', + 't0602-reffiles-fsck.sh', + 't0610-reftable-basics.sh', + 't0611-reftable-httpd.sh', + 't0612-reftable-jgit-compatibility.sh', + 't0613-reftable-write-options.sh', + 't1000-read-tree-m-3way.sh', + 't1001-read-tree-m-2way.sh', + 't1002-read-tree-m-u-2way.sh', + 't1003-read-tree-prefix.sh', + 't1004-read-tree-m-u-wf.sh', + 't1005-read-tree-reset.sh', + 't1006-cat-file.sh', + 't1007-hash-object.sh', + 't1008-read-tree-overlay.sh', + 't1009-read-tree-new-index.sh', + 't1010-mktree.sh', + 't1011-read-tree-sparse-checkout.sh', + 't1012-read-tree-df.sh', + 't1013-read-tree-submodule.sh', + 't1014-read-tree-confusing.sh', + 't1015-read-index-unmerged.sh', + 't1016-compatObjectFormat.sh', + 't1020-subdirectory.sh', + 't1021-rerere-in-workdir.sh', + 't1022-read-tree-partial-clone.sh', + 't1050-large.sh', + 't1051-large-conversion.sh', + 't1060-object-corruption.sh', + 't1090-sparse-checkout-scope.sh', + 't1091-sparse-checkout-builtin.sh', + 't1092-sparse-checkout-compatibility.sh', + 't1100-commit-tree-options.sh', + 't1300-config.sh', + 't1301-shared-repo.sh', + 't1302-repo-version.sh', + 't1303-wacky-config.sh', + 't1304-default-acl.sh', + 't1305-config-include.sh', + 't1306-xdg-files.sh', + 't1307-config-blob.sh', + 't1308-config-set.sh', + 't1309-early-config.sh', + 't1310-config-default.sh', + 't1350-config-hooks-path.sh', + 't1400-update-ref.sh', + 't1401-symbolic-ref.sh', + 't1402-check-ref-format.sh', + 't1403-show-ref.sh', + 't1404-update-ref-errors.sh', + 't1405-main-ref-store.sh', + 't1406-submodule-ref-store.sh', + 't1407-worktree-ref-store.sh', + 't1408-packed-refs.sh', + 't1409-avoid-packing-refs.sh', + 't1410-reflog.sh', + 't1411-reflog-show.sh', + 't1412-reflog-loop.sh', + 't1413-reflog-detach.sh', + 't1414-reflog-walk.sh', + 't1415-worktree-refs.sh', + 't1416-ref-transaction-hooks.sh', + 't1417-reflog-updateref.sh', + 't1418-reflog-exists.sh', + 't1419-exclude-refs.sh', + 't1420-lost-found.sh', + 't1430-bad-ref-name.sh', + 't1450-fsck.sh', + 't1451-fsck-buffer.sh', + 't1460-refs-migrate.sh', + 't1500-rev-parse.sh', + 't1501-work-tree.sh', + 't1502-rev-parse-parseopt.sh', + 't1503-rev-parse-verify.sh', + 't1504-ceiling-dirs.sh', + 't1505-rev-parse-last.sh', + 't1506-rev-parse-diagnosis.sh', + 't1507-rev-parse-upstream.sh', + 't1508-at-combinations.sh', + 't1509-root-work-tree.sh', + 't1510-repo-setup.sh', + 't1511-rev-parse-caret.sh', + 't1512-rev-parse-disambiguation.sh', + 't1513-rev-parse-prefix.sh', + 't1514-rev-parse-push.sh', + 't1515-rev-parse-outside-repo.sh', + 't1517-outside-repo.sh', + 't1600-index.sh', + 't1601-index-bogus.sh', + 't1700-split-index.sh', + 't1701-racy-split-index.sh', + 't1800-hook.sh', + 't2000-conflict-when-checking-files-out.sh', + 't2002-checkout-cache-u.sh', + 't2003-checkout-cache-mkdir.sh', + 't2004-checkout-cache-temp.sh', + 't2005-checkout-index-symlinks.sh', + 't2006-checkout-index-basic.sh', + 't2007-checkout-symlink.sh', + 't2008-checkout-subdir.sh', + 't2009-checkout-statinfo.sh', + 't2010-checkout-ambiguous.sh', + 't2011-checkout-invalid-head.sh', + 't2012-checkout-last.sh', + 't2013-checkout-submodule.sh', + 't2014-checkout-switch.sh', + 't2015-checkout-unborn.sh', + 't2016-checkout-patch.sh', + 't2017-checkout-orphan.sh', + 't2018-checkout-branch.sh', + 't2019-checkout-ambiguous-ref.sh', + 't2020-checkout-detach.sh', + 't2021-checkout-overwrite.sh', + 't2022-checkout-paths.sh', + 't2023-checkout-m.sh', + 't2024-checkout-dwim.sh', + 't2025-checkout-no-overlay.sh', + 't2026-checkout-pathspec-file.sh', + 't2027-checkout-track.sh', + 't2030-unresolve-info.sh', + 't2050-git-dir-relative.sh', + 't2060-switch.sh', + 't2070-restore.sh', + 't2071-restore-patch.sh', + 't2072-restore-pathspec-file.sh', + 't2080-parallel-checkout-basics.sh', + 't2081-parallel-checkout-collisions.sh', + 't2082-parallel-checkout-attributes.sh', + 't2100-update-cache-badpath.sh', + 't2101-update-index-reupdate.sh', + 't2102-update-index-symlinks.sh', + 't2103-update-index-ignore-missing.sh', + 't2104-update-index-skip-worktree.sh', + 't2105-update-index-gitfile.sh', + 't2106-update-index-assume-unchanged.sh', + 't2107-update-index-basic.sh', + 't2108-update-index-refresh-racy.sh', + 't2200-add-update.sh', + 't2201-add-update-typechange.sh', + 't2202-add-addremove.sh', + 't2203-add-intent.sh', + 't2204-add-ignored.sh', + 't2205-add-worktree-config.sh', + 't2300-cd-to-toplevel.sh', + 't2400-worktree-add.sh', + 't2401-worktree-prune.sh', + 't2402-worktree-list.sh', + 't2403-worktree-move.sh', + 't2404-worktree-config.sh', + 't2405-worktree-submodule.sh', + 't2406-worktree-repair.sh', + 't2407-worktree-heads.sh', + 't2500-untracked-overwriting.sh', + 't2501-cwd-empty.sh', + 't3000-ls-files-others.sh', + 't3001-ls-files-others-exclude.sh', + 't3002-ls-files-dashpath.sh', + 't3003-ls-files-exclude.sh', + 't3004-ls-files-basic.sh', + 't3005-ls-files-relative.sh', + 't3006-ls-files-long.sh', + 't3007-ls-files-recurse-submodules.sh', + 't3008-ls-files-lazy-init-name-hash.sh', + 't3009-ls-files-others-nonsubmodule.sh', + 't3010-ls-files-killed-modified.sh', + 't3011-common-prefixes-and-directory-traversal.sh', + 't3012-ls-files-dedup.sh', + 't3013-ls-files-format.sh', + 't3020-ls-files-error-unmatch.sh', + 't3040-subprojects-basic.sh', + 't3050-subprojects-fetch.sh', + 't3060-ls-files-with-tree.sh', + 't3070-wildmatch.sh', + 't3100-ls-tree-restrict.sh', + 't3101-ls-tree-dirname.sh', + 't3102-ls-tree-wildcards.sh', + 't3103-ls-tree-misc.sh', + 't3104-ls-tree-format.sh', + 't3105-ls-tree-output.sh', + 't3200-branch.sh', + 't3201-branch-contains.sh', + 't3202-show-branch.sh', + 't3203-branch-output.sh', + 't3204-branch-name-interpretation.sh', + 't3205-branch-color.sh', + 't3206-range-diff.sh', + 't3207-branch-submodule.sh', + 't3211-peel-ref.sh', + 't3300-funny-names.sh', + 't3301-notes.sh', + 't3302-notes-index-expensive.sh', + 't3303-notes-subtrees.sh', + 't3304-notes-mixed.sh', + 't3305-notes-fanout.sh', + 't3306-notes-prune.sh', + 't3307-notes-man.sh', + 't3308-notes-merge.sh', + 't3309-notes-merge-auto-resolve.sh', + 't3310-notes-merge-manual-resolve.sh', + 't3311-notes-merge-fanout.sh', + 't3320-notes-merge-worktrees.sh', + 't3321-notes-stripspace.sh', + 't3400-rebase.sh', + 't3401-rebase-and-am-rename.sh', + 't3402-rebase-merge.sh', + 't3403-rebase-skip.sh', + 't3404-rebase-interactive.sh', + 't3405-rebase-malformed.sh', + 't3406-rebase-message.sh', + 't3407-rebase-abort.sh', + 't3408-rebase-multi-line.sh', + 't3409-rebase-environ.sh', + 't3412-rebase-root.sh', + 't3413-rebase-hook.sh', + 't3415-rebase-autosquash.sh', + 't3416-rebase-onto-threedots.sh', + 't3417-rebase-whitespace-fix.sh', + 't3418-rebase-continue.sh', + 't3419-rebase-patch-id.sh', + 't3420-rebase-autostash.sh', + 't3421-rebase-topology-linear.sh', + 't3422-rebase-incompatible-options.sh', + 't3423-rebase-reword.sh', + 't3424-rebase-empty.sh', + 't3425-rebase-topology-merges.sh', + 't3426-rebase-submodule.sh', + 't3427-rebase-subtree.sh', + 't3428-rebase-signoff.sh', + 't3429-rebase-edit-todo.sh', + 't3430-rebase-merges.sh', + 't3431-rebase-fork-point.sh', + 't3432-rebase-fast-forward.sh', + 't3433-rebase-across-mode-change.sh', + 't3434-rebase-i18n.sh', + 't3435-rebase-gpg-sign.sh', + 't3436-rebase-more-options.sh', + 't3437-rebase-fixup-options.sh', + 't3438-rebase-broken-files.sh', + 't3500-cherry.sh', + 't3501-revert-cherry-pick.sh', + 't3502-cherry-pick-merge.sh', + 't3503-cherry-pick-root.sh', + 't3504-cherry-pick-rerere.sh', + 't3505-cherry-pick-empty.sh', + 't3506-cherry-pick-ff.sh', + 't3507-cherry-pick-conflict.sh', + 't3508-cherry-pick-many-commits.sh', + 't3509-cherry-pick-merge-df.sh', + 't3510-cherry-pick-sequence.sh', + 't3511-cherry-pick-x.sh', + 't3512-cherry-pick-submodule.sh', + 't3513-revert-submodule.sh', + 't3514-cherry-pick-revert-gpg.sh', + 't3600-rm.sh', + 't3601-rm-pathspec-file.sh', + 't3602-rm-sparse-checkout.sh', + 't3650-replay-basics.sh', + 't3700-add.sh', + 't3701-add-interactive.sh', + 't3702-add-edit.sh', + 't3703-add-magic-pathspec.sh', + 't3704-add-pathspec-file.sh', + 't3705-add-sparse-checkout.sh', + 't3800-mktag.sh', + 't3900-i18n-commit.sh', + 't3901-i18n-patch.sh', + 't3902-quoted.sh', + 't3903-stash.sh', + 't3904-stash-patch.sh', + 't3905-stash-include-untracked.sh', + 't3906-stash-submodule.sh', + 't3907-stash-show-config.sh', + 't3908-stash-in-worktree.sh', + 't3909-stash-pathspec-file.sh', + 't3910-mac-os-precompose.sh', + 't3920-crlf-messages.sh', + 't4000-diff-format.sh', + 't4001-diff-rename.sh', + 't4002-diff-basic.sh', + 't4003-diff-rename-1.sh', + 't4004-diff-rename-symlink.sh', + 't4005-diff-rename-2.sh', + 't4006-diff-mode.sh', + 't4007-rename-3.sh', + 't4008-diff-break-rewrite.sh', + 't4009-diff-rename-4.sh', + 't4010-diff-pathspec.sh', + 't4011-diff-symlink.sh', + 't4012-diff-binary.sh', + 't4013-diff-various.sh', + 't4014-format-patch.sh', + 't4015-diff-whitespace.sh', + 't4016-diff-quote.sh', + 't4017-diff-retval.sh', + 't4018-diff-funcname.sh', + 't4019-diff-wserror.sh', + 't4020-diff-external.sh', + 't4021-format-patch-numbered.sh', + 't4022-diff-rewrite.sh', + 't4023-diff-rename-typechange.sh', + 't4024-diff-optimize-common.sh', + 't4025-hunk-header.sh', + 't4026-color.sh', + 't4027-diff-submodule.sh', + 't4028-format-patch-mime-headers.sh', + 't4029-diff-trailing-space.sh', + 't4030-diff-textconv.sh', + 't4031-diff-rewrite-binary.sh', + 't4032-diff-inter-hunk-context.sh', + 't4033-diff-patience.sh', + 't4034-diff-words.sh', + 't4035-diff-quiet.sh', + 't4036-format-patch-signer-mime.sh', + 't4037-diff-r-t-dirs.sh', + 't4038-diff-combined.sh', + 't4039-diff-assume-unchanged.sh', + 't4040-whitespace-status.sh', + 't4041-diff-submodule-option.sh', + 't4042-diff-textconv-caching.sh', + 't4043-diff-rename-binary.sh', + 't4044-diff-index-unique-abbrev.sh', + 't4045-diff-relative.sh', + 't4046-diff-unmerged.sh', + 't4047-diff-dirstat.sh', + 't4048-diff-combined-binary.sh', + 't4049-diff-stat-count.sh', + 't4050-diff-histogram.sh', + 't4051-diff-function-context.sh', + 't4052-stat-output.sh', + 't4053-diff-no-index.sh', + 't4054-diff-bogus-tree.sh', + 't4055-diff-context.sh', + 't4056-diff-order.sh', + 't4057-diff-combined-paths.sh', + 't4058-diff-duplicates.sh', + 't4059-diff-submodule-not-initialized.sh', + 't4060-diff-submodule-option-diff-format.sh', + 't4061-diff-indent.sh', + 't4062-diff-pickaxe.sh', + 't4063-diff-blobs.sh', + 't4064-diff-oidfind.sh', + 't4065-diff-anchored.sh', + 't4066-diff-emit-delay.sh', + 't4067-diff-partial-clone.sh', + 't4068-diff-symmetric-merge-base.sh', + 't4069-remerge-diff.sh', + 't4100-apply-stat.sh', + 't4101-apply-nonl.sh', + 't4102-apply-rename.sh', + 't4103-apply-binary.sh', + 't4104-apply-boundary.sh', + 't4105-apply-fuzz.sh', + 't4106-apply-stdin.sh', + 't4107-apply-ignore-whitespace.sh', + 't4108-apply-threeway.sh', + 't4109-apply-multifrag.sh', + 't4110-apply-scan.sh', + 't4111-apply-subdir.sh', + 't4112-apply-renames.sh', + 't4113-apply-ending.sh', + 't4114-apply-typechange.sh', + 't4115-apply-symlink.sh', + 't4116-apply-reverse.sh', + 't4117-apply-reject.sh', + 't4118-apply-empty-context.sh', + 't4119-apply-config.sh', + 't4120-apply-popt.sh', + 't4121-apply-diffs.sh', + 't4122-apply-symlink-inside.sh', + 't4123-apply-shrink.sh', + 't4124-apply-ws-rule.sh', + 't4125-apply-ws-fuzz.sh', + 't4126-apply-empty.sh', + 't4127-apply-same-fn.sh', + 't4128-apply-root.sh', + 't4129-apply-samemode.sh', + 't4130-apply-criss-cross-rename.sh', + 't4131-apply-fake-ancestor.sh', + 't4132-apply-removal.sh', + 't4133-apply-filenames.sh', + 't4134-apply-submodule.sh', + 't4135-apply-weird-filenames.sh', + 't4136-apply-check.sh', + 't4137-apply-submodule.sh', + 't4138-apply-ws-expansion.sh', + 't4139-apply-escape.sh', + 't4140-apply-ita.sh', + 't4141-apply-too-large.sh', + 't4150-am.sh', + 't4151-am-abort.sh', + 't4152-am-subjects.sh', + 't4153-am-resume-override-opts.sh', + 't4200-rerere.sh', + 't4201-shortlog.sh', + 't4202-log.sh', + 't4203-mailmap.sh', + 't4204-patch-id.sh', + 't4205-log-pretty-formats.sh', + 't4206-log-follow-harder-copies.sh', + 't4207-log-decoration-colors.sh', + 't4208-log-magic-pathspec.sh', + 't4209-log-pickaxe.sh', + 't4210-log-i18n.sh', + 't4211-line-log.sh', + 't4212-log-corrupt.sh', + 't4213-log-tabexpand.sh', + 't4214-log-graph-octopus.sh', + 't4215-log-skewed-merges.sh', + 't4216-log-bloom.sh', + 't4217-log-limit.sh', + 't4252-am-options.sh', + 't4253-am-keep-cr-dos.sh', + 't4254-am-corrupt.sh', + 't4255-am-submodule.sh', + 't4256-am-format-flowed.sh', + 't4257-am-interactive.sh', + 't4258-am-quoted-cr.sh', + 't4300-merge-tree.sh', + 't4301-merge-tree-write-tree.sh', + 't5000-tar-tree.sh', + 't5001-archive-attr.sh', + 't5002-archive-attr-pattern.sh', + 't5003-archive-zip.sh', + 't5004-archive-corner-cases.sh', + 't5100-mailinfo.sh', + 't5150-request-pull.sh', + 't5200-update-server-info.sh', + 't5300-pack-object.sh', + 't5301-sliding-window.sh', + 't5302-pack-index.sh', + 't5303-pack-corruption-resilience.sh', + 't5304-prune.sh', + 't5305-include-tag.sh', + 't5306-pack-nobase.sh', + 't5307-pack-missing-commit.sh', + 't5308-pack-detect-duplicates.sh', + 't5309-pack-delta-cycles.sh', + 't5310-pack-bitmaps.sh', + 't5311-pack-bitmaps-shallow.sh', + 't5312-prune-corruption.sh', + 't5313-pack-bounds-checks.sh', + 't5314-pack-cycle-detection.sh', + 't5315-pack-objects-compression.sh', + 't5316-pack-delta-depth.sh', + 't5317-pack-objects-filter-objects.sh', + 't5318-commit-graph.sh', + 't5319-multi-pack-index.sh', + 't5320-delta-islands.sh', + 't5321-pack-large-objects.sh', + 't5322-pack-objects-sparse.sh', + 't5323-pack-redundant.sh', + 't5324-split-commit-graph.sh', + 't5325-reverse-index.sh', + 't5326-multi-pack-bitmaps.sh', + 't5327-multi-pack-bitmaps-rev.sh', + 't5328-commit-graph-64bit-time.sh', + 't5329-pack-objects-cruft.sh', + 't5330-no-lazy-fetch-with-commit-graph.sh', + 't5331-pack-objects-stdin.sh', + 't5332-multi-pack-reuse.sh', + 't5333-pseudo-merge-bitmaps.sh', + 't5334-incremental-multi-pack-index.sh', + 't5351-unpack-large-objects.sh', + 't5400-send-pack.sh', + 't5401-update-hooks.sh', + 't5402-post-merge-hook.sh', + 't5403-post-checkout-hook.sh', + 't5404-tracking-branches.sh', + 't5405-send-pack-rewind.sh', + 't5406-remote-rejects.sh', + 't5407-post-rewrite-hook.sh', + 't5408-send-pack-stdin.sh', + 't5409-colorize-remote-messages.sh', + 't5410-receive-pack-alternates.sh', + 't5411-proc-receive-hook.sh', + 't5500-fetch-pack.sh', + 't5501-fetch-push-alternates.sh', + 't5502-quickfetch.sh', + 't5503-tagfollow.sh', + 't5504-fetch-receive-strict.sh', + 't5505-remote.sh', + 't5506-remote-groups.sh', + 't5507-remote-environment.sh', + 't5509-fetch-push-namespaces.sh', + 't5510-fetch.sh', + 't5511-refspec.sh', + 't5512-ls-remote.sh', + 't5513-fetch-track.sh', + 't5514-fetch-multiple.sh', + 't5515-fetch-merge-logic.sh', + 't5516-fetch-push.sh', + 't5517-push-mirror.sh', + 't5518-fetch-exit-status.sh', + 't5519-push-alternates.sh', + 't5520-pull.sh', + 't5521-pull-options.sh', + 't5522-pull-symlink.sh', + 't5523-push-upstream.sh', + 't5524-pull-msg.sh', + 't5525-fetch-tagopt.sh', + 't5526-fetch-submodules.sh', + 't5527-fetch-odd-refs.sh', + 't5528-push-default.sh', + 't5529-push-errors.sh', + 't5530-upload-pack-error.sh', + 't5531-deep-submodule-push.sh', + 't5532-fetch-proxy.sh', + 't5533-push-cas.sh', + 't5534-push-signed.sh', + 't5535-fetch-push-symref.sh', + 't5536-fetch-conflicts.sh', + 't5537-fetch-shallow.sh', + 't5538-push-shallow.sh', + 't5539-fetch-http-shallow.sh', + 't5540-http-push-webdav.sh', + 't5541-http-push-smart.sh', + 't5542-push-http-shallow.sh', + 't5543-atomic-push.sh', + 't5544-pack-objects-hook.sh', + 't5545-push-options.sh', + 't5546-receive-limits.sh', + 't5547-push-quarantine.sh', + 't5548-push-porcelain.sh', + 't5549-fetch-push-http.sh', + 't5550-http-fetch-dumb.sh', + 't5551-http-fetch-smart.sh', + 't5552-skipping-fetch-negotiator.sh', + 't5553-set-upstream.sh', + 't5554-noop-fetch-negotiator.sh', + 't5555-http-smart-common.sh', + 't5557-http-get.sh', + 't5558-clone-bundle-uri.sh', + 't5559-http-fetch-smart-http2.sh', + 't5560-http-backend-noserver.sh', + 't5561-http-backend.sh', + 't5562-http-backend-content-length.sh', + 't5563-simple-http-auth.sh', + 't5564-http-proxy.sh', + 't5570-git-daemon.sh', + 't5571-pre-push-hook.sh', + 't5572-pull-submodule.sh', + 't5573-pull-verify-signatures.sh', + 't5574-fetch-output.sh', + 't5580-unc-paths.sh', + 't5581-http-curl-verbose.sh', + 't5582-fetch-negative-refspec.sh', + 't5583-push-branches.sh', + 't5600-clone-fail-cleanup.sh', + 't5601-clone.sh', + 't5602-clone-remote-exec.sh', + 't5603-clone-dirname.sh', + 't5604-clone-reference.sh', + 't5605-clone-local.sh', + 't5606-clone-options.sh', + 't5607-clone-bundle.sh', + 't5608-clone-2gb.sh', + 't5609-clone-branch.sh', + 't5610-clone-detached.sh', + 't5611-clone-config.sh', + 't5612-clone-refspec.sh', + 't5613-info-alternate.sh', + 't5614-clone-submodules-shallow.sh', + 't5615-alternate-env.sh', + 't5616-partial-clone.sh', + 't5617-clone-submodules-remote.sh', + 't5618-alternate-refs.sh', + 't5619-clone-local-ambiguous-transport.sh', + 't5700-protocol-v1.sh', + 't5701-git-serve.sh', + 't5702-protocol-v2.sh', + 't5703-upload-pack-ref-in-want.sh', + 't5704-protocol-violations.sh', + 't5705-session-id-in-capabilities.sh', + 't5730-protocol-v2-bundle-uri-file.sh', + 't5731-protocol-v2-bundle-uri-git.sh', + 't5732-protocol-v2-bundle-uri-http.sh', + 't5750-bundle-uri-parse.sh', + 't5801-remote-helpers.sh', + 't5802-connect-helper.sh', + 't5810-proto-disable-local.sh', + 't5811-proto-disable-git.sh', + 't5812-proto-disable-http.sh', + 't5813-proto-disable-ssh.sh', + 't5814-proto-disable-ext.sh', + 't5815-submodule-protos.sh', + 't5900-repo-selection.sh', + 't6000-rev-list-misc.sh', + 't6001-rev-list-graft.sh', + 't6002-rev-list-bisect.sh', + 't6003-rev-list-topo-order.sh', + 't6004-rev-list-path-optim.sh', + 't6005-rev-list-count.sh', + 't6006-rev-list-format.sh', + 't6007-rev-list-cherry-pick-file.sh', + 't6008-rev-list-submodule.sh', + 't6009-rev-list-parent.sh', + 't6010-merge-base.sh', + 't6011-rev-list-with-bad-commit.sh', + 't6012-rev-list-simplify.sh', + 't6013-rev-list-reverse-parents.sh', + 't6014-rev-list-all.sh', + 't6016-rev-list-graph-simplify-history.sh', + 't6017-rev-list-stdin.sh', + 't6018-rev-list-glob.sh', + 't6019-rev-list-ancestry-path.sh', + 't6020-bundle-misc.sh', + 't6021-rev-list-exclude-hidden.sh', + 't6022-rev-list-missing.sh', + 't6030-bisect-porcelain.sh', + 't6040-tracking-info.sh', + 't6041-bisect-submodule.sh', + 't6050-replace.sh', + 't6060-merge-index.sh', + 't6100-rev-list-in-order.sh', + 't6101-rev-parse-parents.sh', + 't6102-rev-list-unexpected-objects.sh', + 't6110-rev-list-sparse.sh', + 't6111-rev-list-treesame.sh', + 't6112-rev-list-filters-objects.sh', + 't6113-rev-list-bitmap-filters.sh', + 't6114-keep-packs.sh', + 't6115-rev-list-du.sh', + 't6120-describe.sh', + 't6130-pathspec-noglob.sh', + 't6131-pathspec-icase.sh', + 't6132-pathspec-exclude.sh', + 't6133-pathspec-rev-dwim.sh', + 't6134-pathspec-in-submodule.sh', + 't6135-pathspec-with-attrs.sh', + 't6136-pathspec-in-bare.sh', + 't6200-fmt-merge-msg.sh', + 't6300-for-each-ref.sh', + 't6301-for-each-ref-errors.sh', + 't6302-for-each-ref-filter.sh', + 't6400-merge-df.sh', + 't6401-merge-criss-cross.sh', + 't6402-merge-rename.sh', + 't6403-merge-file.sh', + 't6404-recursive-merge.sh', + 't6405-merge-symlinks.sh', + 't6406-merge-attr.sh', + 't6407-merge-binary.sh', + 't6408-merge-up-to-date.sh', + 't6409-merge-subtree.sh', + 't6411-merge-filemode.sh', + 't6412-merge-large-rename.sh', + 't6413-merge-crlf.sh', + 't6414-merge-rename-nocruft.sh', + 't6415-merge-dir-to-symlink.sh', + 't6416-recursive-corner-cases.sh', + 't6417-merge-ours-theirs.sh', + 't6418-merge-text-auto.sh', + 't6419-merge-ignorecase.sh', + 't6421-merge-partial-clone.sh', + 't6422-merge-rename-corner-cases.sh', + 't6423-merge-rename-directories.sh', + 't6424-merge-unrelated-index-changes.sh', + 't6425-merge-rename-delete.sh', + 't6426-merge-skip-unneeded-updates.sh', + 't6427-diff3-conflict-markers.sh', + 't6428-merge-conflicts-sparse.sh', + 't6429-merge-sequence-rename-caching.sh', + 't6430-merge-recursive.sh', + 't6431-merge-criscross.sh', + 't6432-merge-recursive-space-options.sh', + 't6433-merge-toplevel.sh', + 't6434-merge-recursive-rename-options.sh', + 't6435-merge-sparse.sh', + 't6436-merge-overwrite.sh', + 't6437-submodule-merge.sh', + 't6438-submodule-directory-file-conflicts.sh', + 't6439-merge-co-error-msgs.sh', + 't6500-gc.sh', + 't6501-freshen-objects.sh', + 't6600-test-reach.sh', + 't6700-tree-depth.sh', + 't7001-mv.sh', + 't7002-mv-sparse-checkout.sh', + 't7003-filter-branch.sh', + 't7004-tag.sh', + 't7005-editor.sh', + 't7006-pager.sh', + 't7007-show.sh', + 't7008-filter-branch-null-sha1.sh', + 't7010-setup.sh', + 't7011-skip-worktree-reading.sh', + 't7012-skip-worktree-writing.sh', + 't7030-verify-tag.sh', + 't7031-verify-tag-signed-ssh.sh', + 't7060-wtstatus.sh', + 't7061-wtstatus-ignore.sh', + 't7062-wtstatus-ignorecase.sh', + 't7063-status-untracked-cache.sh', + 't7064-wtstatus-pv2.sh', + 't7101-reset-empty-subdirs.sh', + 't7102-reset.sh', + 't7103-reset-bare.sh', + 't7104-reset-hard.sh', + 't7105-reset-patch.sh', + 't7106-reset-unborn-branch.sh', + 't7107-reset-pathspec-file.sh', + 't7110-reset-merge.sh', + 't7111-reset-table.sh', + 't7112-reset-submodule.sh', + 't7113-post-index-change-hook.sh', + 't7201-co.sh', + 't7300-clean.sh', + 't7301-clean-interactive.sh', + 't7400-submodule-basic.sh', + 't7401-submodule-summary.sh', + 't7402-submodule-rebase.sh', + 't7403-submodule-sync.sh', + 't7406-submodule-update.sh', + 't7407-submodule-foreach.sh', + 't7408-submodule-reference.sh', + 't7409-submodule-detached-work-tree.sh', + 't7411-submodule-config.sh', + 't7412-submodule-absorbgitdirs.sh', + 't7413-submodule-is-active.sh', + 't7414-submodule-mistakes.sh', + 't7416-submodule-dash-url.sh', + 't7417-submodule-path-url.sh', + 't7418-submodule-sparse-gitmodules.sh', + 't7419-submodule-set-branch.sh', + 't7420-submodule-set-url.sh', + 't7421-submodule-summary-add.sh', + 't7422-submodule-output.sh', + 't7423-submodule-symlinks.sh', + 't7424-submodule-mixed-ref-formats.sh', + 't7450-bad-git-dotfiles.sh', + 't7500-commit-template-squash-signoff.sh', + 't7501-commit-basic-functionality.sh', + 't7502-commit-porcelain.sh', + 't7503-pre-commit-and-pre-merge-commit-hooks.sh', + 't7504-commit-msg-hook.sh', + 't7505-prepare-commit-msg-hook.sh', + 't7506-status-submodule.sh', + 't7507-commit-verbose.sh', + 't7508-status.sh', + 't7509-commit-authorship.sh', + 't7510-signed-commit.sh', + 't7511-status-index.sh', + 't7512-status-help.sh', + 't7513-interpret-trailers.sh', + 't7514-commit-patch.sh', + 't7515-status-symlinks.sh', + 't7516-commit-races.sh', + 't7517-per-repo-email.sh', + 't7518-ident-corner-cases.sh', + 't7519-status-fsmonitor.sh', + 't7520-ignored-hook-warning.sh', + 't7521-ignored-mode.sh', + 't7524-commit-summary.sh', + 't7525-status-rename.sh', + 't7526-commit-pathspec-file.sh', + 't7527-builtin-fsmonitor.sh', + 't7528-signed-commit-ssh.sh', + 't7600-merge.sh', + 't7601-merge-pull-config.sh', + 't7602-merge-octopus-many.sh', + 't7603-merge-reduce-heads.sh', + 't7604-merge-custom-message.sh', + 't7605-merge-resolve.sh', + 't7606-merge-custom.sh', + 't7607-merge-state.sh', + 't7608-merge-messages.sh', + 't7609-mergetool--lib.sh', + 't7610-mergetool.sh', + 't7611-merge-abort.sh', + 't7612-merge-verify-signatures.sh', + 't7614-merge-signoff.sh', + 't7615-diff-algo-with-mergy-operations.sh', + 't7700-repack.sh', + 't7701-repack-unpack-unreachable.sh', + 't7702-repack-cyclic-alternate.sh', + 't7703-repack-geometric.sh', + 't7704-repack-cruft.sh', + 't7800-difftool.sh', + 't7810-grep.sh', + 't7811-grep-open.sh', + 't7812-grep-icase-non-ascii.sh', + 't7813-grep-icase-iso.sh', + 't7814-grep-recurse-submodules.sh', + 't7815-grep-binary.sh', + 't7816-grep-binary-pattern.sh', + 't7817-grep-sparse-checkout.sh', + 't7900-maintenance.sh', + 't8001-annotate.sh', + 't8002-blame.sh', + 't8003-blame-corner-cases.sh', + 't8004-blame-with-conflicts.sh', + 't8005-blame-i18n.sh', + 't8006-blame-textconv.sh', + 't8007-cat-file-textconv.sh', + 't8008-blame-formats.sh', + 't8009-blame-vs-topicbranches.sh', + 't8010-cat-file-filters.sh', + 't8011-blame-split-file.sh', + 't8012-blame-colors.sh', + 't8013-blame-ignore-revs.sh', + 't8014-blame-ignore-fuzzy.sh', + 't9001-send-email.sh', + 't9002-column.sh', + 't9003-help-autocorrect.sh', + 't9100-git-svn-basic.sh', + 't9101-git-svn-props.sh', + 't9102-git-svn-deep-rmdir.sh', + 't9103-git-svn-tracked-directory-removed.sh', + 't9104-git-svn-follow-parent.sh', + 't9105-git-svn-commit-diff.sh', + 't9106-git-svn-commit-diff-clobber.sh', + 't9107-git-svn-migrate.sh', + 't9108-git-svn-glob.sh', + 't9109-git-svn-multi-glob.sh', + 't9110-git-svn-use-svm-props.sh', + 't9111-git-svn-use-svnsync-props.sh', + 't9112-git-svn-md5less-file.sh', + 't9113-git-svn-dcommit-new-file.sh', + 't9114-git-svn-dcommit-merge.sh', + 't9115-git-svn-dcommit-funky-renames.sh', + 't9116-git-svn-log.sh', + 't9117-git-svn-init-clone.sh', + 't9118-git-svn-funky-branch-names.sh', + 't9119-git-svn-info.sh', + 't9120-git-svn-clone-with-percent-escapes.sh', + 't9121-git-svn-fetch-renamed-dir.sh', + 't9122-git-svn-author.sh', + 't9123-git-svn-rebuild-with-rewriteroot.sh', + 't9124-git-svn-dcommit-auto-props.sh', + 't9125-git-svn-multi-glob-branch-names.sh', + 't9126-git-svn-follow-deleted-readded-directory.sh', + 't9127-git-svn-partial-rebuild.sh', + 't9128-git-svn-cmd-branch.sh', + 't9129-git-svn-i18n-commitencoding.sh', + 't9130-git-svn-authors-file.sh', + 't9131-git-svn-empty-symlink.sh', + 't9132-git-svn-broken-symlink.sh', + 't9133-git-svn-nested-git-repo.sh', + 't9134-git-svn-ignore-paths.sh', + 't9135-git-svn-moved-branch-empty-file.sh', + 't9136-git-svn-recreated-branch-empty-file.sh', + 't9137-git-svn-dcommit-clobber-series.sh', + 't9138-git-svn-authors-prog.sh', + 't9139-git-svn-non-utf8-commitencoding.sh', + 't9140-git-svn-reset.sh', + 't9141-git-svn-multiple-branches.sh', + 't9142-git-svn-shallow-clone.sh', + 't9143-git-svn-gc.sh', + 't9144-git-svn-old-rev_map.sh', + 't9145-git-svn-master-branch.sh', + 't9146-git-svn-empty-dirs.sh', + 't9147-git-svn-include-paths.sh', + 't9148-git-svn-propset.sh', + 't9150-svk-mergetickets.sh', + 't9151-svn-mergeinfo.sh', + 't9152-svn-empty-dirs-after-gc.sh', + 't9153-git-svn-rewrite-uuid.sh', + 't9154-git-svn-fancy-glob.sh', + 't9155-git-svn-fetch-deleted-tag.sh', + 't9156-git-svn-fetch-deleted-tag-2.sh', + 't9157-git-svn-fetch-merge.sh', + 't9158-git-svn-mergeinfo.sh', + 't9159-git-svn-no-parent-mergeinfo.sh', + 't9160-git-svn-preserve-empty-dirs.sh', + 't9161-git-svn-mergeinfo-push.sh', + 't9162-git-svn-dcommit-interactive.sh', + 't9163-git-svn-reset-clears-caches.sh', + 't9164-git-svn-dcommit-concurrent.sh', + 't9165-git-svn-fetch-merge-branch-of-branch.sh', + 't9166-git-svn-fetch-merge-branch-of-branch2.sh', + 't9167-git-svn-cmd-branch-subproject.sh', + 't9168-git-svn-partially-globbed-names.sh', + 't9169-git-svn-dcommit-crlf.sh', + 't9200-git-cvsexportcommit.sh', + 't9210-scalar.sh', + 't9211-scalar-clone.sh', + 't9300-fast-import.sh', + 't9301-fast-import-notes.sh', + 't9302-fast-import-unpack-limit.sh', + 't9303-fast-import-compression.sh', + 't9304-fast-import-marks.sh', + 't9350-fast-export.sh', + 't9351-fast-export-anonymize.sh', + 't9400-git-cvsserver-server.sh', + 't9401-git-cvsserver-crlf.sh', + 't9402-git-cvsserver-refs.sh', + 't9500-gitweb-standalone-no-errors.sh', + 't9501-gitweb-standalone-http-status.sh', + 't9502-gitweb-standalone-parse-output.sh', + 't9600-cvsimport.sh', + 't9601-cvsimport-vendor-branch.sh', + 't9602-cvsimport-branches-tags.sh', + 't9603-cvsimport-patchsets.sh', + 't9604-cvsimport-timestamps.sh', + 't9700-perl-git.sh', + 't9800-git-p4-basic.sh', + 't9801-git-p4-branch.sh', + 't9802-git-p4-filetype.sh', + 't9803-git-p4-shell-metachars.sh', + 't9804-git-p4-label.sh', + 't9805-git-p4-skip-submit-edit.sh', + 't9806-git-p4-options.sh', + 't9807-git-p4-submit.sh', + 't9808-git-p4-chdir.sh', + 't9809-git-p4-client-view.sh', + 't9810-git-p4-rcs.sh', + 't9811-git-p4-label-import.sh', + 't9812-git-p4-wildcards.sh', + 't9813-git-p4-preserve-users.sh', + 't9814-git-p4-rename.sh', + 't9815-git-p4-submit-fail.sh', + 't9816-git-p4-locked.sh', + 't9817-git-p4-exclude.sh', + 't9818-git-p4-block.sh', + 't9819-git-p4-case-folding.sh', + 't9820-git-p4-editor-handling.sh', + 't9821-git-p4-path-variations.sh', + 't9822-git-p4-path-encoding.sh', + 't9823-git-p4-mock-lfs.sh', + 't9824-git-p4-git-lfs.sh', + 't9825-git-p4-handle-utf16-without-bom.sh', + 't9826-git-p4-keep-empty-commits.sh', + 't9827-git-p4-change-filetype.sh', + 't9828-git-p4-map-user.sh', + 't9829-git-p4-jobs.sh', + 't9830-git-p4-symlink-dir.sh', + 't9831-git-p4-triggers.sh', + 't9832-unshelve.sh', + 't9833-errors.sh', + 't9834-git-p4-file-dir-bug.sh', + 't9835-git-p4-metadata-encoding-python2.sh', + 't9836-git-p4-metadata-encoding-python3.sh', + 't9850-shell.sh', + 't9901-git-web--browse.sh', + 't9902-completion.sh', + 't9903-bash-prompt.sh', +] + +# GIT_BUILD_DIR needs to be Unix-style without drive prefixes as it get added +# to the PATH variable. And given that drive prefixes contain a colon we'd +# otherwise end up with a broken PATH if we didn't convert it. +git_build_dir = meson.project_build_root() +if cygpath.found() + git_build_dir = run_command(cygpath, git_build_dir, check: true).stdout().strip() +endif + +test_environment = script_environment +test_environment.set('GIT_BUILD_DIR', git_build_dir) + +foreach integration_test : integration_tests + test(fs.stem(integration_test), shell, + args: [ integration_test ], + workdir: meson.current_source_dir(), + env: test_environment, + depends: test_dependencies + bin_wrappers, + timeout: 0, + ) +endforeach diff --git a/templates/hooks/meson.build b/templates/hooks/meson.build new file mode 100644 index 0000000000..ef85e10a16 --- /dev/null +++ b/templates/hooks/meson.build @@ -0,0 +1,26 @@ +hooks = [ + 'applypatch-msg.sample', + 'commit-msg.sample', + 'fsmonitor-watchman.sample', + 'post-update.sample', + 'pre-applypatch.sample', + 'pre-commit.sample', + 'pre-merge-commit.sample', + 'prepare-commit-msg.sample', + 'pre-push.sample', + 'pre-rebase.sample', + 'pre-receive.sample', + 'push-to-checkout.sample', + 'sendemail-validate.sample', + 'update.sample', +] + +foreach hook : hooks + configure_file( + input: hook, + output: hook, + configuration: template_config, + install: true, + install_dir: get_option('datadir') / 'git-core/templates/hooks', + ) +endforeach diff --git a/templates/info/meson.build b/templates/info/meson.build new file mode 100644 index 0000000000..026f231385 --- /dev/null +++ b/templates/info/meson.build @@ -0,0 +1,7 @@ +configure_file( + input: 'exclude', + output: 'exclude', + configuration: template_config, + install: true, + install_dir: get_option('datadir') / 'git-core/templates/info', +) diff --git a/templates/meson.build b/templates/meson.build new file mode 100644 index 0000000000..1faf9a44ce --- /dev/null +++ b/templates/meson.build @@ -0,0 +1,15 @@ +template_config = configuration_data() +template_config.set('PERL_PATH', perl.found() ? fs.as_posix(perl.full_path()) : '') +template_config.set('SHELL_PATH', fs.as_posix(shell.full_path())) +template_config.set('GITWEBDIR', fs.as_posix(get_option('prefix') / get_option('datadir') / 'gitweb')) + +configure_file( + input: 'description', + output: 'description', + configuration: template_config, + install: true, + install_dir: get_option('datadir') / 'git-core/templates', +) + +subdir('hooks') +subdir('info') -- cgit v1.2.3 From 49c6b912e2f4c49784d471f8c9364077c423dbf5 Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Fri, 6 Dec 2024 14:13:19 +0100 Subject: reftable/writer: ensure valid range for log's update_index Each reftable addition has an associated update_index. While writing refs, the update_index is verified to be within the range of the reftable writer, i.e. `writer.min_update_index <= ref.update_index` and `writer.max_update_index => ref.update_index`. The corresponding check for reflogs in `reftable_writer_add_log` is however missing. Add a similar check, but only check for the upper limit. This is because reflogs are treated a bit differently than refs. Each reflog entry in reftable has an associated update_index and we also allow expiring entries in the middle, which is done by simply writing a new reflog entry with the same update_index. This means, writing reflog entries with update_index lesser than the writer's update_index is an expected scenario. Add a new unit test to check for the limits and fix some of the existing tests, which were setting arbitrary values for the update_index by ensuring they stay within the now checked limits. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- reftable/writer.c | 12 ++++++++++ t/unit-tests/t-reftable-readwrite.c | 47 +++++++++++++++++++++++++++++++++++-- t/unit-tests/t-reftable-stack.c | 8 +++++-- 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/reftable/writer.c b/reftable/writer.c index fd136794d5..f87086777c 100644 --- a/reftable/writer.c +++ b/reftable/writer.c @@ -412,6 +412,18 @@ int reftable_writer_add_log(struct reftable_writer *w, if (log->value_type == REFTABLE_LOG_DELETION) return reftable_writer_add_log_verbatim(w, log); + /* + * Verify only the upper limit of the update_index. Each reflog entry + * is tied to a specific update_index. Entries in the reflog can be + * replaced by adding a new entry with the same update_index, + * effectively canceling the old one. + * + * Consequently, reflog updates may include update_index values lower + * than the writer's min_update_index. + */ + if (log->update_index > w->max_update_index) + return REFTABLE_API_ERROR; + if (!log->refname) return REFTABLE_API_ERROR; diff --git a/t/unit-tests/t-reftable-readwrite.c b/t/unit-tests/t-reftable-readwrite.c index d279b86df0..7ffbd78c67 100644 --- a/t/unit-tests/t-reftable-readwrite.c +++ b/t/unit-tests/t-reftable-readwrite.c @@ -90,7 +90,7 @@ static void t_log_buffer_size(void) int i; struct reftable_log_record log = { .refname = (char *) "refs/heads/master", - .update_index = 0xa, + .update_index = update_index, .value_type = REFTABLE_LOG_UPDATE, .value = { .update = { .name = (char *) "Han-Wen Nienhuys", @@ -127,7 +127,7 @@ static void t_log_overflow(void) int err; struct reftable_log_record log = { .refname = (char *) "refs/heads/master", - .update_index = 0xa, + .update_index = update_index, .value_type = REFTABLE_LOG_UPDATE, .value = { .update = { @@ -151,6 +151,48 @@ static void t_log_overflow(void) reftable_buf_release(&buf); } +static void t_log_write_limits(void) +{ + struct reftable_write_options opts = { 0 }; + struct reftable_buf buf = REFTABLE_BUF_INIT; + struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); + struct reftable_log_record log = { + .refname = (char *)"refs/head/master", + .update_index = 0, + .value_type = REFTABLE_LOG_UPDATE, + .value = { + .update = { + .old_hash = { 1 }, + .new_hash = { 2 }, + .name = (char *)"Han-Wen Nienhuys", + .email = (char *)"hanwen@google.com", + .tz_offset = 100, + .time = 0x5e430672, + }, + }, + }; + int err; + + reftable_writer_set_limits(w, 1, 1); + + /* write with update_index (0) below set limits (1, 1) */ + err = reftable_writer_add_log(w, &log); + check_int(err, ==, 0); + + /* write with update_index (1) in the set limits (1, 1) */ + log.update_index = 1; + err = reftable_writer_add_log(w, &log); + check_int(err, ==, 0); + + /* write with update_index (3) above set limits (1, 1) */ + log.update_index = 3; + err = reftable_writer_add_log(w, &log); + check_int(err, ==, REFTABLE_API_ERROR); + + reftable_writer_free(w); + reftable_buf_release(&buf); +} + static void t_log_write_read(void) { struct reftable_write_options opts = { @@ -917,6 +959,7 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED) TEST(t_corrupt_table_empty(), "read-write on an empty table"); TEST(t_log_buffer_size(), "buffer extension for log compression"); TEST(t_log_overflow(), "log overflow returns expected error"); + TEST(t_log_write_limits(), "writer limits for writing log records"); TEST(t_log_write_read(), "read-write on log records"); TEST(t_log_zlib_corruption(), "reading corrupted log record returns expected error"); TEST(t_table_read_api(), "read on a table"); diff --git a/t/unit-tests/t-reftable-stack.c b/t/unit-tests/t-reftable-stack.c index 72f6747064..52b81475c3 100644 --- a/t/unit-tests/t-reftable-stack.c +++ b/t/unit-tests/t-reftable-stack.c @@ -770,8 +770,12 @@ static void t_reftable_stack_tombstone(void) } logs[i].refname = xstrdup(buf); - /* update_index is part of the key. */ - logs[i].update_index = 42; + /* + * update_index is part of the key so should be constant. + * The value itself should be less than the writer's upper + * limit. + */ + logs[i].update_index = 1; if (i % 2 == 0) { logs[i].value_type = REFTABLE_LOG_UPDATE; t_reftable_set_hash(logs[i].value.update.new_hash, i, -- cgit v1.2.3 From 6c915c3f85f70b6adbe1a6b17dea743e8ff6dee1 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 6 Dec 2024 17:08:00 +0900 Subject: fetch: do not ask for HEAD unnecessarily In 3f763ddf28 (fetch: set remote/HEAD if it does not exist, 2024-11-22), git-fetch learned to opportunistically set $REMOTE/HEAD when fetching by always asking for remote HEAD, in the hope that it will help setting refs/remotes//HEAD if missing. But it is not needed to always ask for remote HEAD. When we are fetching from a remote, for which we have remote-tracking branches, we do need to know about HEAD. But if we are doing one-shot fetch, e.g., $ git fetch --tags https://github.com/git/git we do not even know what sub-hierarchy of refs/remotes// we need to adjust the remote HEAD for. There is no need to ask for HEAD in such a case. Incidentally, because the unconditional request to list "HEAD" affected the number of ref-prefixes requested in the ls-remote request, this affected how the requests for tags are added to the same ls-remote request, breaking "git fetch --tags $URL" performed against a URL that is not configured as a remote. Reported-by: Josh Steadmon [jc: tests are also borrowed from Josh's patch] Signed-off-by: Junio C Hamano --- builtin/fetch.c | 20 +++++++++++++++++++- t/t5510-fetch.sh | 17 +++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/builtin/fetch.c b/builtin/fetch.c index a64de4485f..3eb6f3acc9 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1643,6 +1643,21 @@ cleanup: return result; } +static int uses_remote_tracking(struct transport *transport, struct refspec *rs) +{ + if (!remote_is_configured(transport->remote, 0)) + return 0; + + if (!rs->nr) + rs = &transport->remote->fetch; + + for (int i = 0; i < rs->nr; i++) + if (rs->items[i].dst) + return 1; + + return 0; +} + static int do_fetch(struct transport *transport, struct refspec *rs, const struct fetch_config *config) @@ -1712,7 +1727,10 @@ static int do_fetch(struct transport *transport, "refs/tags/"); } - strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD"); + if (uses_remote_tracking(transport, rs)) { + must_list_refs = 1; + strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD"); + } if (must_list_refs) { trace2_region_enter("fetch", "remote_refs", the_repository); diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 87698341f5..d7602333ff 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -189,6 +189,23 @@ test_expect_success 'fetch --prune --tags with refspec prunes based on refspec' git rev-parse sometag ' +test_expect_success 'fetch --tags gets tags even without a configured remote' ' + REMOTE="$(pwd)/test_tag_1" && + git init test_tag_1 && + ( + cd test_tag_1 && + test_commit foo + ) && + git init test_tag_2 && + ( + cd test_tag_2 && + git fetch --tags "file://$REMOTE" && + echo "foo" >expect && + git tag >actual && + test_cmp expect actual + ) +' + test_expect_success REFFILES 'fetch --prune fails to delete branches' ' cd "$D" && git clone . prune-fail && -- cgit v1.2.3 From 0ff919e87a08b7ab81507917ca55eb613296d043 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 6 Dec 2024 16:45:13 +0100 Subject: object-name: fix reversed ordering with ":/" revisions Recently it was reported [1] that "look for the youngest commit reachable from any ref with log message that match the given pattern" syntax (i.e. ':/') started to return results in reverse recency order. This regression was introduced in Git v2.47.0 and is caused by a memory leak fix done in 57fb139b5e (object-name: fix leaking commit list items, 2024-08-01). The intent of the identified commit is to stop modifying the commit list provided by the caller such that the caller can properly free all commit list items, including those that the called function might potentially remove from the list. This was done by creating a copy of the passed-in commit list and modifying this copy instead of the caller-provided list. We already knew to create such a copy beforehand with the `backup` list, which was used to clear the `ONELINE_SEEN` commit mark after we were done. So the refactoring simply renamed that list to `copy` and started to operate on that list instead. There is a gotcha though: the backup list, and thus now also the copied list, is always being prepended to, so the resulting list is in reverse order! The end result is that we pop commits from the wrong end of the commit list, returning commits in reverse recency order. Fix the bug by appending to the list instead. [1]: Reported-by: Aarni Koskela Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- object-name.c | 4 ++-- t/t1500-rev-parse.sh | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/object-name.c b/object-name.c index 240a93e7ce..4c50559ee8 100644 --- a/object-name.c +++ b/object-name.c @@ -1393,7 +1393,7 @@ static int get_oid_oneline(struct repository *r, const char *prefix, struct object_id *oid, const struct commit_list *list) { - struct commit_list *copy = NULL; + struct commit_list *copy = NULL, **copy_tail = © const struct commit_list *l; int found = 0; int negative = 0; @@ -1415,7 +1415,7 @@ static int get_oid_oneline(struct repository *r, for (l = list; l; l = l->next) { l->item->object.flags |= ONELINE_SEEN; - commit_list_insert(l->item, ©); + copy_tail = &commit_list_insert(l->item, copy_tail)->next; } while (copy) { const char *p, *buf; diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh index 30c31918fd..42c4a63cb9 100755 --- a/t/t1500-rev-parse.sh +++ b/t/t1500-rev-parse.sh @@ -310,4 +310,19 @@ test_expect_success '--short= truncates to the actual hash length' ' test_cmp expect actual ' +test_expect_success ':/ and HEAD^{/} favor more recent matching commits' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit common-old && + test_commit --no-tag common-new && + git rev-parse HEAD >expect && + git rev-parse :/common >actual && + test_cmp expect actual && + git rev-parse HEAD^{/common} >actual && + test_cmp expect actual + ) +' + test_done -- cgit v1.2.3 From e5b5eca3f226e7b48f61f806c419f66b03db99e6 Mon Sep 17 00:00:00 2001 From: Yuri Konotopov Date: Fri, 22 Sep 2023 22:58:39 +0400 Subject: git-gui: use system encoding to show console output This change makes non-ascii console output (eg server messages in the `git push` command output) properly render in the git gui windows. Fixes: https://github.com/prati0100/git-gui/issues/68 Signed-off-by: Yuri Konotopov --- lib/console.tcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/console.tcl b/lib/console.tcl index bb6b9c889e..fafafb81f1 100644 --- a/lib/console.tcl +++ b/lib/console.tcl @@ -97,7 +97,7 @@ method exec {cmd {after {}}} { lappend cmd 2>@1 set fd_f [_open_stdout_stderr $cmd] } - fconfigure $fd_f -blocking 0 -translation binary + fconfigure $fd_f -blocking 0 -translation binary -encoding [encoding system] fileevent $fd_f readable [cb _read $fd_f $after] } -- cgit v1.2.3 From b2490ae42f00f6a40b8fd83d2b2069eb15ef84e2 Mon Sep 17 00:00:00 2001 From: Christoph Sommer Date: Thu, 5 Dec 2024 20:29:39 +0100 Subject: gitk: make headings of preferences bold Make preference groups like "Diff display options" stand out more. Signed-off-by: Christoph Sommer Signed-off-by: Johannes Sixt --- gitk | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gitk b/gitk index de278557b3..2ef01bf5c6 100755 --- a/gitk +++ b/gitk @@ -11581,7 +11581,7 @@ proc prefspage_general {notebook} { set page [create_prefs_page $notebook.general] - ${NS}::label $page.ldisp -text [mc "Commit list display options"] + ${NS}::label $page.ldisp -text [mc "Commit list display options"] -font mainfontbold grid $page.ldisp - -sticky w -pady 10 ${NS}::label $page.spacer -text " " ${NS}::label $page.maxwidthl -text [mc "Maximum graph width (lines)"] @@ -11602,7 +11602,7 @@ proc prefspage_general {notebook} { -variable hideremotes grid x $page.hideremotes -sticky w - ${NS}::label $page.ddisp -text [mc "Diff display options"] + ${NS}::label $page.ddisp -text [mc "Diff display options"] -font mainfontbold grid $page.ddisp - -sticky w -pady 10 ${NS}::label $page.tabstopl -text [mc "Tab spacing"] spinbox $page.tabstop -from 1 -to 20 -width 4 -textvariable tabstop @@ -11635,7 +11635,7 @@ proc prefspage_general {notebook} { pack configure $page.webbrowserf.l -padx 10 grid x $page.webbrowserf $page.webbrowser -sticky ew - ${NS}::label $page.lgen -text [mc "General options"] + ${NS}::label $page.lgen -text [mc "General options"] -font mainfontbold grid $page.lgen - -sticky w -pady 10 ${NS}::checkbutton $page.want_ttk -variable want_ttk \ -text [mc "Use themed widgets"] @@ -11654,7 +11654,7 @@ proc prefspage_colors {notebook} { set page [create_prefs_page $notebook.colors] - ${NS}::label $page.cdisp -text [mc "Colors: press to choose"] + ${NS}::label $page.cdisp -text [mc "Colors: press to choose"] -font mainfontbold grid $page.cdisp - -sticky w -pady 10 label $page.ui -padx 40 -relief sunk -background $uicolor ${NS}::button $page.uibut -text [mc "Interface"] \ @@ -11712,7 +11712,7 @@ proc prefspage_colors {notebook} { proc prefspage_fonts {notebook} { global NS set page [create_prefs_page $notebook.fonts] - ${NS}::label $page.cfont -text [mc "Fonts: press to choose"] + ${NS}::label $page.cfont -text [mc "Fonts: press to choose"] -font mainfontbold grid $page.cfont - -sticky w -pady 10 mkfontdisp mainfont $page [mc "Main font"] mkfontdisp textfont $page [mc "Diff display font"] -- cgit v1.2.3 From 904b36b815ff174ad6abc37b8aa5b8b0f4cedc32 Mon Sep 17 00:00:00 2001 From: Christoph Sommer Date: Thu, 5 Dec 2024 20:33:44 +0100 Subject: gitk: add text wrapping preferences Add a new preference "wrapdefault" which allows enabling char/word wrap. Impacts all text in the ctext widget for which no other preference exists. Also make the (existing) preference "wrapcomment" configurable graphically. Its setting impacts only the "comment" part of the ctext widget. Signed-off-by: Christoph Sommer Signed-off-by: Johannes Sixt --- gitk | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/gitk b/gitk index 2ef01bf5c6..9012a6951a 100755 --- a/gitk +++ b/gitk @@ -2089,7 +2089,7 @@ proc makewindow {} { global diffcontextstring diffcontext global ignorespace global maincursor textcursor curtextcursor - global rowctxmenu fakerowmenu mergemax wrapcomment + global rowctxmenu fakerowmenu mergemax wrapcomment wrapdefault global highlight_files gdttype global searchstring sstring global bgcolor fgcolor bglist fglist diffcolors diffbgcolors selectbgcolor @@ -2431,7 +2431,7 @@ proc makewindow {} { set ctext .bleft.bottom.ctext text $ctext -background $bgcolor -foreground $fgcolor \ -state disabled -undo 0 -font textfont \ - -yscrollcommand scrolltext -wrap none \ + -yscrollcommand scrolltext -wrap $wrapdefault \ -xscrollcommand ".bleft.bottom.sbhorizontal set" if {$have_tk85} { $ctext conf -tabstyle wordprocessor @@ -11576,7 +11576,7 @@ proc create_prefs_page {w} { proc prefspage_general {notebook} { global NS maxwidth maxgraphpct showneartags showlocalchanges - global tabstop limitdiffs autoselect autosellen extdifftool perfile_attrs + global tabstop wrapcomment wrapdefault limitdiffs autoselect autosellen extdifftool perfile_attrs global hideremotes want_ttk have_ttk maxrefs web_browser set page [create_prefs_page $notebook.general] @@ -11607,6 +11607,17 @@ proc prefspage_general {notebook} { ${NS}::label $page.tabstopl -text [mc "Tab spacing"] spinbox $page.tabstop -from 1 -to 20 -width 4 -textvariable tabstop grid x $page.tabstopl $page.tabstop -sticky w + + ${NS}::label $page.wrapcommentl -text [mc "Wrap comment text"] + ${NS}::combobox $page.wrapcomment -values {none char word} -state readonly \ + -textvariable wrapcomment + grid x $page.wrapcommentl $page.wrapcomment -sticky w + + ${NS}::label $page.wrapdefaultl -text [mc "Wrap other text"] + ${NS}::combobox $page.wrapdefault -values {none char word} -state readonly \ + -textvariable wrapdefault + grid x $page.wrapdefaultl $page.wrapdefault -sticky w + ${NS}::checkbutton $page.ntag -text [mc "Display nearby tags/heads"] \ -variable showneartags grid x $page.ntag -sticky w @@ -11725,7 +11736,7 @@ proc doprefs {} { global oldprefs prefstop showneartags showlocalchanges global uicolor bgcolor fgcolor ctext diffcolors selectbgcolor markbgcolor global tabstop limitdiffs autoselect autosellen extdifftool perfile_attrs - global hideremotes want_ttk have_ttk + global hideremotes want_ttk have_ttk wrapcomment wrapdefault set top .gitkprefs set prefstop $top @@ -11734,7 +11745,7 @@ proc doprefs {} { return } foreach v {maxwidth maxgraphpct showneartags showlocalchanges \ - limitdiffs tabstop perfile_attrs hideremotes want_ttk} { + limitdiffs tabstop perfile_attrs hideremotes want_ttk wrapcomment wrapdefault} { set oldprefs($v) [set $v] } ttk_toplevel $top @@ -11860,7 +11871,7 @@ proc prefscan {} { global oldprefs prefstop foreach v {maxwidth maxgraphpct showneartags showlocalchanges \ - limitdiffs tabstop perfile_attrs hideremotes want_ttk} { + limitdiffs tabstop perfile_attrs hideremotes want_ttk wrapcomment wrapdefault} { global $v set $v $oldprefs($v) } @@ -11874,7 +11885,8 @@ proc prefsok {} { global oldprefs prefstop showneartags showlocalchanges global fontpref mainfont textfont uifont global limitdiffs treediffs perfile_attrs - global hideremotes + global hideremotes wrapcomment wrapdefault + global ctext catch {destroy $prefstop} unset prefstop @@ -11923,6 +11935,12 @@ proc prefsok {} { if {$hideremotes != $oldprefs(hideremotes)} { rereadrefs } + if {$wrapcomment != $oldprefs(wrapcomment)} { + $ctext tag conf comment -wrap $wrapcomment + } + if {$wrapdefault != $oldprefs(wrapdefault)} { + $ctext configure -wrap $wrapdefault + } } proc formatdate {d} { @@ -12392,6 +12410,7 @@ set downarrowlen 5 set mingaplen 100 set cmitmode "patch" set wrapcomment "none" +set wrapdefault "none" set showneartags 1 set hideremotes 0 set maxrefs 20 @@ -12497,7 +12516,7 @@ config_check_tmp_exists 50 set config_variables { mainfont textfont uifont tabstop findmergefiles maxgraphpct maxwidth - cmitmode wrapcomment autoselect autosellen showneartags maxrefs visiblerefs + cmitmode wrapcomment wrapdefault autoselect autosellen showneartags maxrefs visiblerefs hideremotes showlocalchanges datetimeformat limitdiffs uicolor want_ttk bgcolor fgcolor uifgcolor uifgdisabledcolor colors diffcolors mergecolors markbgcolor diffcontext selectbgcolor foundbgcolor currentsearchhitbgcolor -- cgit v1.2.3 From 8525e928868757c2ebce3859dae0a9fd0f9ac9fd Mon Sep 17 00:00:00 2001 From: Alejandro Barreto Date: Mon, 9 Dec 2024 19:18:14 +0000 Subject: Document HOME environment variable Git documentation refers to $HOME and $XDG_CONFIG_HOME often, but does not specify how or where these values come from on Windows where neither is set by default. The new documentation reflects the behavior of setup_windows_environment() in compat/mingw.c. Signed-off-by: Alejandro Barreto Signed-off-by: M Hickford Signed-off-by: Junio C Hamano --- Documentation/git.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/git.txt b/Documentation/git.txt index d15a869762..47509c9e1a 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -477,6 +477,14 @@ their values the same way as Boolean valued configuration variables, e.g. Here are the variables: +System +~~~~~~~~~~~~~~~~~~ +`HOME`:: + Specifies the path to the user's home directory. On Windows, if + unset, Git will set a process environment variable equal to: + `$HOMEDRIVE$HOMEPATH` if both `$HOMEDRIVE` and `$HOMEPATH` exist; + otherwise `$USERPROFILE` if `$USERPROFILE` exists. + The Git Repository ~~~~~~~~~~~~~~~~~~ These environment variables apply to 'all' core Git commands. Nb: it -- cgit v1.2.3 From 911d14203c019d52431b1197dcbf44f163eac024 Mon Sep 17 00:00:00 2001 From: Jonathan Tan Date: Tue, 3 Dec 2024 13:52:54 -0800 Subject: index-pack --promisor: dedup before checking links Commit c08589efdc (index-pack: repack local links into promisor packs, 2024-11-01) fixed a bug with what was believed to be a negligible decrease in performance [1] [2]. But at $DAYJOB, with at least one repo, it was found that the decrease in performance was very significant. Looking at the patch, whenever we parse an object in the packfile to be indexed, we check the targets of all its outgoing links for its existence. However, this could be optimized by first collecting all such targets into an oidset (thus deduplicating them) before checking. Teach Git to do that. On a certain fetch from the aforementioned repo, this improved performance from approximately 7 hours to 24m47.815s. This number will be further reduced in a subsequent patch. [1] https://lore.kernel.org/git/CAG1j3zGiNMbri8rZNaF0w+yP+6OdMz0T8+8_Wgd1R_p1HzVasg@mail.gmail.com/ [2] https://lore.kernel.org/git/20241105212849.3759572-1-jonathantanmy@google.com/ Signed-off-by: Jonathan Tan Signed-off-by: Junio C Hamano --- builtin/index-pack.c | 75 +++++++++++++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 95babdc5ea..347a92c2f1 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -155,11 +155,11 @@ static int input_fd, output_fd; static const char *curr_pack; /* - * local_links is guarded by read_mutex, and record_local_links is read-only in - * a thread. + * outgoing_links is guarded by read_mutex, and record_outgoing_links is + * read-only in a thread. */ -static struct oidset local_links = OIDSET_INIT; -static int record_local_links; +static struct oidset outgoing_links = OIDSET_INIT; +static int record_outgoing_links; static struct thread_local_data *thread_data; static int nr_dispatched; @@ -812,18 +812,12 @@ static int check_collison(struct object_entry *entry) return 0; } -static void record_if_local_object(const struct object_id *oid) +static void record_outgoing_link(const struct object_id *oid) { - struct object_info info = OBJECT_INFO_INIT; - if (oid_object_info_extended(the_repository, oid, &info, 0)) - /* Missing; assume it is a promisor object */ - return; - if (info.whence == OI_PACKED && info.u.packed.pack->pack_promisor) - return; - oidset_insert(&local_links, oid); + oidset_insert(&outgoing_links, oid); } -static void do_record_local_links(struct object *obj) +static void do_record_outgoing_links(struct object *obj) { if (obj->type == OBJ_TREE) { struct tree *tree = (struct tree *)obj; @@ -837,16 +831,16 @@ static void do_record_local_links(struct object *obj) */ return; while (tree_entry_gently(&desc, &entry)) - record_if_local_object(&entry.oid); + record_outgoing_link(&entry.oid); } else if (obj->type == OBJ_COMMIT) { struct commit *commit = (struct commit *) obj; struct commit_list *parents = commit->parents; for (; parents; parents = parents->next) - record_if_local_object(&parents->item->object.oid); + record_outgoing_link(&parents->item->object.oid); } else if (obj->type == OBJ_TAG) { struct tag *tag = (struct tag *) obj; - record_if_local_object(get_tagged_oid(tag)); + record_outgoing_link(get_tagged_oid(tag)); } } @@ -896,7 +890,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry, free(has_data); } - if (strict || do_fsck_object || record_local_links) { + if (strict || do_fsck_object || record_outgoing_links) { read_lock(); if (type == OBJ_BLOB) { struct blob *blob = lookup_blob(the_repository, oid); @@ -928,8 +922,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry, die(_("fsck error in packed object")); if (strict && fsck_walk(obj, NULL, &fsck_options)) die(_("Not all child objects of %s are reachable"), oid_to_hex(&obj->oid)); - if (record_local_links) - do_record_local_links(obj); + if (record_outgoing_links) + do_record_outgoing_links(obj); if (obj->type == OBJ_TREE) { struct tree *item = (struct tree *) obj; @@ -1779,28 +1773,43 @@ static void repack_local_links(void) struct strbuf line = STRBUF_INIT; struct oidset_iter iter; struct object_id *oid; - char *base_name; + char *base_name = NULL; - if (!oidset_size(&local_links)) + if (!oidset_size(&outgoing_links)) return; - base_name = mkpathdup("%s/pack/pack", repo_get_object_directory(the_repository)); + oidset_iter_init(&outgoing_links, &iter); + while ((oid = oidset_iter_next(&iter))) { + struct object_info info = OBJECT_INFO_INIT; + if (oid_object_info_extended(the_repository, oid, &info, 0)) + /* Missing; assume it is a promisor object */ + continue; + if (info.whence == OI_PACKED && info.u.packed.pack->pack_promisor) + continue; - strvec_push(&cmd.args, "pack-objects"); - strvec_push(&cmd.args, "--exclude-promisor-objects-best-effort"); - strvec_push(&cmd.args, base_name); - cmd.git_cmd = 1; - cmd.in = -1; - cmd.out = -1; - if (start_command(&cmd)) - die(_("could not start pack-objects to repack local links")); + if (!cmd.args.nr) { + base_name = mkpathdup( + "%s/pack/pack", + repo_get_object_directory(the_repository)); + strvec_push(&cmd.args, "pack-objects"); + strvec_push(&cmd.args, + "--exclude-promisor-objects-best-effort"); + strvec_push(&cmd.args, base_name); + cmd.git_cmd = 1; + cmd.in = -1; + cmd.out = -1; + if (start_command(&cmd)) + die(_("could not start pack-objects to repack local links")); + } - oidset_iter_init(&local_links, &iter); - while ((oid = oidset_iter_next(&iter))) { if (write_in_full(cmd.in, oid_to_hex(oid), the_hash_algo->hexsz) < 0 || write_in_full(cmd.in, "\n", 1) < 0) die(_("failed to feed local object to pack-objects")); } + + if (!cmd.args.nr) + return; + close(cmd.in); out = xfdopen(cmd.out, "r"); @@ -1899,7 +1908,7 @@ int cmd_index_pack(int argc, } else if (skip_to_optional_arg(arg, "--keep", &keep_msg)) { ; /* nothing to do */ } else if (skip_to_optional_arg(arg, "--promisor", &promisor_msg)) { - record_local_links = 1; + record_outgoing_links = 1; } else if (starts_with(arg, "--threads=")) { char *end; nr_threads = strtoul(arg+10, &end, 0); -- cgit v1.2.3 From 36198026d85848119a8eeb9286d10e795a9e0461 Mon Sep 17 00:00:00 2001 From: Jonathan Tan Date: Tue, 3 Dec 2024 13:52:55 -0800 Subject: index-pack --promisor: don't check blobs As a follow-up to the parent of this commit, it was found that not checking for the existence of blobs linked from trees sped up the fetch from 24m47.815s to 2m2.127s. Teach Git to do that. The tradeoff of not checking blobs is documented in a code comment. (Blobs may also be linked from tag objects, but it is impossible to know the type of an object linked from a tag object without looking it up in the object database, so the code for that is untouched.) Signed-off-by: Jonathan Tan Signed-off-by: Junio C Hamano --- builtin/index-pack.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 347a92c2f1..f811d1112a 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -817,6 +817,35 @@ static void record_outgoing_link(const struct object_id *oid) oidset_insert(&outgoing_links, oid); } +static void maybe_record_name_entry(const struct name_entry *entry) +{ + /* + * Checking only trees here results in a significantly faster packfile + * indexing, but the drawback is that if the packfile to be indexed + * references a local blob only directly (that is, never through a + * local tree), that local blob is in danger of being garbage + * collected. Such a situation may arise if we push local commits, + * including one with a change to a blob in the root tree, and then the + * server incorporates them into its main branch through a "rebase" or + * "squash" merge strategy, and then we fetch the new main branch from + * the server. + * + * This situation has not been observed yet - we have only noticed + * missing commits, not missing trees or blobs. (In fact, if it were + * believed that only missing commits are problematic, one could argue + * that we should also exclude trees during the outgoing link check; + * but it is safer to include them.) + * + * Due to the rarity of the situation (it has not been observed to + * happen in real life), and because the "penalty" in such a situation + * is merely to refetch the missing blob when it's needed (and this + * happens only once - when refetched, the blob goes into a promisor + * pack, so it won't be GC-ed, the tradeoff seems worth it. + */ + if (S_ISDIR(entry->mode)) + record_outgoing_link(&entry->oid); +} + static void do_record_outgoing_links(struct object *obj) { if (obj->type == OBJ_TREE) { @@ -831,7 +860,7 @@ static void do_record_outgoing_links(struct object *obj) */ return; while (tree_entry_gently(&desc, &entry)) - record_outgoing_link(&entry.oid); + maybe_record_name_entry(&entry); } else if (obj->type == OBJ_COMMIT) { struct commit *commit = (struct commit *) obj; struct commit_list *parents = commit->parents; -- cgit v1.2.3 From 1a14c857dbac02715725e8abcff35266c4c5ac93 Mon Sep 17 00:00:00 2001 From: Jonathan Tan Date: Tue, 3 Dec 2024 13:52:56 -0800 Subject: index-pack --promisor: also check commits' trees Commit c08589efdc (index-pack: repack local links into promisor packs, 2024-11-01) seems to contain an oversight in that the tree of a commit is not checked. Teach git to check these trees. The fix slows down a fetch from a certain repo at $DAYJOB from 2m2.127s to 2m45.052s, but in order to make the fetch correct, it seems worth it. In order to test this, we could create server and client repos as follows... C S \ / O (O and C are commits both on the client and server. S is a commit only on the server. C and S have the same tree but different commit messages. The diff between O and C is non-zero.) ...and then, from the client, fetch S from the server. In theory, the client declares "have C" and the server can use this information to exclude S's tree (since it knows that the client has C's tree, which is the same as S's tree). However, it is also possible for the server to compute that it needs to send S and not O, and proceed from there; therefore the objects of C are not considered at all when determining what to send in the packfile. In order to prevent a test of client functionality from having such a dependence on server behavior, I have not included such a test. Signed-off-by: Jonathan Tan Signed-off-by: Junio C Hamano --- builtin/index-pack.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin/index-pack.c b/builtin/index-pack.c index f811d1112a..8e600a58bf 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -865,6 +865,7 @@ static void do_record_outgoing_links(struct object *obj) struct commit *commit = (struct commit *) obj; struct commit_list *parents = commit->parents; + record_outgoing_link(get_commit_tree_oid(commit)); for (; parents; parents = parents->next) record_outgoing_link(&parents->item->object.oid); } else if (obj->type == OBJ_TAG) { -- cgit v1.2.3 From 14ef8c04c545d729174839b3ecbad2b5f24b1de6 Mon Sep 17 00:00:00 2001 From: Rubén Justo Date: Wed, 4 Dec 2024 23:44:25 +0100 Subject: strvec: `strvec_splice()` to a statically initialized vector MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use a singleton empty array to initialize a `struct strvec`; similar to the empty string singleton we use to initialize a `struct strbuf`. Note that an empty strvec instance (with zero elements) does not necessarily need to be an instance initialized with the singleton. Let's refer to strvec instances initialized with the singleton as "empty-singleton" instances. As a side note, this is the current `strvec_pop()`: void strvec_pop(struct strvec *array) { if (!array->nr) return; free((char *)array->v[array->nr - 1]); array->v[array->nr - 1] = NULL; array->nr--; } So, with `strvec_pop()` an instance can become empty but it does not going to be the an "empty-singleton". This "empty-singleton" circumstance requires us to be careful when adding elements to instances. Specifically, when adding the first element: when we detach the strvec instance from the singleton and set the internal pointer in the instance to NULL. After this point we apply `realloc()` on the pointer. We do this in `strvec_push_nodup()`, for example. The recently introduced `strvec_splice()` API is expected to be normally used with non-empty strvec's. However, it can also end up being used with "empty-singleton" strvec's: struct strvec arr = STRVEC_INIT; int a = 0, b = 0; ... no modification to arr, a or b ... const char *rep[] = { "foo" }; strvec_splice(&arr, a, b, rep, ARRAY_SIZE(rep)); So, we'll try to add elements to an "empty-singleton" strvec instance. Avoid misapplying `realloc()` to the singleton in `strvec_splice()` by adding a special case for strvec's initialized with the singleton. Signed-off-by: Rubén Justo Signed-off-by: Junio C Hamano --- strvec.c | 11 +++++++---- t/unit-tests/strvec.c | 10 ++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/strvec.c b/strvec.c index d1cf4e2496..d67596e571 100644 --- a/strvec.c +++ b/strvec.c @@ -61,16 +61,19 @@ void strvec_splice(struct strvec *array, size_t idx, size_t len, { if (idx + len > array->nr) BUG("range outside of array boundary"); - if (replacement_len > len) + if (replacement_len > len) { + if (array->v == empty_strvec) + array->v = NULL; ALLOC_GROW(array->v, array->nr + (replacement_len - len) + 1, array->alloc); + array->v[array->nr + (replacement_len - len)] = NULL; + } for (size_t i = 0; i < len; i++) free((char *)array->v[idx + i]); - if (replacement_len != len) { + if ((replacement_len != len) && array->nr) memmove(array->v + idx + replacement_len, array->v + idx + len, (array->nr - idx - len + 1) * sizeof(char *)); - array->nr += (replacement_len - len); - } + array->nr += replacement_len - len; for (size_t i = 0; i < replacement_len; i++) array->v[idx + i] = xstrdup(replacement[i]); } diff --git a/t/unit-tests/strvec.c b/t/unit-tests/strvec.c index 855b602337..e66b7bbfae 100644 --- a/t/unit-tests/strvec.c +++ b/t/unit-tests/strvec.c @@ -88,6 +88,16 @@ void test_strvec__pushv(void) strvec_clear(&vec); } +void test_strvec__splice_just_initialized_strvec(void) +{ + struct strvec vec = STRVEC_INIT; + const char *replacement[] = { "foo" }; + + strvec_splice(&vec, 0, 0, replacement, ARRAY_SIZE(replacement)); + check_strvec(&vec, "foo", NULL); + strvec_clear(&vec); +} + void test_strvec__splice_with_same_size_replacement(void) { struct strvec vec = STRVEC_INIT; -- cgit v1.2.3 From caacdb5dfd60540ecec30ec479f147f3c8167e11 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 10 Dec 2024 09:36:41 +0900 Subject: The fifteenth batch Signed-off-by: Junio C Hamano --- Documentation/RelNotes/2.48.0.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Documentation/RelNotes/2.48.0.txt b/Documentation/RelNotes/2.48.0.txt index b9d1b129cd..bf75cda275 100644 --- a/Documentation/RelNotes/2.48.0.txt +++ b/Documentation/RelNotes/2.48.0.txt @@ -21,6 +21,9 @@ UI, Workflows & Features * Drop support for older libcURL and Perl. + * End-user experience of "git mergetool" when the command errors out + has been improved. + Performance, Internal Implementation, Development Support etc. -------------------------------------------------------------- @@ -107,6 +110,14 @@ Performance, Internal Implementation, Development Support etc. * Built-in Git subcommands are supplied the repository object to work with; they learned to do the same when they invoke sub-subcommands. + * Drop support for ancient environments in various CI jobs. + + * Isolates the reftable subsystem from the rest of Git's codebase by + using fewer pieces of Git's infrastructure. + + * Optimize reading random references out of the reftable backend by + allowing reuse of iterator objects. + Fixes since v2.47 ----------------- @@ -204,6 +215,15 @@ Fixes since v2.47 * The sequencer failed to honor core.commentString in some places. + * Describe a case where an option value needs to be spelled as a + separate argument, i.e. "--opt val", not "--opt=val". + (merge 1bc1e94091 jc/doc-opt-tilde-expand later to maint). + + * Loosen overly strict ownership check introduced in the recent past, + to keep the promise "cloning a suspicious repository is a safe + first step to inspect it". + (merge 0ffb5a6bf1 bc/allow-upload-pack-from-other-people later to maint). + * Other code cleanup, docfix, build fix, etc. (merge 77af53f56f aa/t7300-modernize later to maint). (merge dcd590a39d bf/t-readme-mention-reftable later to maint). -- cgit v1.2.3 From b71687ca03fe5909eae54cd6f2e044822ca335de Mon Sep 17 00:00:00 2001 From: Roy Eldar Date: Wed, 11 Dec 2024 08:32:28 +0200 Subject: git-submodule.sh: improve parsing of some long options Some command-line options have a long form which takes an argument. In this case, the argument can be given right after `='; for example, "--depth" takes a numerical argument, which can be given as "--depth=X". Support the case where the argument is given right after `=' for all long options, in order to improve consistency throughout the script. Signed-off-by: Roy Eldar Signed-off-by: Junio C Hamano --- git-submodule.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/git-submodule.sh b/git-submodule.sh index 03c5a220a2..d3e3669fde 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -77,6 +77,9 @@ cmd_add() branch=$2 shift ;; + --branch=*) + branch="${1#--branch=}" + ;; -f | --force) force=$1 ;; @@ -110,6 +113,9 @@ cmd_add() custom_name=$2 shift ;; + --name=*) + custom_name="${1#--name=}" + ;; --depth) case "$2" in '') usage ;; esac depth="--depth=$2" @@ -425,6 +431,9 @@ cmd_set_branch() { branch=$2 shift ;; + --branch=*) + branch="${1#--branch=}" + ;; --) shift break -- cgit v1.2.3 From e6c3e349458ec2ad36addc6004cffcfa6d663c38 Mon Sep 17 00:00:00 2001 From: Roy Eldar Date: Wed, 11 Dec 2024 08:32:29 +0200 Subject: git-submodule.sh: improve parsing of short options Some command-line options have a short form which takes an argument; for example, "--jobs" has the form "-j", and it takes a numerical argument. When parsing short options, support the case where there is no space between the flag and the option argument, in order to improve consistency with the rest of the builtin git commands. Signed-off-by: Roy Eldar Signed-off-by: Junio C Hamano --- git-submodule.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/git-submodule.sh b/git-submodule.sh index d3e3669fde..fd54cb8fa6 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -77,6 +77,9 @@ cmd_add() branch=$2 shift ;; + -b*) + branch="${1#-b}" + ;; --branch=*) branch="${1#--branch=}" ;; @@ -352,6 +355,9 @@ cmd_update() jobs="--jobs=$2" shift ;; + -j*) + jobs="--jobs=${1#-j}" + ;; --jobs=*) jobs=$1 ;; @@ -431,6 +437,9 @@ cmd_set_branch() { branch=$2 shift ;; + -b*) + branch="${1#-b}" + ;; --branch=*) branch="${1#--branch=}" ;; @@ -519,6 +528,10 @@ cmd_summary() { isnumber "$summary_limit" || usage shift ;; + -n*) + summary_limit="${1#-n}" + isnumber "$summary_limit" || usage + ;; --summary-limit=*) summary_limit="${1#--summary-limit=}" isnumber "$summary_limit" || usage -- cgit v1.2.3 From 006f546bc30bd42de6ba569ab70ec80441f54430 Mon Sep 17 00:00:00 2001 From: Roy Eldar Date: Wed, 11 Dec 2024 08:32:30 +0200 Subject: git-submodule.sh: get rid of isnumber It's entirely unnecessary to check whether the argument given to an option (i.e. --summary-limit) is valid in the shell wrapper, since it's already done when parsing the various options in git-submodule--helper. Remove this check from the script; this both improves consistency throughout the script, and the error message shown to the user in case some invalid non-numeric argument was passed to "--summary-limit" is more informative as well. Signed-off-by: Roy Eldar Signed-off-by: Junio C Hamano --- git-submodule.sh | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/git-submodule.sh b/git-submodule.sh index fd54cb8fa6..3adaa8d9a3 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -53,11 +53,6 @@ jobs= recommend_shallow= filter= -isnumber() -{ - n=$(($1 + 0)) 2>/dev/null && test "$n" = "$1" -} - # # Add a new submodule to the working tree, .gitmodules and the index # @@ -524,17 +519,15 @@ cmd_summary() { for_status="$1" ;; -n|--summary-limit) + case "$2" in '') usage ;; esac summary_limit="$2" - isnumber "$summary_limit" || usage shift ;; -n*) summary_limit="${1#-n}" - isnumber "$summary_limit" || usage ;; --summary-limit=*) summary_limit="${1#--summary-limit=}" - isnumber "$summary_limit" || usage ;; --) shift @@ -554,7 +547,7 @@ cmd_summary() { ${files:+--files} \ ${cached:+--cached} \ ${for_status:+--for-status} \ - ${summary_limit:+-n $summary_limit} \ + ${summary_limit:+-n "$summary_limit"} \ -- \ "$@" } -- cgit v1.2.3 From 402e46daf5ebf96f2cb31bf37e3d1637247688e5 Mon Sep 17 00:00:00 2001 From: Roy Eldar Date: Wed, 11 Dec 2024 08:32:31 +0200 Subject: git-submodule.sh: get rid of unused variable Remove the variable "$diff_cmd" which is no longer used. Signed-off-by: Roy Eldar Signed-off-by: Junio C Hamano --- git-submodule.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/git-submodule.sh b/git-submodule.sh index 3adaa8d9a3..ba3bef8821 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -503,7 +503,6 @@ cmd_set_url() { cmd_summary() { summary_limit=-1 for_status= - diff_cmd=diff-index # parse $args after "submodule ... summary". while test $# -ne 0 -- cgit v1.2.3 From 57f9b30fcd7707b3917d96e98dc109fb541cd30b Mon Sep 17 00:00:00 2001 From: Roy Eldar Date: Wed, 11 Dec 2024 08:32:32 +0200 Subject: git-submodule.sh: add some comments Add a couple of comments in a few functions where they were missing. Signed-off-by: Roy Eldar Signed-off-by: Junio C Hamano --- git-submodule.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-submodule.sh b/git-submodule.sh index ba3bef8821..ee86e4de46 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -418,6 +418,7 @@ cmd_set_branch() { default= branch= + # parse $args after "submodule ... set-branch". while test $# -ne 0 do case "$1" in @@ -466,6 +467,7 @@ cmd_set_branch() { # $@ = requested path, requested url # cmd_set_url() { + # parse $args after "submodule ... set-url". while test $# -ne 0 do case "$1" in @@ -604,6 +606,7 @@ cmd_status() # cmd_sync() { + # parse $args after "submodule ... sync". while test $# -ne 0 do case "$1" in -- cgit v1.2.3 From 3ad0ba72274436f4e1eef6bed392e3e875484e2b Mon Sep 17 00:00:00 2001 From: Roy Eldar Date: Wed, 11 Dec 2024 08:32:33 +0200 Subject: git-submodule.sh: improve variables readability When git-submodule.sh parses various options and switches, it sets some variables to values; the variables in turn affect the options given to git-submodule--helper. Currently, variables which correspond to switches have boolean values (for example, whenever "--force" is passed, force=1), while variables which correspond to options which take arguments have string values that sometimes contain the option name and sometimes only the option value. Set all of the variables to strings which contain the option name (e.g. force="--force" rather than force=1); this has a couple of advantages: it improves consistency, readability and debuggability. Suggested-by: Junio C Hamano Signed-off-by: Roy Eldar Signed-off-by: Junio C Hamano --- git-submodule.sh | 213 +++++++++++++++++++++++++------------------------------ 1 file changed, 95 insertions(+), 118 deletions(-) diff --git a/git-submodule.sh b/git-submodule.sh index ee86e4de46..6df25efc48 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -52,6 +52,10 @@ single_branch= jobs= recommend_shallow= filter= +deinit_all= +default= +summary_limit= +for_status= # # Add a new submodule to the working tree, .gitmodules and the index @@ -63,37 +67,33 @@ filter= cmd_add() { # parse $args after "submodule ... add". - reference_path= while test $# -ne 0 do case "$1" in -b | --branch) case "$2" in '') usage ;; esac - branch=$2 + branch="--branch=$2" shift ;; - -b*) - branch="${1#-b}" - ;; - --branch=*) - branch="${1#--branch=}" + -b* | --branch=*) + branch="$1" ;; -f | --force) force=$1 ;; -q|--quiet) - quiet=1 + quiet=$1 ;; --progress) - progress=1 + progress=$1 ;; --reference) case "$2" in '') usage ;; esac - reference_path=$2 + reference="--reference=$2" shift ;; --reference=*) - reference_path="${1#--reference=}" + reference="$1" ;; --ref-format) case "$2" in '') usage ;; esac @@ -104,15 +104,15 @@ cmd_add() ref_format="$1" ;; --dissociate) - dissociate=1 + dissociate=$1 ;; --name) case "$2" in '') usage ;; esac - custom_name=$2 + custom_name="--name=$2" shift ;; --name=*) - custom_name="${1#--name=}" + custom_name="$1" ;; --depth) case "$2" in '') usage ;; esac @@ -120,7 +120,7 @@ cmd_add() shift ;; --depth=*) - depth=$1 + depth="$1" ;; --) shift @@ -142,14 +142,14 @@ cmd_add() fi git ${wt_prefix:+-C "$wt_prefix"} submodule--helper add \ - ${quiet:+--quiet} \ - ${force:+--force} \ - ${progress:+"--progress"} \ - ${branch:+--branch "$branch"} \ - ${reference_path:+--reference "$reference_path"} \ + $quiet \ + $force \ + $progress \ + ${branch:+"$branch"} \ + ${reference:+"$reference"} \ ${ref_format:+"$ref_format"} \ - ${dissociate:+--dissociate} \ - ${custom_name:+--name "$custom_name"} \ + $dissociate \ + ${custom_name:+"$custom_name"} \ ${depth:+"$depth"} \ -- \ "$@" @@ -168,10 +168,10 @@ cmd_foreach() do case "$1" in -q|--quiet) - quiet=1 + quiet=$1 ;; --recursive) - recursive=1 + recursive=$1 ;; -*) usage @@ -184,8 +184,8 @@ cmd_foreach() done git ${wt_prefix:+-C "$wt_prefix"} submodule--helper foreach \ - ${quiet:+--quiet} \ - ${recursive:+--recursive} \ + $quiet \ + $recursive \ -- \ "$@" } @@ -202,7 +202,7 @@ cmd_init() do case "$1" in -q|--quiet) - quiet=1 + quiet=$1 ;; --) shift @@ -219,7 +219,7 @@ cmd_init() done git ${wt_prefix:+-C "$wt_prefix"} submodule--helper init \ - ${quiet:+--quiet} \ + $quiet \ -- \ "$@" } @@ -230,7 +230,6 @@ cmd_init() cmd_deinit() { # parse $args after "submodule ... deinit". - deinit_all= while test $# -ne 0 do case "$1" in @@ -238,10 +237,10 @@ cmd_deinit() force=$1 ;; -q|--quiet) - quiet=1 + quiet=$1 ;; --all) - deinit_all=t + deinit_all=$1 ;; --) shift @@ -258,9 +257,9 @@ cmd_deinit() done git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit \ - ${quiet:+--quiet} \ - ${force:+--force} \ - ${deinit_all:+--all} \ + $quiet \ + $force \ + $deinit_all \ -- \ "$@" } @@ -277,31 +276,31 @@ cmd_update() do case "$1" in -q|--quiet) - quiet=1 + quiet=$1 ;; -v|--verbose) - quiet=0 + quiet= ;; --progress) - progress=1 + progress=$1 ;; -i|--init) - init=1 + init=$1 ;; --require-init) - require_init=1 + require_init=$1 ;; --remote) - remote=1 + remote=$1 ;; -N|--no-fetch) - nofetch=1 + nofetch=$1 ;; -f|--force) force=$1 ;; -r|--rebase) - rebase=1 + rebase=$1 ;; --ref-format) case "$2" in '') usage ;; esac @@ -320,22 +319,19 @@ cmd_update() reference="$1" ;; --dissociate) - dissociate=1 + dissociate=$1 ;; -m|--merge) - merge=1 + merge=$1 ;; --recursive) - recursive=1 + recursive=$1 ;; --checkout) - checkout=1 - ;; - --recommend-shallow) - recommend_shallow="--recommend-shallow" + checkout=$1 ;; - --no-recommend-shallow) - recommend_shallow="--no-recommend-shallow" + --recommend-shallow|--no-recommend-shallow) + recommend_shallow=$1 ;; --depth) case "$2" in '') usage ;; esac @@ -343,24 +339,18 @@ cmd_update() shift ;; --depth=*) - depth=$1 + depth="$1" ;; -j|--jobs) case "$2" in '') usage ;; esac jobs="--jobs=$2" shift ;; - -j*) - jobs="--jobs=${1#-j}" - ;; - --jobs=*) - jobs=$1 + -j*|--jobs=*) + jobs="$1" ;; - --single-branch) - single_branch="--single-branch" - ;; - --no-single-branch) - single_branch="--no-single-branch" + --single-branch|--no-single-branch) + single_branch=$1 ;; --filter) case "$2" in '') usage ;; esac @@ -385,22 +375,21 @@ cmd_update() done git ${wt_prefix:+-C "$wt_prefix"} submodule--helper update \ - ${quiet:+--quiet} \ - ${force:+--force} \ - ${progress:+"--progress"} \ - ${remote:+--remote} \ - ${recursive:+--recursive} \ - ${init:+--init} \ - ${nofetch:+--no-fetch} \ - ${rebase:+--rebase} \ - ${merge:+--merge} \ - ${checkout:+--checkout} \ + $quiet \ + $force \ + $progress \ + $remote \ + $recursive \ + $init \ + $nofetch \ + $rebase \ + $merge \ + $checkout \ ${ref_format:+"$ref_format"} \ ${reference:+"$reference"} \ - ${dissociate:+"--dissociate"} \ + $dissociate \ ${depth:+"$depth"} \ - ${require_init:+--require-init} \ - ${dissociate:+"--dissociate"} \ + $require_init \ $single_branch \ $recommend_shallow \ $jobs \ @@ -415,9 +404,6 @@ cmd_update() # $@ = requested path # cmd_set_branch() { - default= - branch= - # parse $args after "submodule ... set-branch". while test $# -ne 0 do @@ -426,18 +412,15 @@ cmd_set_branch() { # we don't do anything with this but we need to accept it ;; -d|--default) - default=1 + default=$1 ;; -b|--branch) case "$2" in '') usage ;; esac - branch=$2 + branch="--branch=$2" shift ;; - -b*) - branch="${1#-b}" - ;; - --branch=*) - branch="${1#--branch=}" + -b*|--branch=*) + branch="$1" ;; --) shift @@ -454,9 +437,9 @@ cmd_set_branch() { done git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-branch \ - ${quiet:+--quiet} \ - ${branch:+--branch "$branch"} \ - ${default:+--default} \ + $quiet \ + ${branch:+"$branch"} \ + $default \ -- \ "$@" } @@ -472,7 +455,7 @@ cmd_set_url() { do case "$1" in -q|--quiet) - quiet=1 + quiet=$1 ;; --) shift @@ -489,7 +472,7 @@ cmd_set_url() { done git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-url \ - ${quiet:+--quiet} \ + $quiet \ -- \ "$@" } @@ -503,32 +486,26 @@ cmd_set_url() { # $@ = [commit (default 'HEAD'),] requested paths (default all) # cmd_summary() { - summary_limit=-1 - for_status= - # parse $args after "submodule ... summary". while test $# -ne 0 do case "$1" in --cached) - cached=1 + cached=$1 ;; --files) - files="$1" + files=$1 ;; --for-status) - for_status="$1" + for_status=$1 ;; -n|--summary-limit) case "$2" in '') usage ;; esac - summary_limit="$2" + summary_limit="--summary-limit=$2" shift ;; - -n*) - summary_limit="${1#-n}" - ;; - --summary-limit=*) - summary_limit="${1#--summary-limit=}" + -n*|--summary-limit=*) + summary_limit="$1" ;; --) shift @@ -545,10 +522,10 @@ cmd_summary() { done git ${wt_prefix:+-C "$wt_prefix"} submodule--helper summary \ - ${files:+--files} \ - ${cached:+--cached} \ - ${for_status:+--for-status} \ - ${summary_limit:+-n "$summary_limit"} \ + $files \ + $cached \ + $for_status \ + ${summary_limit:+"$summary_limit"} \ -- \ "$@" } @@ -569,13 +546,13 @@ cmd_status() do case "$1" in -q|--quiet) - quiet=1 + quiet=$1 ;; --cached) - cached=1 + cached=$1 ;; --recursive) - recursive=1 + recursive=$1 ;; --) shift @@ -592,9 +569,9 @@ cmd_status() done git ${wt_prefix:+-C "$wt_prefix"} submodule--helper status \ - ${quiet:+--quiet} \ - ${cached:+--cached} \ - ${recursive:+--recursive} \ + $quiet \ + $cached \ + $recursive \ -- \ "$@" } @@ -611,11 +588,11 @@ cmd_sync() do case "$1" in -q|--quiet) - quiet=1 + quiet=$1 shift ;; --recursive) - recursive=1 + recursive=$1 shift ;; --) @@ -632,8 +609,8 @@ cmd_sync() done git ${wt_prefix:+-C "$wt_prefix"} submodule--helper sync \ - ${quiet:+--quiet} \ - ${recursive:+--recursive} \ + $quiet \ + $recursive \ -- \ "$@" } @@ -656,10 +633,10 @@ do command=$1 ;; -q|--quiet) - quiet=1 + quiet=$1 ;; --cached) - cached=1 + cached=$1 ;; --) break -- cgit v1.2.3 From b86f0f9071dd881a14cb9a71d94a66ae3186a2b9 Mon Sep 17 00:00:00 2001 From: Roy Eldar Date: Wed, 11 Dec 2024 08:32:34 +0200 Subject: git-submodule.sh: rename some variables Every switch and option which is passed to git-submodule.sh has a corresponding variable which is set accordingly; by convention, the name of the variable is the option name (for example, "--jobs" and "$jobs"). Rename "$custom_name", "$deinit_all" and "$nofetch", for consistency. Signed-off-by: Roy Eldar Signed-off-by: Junio C Hamano --- git-submodule.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/git-submodule.sh b/git-submodule.sh index 6df25efc48..2999b31fad 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -40,11 +40,11 @@ init= require_init= files= remote= -nofetch= +no_fetch= rebase= merge= checkout= -custom_name= +name= depth= progress= dissociate= @@ -52,7 +52,7 @@ single_branch= jobs= recommend_shallow= filter= -deinit_all= +all= default= summary_limit= for_status= @@ -108,11 +108,11 @@ cmd_add() ;; --name) case "$2" in '') usage ;; esac - custom_name="--name=$2" + name="--name=$2" shift ;; --name=*) - custom_name="$1" + name="$1" ;; --depth) case "$2" in '') usage ;; esac @@ -149,7 +149,7 @@ cmd_add() ${reference:+"$reference"} \ ${ref_format:+"$ref_format"} \ $dissociate \ - ${custom_name:+"$custom_name"} \ + ${name:+"$name"} \ ${depth:+"$depth"} \ -- \ "$@" @@ -240,7 +240,7 @@ cmd_deinit() quiet=$1 ;; --all) - deinit_all=$1 + all=$1 ;; --) shift @@ -259,7 +259,7 @@ cmd_deinit() git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit \ $quiet \ $force \ - $deinit_all \ + $all \ -- \ "$@" } @@ -294,7 +294,7 @@ cmd_update() remote=$1 ;; -N|--no-fetch) - nofetch=$1 + no_fetch=$1 ;; -f|--force) force=$1 @@ -381,7 +381,7 @@ cmd_update() $remote \ $recursive \ $init \ - $nofetch \ + $no_fetch \ $rebase \ $merge \ $checkout \ -- cgit v1.2.3 From e1b52cf71ee740b128c7b08ccd4372dedf7741cc Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 12 Dec 2024 07:47:14 +0100 Subject: gitlab-ci: update macOS images to Sonoma The macOS Ventura images we use for GitLab CI runners have been deprecated. Update them to macOS 14, aka Sonoma. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4abfbc3e20..d4709aaef6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -90,10 +90,10 @@ test:osx: parallel: matrix: - jobname: osx-clang - image: macos-13-xcode-14 + image: macos-14-xcode-15 CC: clang - jobname: osx-reftable - image: macos-13-xcode-14 + image: macos-14-xcode-15 CC: clang artifacts: paths: -- cgit v1.2.3 From 33b06fa603958ba936ea7602c9b81d10ffcd08bb Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 12 Dec 2024 07:47:15 +0100 Subject: ci/lib: remove duplicate trap to end "CI setup" group We exlicitly trap on EXIT in order to end the "CI setup" group. This isn't necessary though given that `begin_group ()` already sets up the trap for us. Remove the duplicate trap. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- ci/lib.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/ci/lib.sh b/ci/lib.sh index 74b430be23..de3a95cea1 100755 --- a/ci/lib.sh +++ b/ci/lib.sh @@ -56,7 +56,6 @@ group () { } begin_group "CI setup" -trap "end_group 'CI setup'" EXIT # Set 'exit on error' for all CI scripts to let the caller know that # something went wrong. -- cgit v1.2.3 From d2ca12020ffb7ee7f0ee1154f394a994f045b5a9 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 12 Dec 2024 07:47:16 +0100 Subject: ci/lib: do not interpret escape sequences in `group ()` arguments We use printf to set up sections with GitLab CI, which requires us to print a bunch of escape sequences via printf. The group name is controlled by the user and is expanded directly into the formatting string, which may cause problems in case the argument contains escape sequences or formatting directives. Fix this potential issue by using formatting directives to pass variable data. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- ci/lib.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ci/lib.sh b/ci/lib.sh index de3a95cea1..803f56bc82 100755 --- a/ci/lib.sh +++ b/ci/lib.sh @@ -18,7 +18,8 @@ elif test true = "$GITLAB_CI" then begin_group () { need_to_end_group=t - printf "\e[0Ksection_start:$(date +%s):$(echo "$1" | tr ' ' _)[collapsed=true]\r\e[0K$1\n" + printf '\e[0Ksection_start:%s:%s[collapsed=true]\r\e[0K%s\n' \ + "$(date +%s)" "$(echo "$1" | tr ' ' _)" "$1" trap "end_group '$1'" EXIT set -x } @@ -27,7 +28,8 @@ then test -n "$need_to_end_group" || return 0 set +x need_to_end_group= - printf "\e[0Ksection_end:$(date +%s):$(echo "$1" | tr ' ' _)\r\e[0K\n" + printf '\e[0Ksection_end:%s:%s\r\e[0K\n' \ + "$(date +%s)" "$(echo "$1" | tr ' ' _)" trap - EXIT } else -- cgit v1.2.3 From c6b43f663eb252deb28cfff79e1ccdefed87c971 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 12 Dec 2024 07:47:17 +0100 Subject: ci/lib: fix "CI setup" sections with GitLab CI Whenever we source "ci/lib.sh" we wrap the directives in a separate group so that they can easily be collapsed in the web UI. And as we source the script multiple times during a single CI run we thus end up with the same section name reused multiple times, as well. This is broken on GitLab CI though, where reusing the same group name is not supported. The consequence is that only the last of these sections can be collapsed. Fix this issue by including the name of the sourcing script in the group's name. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- ci/lib.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/lib.sh b/ci/lib.sh index 803f56bc82..63c42fe93a 100755 --- a/ci/lib.sh +++ b/ci/lib.sh @@ -57,7 +57,7 @@ group () { return $res } -begin_group "CI setup" +begin_group "CI setup via $(basename $0)" # Set 'exit on error' for all CI scripts to let the caller know that # something went wrong. @@ -388,5 +388,5 @@ esac MAKEFLAGS="$MAKEFLAGS CC=${CC:-cc}" -end_group "CI setup" +end_group "CI setup via $(basename $0)" set -x -- cgit v1.2.3 From dd1072dfa8bb3ab3e4fc300403b2bb2f3c68e6ed Mon Sep 17 00:00:00 2001 From: Toon Claes Date: Wed, 11 Dec 2024 21:51:14 +0100 Subject: bundle: remove unneeded code The changes in commit c06793a4ed (allow git-bundle to create bottomless bundle, 2007-08-08) ensure annotated tags are properly preserved when creating a bundle using a revision range operation. At the time the range notation would peel the ends to their corresponding commit, meaning ref v2.0 would point to the v2.0^0 commit. So the above workaround was introduced. This code looks up the ref before it's written to the bundle, and if the ref doesn't point to the object we expect (for tags this would be a tag object), we skip the ref from the bundle. Instead, when the ref is a tag that's the positive end of the range (e.g. v2.0 from the range "v1.0..v2.0"), then that ref is written to the bundle instead. Later, in 895c5ba3c1 (revision: do not peel tags used in range notation, 2013-09-19), the behavior of parsing ranges was changed and the problem was fixed at the cause. But the workaround in bundle.c was not reverted. Now it seems this workaround can cause a race condition. git-bundle(1) uses setup_revisions() to parse the input into `struct rev_info`. Later, in write_bundle_refs(), it uses this info to write refs to the bundle. As mentioned at this point each ref is looked up again and checked whether it points to the object we expect. If not, the ref is not written to the bundle. But, when creating a bundle in a heavy traffic repository (a repo with many references, and frequent ref updates) it's possible a branch ref was updated between setup_revisions() and write_bundle_refs() and thus the extra check causes the ref to be skipped. The workaround was originally added to deal with tags, but the code path also gets hit by non-tag refs, causing this race condition. Because it's no longer needed, remove it and fix the possible race condition. Signed-off-by: Toon Claes Signed-off-by: Junio C Hamano --- bundle.c | 30 ------------------------------ t/t6020-bundle-misc.sh | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 30 deletions(-) diff --git a/bundle.c b/bundle.c index 4773b51eb1..dfb5b7a5ec 100644 --- a/bundle.c +++ b/bundle.c @@ -420,36 +420,6 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs) e->name); goto skip_write_ref; } - /* - * If you run "git bundle create bndl v1.0..v2.0", the - * name of the positive ref is "v2.0" but that is the - * commit that is referenced by the tag, and not the tag - * itself. - */ - if (!oideq(&oid, &e->item->oid)) { - /* - * Is this the positive end of a range expressed - * in terms of a tag (e.g. v2.0 from the range - * "v1.0..v2.0")? - */ - struct commit *one = lookup_commit_reference(revs->repo, &oid); - struct object *obj; - - if (e->item == &(one->object)) { - /* - * Need to include e->name as an - * independent ref to the pack-objects - * input, so that the tag is included - * in the output; otherwise we would - * end up triggering "empty bundle" - * error. - */ - obj = parse_object_or_die(&oid, e->name); - obj->flags |= SHOWN; - add_pending_object(revs, obj, e->name); - } - goto skip_write_ref; - } ref_count++; write_or_die(bundle_fd, oid_to_hex(&e->item->oid), the_hash_algo->hexsz); diff --git a/t/t6020-bundle-misc.sh b/t/t6020-bundle-misc.sh index 34b5cd62c2..ff66f24f70 100755 --- a/t/t6020-bundle-misc.sh +++ b/t/t6020-bundle-misc.sh @@ -505,6 +505,50 @@ test_expect_success 'unfiltered bundle with --objects' ' test_cmp expect actual ' +test_expect_success 'full bundle upto annotated tag' ' + git bundle create v2.bdl \ + v2 && + + git bundle verify v2.bdl | + make_user_friendly_and_stable_output >actual && + + format_and_save_expect <<-EOF && + The bundle contains this ref: + refs/tags/v2 + The bundle records a complete history. + $HASH_MESSAGE + EOF + test_cmp expect actual +' + +test_expect_success 'clone from full bundle upto annotated tag' ' + git clone --mirror v2.bdl tag-clone.git && + git -C tag-clone.git show-ref | + make_user_friendly_and_stable_output >actual && + cat >expect <<-\EOF && + refs/tags/v2 + EOF + test_cmp expect actual +' + +test_expect_success 'incremental bundle between two annotated tags' ' + git bundle create v1-v2.bdl \ + v1..v2 && + + git bundle verify v1-v2.bdl | + make_user_friendly_and_stable_output >actual && + + format_and_save_expect <<-EOF && + The bundle contains this ref: + refs/tags/v2 + The bundle requires these 2 refs: + Z + Z + $HASH_MESSAGE + EOF + test_cmp expect actual +' + for filter in "blob:none" "tree:0" "tree:1" "blob:limit=100" do test_expect_success "filtered bundle: $filter" ' -- cgit v1.2.3 From 66496dabd4fe26e8b2093ab923c7dea30e0fe7e4 Mon Sep 17 00:00:00 2001 From: "Avi Halachmi (:avih)" Date: Wed, 11 Dec 2024 10:07:54 +0200 Subject: gitk: UI text: change "SHA1 ID" to "Commit ID" SHA1 might not stay forever, and plans to use SHA256 already exist, so use the official name for it - "Commit ID". Only visible UI texts are modified to reduce the noise when using git-blame, while comments and variable names still contain SHA1/sha1. Signed-off-by: Avi Halachmi (:avih) --- gitk | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gitk b/gitk index de278557b3..7d1da05256 100755 --- a/gitk +++ b/gitk @@ -2223,7 +2223,7 @@ proc makewindow {} { set sha1entry .tf.bar.sha1 set entries $sha1entry set sha1but .tf.bar.sha1label - button $sha1but -text "[mc "SHA1 ID:"] " -state disabled -relief flat \ + button $sha1but -text "[mc "Commit ID:"] " -state disabled -relief flat \ -command gotocommit -width 8 $sha1but conf -disabledforeground [$sha1but cget -foreground] pack .tf.bar.sha1label -side left @@ -8756,7 +8756,7 @@ proc sha1change {n1 n2 op} { if {$state == "normal"} { $sha1but conf -state normal -relief raised -text "[mc "Goto:"] " } else { - $sha1but conf -state disabled -relief flat -text "[mc "SHA1 ID:"] " + $sha1but conf -state disabled -relief flat -text "[mc "Commit ID:"] " } } @@ -8775,7 +8775,7 @@ proc gotocommit {} { set matches [longid $id] if {$matches ne {}} { if {[llength $matches] > 1} { - error_popup [mc "Short SHA1 id %s is ambiguous" $id] + error_popup [mc "Short commit ID %s is ambiguous" $id] return } set id [lindex $matches 0] @@ -8792,7 +8792,7 @@ proc gotocommit {} { return } if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} { - set msg [mc "SHA1 id %s is not known" $sha1string] + set msg [mc "Commit ID %s is not known" $sha1string] } else { set msg [mc "Revision %s is not in the current view" $sha1string] } @@ -11594,7 +11594,7 @@ proc prefspage_general {notebook} { ${NS}::checkbutton $page.showlocal -text [mc "Show local changes"] \ -variable showlocalchanges grid x $page.showlocal -sticky w - ${NS}::checkbutton $page.autoselect -text [mc "Auto-select SHA1 (length)"] \ + ${NS}::checkbutton $page.autoselect -text [mc "Auto-select commit ID (length)"] \ -variable autoselect spinbox $page.autosellen -from 1 -to 40 -width 4 -textvariable autosellen grid x $page.autoselect $page.autosellen -sticky w -- cgit v1.2.3 From 92d911a531e905ec730fa527d55d1622e948d83a Mon Sep 17 00:00:00 2001 From: "Avi Halachmi (:avih)" Date: Wed, 11 Dec 2024 10:18:31 +0200 Subject: gitk: prefs dialog: refine Auto-select UI Tl;DR: change Auto-select text, move the length input to a new line. The Auto-select preference auto-selects [part of] the commit ID text at the respective widget on startup, and when the current commit at the graph changes. Its real premise, however, is to populate the selection clipboard with the commit ID. Consider, for instance, how meaningless it is on platforms without a selection clipboard - like Windows or macOS (on Windows the selection is not even visible with the default Tk theme, because it's only visible in focused widgets - which the commit ID widget is not during normal application of this selection). So rename the Auto-select label to "Copy commit ID to X11 selection", to reflect better the ultimate outcome of its application Note that there exists other, non-X11 platforms with a selection clipboard, like Wayland, and if a native Tk client exists on such platforms, then the description will not be accurate, but hopefully it's not too misleading either. Additionally, move the length input widget to a new line, because: - This length applies to both Auto-select and "Copy commit reference" context menu item, so it's not exclusive to the selection length. - The next commit will add support for primary clipboard as well, where this length will also be used. Also, move the "Hide remotes" item above these selection prefs, to keep the selection prefs semi-grouped before the spacing of the following title "Diff display options". Signed-off-by: Avi Halachmi (:avih) --- gitk | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/gitk b/gitk index 7d1da05256..322236d361 100755 --- a/gitk +++ b/gitk @@ -11594,14 +11594,17 @@ proc prefspage_general {notebook} { ${NS}::checkbutton $page.showlocal -text [mc "Show local changes"] \ -variable showlocalchanges grid x $page.showlocal -sticky w - ${NS}::checkbutton $page.autoselect -text [mc "Auto-select commit ID (length)"] \ - -variable autoselect - spinbox $page.autosellen -from 1 -to 40 -width 4 -textvariable autosellen - grid x $page.autoselect $page.autosellen -sticky w ${NS}::checkbutton $page.hideremotes -text [mc "Hide remote refs"] \ -variable hideremotes grid x $page.hideremotes -sticky w + ${NS}::checkbutton $page.autoselect -text [mc "Copy commit ID to X11 selection"] \ + -variable autoselect + grid x $page.autoselect -sticky w + spinbox $page.autosellen -from 1 -to 40 -width 4 -textvariable autosellen + ${NS}::label $page.autosellenl -text [mc "Length of commit ID to copy"] + grid x $page.autosellenl $page.autosellen -sticky w + ${NS}::label $page.ddisp -text [mc "Diff display options"] grid $page.ddisp - -sticky w -pady 10 ${NS}::label $page.tabstopl -text [mc "Tab spacing"] -- cgit v1.2.3 From d77c3e35bbca78a0cee6f0eacecccd9aac957c8b Mon Sep 17 00:00:00 2001 From: "Avi Halachmi (:avih)" Date: Wed, 11 Dec 2024 11:22:03 +0200 Subject: gitk: support auto-copy comit ID to primary clipboard Auto-select ("Copy commit ID to X11 selection") is useful when a selection cliboard exists, but otherwise generally meaningless, for instance on Windows. Add a similar pref and behavior which copies the commit ID to the primary clipboard - for platforms without a selection clipboard, but which can also be useful additionally on platforms with selection. Note that while autoselect is enabled by default, autocopy isn't. That's because the selection clipboard is typically dispensable, while the primary clipboard can be considered a more precious resource, which we don't want to (clear and) overwrite by default. Signed-off-by: Avi Halachmi (:avih) --- gitk | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/gitk b/gitk index 322236d361..38baf20b95 100755 --- a/gitk +++ b/gitk @@ -7344,7 +7344,7 @@ proc selectline {l isnew {desired_loc {}} {switch_to_patch 0}} { global mergemax numcommits pending_select global cmitmode showneartags allcommits global targetrow targetid lastscrollrows - global autoselect autosellen jump_to_here + global autocopy autoselect autosellen jump_to_here global vinlinediff unset -nocomplain pending_select @@ -7413,6 +7413,10 @@ proc selectline {l isnew {desired_loc {}} {switch_to_patch 0}} { if {$autoselect} { $sha1entry selection range 0 $autosellen } + if {$autocopy} { + clipboard clear + clipboard append [string range $id 0 [expr $autosellen - 1]] + } rhighlight_sel $id $ctext conf -state normal @@ -11576,7 +11580,7 @@ proc create_prefs_page {w} { proc prefspage_general {notebook} { global NS maxwidth maxgraphpct showneartags showlocalchanges - global tabstop limitdiffs autoselect autosellen extdifftool perfile_attrs + global tabstop limitdiffs autocopy autoselect autosellen extdifftool perfile_attrs global hideremotes want_ttk have_ttk maxrefs web_browser set page [create_prefs_page $notebook.general] @@ -11598,6 +11602,9 @@ proc prefspage_general {notebook} { -variable hideremotes grid x $page.hideremotes -sticky w + ${NS}::checkbutton $page.autocopy -text [mc "Copy commit ID to clipboard"] \ + -variable autocopy + grid x $page.autocopy -sticky w ${NS}::checkbutton $page.autoselect -text [mc "Copy commit ID to X11 selection"] \ -variable autoselect grid x $page.autoselect -sticky w @@ -12403,6 +12410,7 @@ set maxlinelen 200 set showlocalchanges 1 set limitdiffs 1 set datetimeformat "%Y-%m-%d %H:%M:%S" +set autocopy 0 set autoselect 1 set autosellen 40 set perfile_attrs 0 @@ -12500,7 +12508,7 @@ config_check_tmp_exists 50 set config_variables { mainfont textfont uifont tabstop findmergefiles maxgraphpct maxwidth - cmitmode wrapcomment autoselect autosellen showneartags maxrefs visiblerefs + cmitmode wrapcomment autocopy autoselect autosellen showneartags maxrefs visiblerefs hideremotes showlocalchanges datetimeformat limitdiffs uicolor want_ttk bgcolor fgcolor uifgcolor uifgdisabledcolor colors diffcolors mergecolors markbgcolor diffcontext selectbgcolor foundbgcolor currentsearchhitbgcolor -- cgit v1.2.3 From 714c134dd6f29d23b46cb85cd8bd82a2ce894c65 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 13 Dec 2024 11:41:16 +0100 Subject: ci/lib: support custom output directories when creating test artifacts Update `create_failed_test_artifacts ()` so that it can handle arbitrary test output directories. This fixes creation of these artifacts for macOS on GitLab CI, which uses a separate output directory already. This will also be used by our out-of-tree builds with Meson. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- ci/lib.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ci/lib.sh b/ci/lib.sh index 930f98d722..2e7a5f0540 100755 --- a/ci/lib.sh +++ b/ci/lib.sh @@ -180,9 +180,9 @@ handle_failed_tests () { } create_failed_test_artifacts () { - mkdir -p t/failed-test-artifacts + mkdir -p "${TEST_OUTPUT_DIRECTORY:-t}"/failed-test-artifacts - for test_exit in t/test-results/*.exit + for test_exit in "${TEST_OUTPUT_DIRECTORY:-t}"/test-results/*.exit do test 0 != "$(cat "$test_exit")" || continue @@ -191,11 +191,11 @@ create_failed_test_artifacts () { printf "\\e[33m\\e[1m=== Failed test: ${test_name} ===\\e[m\\n" echo "The full logs are in the 'print test failures' step below." echo "See also the 'failed-tests-*' artifacts attached to this run." - cat "t/test-results/$test_name.markup" + cat "${TEST_OUTPUT_DIRECTORY:-t}/test-results/$test_name.markup" - trash_dir="t/trash directory.$test_name" - cp "t/test-results/$test_name.out" t/failed-test-artifacts/ - tar czf t/failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir" + trash_dir="${TEST_OUTPUT_DIRECTORY:-t}/trash directory.$test_name" + cp "${TEST_OUTPUT_DIRECTORY:-t}/test-results/$test_name.out" "${TEST_OUTPUT_DIRECTORY:-t}"/failed-test-artifacts/ + tar czf "${TEST_OUTPUT_DIRECTORY:-t}/failed-test-artifacts/$test_name.trash.tar.gz" "$trash_dir" done } -- cgit v1.2.3 From 23eeee08d6a22de197b17e791508ddcb3a953dc7 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 13 Dec 2024 11:41:17 +0100 Subject: Makefile: drop -DSUPPRESS_ANNOTATED_LEAKS The -DSUPPRESS_ANNOTATED_LEAKS preprocessor directive was used to enable our `UNLEAK()` macro in the past, which marks memory as still-reachable so that the leak sanitizer does not complain. Starting with 52c7dbd036 (git-compat-util: drop now-unused `UNLEAK()` macro, 2024-11-20) this macro has been removed, and thus the preprocessor directive is not required anymore, either. Drop it. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Makefile | 1 - meson.build | 1 - 2 files changed, 2 deletions(-) diff --git a/Makefile b/Makefile index 06f01149ec..2506f3b7e3 100644 --- a/Makefile +++ b/Makefile @@ -1490,7 +1490,6 @@ ifneq ($(filter undefined,$(SANITIZERS)),) BASIC_CFLAGS += -DSHA1DC_FORCE_ALIGNED_ACCESS endif ifneq ($(filter leak,$(SANITIZERS)),) -BASIC_CFLAGS += -DSUPPRESS_ANNOTATED_LEAKS BASIC_CFLAGS += -O0 SANITIZE_LEAK = YesCompiledWithIt endif diff --git a/meson.build b/meson.build index 0dccebcdf1..1af25af5cc 100644 --- a/meson.build +++ b/meson.build @@ -712,7 +712,6 @@ else build_options_config.set('SANITIZE_ADDRESS', '') endif if get_option('b_sanitize').contains('leak') - libgit_c_args += '-DSUPPRESS_ANNOTATED_LEAKS' build_options_config.set('SANITIZE_LEAK', 'YesCompiledWithIt') else build_options_config.set('SANITIZE_LEAK', '') -- cgit v1.2.3 From c081e7340f5545342f80e77f4578851d77dc9cf6 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 13 Dec 2024 11:41:18 +0100 Subject: t/unit-tests: rename clar-based unit tests to have a common prefix All of the code files for unit tests using the self-grown unit testing framework have a "t-" prefix to their name. This makes it easy to identify them and use globbing in our Makefile and in other places. On the other hand though, our clar-based unit tests have no prefix at all and thus cannot easily be discerned from other files in the unit test directory. Introduce a new "u-" prefix for clar-based unit tests. This prefix will be used in a subsequent commit to easily identify such tests. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Makefile | 4 +- t/meson.build | 4 +- t/unit-tests/ctype.c | 102 ------------ t/unit-tests/generate-clar-decls.sh | 5 +- t/unit-tests/strvec.c | 306 ------------------------------------ t/unit-tests/u-ctype.c | 102 ++++++++++++ t/unit-tests/u-strvec.c | 306 ++++++++++++++++++++++++++++++++++++ 7 files changed, 416 insertions(+), 413 deletions(-) delete mode 100644 t/unit-tests/ctype.c delete mode 100644 t/unit-tests/strvec.c create mode 100644 t/unit-tests/u-ctype.c create mode 100644 t/unit-tests/u-strvec.c diff --git a/Makefile b/Makefile index 2506f3b7e3..6eafaf174a 100644 --- a/Makefile +++ b/Makefile @@ -1344,8 +1344,8 @@ THIRD_PARTY_SOURCES += sha1dc/% THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/% THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/clar/% -CLAR_TEST_SUITES += ctype -CLAR_TEST_SUITES += strvec +CLAR_TEST_SUITES += u-ctype +CLAR_TEST_SUITES += u-strvec CLAR_TEST_PROG = $(UNIT_TEST_BIN)/unit-tests$(X) CLAR_TEST_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(CLAR_TEST_SUITES)) CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/clar/clar.o diff --git a/t/meson.build b/t/meson.build index 13fe854ba0..9e676e6936 100644 --- a/t/meson.build +++ b/t/meson.build @@ -1,6 +1,6 @@ clar_test_suites = [ - 'unit-tests/ctype.c', - 'unit-tests/strvec.c', + 'unit-tests/u-ctype.c', + 'unit-tests/u-strvec.c', ] clar_sources = [ diff --git a/t/unit-tests/ctype.c b/t/unit-tests/ctype.c deleted file mode 100644 index 32e65867cd..0000000000 --- a/t/unit-tests/ctype.c +++ /dev/null @@ -1,102 +0,0 @@ -#include "unit-test.h" - -#define TEST_CHAR_CLASS(class, string) do { \ - size_t len = ARRAY_SIZE(string) - 1 + \ - BUILD_ASSERT_OR_ZERO(ARRAY_SIZE(string) > 0) + \ - BUILD_ASSERT_OR_ZERO(sizeof(string[0]) == sizeof(char)); \ - for (int i = 0; i < 256; i++) { \ - int actual = class(i), expect = !!memchr(string, i, len); \ - if (actual != expect) \ - cl_failf("0x%02x is classified incorrectly: expected %d, got %d", \ - i, expect, actual); \ - } \ - cl_assert(!class(EOF)); \ -} while (0) - -#define DIGIT "0123456789" -#define LOWER "abcdefghijklmnopqrstuvwxyz" -#define UPPER "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -#define PUNCT "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" -#define ASCII \ - "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \ - "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \ - "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" \ - "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" \ - "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" \ - "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" \ - "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" \ - "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" -#define CNTRL \ - "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \ - "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \ - "\x7f" - -void test_ctype__isspace(void) -{ - TEST_CHAR_CLASS(isspace, " \n\r\t"); -} - -void test_ctype__isdigit(void) -{ - TEST_CHAR_CLASS(isdigit, DIGIT); -} - -void test_ctype__isalpha(void) -{ - TEST_CHAR_CLASS(isalpha, LOWER UPPER); -} - -void test_ctype__isalnum(void) -{ - TEST_CHAR_CLASS(isalnum, LOWER UPPER DIGIT); -} - -void test_ctype__is_glob_special(void) -{ - TEST_CHAR_CLASS(is_glob_special, "*?[\\"); -} - -void test_ctype__is_regex_special(void) -{ - TEST_CHAR_CLASS(is_regex_special, "$()*+.?[\\^{|"); -} - -void test_ctype__is_pathspec_magic(void) -{ - TEST_CHAR_CLASS(is_pathspec_magic, "!\"#%&',-/:;<=>@_`~"); -} - -void test_ctype__isascii(void) -{ - TEST_CHAR_CLASS(isascii, ASCII); -} - -void test_ctype__islower(void) -{ - TEST_CHAR_CLASS(islower, LOWER); -} - -void test_ctype__isupper(void) -{ - TEST_CHAR_CLASS(isupper, UPPER); -} - -void test_ctype__iscntrl(void) -{ - TEST_CHAR_CLASS(iscntrl, CNTRL); -} - -void test_ctype__ispunct(void) -{ - TEST_CHAR_CLASS(ispunct, PUNCT); -} - -void test_ctype__isxdigit(void) -{ - TEST_CHAR_CLASS(isxdigit, DIGIT "abcdefABCDEF"); -} - -void test_ctype__isprint(void) -{ - TEST_CHAR_CLASS(isprint, LOWER UPPER DIGIT PUNCT " "); -} diff --git a/t/unit-tests/generate-clar-decls.sh b/t/unit-tests/generate-clar-decls.sh index 688e0885f4..3b315c64b3 100755 --- a/t/unit-tests/generate-clar-decls.sh +++ b/t/unit-tests/generate-clar-decls.sh @@ -11,6 +11,9 @@ shift for suite in "$@" do - sed -ne "s/^\(void test_$(basename "${suite%.c}")__[a-zA-Z_0-9][a-zA-Z_0-9]*(void)\)$/extern \1;/p" "$suite" || + suite_name=$(basename "$suite") + suite_name=${suite_name%.c} + suite_name=${suite_name#u-} + sed -ne "s/^\(void test_${suite_name}__[a-zA-Z_0-9][a-zA-Z_0-9]*(void)\)$/extern \1;/p" "$suite" || exit 1 done >"$OUTPUT" diff --git a/t/unit-tests/strvec.c b/t/unit-tests/strvec.c deleted file mode 100644 index 855b602337..0000000000 --- a/t/unit-tests/strvec.c +++ /dev/null @@ -1,306 +0,0 @@ -#include "unit-test.h" -#include "strbuf.h" -#include "strvec.h" - -#define check_strvec(vec, ...) \ - do { \ - const char *expect[] = { __VA_ARGS__ }; \ - size_t expect_len = ARRAY_SIZE(expect); \ - cl_assert(expect_len > 0); \ - cl_assert_equal_p(expect[expect_len - 1], NULL); \ - cl_assert_equal_i((vec)->nr, expect_len - 1); \ - cl_assert((vec)->nr <= (vec)->alloc); \ - for (size_t i = 0; i < expect_len; i++) \ - cl_assert_equal_s((vec)->v[i], expect[i]); \ - } while (0) - -void test_strvec__init(void) -{ - struct strvec vec = STRVEC_INIT; - - cl_assert_equal_p(vec.v, empty_strvec); - cl_assert_equal_i(vec.nr, 0); - cl_assert_equal_i(vec.alloc, 0); -} - -void test_strvec__dynamic_init(void) -{ - struct strvec vec; - - strvec_init(&vec); - cl_assert_equal_p(vec.v, empty_strvec); - cl_assert_equal_i(vec.nr, 0); - cl_assert_equal_i(vec.alloc, 0); -} - -void test_strvec__clear(void) -{ - struct strvec vec = STRVEC_INIT; - - strvec_push(&vec, "foo"); - strvec_clear(&vec); - cl_assert_equal_p(vec.v, empty_strvec); - cl_assert_equal_i(vec.nr, 0); - cl_assert_equal_i(vec.alloc, 0); -} - -void test_strvec__push(void) -{ - struct strvec vec = STRVEC_INIT; - - strvec_push(&vec, "foo"); - check_strvec(&vec, "foo", NULL); - - strvec_push(&vec, "bar"); - check_strvec(&vec, "foo", "bar", NULL); - - strvec_clear(&vec); -} - -void test_strvec__pushf(void) -{ - struct strvec vec = STRVEC_INIT; - - strvec_pushf(&vec, "foo: %d", 1); - check_strvec(&vec, "foo: 1", NULL); - strvec_clear(&vec); -} - -void test_strvec__pushl(void) -{ - struct strvec vec = STRVEC_INIT; - - strvec_pushl(&vec, "foo", "bar", "baz", NULL); - check_strvec(&vec, "foo", "bar", "baz", NULL); - strvec_clear(&vec); -} - -void test_strvec__pushv(void) -{ - const char *strings[] = { - "foo", "bar", "baz", NULL, - }; - struct strvec vec = STRVEC_INIT; - - strvec_pushv(&vec, strings); - check_strvec(&vec, "foo", "bar", "baz", NULL); - - strvec_clear(&vec); -} - -void test_strvec__splice_with_same_size_replacement(void) -{ - struct strvec vec = STRVEC_INIT; - const char *replacement[] = { "1" }; - - strvec_pushl(&vec, "foo", "bar", "baz", NULL); - strvec_splice(&vec, 1, 1, replacement, ARRAY_SIZE(replacement)); - check_strvec(&vec, "foo", "1", "baz", NULL); - strvec_clear(&vec); -} - -void test_strvec__splice_with_smaller_replacement(void) -{ - struct strvec vec = STRVEC_INIT; - const char *replacement[] = { "1" }; - - strvec_pushl(&vec, "foo", "bar", "baz", NULL); - strvec_splice(&vec, 1, 2, replacement, ARRAY_SIZE(replacement)); - check_strvec(&vec, "foo", "1", NULL); - strvec_clear(&vec); -} - -void test_strvec__splice_with_bigger_replacement(void) -{ - struct strvec vec = STRVEC_INIT; - const char *replacement[] = { "1", "2", "3" }; - - strvec_pushl(&vec, "foo", "bar", "baz", NULL); - strvec_splice(&vec, 0, 2, replacement, ARRAY_SIZE(replacement)); - check_strvec(&vec, "1", "2", "3", "baz", NULL); - strvec_clear(&vec); -} - -void test_strvec__splice_with_empty_replacement(void) -{ - struct strvec vec = STRVEC_INIT; - - strvec_pushl(&vec, "foo", "bar", "baz", NULL); - strvec_splice(&vec, 0, 2, NULL, 0); - check_strvec(&vec, "baz", NULL); - strvec_clear(&vec); -} - -void test_strvec__splice_with_empty_original(void) -{ - struct strvec vec = STRVEC_INIT; - const char *replacement[] = { "1", "2" }; - - strvec_pushl(&vec, "foo", "bar", "baz", NULL); - strvec_splice(&vec, 1, 0, replacement, ARRAY_SIZE(replacement)); - check_strvec(&vec, "foo", "1", "2", "bar", "baz", NULL); - strvec_clear(&vec); -} - -void test_strvec__splice_at_tail(void) -{ - struct strvec vec = STRVEC_INIT; - const char *replacement[] = { "1", "2" }; - - strvec_pushl(&vec, "foo", "bar", NULL); - strvec_splice(&vec, 2, 0, replacement, ARRAY_SIZE(replacement)); - check_strvec(&vec, "foo", "bar", "1", "2", NULL); - strvec_clear(&vec); -} - -void test_strvec__replace_at_head(void) -{ - struct strvec vec = STRVEC_INIT; - - strvec_pushl(&vec, "foo", "bar", "baz", NULL); - strvec_replace(&vec, 0, "replaced"); - check_strvec(&vec, "replaced", "bar", "baz", NULL); - strvec_clear(&vec); -} - -void test_strvec__replace_at_tail(void) -{ - struct strvec vec = STRVEC_INIT; - strvec_pushl(&vec, "foo", "bar", "baz", NULL); - strvec_replace(&vec, 2, "replaced"); - check_strvec(&vec, "foo", "bar", "replaced", NULL); - strvec_clear(&vec); -} - -void test_strvec__replace_in_between(void) -{ - struct strvec vec = STRVEC_INIT; - - strvec_pushl(&vec, "foo", "bar", "baz", NULL); - strvec_replace(&vec, 1, "replaced"); - check_strvec(&vec, "foo", "replaced", "baz", NULL); - strvec_clear(&vec); -} - -void test_strvec__replace_with_substring(void) -{ - struct strvec vec = STRVEC_INIT; - - strvec_pushl(&vec, "foo", NULL); - strvec_replace(&vec, 0, vec.v[0] + 1); - check_strvec(&vec, "oo", NULL); - strvec_clear(&vec); -} - -void test_strvec__remove_at_head(void) -{ - struct strvec vec = STRVEC_INIT; - - strvec_pushl(&vec, "foo", "bar", "baz", NULL); - strvec_remove(&vec, 0); - check_strvec(&vec, "bar", "baz", NULL); - strvec_clear(&vec); -} - -void test_strvec__remove_at_tail(void) -{ - struct strvec vec = STRVEC_INIT; - - strvec_pushl(&vec, "foo", "bar", "baz", NULL); - strvec_remove(&vec, 2); - check_strvec(&vec, "foo", "bar", NULL); - strvec_clear(&vec); -} - -void test_strvec__remove_in_between(void) -{ - struct strvec vec = STRVEC_INIT; - - strvec_pushl(&vec, "foo", "bar", "baz", NULL); - strvec_remove(&vec, 1); - check_strvec(&vec, "foo", "baz", NULL); - strvec_clear(&vec); -} - -void test_strvec__pop_empty_array(void) -{ - struct strvec vec = STRVEC_INIT; - - strvec_pop(&vec); - check_strvec(&vec, NULL); - strvec_clear(&vec); -} - -void test_strvec__pop_non_empty_array(void) -{ - struct strvec vec = STRVEC_INIT; - - strvec_pushl(&vec, "foo", "bar", "baz", NULL); - strvec_pop(&vec); - check_strvec(&vec, "foo", "bar", NULL); - strvec_clear(&vec); -} - -void test_strvec__split_empty_string(void) -{ - struct strvec vec = STRVEC_INIT; - - strvec_split(&vec, ""); - check_strvec(&vec, NULL); - strvec_clear(&vec); -} - -void test_strvec__split_single_item(void) -{ - struct strvec vec = STRVEC_INIT; - - strvec_split(&vec, "foo"); - check_strvec(&vec, "foo", NULL); - strvec_clear(&vec); -} - -void test_strvec__split_multiple_items(void) -{ - struct strvec vec = STRVEC_INIT; - - strvec_split(&vec, "foo bar baz"); - check_strvec(&vec, "foo", "bar", "baz", NULL); - strvec_clear(&vec); -} - -void test_strvec__split_whitespace_only(void) -{ - struct strvec vec = STRVEC_INIT; - - strvec_split(&vec, " \t\n"); - check_strvec(&vec, NULL); - strvec_clear(&vec); -} - -void test_strvec__split_multiple_consecutive_whitespaces(void) -{ - struct strvec vec = STRVEC_INIT; - - strvec_split(&vec, "foo\n\t bar"); - check_strvec(&vec, "foo", "bar", NULL); - strvec_clear(&vec); -} - -void test_strvec__detach(void) -{ - struct strvec vec = STRVEC_INIT; - const char **detached; - - strvec_push(&vec, "foo"); - - detached = strvec_detach(&vec); - cl_assert_equal_s(detached[0], "foo"); - cl_assert_equal_p(detached[1], NULL); - - cl_assert_equal_p(vec.v, empty_strvec); - cl_assert_equal_i(vec.nr, 0); - cl_assert_equal_i(vec.alloc, 0); - - free((char *) detached[0]); - free(detached); -} diff --git a/t/unit-tests/u-ctype.c b/t/unit-tests/u-ctype.c new file mode 100644 index 0000000000..32e65867cd --- /dev/null +++ b/t/unit-tests/u-ctype.c @@ -0,0 +1,102 @@ +#include "unit-test.h" + +#define TEST_CHAR_CLASS(class, string) do { \ + size_t len = ARRAY_SIZE(string) - 1 + \ + BUILD_ASSERT_OR_ZERO(ARRAY_SIZE(string) > 0) + \ + BUILD_ASSERT_OR_ZERO(sizeof(string[0]) == sizeof(char)); \ + for (int i = 0; i < 256; i++) { \ + int actual = class(i), expect = !!memchr(string, i, len); \ + if (actual != expect) \ + cl_failf("0x%02x is classified incorrectly: expected %d, got %d", \ + i, expect, actual); \ + } \ + cl_assert(!class(EOF)); \ +} while (0) + +#define DIGIT "0123456789" +#define LOWER "abcdefghijklmnopqrstuvwxyz" +#define UPPER "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define PUNCT "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" +#define ASCII \ + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \ + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \ + "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" \ + "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" \ + "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" \ + "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" \ + "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" \ + "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" +#define CNTRL \ + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \ + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \ + "\x7f" + +void test_ctype__isspace(void) +{ + TEST_CHAR_CLASS(isspace, " \n\r\t"); +} + +void test_ctype__isdigit(void) +{ + TEST_CHAR_CLASS(isdigit, DIGIT); +} + +void test_ctype__isalpha(void) +{ + TEST_CHAR_CLASS(isalpha, LOWER UPPER); +} + +void test_ctype__isalnum(void) +{ + TEST_CHAR_CLASS(isalnum, LOWER UPPER DIGIT); +} + +void test_ctype__is_glob_special(void) +{ + TEST_CHAR_CLASS(is_glob_special, "*?[\\"); +} + +void test_ctype__is_regex_special(void) +{ + TEST_CHAR_CLASS(is_regex_special, "$()*+.?[\\^{|"); +} + +void test_ctype__is_pathspec_magic(void) +{ + TEST_CHAR_CLASS(is_pathspec_magic, "!\"#%&',-/:;<=>@_`~"); +} + +void test_ctype__isascii(void) +{ + TEST_CHAR_CLASS(isascii, ASCII); +} + +void test_ctype__islower(void) +{ + TEST_CHAR_CLASS(islower, LOWER); +} + +void test_ctype__isupper(void) +{ + TEST_CHAR_CLASS(isupper, UPPER); +} + +void test_ctype__iscntrl(void) +{ + TEST_CHAR_CLASS(iscntrl, CNTRL); +} + +void test_ctype__ispunct(void) +{ + TEST_CHAR_CLASS(ispunct, PUNCT); +} + +void test_ctype__isxdigit(void) +{ + TEST_CHAR_CLASS(isxdigit, DIGIT "abcdefABCDEF"); +} + +void test_ctype__isprint(void) +{ + TEST_CHAR_CLASS(isprint, LOWER UPPER DIGIT PUNCT " "); +} diff --git a/t/unit-tests/u-strvec.c b/t/unit-tests/u-strvec.c new file mode 100644 index 0000000000..855b602337 --- /dev/null +++ b/t/unit-tests/u-strvec.c @@ -0,0 +1,306 @@ +#include "unit-test.h" +#include "strbuf.h" +#include "strvec.h" + +#define check_strvec(vec, ...) \ + do { \ + const char *expect[] = { __VA_ARGS__ }; \ + size_t expect_len = ARRAY_SIZE(expect); \ + cl_assert(expect_len > 0); \ + cl_assert_equal_p(expect[expect_len - 1], NULL); \ + cl_assert_equal_i((vec)->nr, expect_len - 1); \ + cl_assert((vec)->nr <= (vec)->alloc); \ + for (size_t i = 0; i < expect_len; i++) \ + cl_assert_equal_s((vec)->v[i], expect[i]); \ + } while (0) + +void test_strvec__init(void) +{ + struct strvec vec = STRVEC_INIT; + + cl_assert_equal_p(vec.v, empty_strvec); + cl_assert_equal_i(vec.nr, 0); + cl_assert_equal_i(vec.alloc, 0); +} + +void test_strvec__dynamic_init(void) +{ + struct strvec vec; + + strvec_init(&vec); + cl_assert_equal_p(vec.v, empty_strvec); + cl_assert_equal_i(vec.nr, 0); + cl_assert_equal_i(vec.alloc, 0); +} + +void test_strvec__clear(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_push(&vec, "foo"); + strvec_clear(&vec); + cl_assert_equal_p(vec.v, empty_strvec); + cl_assert_equal_i(vec.nr, 0); + cl_assert_equal_i(vec.alloc, 0); +} + +void test_strvec__push(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_push(&vec, "foo"); + check_strvec(&vec, "foo", NULL); + + strvec_push(&vec, "bar"); + check_strvec(&vec, "foo", "bar", NULL); + + strvec_clear(&vec); +} + +void test_strvec__pushf(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_pushf(&vec, "foo: %d", 1); + check_strvec(&vec, "foo: 1", NULL); + strvec_clear(&vec); +} + +void test_strvec__pushl(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + check_strvec(&vec, "foo", "bar", "baz", NULL); + strvec_clear(&vec); +} + +void test_strvec__pushv(void) +{ + const char *strings[] = { + "foo", "bar", "baz", NULL, + }; + struct strvec vec = STRVEC_INIT; + + strvec_pushv(&vec, strings); + check_strvec(&vec, "foo", "bar", "baz", NULL); + + strvec_clear(&vec); +} + +void test_strvec__splice_with_same_size_replacement(void) +{ + struct strvec vec = STRVEC_INIT; + const char *replacement[] = { "1" }; + + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_splice(&vec, 1, 1, replacement, ARRAY_SIZE(replacement)); + check_strvec(&vec, "foo", "1", "baz", NULL); + strvec_clear(&vec); +} + +void test_strvec__splice_with_smaller_replacement(void) +{ + struct strvec vec = STRVEC_INIT; + const char *replacement[] = { "1" }; + + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_splice(&vec, 1, 2, replacement, ARRAY_SIZE(replacement)); + check_strvec(&vec, "foo", "1", NULL); + strvec_clear(&vec); +} + +void test_strvec__splice_with_bigger_replacement(void) +{ + struct strvec vec = STRVEC_INIT; + const char *replacement[] = { "1", "2", "3" }; + + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_splice(&vec, 0, 2, replacement, ARRAY_SIZE(replacement)); + check_strvec(&vec, "1", "2", "3", "baz", NULL); + strvec_clear(&vec); +} + +void test_strvec__splice_with_empty_replacement(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_splice(&vec, 0, 2, NULL, 0); + check_strvec(&vec, "baz", NULL); + strvec_clear(&vec); +} + +void test_strvec__splice_with_empty_original(void) +{ + struct strvec vec = STRVEC_INIT; + const char *replacement[] = { "1", "2" }; + + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_splice(&vec, 1, 0, replacement, ARRAY_SIZE(replacement)); + check_strvec(&vec, "foo", "1", "2", "bar", "baz", NULL); + strvec_clear(&vec); +} + +void test_strvec__splice_at_tail(void) +{ + struct strvec vec = STRVEC_INIT; + const char *replacement[] = { "1", "2" }; + + strvec_pushl(&vec, "foo", "bar", NULL); + strvec_splice(&vec, 2, 0, replacement, ARRAY_SIZE(replacement)); + check_strvec(&vec, "foo", "bar", "1", "2", NULL); + strvec_clear(&vec); +} + +void test_strvec__replace_at_head(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_replace(&vec, 0, "replaced"); + check_strvec(&vec, "replaced", "bar", "baz", NULL); + strvec_clear(&vec); +} + +void test_strvec__replace_at_tail(void) +{ + struct strvec vec = STRVEC_INIT; + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_replace(&vec, 2, "replaced"); + check_strvec(&vec, "foo", "bar", "replaced", NULL); + strvec_clear(&vec); +} + +void test_strvec__replace_in_between(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_replace(&vec, 1, "replaced"); + check_strvec(&vec, "foo", "replaced", "baz", NULL); + strvec_clear(&vec); +} + +void test_strvec__replace_with_substring(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_pushl(&vec, "foo", NULL); + strvec_replace(&vec, 0, vec.v[0] + 1); + check_strvec(&vec, "oo", NULL); + strvec_clear(&vec); +} + +void test_strvec__remove_at_head(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_remove(&vec, 0); + check_strvec(&vec, "bar", "baz", NULL); + strvec_clear(&vec); +} + +void test_strvec__remove_at_tail(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_remove(&vec, 2); + check_strvec(&vec, "foo", "bar", NULL); + strvec_clear(&vec); +} + +void test_strvec__remove_in_between(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_remove(&vec, 1); + check_strvec(&vec, "foo", "baz", NULL); + strvec_clear(&vec); +} + +void test_strvec__pop_empty_array(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_pop(&vec); + check_strvec(&vec, NULL); + strvec_clear(&vec); +} + +void test_strvec__pop_non_empty_array(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_pop(&vec); + check_strvec(&vec, "foo", "bar", NULL); + strvec_clear(&vec); +} + +void test_strvec__split_empty_string(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_split(&vec, ""); + check_strvec(&vec, NULL); + strvec_clear(&vec); +} + +void test_strvec__split_single_item(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_split(&vec, "foo"); + check_strvec(&vec, "foo", NULL); + strvec_clear(&vec); +} + +void test_strvec__split_multiple_items(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_split(&vec, "foo bar baz"); + check_strvec(&vec, "foo", "bar", "baz", NULL); + strvec_clear(&vec); +} + +void test_strvec__split_whitespace_only(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_split(&vec, " \t\n"); + check_strvec(&vec, NULL); + strvec_clear(&vec); +} + +void test_strvec__split_multiple_consecutive_whitespaces(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_split(&vec, "foo\n\t bar"); + check_strvec(&vec, "foo", "bar", NULL); + strvec_clear(&vec); +} + +void test_strvec__detach(void) +{ + struct strvec vec = STRVEC_INIT; + const char **detached; + + strvec_push(&vec, "foo"); + + detached = strvec_detach(&vec); + cl_assert_equal_s(detached[0], "foo"); + cl_assert_equal_p(detached[1], NULL); + + cl_assert_equal_p(vec.v, empty_strvec); + cl_assert_equal_i(vec.nr, 0); + cl_assert_equal_i(vec.alloc, 0); + + free((char *) detached[0]); + free(detached); +} -- cgit v1.2.3 From 0ed15121419e802476c17f904a499c6806acd710 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 13 Dec 2024 11:41:19 +0100 Subject: meson: detect missing tests at configure time It is quite easy for the list of integration tests to go out-of-sync without anybody noticing. Introduce a new configure-time check that verifies that all tests are wired up properly. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- t/meson.build | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/t/meson.build b/t/meson.build index 9e676e6936..602ebfe6a2 100644 --- a/t/meson.build +++ b/t/meson.build @@ -1092,6 +1092,42 @@ integration_tests = [ 't9903-bash-prompt.sh', ] +# Sanity check that we are not missing any tests present in 't/'. This check +# only runs once at configure time and is thus best-effort, only. It is +# sufficient to catch missing test suites in our CI though. +foreach glob, tests : { + 't[0-9][0-9][0-9][0-9]-*.sh': integration_tests, + 'unit-tests/t-*.c': unit_test_programs, + 'unit-tests/u-*.c': clar_test_suites, +} + actual_tests = run_command(shell, '-c', 'ls ' + glob, + check: true, + env: script_environment, + ).stdout().strip().split('\n') + + if tests != actual_tests + missing_tests = [ ] + foreach actual_test : actual_tests + if actual_test not in tests + missing_tests += actual_test + endif + endforeach + if missing_tests.length() > 0 + error('Test files found, but not configured:\n\n - ' + '\n - '.join(missing_tests)) + endif + + superfluous_tests = [ ] + foreach integration_test : tests + if integration_test not in actual_tests + superfluous_tests += integration_test + endif + endforeach + if superfluous_tests.length() > 0 + error('Test files configured, but not found:\n\n - ' + '\n - '.join(superfluous_tests)) + endif + endif +endforeach + # GIT_BUILD_DIR needs to be Unix-style without drive prefixes as it get added # to the PATH variable. And given that drive prefixes contain a colon we'd # otherwise end up with a broken PATH if we didn't convert it. -- cgit v1.2.3 From 154ce05cce0ae23581fa79fe988521a2d91df134 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 13 Dec 2024 11:41:20 +0100 Subject: Makefile: detect missing Meson tests In the preceding commit, we have introduced consistency checks to Meson to detect any discrepancies with missing or extraneous tests in its build instructions. These checks only get executed in Meson though, so any users of our Makefiles wouldn't be alerted of the fact that they have to modify the Meson build instructions in case they add or remove any tests. Add a comparable test target to our Makefile to plug this gap. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- t/Makefile | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/t/Makefile b/t/Makefile index 131ffd778f..290fb03ff0 100644 --- a/t/Makefile +++ b/t/Makefile @@ -59,7 +59,7 @@ CHAINLINTSUPPRESS = GIT_TEST_EXT_CHAIN_LINT=0 && export GIT_TEST_EXT_CHAIN_LINT all:: $(DEFAULT_TEST_TARGET) -test: pre-clean check-chainlint $(TEST_LINT) +test: pre-clean check-chainlint check-meson $(TEST_LINT) $(CHAINLINTSUPPRESS) $(MAKE) aggregate-results-and-cleanup failed: @@ -114,6 +114,22 @@ check-chainlint: { $(CHAINLINT) --emit-all '$(CHAINLINTTMP_SQ)'/tests >'$(CHAINLINTTMP_SQ)'/actual || true; } && \ diff -u '$(CHAINLINTTMP_SQ)'/expect '$(CHAINLINTTMP_SQ)'/actual +check-meson: + @# awk acts up when trying to match single quotes, so we use \047 instead. + @printf "%s\n" \ + "integration_tests t[0-9][0-9][0-9][0-9]-*.sh" \ + "unit_test_programs unit-tests/t-*.c" \ + "clar_test_suites unit-tests/u-*.c" | \ + while read -r variable pattern; do \ + meson_tests=$$(awk "/^$$variable = \[\$$/ {flag=1 ; next } /^]$$/ { flag=0 } flag { gsub(/^ \047/, \"\"); gsub(/\047,\$$/, \"\"); print }" meson.build) && \ + actual_tests=$$(ls $$pattern) && \ + if test "$$meson_tests" != "$$actual_tests"; then \ + echo "Meson tests differ from actual tests:"; \ + diff -u <(echo "$$meson_tests") <(echo "$$actual_tests"); \ + exit 1; \ + fi; \ + done + test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax \ test-lint-filenames ifneq ($(GIT_TEST_CHAIN_LINT),0) -- cgit v1.2.3 From 78ad7291df6185df54d86908bd268bfeffe0c13d Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 13 Dec 2024 11:41:21 +0100 Subject: t: fix out-of-tree tests for some git-p4 tests Both t9835 and t9836 exercise git-p4, but one exercises Python 2 whereas the other one uses Python 3. These tests do not exercise "git p4", but instead they use "git p4.py". This calls the unbuilt version of "git-p4.py" that still has the "#!/usr/bin/env python" shebang, which allows the test to modify which Python version comes first in $PATH, making it possible to force a Python version. But "git-p4.py" is not in our PATH during out-of-tree builds, and thus we cannot locate "git-p4.py". The tests thus break with CMake and Meson. Fix this by instead manually setting up script wrappers that invoke the respective Python interpreter directly. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- t/t9835-git-p4-metadata-encoding-python2.sh | 50 ++++++++++++++--------------- t/t9836-git-p4-metadata-encoding-python3.sh | 50 ++++++++++++++--------------- 2 files changed, 50 insertions(+), 50 deletions(-) diff --git a/t/t9835-git-p4-metadata-encoding-python2.sh b/t/t9835-git-p4-metadata-encoding-python2.sh index 036bf79c66..6116f806f6 100755 --- a/t/t9835-git-p4-metadata-encoding-python2.sh +++ b/t/t9835-git-p4-metadata-encoding-python2.sh @@ -8,29 +8,29 @@ failing, and produces maximally sane output in git.' . ./lib-git-p4.sh -python_target_version='2' - ############################### ## SECTION REPEATED IN t9836 ## ############################### -# Please note: this test calls "git-p4.py" rather than "git-p4", because the -# latter references a specific path so we can't easily force it to run under -# the python version we need to. - -python_major_version=$(python -V 2>&1 | cut -c 8) -python_target_binary=$(which python$python_target_version) -if ! test "$python_major_version" = "$python_target_version" && test "$python_target_binary" +# These tests are specific to Python 2. Write a custom script that executes +# git-p4 directly with the Python 2 interpreter to ensure that we use that +# version even if Git was compiled with Python 3. +python_target_binary=$(which python2) +if test -n "$python_target_binary" then mkdir temp_python - PATH="$(pwd)/temp_python:$PATH" && export PATH - ln -s $python_target_binary temp_python/python + PATH="$(pwd)/temp_python:$PATH" + export PATH + + write_script temp_python/git-p4-python2 <<-EOF + exec "$python_target_binary" "$(git --exec-path)/git-p4" "\$@" + EOF fi -python_major_version=$(python -V 2>&1 | cut -c 8) -if ! test "$python_major_version" = "$python_target_version" +git p4-python2 >err +if ! grep 'valid commands' err then - skip_all="skipping python$python_target_version-specific git p4 tests; python$python_target_version not available" + skip_all="skipping python2 git p4 tests; python2 not available" test_done fi @@ -81,14 +81,14 @@ test_expect_success 'init depot' ' test_expect_success 'clone non-utf8 repo with strict encoding' ' test_when_finished cleanup_git && test_when_finished remove_user_cache && - test_must_fail git -c git-p4.metadataDecodingStrategy=strict p4.py clone --dest="$git" //depot@all 2>err && + test_must_fail git -c git-p4.metadataDecodingStrategy=strict p4-python2 clone --dest="$git" //depot@all 2>err && grep "Decoding perforce metadata failed!" err ' test_expect_success 'check utf-8 contents with passthrough strategy' ' test_when_finished cleanup_git && test_when_finished remove_user_cache && - git -c git-p4.metadataDecodingStrategy=passthrough p4.py clone --dest="$git" //depot@all && + git -c git-p4.metadataDecodingStrategy=passthrough p4-python2 clone --dest="$git" //depot@all && ( cd "$git" && git log >actual && @@ -100,7 +100,7 @@ test_expect_success 'check utf-8 contents with passthrough strategy' ' test_expect_success 'check latin-1 contents corrupted in git with passthrough strategy' ' test_when_finished cleanup_git && test_when_finished remove_user_cache && - git -c git-p4.metadataDecodingStrategy=passthrough p4.py clone --dest="$git" //depot@all && + git -c git-p4.metadataDecodingStrategy=passthrough p4-python2 clone --dest="$git" //depot@all && ( cd "$git" && git log >actual && @@ -114,7 +114,7 @@ test_expect_success 'check latin-1 contents corrupted in git with passthrough st test_expect_success 'check utf-8 contents with fallback strategy' ' test_when_finished cleanup_git && test_when_finished remove_user_cache && - git -c git-p4.metadataDecodingStrategy=fallback p4.py clone --dest="$git" //depot@all && + git -c git-p4.metadataDecodingStrategy=fallback p4-python2 clone --dest="$git" //depot@all && ( cd "$git" && git log >actual && @@ -126,7 +126,7 @@ test_expect_success 'check utf-8 contents with fallback strategy' ' test_expect_success 'check latin-1 contents with fallback strategy' ' test_when_finished cleanup_git && test_when_finished remove_user_cache && - git -c git-p4.metadataDecodingStrategy=fallback p4.py clone --dest="$git" //depot@all && + git -c git-p4.metadataDecodingStrategy=fallback p4-python2 clone --dest="$git" //depot@all && ( cd "$git" && git log >actual && @@ -138,7 +138,7 @@ test_expect_success 'check latin-1 contents with fallback strategy' ' test_expect_success 'check cp-1252 contents with fallback strategy' ' test_when_finished cleanup_git && test_when_finished remove_user_cache && - git -c git-p4.metadataDecodingStrategy=fallback p4.py clone --dest="$git" //depot@all && + git -c git-p4.metadataDecodingStrategy=fallback p4-python2 clone --dest="$git" //depot@all && ( cd "$git" && git log >actual && @@ -150,7 +150,7 @@ test_expect_success 'check cp-1252 contents with fallback strategy' ' test_expect_success 'check cp850 contents parsed with correct fallback' ' test_when_finished cleanup_git && test_when_finished remove_user_cache && - git -c git-p4.metadataDecodingStrategy=fallback -c git-p4.metadataFallbackEncoding=cp850 p4.py clone --dest="$git" //depot@all && + git -c git-p4.metadataDecodingStrategy=fallback -c git-p4.metadataFallbackEncoding=cp850 p4-python2 clone --dest="$git" //depot@all && ( cd "$git" && git log >actual && @@ -162,7 +162,7 @@ test_expect_success 'check cp850 contents parsed with correct fallback' ' test_expect_success 'check cp850-only contents escaped when cp1252 is fallback' ' test_when_finished cleanup_git && test_when_finished remove_user_cache && - git -c git-p4.metadataDecodingStrategy=fallback p4.py clone --dest="$git" //depot@all && + git -c git-p4.metadataDecodingStrategy=fallback p4-python2 clone --dest="$git" //depot@all && ( cd "$git" && git log >actual && @@ -174,7 +174,7 @@ test_expect_success 'check cp850-only contents escaped when cp1252 is fallback' test_expect_success 'check cp-1252 contents on later sync after clone with fallback strategy' ' test_when_finished cleanup_git && test_when_finished remove_user_cache && - git -c git-p4.metadataDecodingStrategy=fallback p4.py clone --dest="$git" //depot@all && + git -c git-p4.metadataDecodingStrategy=fallback p4-python2 clone --dest="$git" //depot@all && ( cd "$cli" && P4USER=cp1252_author && @@ -186,7 +186,7 @@ test_expect_success 'check cp-1252 contents on later sync after clone with fallb ( cd "$git" && - git p4.py sync --branch=master && + git p4-python2 sync --branch=master && git log p4/master >actual && grep "sœme more cp-1252 tæxt" actual && @@ -201,7 +201,7 @@ test_expect_success 'check cp-1252 contents on later sync after clone with fallb test_expect_success 'passthrough (latin-1 contents corrupted in git) is the default with python2' ' test_when_finished cleanup_git && test_when_finished remove_user_cache && - git -c git-p4.metadataDecodingStrategy=passthrough p4.py clone --dest="$git" //depot@all && + git -c git-p4.metadataDecodingStrategy=passthrough p4-python2 clone --dest="$git" //depot@all && ( cd "$git" && git log >actual && diff --git a/t/t9836-git-p4-metadata-encoding-python3.sh b/t/t9836-git-p4-metadata-encoding-python3.sh index 63350dc4b5..5e5217a66b 100755 --- a/t/t9836-git-p4-metadata-encoding-python3.sh +++ b/t/t9836-git-p4-metadata-encoding-python3.sh @@ -8,29 +8,29 @@ failing, and produces maximally sane output in git.' . ./lib-git-p4.sh -python_target_version='3' - ############################### ## SECTION REPEATED IN t9835 ## ############################### -# Please note: this test calls "git-p4.py" rather than "git-p4", because the -# latter references a specific path so we can't easily force it to run under -# the python version we need to. - -python_major_version=$(python -V 2>&1 | cut -c 8) -python_target_binary=$(which python$python_target_version) -if ! test "$python_major_version" = "$python_target_version" && test "$python_target_binary" +# These tests are specific to Python 3. Write a custom script that executes +# git-p4 directly with the Python 3 interpreter to ensure that we use that +# version even if Git was compiled with Python 2. +python_target_binary=$(which python3) +if test -n "$python_target_binary" then mkdir temp_python - PATH="$(pwd)/temp_python:$PATH" && export PATH - ln -s $python_target_binary temp_python/python + PATH="$(pwd)/temp_python:$PATH" + export PATH + + write_script temp_python/git-p4-python3 <<-EOF + exec "$python_target_binary" "$(git --exec-path)/git-p4" "\$@" + EOF fi -python_major_version=$(python -V 2>&1 | cut -c 8) -if ! test "$python_major_version" = "$python_target_version" +git p4-python3 >err +if ! grep 'valid commands' err then - skip_all="skipping python$python_target_version-specific git p4 tests; python$python_target_version not available" + skip_all="skipping python3 git p4 tests; python3 not available" test_done fi @@ -81,14 +81,14 @@ test_expect_success 'init depot' ' test_expect_success 'clone non-utf8 repo with strict encoding' ' test_when_finished cleanup_git && test_when_finished remove_user_cache && - test_must_fail git -c git-p4.metadataDecodingStrategy=strict p4.py clone --dest="$git" //depot@all 2>err && + test_must_fail git -c git-p4.metadataDecodingStrategy=strict p4-python3 clone --dest="$git" //depot@all 2>err && grep "Decoding perforce metadata failed!" err ' test_expect_success 'check utf-8 contents with passthrough strategy' ' test_when_finished cleanup_git && test_when_finished remove_user_cache && - git -c git-p4.metadataDecodingStrategy=passthrough p4.py clone --dest="$git" //depot@all && + git -c git-p4.metadataDecodingStrategy=passthrough p4-python3 clone --dest="$git" //depot@all && ( cd "$git" && git log >actual && @@ -100,7 +100,7 @@ test_expect_success 'check utf-8 contents with passthrough strategy' ' test_expect_success 'check latin-1 contents corrupted in git with passthrough strategy' ' test_when_finished cleanup_git && test_when_finished remove_user_cache && - git -c git-p4.metadataDecodingStrategy=passthrough p4.py clone --dest="$git" //depot@all && + git -c git-p4.metadataDecodingStrategy=passthrough p4-python3 clone --dest="$git" //depot@all && ( cd "$git" && git log >actual && @@ -114,7 +114,7 @@ test_expect_success 'check latin-1 contents corrupted in git with passthrough st test_expect_success 'check utf-8 contents with fallback strategy' ' test_when_finished cleanup_git && test_when_finished remove_user_cache && - git -c git-p4.metadataDecodingStrategy=fallback p4.py clone --dest="$git" //depot@all && + git -c git-p4.metadataDecodingStrategy=fallback p4-python3 clone --dest="$git" //depot@all && ( cd "$git" && git log >actual && @@ -126,7 +126,7 @@ test_expect_success 'check utf-8 contents with fallback strategy' ' test_expect_success 'check latin-1 contents with fallback strategy' ' test_when_finished cleanup_git && test_when_finished remove_user_cache && - git -c git-p4.metadataDecodingStrategy=fallback p4.py clone --dest="$git" //depot@all && + git -c git-p4.metadataDecodingStrategy=fallback p4-python3 clone --dest="$git" //depot@all && ( cd "$git" && git log >actual && @@ -138,7 +138,7 @@ test_expect_success 'check latin-1 contents with fallback strategy' ' test_expect_success 'check cp-1252 contents with fallback strategy' ' test_when_finished cleanup_git && test_when_finished remove_user_cache && - git -c git-p4.metadataDecodingStrategy=fallback p4.py clone --dest="$git" //depot@all && + git -c git-p4.metadataDecodingStrategy=fallback p4-python3 clone --dest="$git" //depot@all && ( cd "$git" && git log >actual && @@ -150,7 +150,7 @@ test_expect_success 'check cp-1252 contents with fallback strategy' ' test_expect_success 'check cp850 contents parsed with correct fallback' ' test_when_finished cleanup_git && test_when_finished remove_user_cache && - git -c git-p4.metadataDecodingStrategy=fallback -c git-p4.metadataFallbackEncoding=cp850 p4.py clone --dest="$git" //depot@all && + git -c git-p4.metadataDecodingStrategy=fallback -c git-p4.metadataFallbackEncoding=cp850 p4-python3 clone --dest="$git" //depot@all && ( cd "$git" && git log >actual && @@ -162,7 +162,7 @@ test_expect_success 'check cp850 contents parsed with correct fallback' ' test_expect_success 'check cp850-only contents escaped when cp1252 is fallback' ' test_when_finished cleanup_git && test_when_finished remove_user_cache && - git -c git-p4.metadataDecodingStrategy=fallback p4.py clone --dest="$git" //depot@all && + git -c git-p4.metadataDecodingStrategy=fallback p4-python3 clone --dest="$git" //depot@all && ( cd "$git" && git log >actual && @@ -174,7 +174,7 @@ test_expect_success 'check cp850-only contents escaped when cp1252 is fallback' test_expect_success 'check cp-1252 contents on later sync after clone with fallback strategy' ' test_when_finished cleanup_git && test_when_finished remove_user_cache && - git -c git-p4.metadataDecodingStrategy=fallback p4.py clone --dest="$git" //depot@all && + git -c git-p4.metadataDecodingStrategy=fallback p4-python3 clone --dest="$git" //depot@all && ( cd "$cli" && P4USER=cp1252_author && @@ -186,7 +186,7 @@ test_expect_success 'check cp-1252 contents on later sync after clone with fallb ( cd "$git" && - git p4.py sync --branch=master && + git p4-python3 sync --branch=master && git log p4/master >actual && grep "sœme more cp-1252 tæxt" actual && @@ -202,7 +202,7 @@ test_expect_success 'check cp-1252 contents on later sync after clone with fallb test_expect_success 'fallback (both utf-8 and cp-1252 contents handled) is the default with python3' ' test_when_finished cleanup_git && test_when_finished remove_user_cache && - git p4.py clone --dest="$git" //depot@all && + git p4-python3 clone --dest="$git" //depot@all && ( cd "$git" && git log >actual && -- cgit v1.2.3 From 9faf3963b6b567421ab29d263e00f0e6e59a39f5 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 13 Dec 2024 11:41:22 +0100 Subject: t: introduce compatibility options to clar-based tests Our unit tests that don't yet use the clar unit testing framework ignore any option that they do not understand. It is thus fine to just pass test options we set up globally to those unit tests as they are simply ignored. This makes our life easier because we don't have to special case those options with Meson, where test options are set up globally via `meson test --test-args=`. But our clar-based unit testing framework is way stricter here and will fail in case it is passed an unknown option. Stub out these options with no-ops to make our life a bit easier. Note that this also requires us to remove the `-x` short option for `--exclude`. This is because `-x` has another meaning in our integration tests, as it enables shell tracing. I doubt there are a lot of people out there using it as we only got a small hand full of clar tests in the first place. So better change it now so that we can in the long run improve compatibility between the two different test drivers. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- parse-options.h | 12 ++++++++++++ t/unit-tests/unit-test.c | 19 ++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/parse-options.h b/parse-options.h index f0801d4532..d01361ca97 100644 --- a/parse-options.h +++ b/parse-options.h @@ -353,6 +353,18 @@ struct option { .callback = parse_opt_noop_cb, \ } +static char *parse_options_noop_ignored_value MAYBE_UNUSED; +#define OPT_NOOP_ARG(s, l) { \ + .type = OPTION_CALLBACK, \ + .short_name = (s), \ + .long_name = (l), \ + .value = &parse_options_noop_ignored_value, \ + .argh = "ignored", \ + .help = N_("no-op (backward compatibility)"), \ + .flags = PARSE_OPT_HIDDEN, \ + .callback = parse_opt_noop_cb, \ +} + #define OPT_ALIAS(s, l, source_long_name) { \ .type = OPTION_ALIAS, \ .short_name = (s), \ diff --git a/t/unit-tests/unit-test.c b/t/unit-tests/unit-test.c index a474cdcfd3..fa8818842a 100644 --- a/t/unit-tests/unit-test.c +++ b/t/unit-tests/unit-test.c @@ -18,8 +18,25 @@ int cmd_main(int argc, const char **argv) N_("immediately exit upon the first failed test")), OPT_STRING_LIST('r', "run", &run_args, N_("suite[::test]"), N_("run only test suite or individual test ")), - OPT_STRING_LIST('x', "exclude", &exclude_args, N_("suite"), + OPT_STRING_LIST(0, "exclude", &exclude_args, N_("suite"), N_("exclude test suite ")), + /* + * Compatibility wrappers so that we don't have to filter + * options understood by integration tests. + */ + OPT_NOOP_NOARG('d', "debug"), + OPT_NOOP_NOARG(0, "github-workflow-markup"), + OPT_NOOP_NOARG(0, "no-bin-wrappers"), + OPT_NOOP_ARG(0, "root"), + OPT_NOOP_ARG(0, "stress"), + OPT_NOOP_NOARG(0, "tee"), + OPT_NOOP_NOARG(0, "with-dashes"), + OPT_NOOP_ARG(0, "valgrind"), + OPT_NOOP_ARG(0, "valgrind-only"), + OPT_NOOP_NOARG('v', "verbose"), + OPT_NOOP_NOARG('V', "verbose-log"), + OPT_NOOP_ARG(0, "verbose-only"), + OPT_NOOP_NOARG('x', NULL), OPT_END(), }; struct strvec args = STRVEC_INIT; -- cgit v1.2.3 From eab5dbab92fa60298aa4a1952fcbc6cae824d939 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 13 Dec 2024 11:41:23 +0100 Subject: ci: wire up Meson builds Wire up CI builds for both GitLab and GitHub that use the Meson build system. While the setup is mostly trivial, one gotcha is the test output directory used to be in "t/", but now it is contained in the build directory. To unify the logic across Makefile- and Meson-based builds we explicitly set up the `TEST_OUTPUT_DIRECTORY` variable so that it is the same for both build systems. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- .github/workflows/main.yml | 7 +++++++ .gitlab-ci.yml | 8 ++++++++ ci/install-dependencies.sh | 7 +++++++ ci/lib.sh | 2 +- ci/print-test-failures.sh | 2 +- ci/run-build-and-tests.sh | 31 ++++++++++++++++++++++++------- 6 files changed, 48 insertions(+), 9 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 808ddc19b8..c231419abc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -286,6 +286,9 @@ jobs: - jobname: osx-gcc cc: gcc-13 pool: macos-13 + - jobname: osx-meson + cc: clang + pool: macos-13 - jobname: linux-gcc-default cc: gcc pool: ubuntu-latest @@ -298,11 +301,15 @@ jobs: - jobname: linux-asan-ubsan cc: clang pool: ubuntu-latest + - jobname: linux-meson + cc: gcc + pool: ubuntu-latest env: CC: ${{matrix.vector.cc}} CC_PACKAGE: ${{matrix.vector.cc_package}} jobname: ${{matrix.vector.jobname}} distro: ${{matrix.vector.pool}} + TEST_OUTPUT_DIRECTORY: ${{github.workspace}}/t runs-on: ${{matrix.vector.pool}} steps: - uses: actions/checkout@v4 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a1bc92893f..3eec72ddc6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -20,6 +20,7 @@ test:linux: - saas-linux-medium-amd64 variables: CUSTOM_PATH: "/custom" + TEST_OUTPUT_DIRECTORY: "/tmp/test-output" before_script: - ./ci/install-dependencies.sh script: @@ -31,6 +32,7 @@ test:linux: if test "$CI_JOB_STATUS" != 'success' then sudo --preserve-env --set-home --user=builder ./ci/print-test-failures.sh + mv "$TEST_OUTPUT_DIRECTORY"/failed-test-artifacts t/ fi parallel: matrix: @@ -67,6 +69,9 @@ test:linux: image: fedora:latest - jobname: linux-musl image: alpine:latest + - jobname: linux-meson + image: ubuntu:latest + CC: gcc artifacts: paths: - t/failed-test-artifacts @@ -104,6 +109,9 @@ test:osx: - jobname: osx-reftable image: macos-13-xcode-14 CC: clang + - jobname: osx-meson + image: macos-14-xcode-15 + CC: clang artifacts: paths: - t/failed-test-artifacts diff --git a/ci/install-dependencies.sh b/ci/install-dependencies.sh index d020cb7aa5..d1cb9fa878 100755 --- a/ci/install-dependencies.sh +++ b/ci/install-dependencies.sh @@ -58,6 +58,7 @@ ubuntu-*|ubuntu32-*|debian-*) make libssl-dev libcurl4-openssl-dev libexpat-dev wget sudo default-jre \ tcl tk gettext zlib1g-dev perl-modules liberror-perl libauthen-sasl-perl \ libemail-valid-perl libio-pty-perl libio-socket-ssl-perl libnet-smtp-ssl-perl libdbd-sqlite3-perl libcgi-pm-perl \ + libpcre2-dev meson ninja-build pkg-config \ ${CC_PACKAGE:-${CC:-gcc}} $PYTHON_PACKAGE case "$distro" in @@ -90,6 +91,12 @@ macos-*) sudo xattr -d com.apple.quarantine "$CUSTOM_PATH/p4" "$CUSTOM_PATH/p4d" 2>/dev/null || true rm helix-core-server.tgz + case "$jobname" in + osx-meson) + brew install meson ninja pcre2 + ;; + esac + if test -n "$CC_PACKAGE" then BREW_PACKAGE=${CC_PACKAGE/-/@} diff --git a/ci/lib.sh b/ci/lib.sh index 2e7a5f0540..b436f85541 100755 --- a/ci/lib.sh +++ b/ci/lib.sh @@ -236,7 +236,7 @@ then CC="${CC_PACKAGE:-${CC:-gcc}}" DONT_SKIP_TAGS=t handle_failed_tests () { - echo "FAILED_TEST_ARTIFACTS=t/failed-test-artifacts" >>$GITHUB_ENV + echo "FAILED_TEST_ARTIFACTS=${TEST_OUTPUT_DIRECTORY:-t}/failed-test-artifacts" >>$GITHUB_ENV create_failed_test_artifacts return 1 } diff --git a/ci/print-test-failures.sh b/ci/print-test-failures.sh index b1f80aeac3..655687dd82 100755 --- a/ci/print-test-failures.sh +++ b/ci/print-test-failures.sh @@ -46,7 +46,7 @@ do ;; github-actions) mkdir -p failed-test-artifacts - echo "FAILED_TEST_ARTIFACTS=t/failed-test-artifacts" >>$GITHUB_ENV + echo "FAILED_TEST_ARTIFACTS=${TEST_OUTPUT_DIRECTORY:t}/failed-test-artifacts" >>$GITHUB_ENV cp "${TEST_EXIT%.exit}.out" failed-test-artifacts/ tar czf failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir" continue diff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh index 2e28d02b20..c4a41bba0b 100755 --- a/ci/run-build-and-tests.sh +++ b/ci/run-build-and-tests.sh @@ -48,12 +48,29 @@ pedantic) ;; esac -group Build make -if test -n "$run_tests" -then - group "Run tests" make test || - handle_failed_tests -fi -check_unignored_build_artifacts +case "$jobname" in +*-meson) + group "Configure" meson setup build . \ + --warnlevel 2 --werror \ + --wrap-mode nofallback + group "Build" meson compile -C build -- + if test -n "$run_tests" + then + group "Run tests" meson test -C build --print-errorlogs --test-args="$GIT_TEST_OPTS" || ( + ./t/aggregate-results.sh "${TEST_OUTPUT_DIRECTORY:-t}/test-results" + handle_failed_tests + ) + fi + ;; +*) + group Build make + if test -n "$run_tests" + then + group "Run tests" make test || + handle_failed_tests + fi + ;; +esac +check_unignored_build_artifacts save_good_tree -- cgit v1.2.3 From f94bfa151623d7e675db9465ae7ff0b33e4825f3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 12 Dec 2024 10:29:12 +0000 Subject: log: --remerge-diff needs to keep around commit parents To show a remerge diff, the merge needs to be recreated. For that to work, the merge base(s) need to be found, which means that the commits' parents have to be traversed until common ancestors are found (if any). However, one optimization that hails all the way back to cb115748ec0d (Some more memory leak avoidance, 2006-06-17) is to release the commit's list of parents immediately after showing it _and to set that parent list to `NULL`_. This can break the merge base computation. This problem is most obvious when traversing the commits in reverse: In that instance, if a parent of a merge commit has been shown as part of the `git log` command, by the time the merge commit's diff needs to be computed, that parent commit's list of parent commits will have been set to `NULL` and as a result no merge base will be found (even if one should be found). Traversing commits in reverse is far from the only circumstance in which this problem occurs, though. There are many avenues to traversing at least one commit in the revision walk that will later be part of a merge base computation, for example when not even walking any revisions in `git show ` where `` is part of the commit graph between the parents of ``. Another way to force a scenario where a commit is traversed before it has to be traversed again as part of a merge base computation is to start with two revisions (where the first one is reachable from the second but not in a first-parent ancestry) and show the commit log with `--topo-order` and `--first-parent`. Let's fix this by special-casing the `remerge_diff` mode, similar to what we did with reflogs in f35650dff6a4 (log: do not free parents when walking reflog, 2017-07-07). Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin/log.c | 8 ++++++-- t/t4069-remerge-diff.sh | 7 +++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/builtin/log.c b/builtin/log.c index a70fba198f..1549aaf77b 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -511,10 +511,14 @@ static int cmd_log_walk_no_free(struct rev_info *rev) * but we didn't actually show the commit. */ rev->max_count++; - if (!rev->reflog_info) { + if (!rev->reflog_info && !rev->remerge_diff) { /* * We may show a given commit multiple times when - * walking the reflogs. + * walking the reflogs. Therefore we still need it. + * + * Likewise, we potentially still need the parents + * of * already shown commits to determine merge + * bases when showing remerge diffs. */ free_commit_buffer(the_repository->parsed_objects, commit); diff --git a/t/t4069-remerge-diff.sh b/t/t4069-remerge-diff.sh index 07323ebafe..a68c6bfa03 100755 --- a/t/t4069-remerge-diff.sh +++ b/t/t4069-remerge-diff.sh @@ -317,4 +317,11 @@ test_expect_success 'remerge-diff turns off history simplification' ' test_cmp expect actual ' +test_expect_success 'remerge-diff with --reverse' ' + git log -1 --remerge-diff --oneline ab_resolution^ >expect && + git log -1 --remerge-diff --oneline ab_resolution >>expect && + git log -2 --remerge-diff --oneline ab_resolution --reverse >actual && + test_cmp expect actual +' + test_done -- cgit v1.2.3 From 2ccc89b0c16c51561da90d21cfbb4b58cc877bf6 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 13 Dec 2024 07:33:05 -0800 Subject: The sixteenth batch Signed-off-by: Junio C Hamano --- Documentation/RelNotes/2.48.0.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Documentation/RelNotes/2.48.0.txt b/Documentation/RelNotes/2.48.0.txt index bf75cda275..802e9a96e5 100644 --- a/Documentation/RelNotes/2.48.0.txt +++ b/Documentation/RelNotes/2.48.0.txt @@ -24,6 +24,10 @@ UI, Workflows & Features * End-user experience of "git mergetool" when the command errors out has been improved. + * "git bundle --unbundle" and "git clone" running on a bundle file + both learned to trigger fsck over the new objects with configurable + fck check levels. + Performance, Internal Implementation, Development Support etc. -------------------------------------------------------------- @@ -118,6 +122,13 @@ Performance, Internal Implementation, Development Support etc. * Optimize reading random references out of the reftable backend by allowing reuse of iterator objects. + * Backport oss-fuzz tests for us to our codebase. + + * Introduce a new repository extension to prevent older Git versions + from mis-interpreting worktrees created with relative paths. + + * Yet another "pass the repository through the callchain" topic. + Fixes since v2.47 ----------------- @@ -224,8 +235,19 @@ Fixes since v2.47 first step to inspect it". (merge 0ffb5a6bf1 bc/allow-upload-pack-from-other-people later to maint). + * "git fast-import" learned to reject paths with ".." and "." as + their components to avoid creating invalid tree objects. + (merge 8cb4c6e62f en/fast-import-verify-path later to maint). + + * The --ancestry-path option is designed to be given a commit that is + on the path, which was not documented, which has been corrected. + (merge bc1a980759 kk/doc-ancestry-path later to maint). + * Other code cleanup, docfix, build fix, etc. (merge 77af53f56f aa/t7300-modernize later to maint). (merge dcd590a39d bf/t-readme-mention-reftable later to maint). (merge 68e3c69efa kh/trailer-in-glossary later to maint). (merge 91f88f76e6 tb/boundary-traversal-fix later to maint). + (merge 168ebb7159 jc/doc-error-message-guidelines later to maint). + (merge 18693d7d65 kh/doc-bundle-typofix later to maint). + (merge e2f5d3b491 kh/doc-update-ref-grammofix later to maint). -- cgit v1.2.3 From 36625a6974156fbc56bbb97c983b09ae303a06ff Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 14 Dec 2024 15:53:35 +0100 Subject: gitk: offer "Copy commit ID to X11 selection" only on X11 This option is only useful where a selection clipboard is available, which is only the case on X11. Do not clutter the UI in other environments. Signed-off-by: Johannes Sixt --- gitk | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/gitk b/gitk index 38baf20b95..12c0dc401e 100755 --- a/gitk +++ b/gitk @@ -1969,6 +1969,10 @@ proc confirm_popup {msg {owner .}} { return $confirm_ok } +proc haveselectionclipboard {} { + return [expr {[tk windowingsystem] eq "x11"}] +} + proc setoptions {} { global use_ttk @@ -7410,7 +7414,7 @@ proc selectline {l isnew {desired_loc {}} {switch_to_patch 0}} { $sha1entry delete 0 end $sha1entry insert 0 $id - if {$autoselect} { + if {$autoselect && [haveselectionclipboard]} { $sha1entry selection range 0 $autosellen } if {$autocopy} { @@ -11605,9 +11609,11 @@ proc prefspage_general {notebook} { ${NS}::checkbutton $page.autocopy -text [mc "Copy commit ID to clipboard"] \ -variable autocopy grid x $page.autocopy -sticky w - ${NS}::checkbutton $page.autoselect -text [mc "Copy commit ID to X11 selection"] \ - -variable autoselect - grid x $page.autoselect -sticky w + if {[haveselectionclipboard]} { + ${NS}::checkbutton $page.autoselect -text [mc "Copy commit ID to X11 selection"] \ + -variable autoselect + grid x $page.autoselect -sticky w + } spinbox $page.autosellen -from 1 -to 40 -width 4 -textvariable autosellen ${NS}::label $page.autosellenl -text [mc "Length of commit ID to copy"] grid x $page.autosellenl $page.autosellen -sticky w -- cgit v1.2.3 From f8043236c6c9cb9e943a87ab2e55e8e394796727 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Dec 2024 14:11:21 +0000 Subject: range-diff: optionally include merge commits' diffs in the analysis The `git log` command already offers support for including diffs for merges, via the `--diff-merges=` option. Let's add corresponding support for `git range-diff`, too. This makes it more convenient to spot differences between commit ranges that contain merges. This is especially true in scenarios with non-trivial merges, i.e. merges introducing changes other than, or in addition to, what merge ORT would have produced. Merging a topic branch that changes a function signature into a branch that added a caller of that function, for example, would require the merge commit itself to adjust that caller to the modified signature. In my code reviews, I found the `--diff-merges=remerge` option particularly useful. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- Documentation/git-range-diff.txt | 13 ++++++++++++- builtin/range-diff.c | 10 ++++++++++ range-diff.c | 15 +++++++++++---- range-diff.h | 1 + t/t3206-range-diff.sh | 16 ++++++++++++++++ 5 files changed, 50 insertions(+), 5 deletions(-) diff --git a/Documentation/git-range-diff.txt b/Documentation/git-range-diff.txt index fbdbe0befe..00c649b140 100644 --- a/Documentation/git-range-diff.txt +++ b/Documentation/git-range-diff.txt @@ -10,7 +10,7 @@ SYNOPSIS [verse] 'git range-diff' [--color=[]] [--no-color] [] [--no-dual-color] [--creation-factor=] - [--left-only | --right-only] + [--left-only | --right-only] [--diff-merges=] ( | ... | ) [[--] ...] @@ -81,6 +81,17 @@ to revert to color all lines according to the outer diff markers Suppress commits that are missing from the second specified range (or the "right range" when using the `...` format). +--diff-merges=:: + Instead of ignoring merge commits, generate diffs for them using the + corresponding `--diff-merges=` option of linkgit:git-log[1], + and include them in the comparison. ++ +Note: In the common case, the `remerge` mode will be the most natural one +to use, as it shows only the diff on top of what Git's merge machinery would +have produced. In other words, if a merge commit is the result of a +non-conflicting `git merge`, the `remerge` mode will represent it with an empty +diff. + --[no-]notes[=]:: This flag is passed to the `git log` program (see linkgit:git-log[1]) that generates the patches. diff --git a/builtin/range-diff.c b/builtin/range-diff.c index 1b33ab66a7..901de5d133 100644 --- a/builtin/range-diff.c +++ b/builtin/range-diff.c @@ -21,6 +21,7 @@ int cmd_range_diff(int argc, { struct diff_options diffopt = { NULL }; struct strvec other_arg = STRVEC_INIT; + struct strvec diff_merges_arg = STRVEC_INIT; struct range_diff_options range_diff_opts = { .creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT, .diffopt = &diffopt, @@ -36,6 +37,8 @@ int cmd_range_diff(int argc, OPT_PASSTHRU_ARGV(0, "notes", &other_arg, N_("notes"), N_("passed to 'git log'"), PARSE_OPT_OPTARG), + OPT_PASSTHRU_ARGV(0, "diff-merges", &diff_merges_arg, + N_("style"), N_("passed to 'git log'"), 0), OPT_BOOL(0, "left-only", &left_only, N_("only emit output related to the first range")), OPT_BOOL(0, "right-only", &right_only, @@ -62,6 +65,12 @@ int cmd_range_diff(int argc, if (!simple_color) diffopt.use_color = 1; + /* If `--diff-merges` was specified, imply `--merges` */ + if (diff_merges_arg.nr) { + range_diff_opts.include_merges = 1; + strvec_pushv(&other_arg, diff_merges_arg.v); + } + for (i = 0; i < argc; i++) if (!strcmp(argv[i], "--")) { dash_dash = i; @@ -155,6 +164,7 @@ int cmd_range_diff(int argc, res = show_range_diff(range1.buf, range2.buf, &range_diff_opts); strvec_clear(&other_arg); + strvec_clear(&diff_merges_arg); strbuf_release(&range1); strbuf_release(&range2); diff --git a/range-diff.c b/range-diff.c index 10885ba301..19673d47d9 100644 --- a/range-diff.c +++ b/range-diff.c @@ -38,7 +38,8 @@ struct patch_util { * as struct object_id (will need to be free()d). */ static int read_patches(const char *range, struct string_list *list, - const struct strvec *other_arg) + const struct strvec *other_arg, + unsigned int include_merges) { struct child_process cp = CHILD_PROCESS_INIT; struct strbuf buf = STRBUF_INIT, contents = STRBUF_INIT; @@ -49,7 +50,7 @@ static int read_patches(const char *range, struct string_list *list, size_t size; int ret = -1; - strvec_pushl(&cp.args, "log", "--no-color", "-p", "--no-merges", + strvec_pushl(&cp.args, "log", "--no-color", "-p", "--reverse", "--date-order", "--decorate=no", "--no-prefix", "--submodule=short", /* @@ -64,6 +65,8 @@ static int read_patches(const char *range, struct string_list *list, "--pretty=medium", "--show-notes-by-default", NULL); + if (!include_merges) + strvec_push(&cp.args, "--no-merges"); strvec_push(&cp.args, range); if (other_arg) strvec_pushv(&cp.args, other_arg->v); @@ -96,11 +99,14 @@ static int read_patches(const char *range, struct string_list *list, } if (skip_prefix(line, "commit ", &p)) { + char *q; if (util) { string_list_append(list, buf.buf)->util = util; strbuf_reset(&buf); } CALLOC_ARRAY(util, 1); + if (include_merges && (q = strstr(p, " (from "))) + *q = '\0'; if (repo_get_oid(the_repository, p, &util->oid)) { error(_("could not parse commit '%s'"), p); FREE_AND_NULL(util); @@ -571,13 +577,14 @@ int show_range_diff(const char *range1, const char *range2, struct string_list branch1 = STRING_LIST_INIT_DUP; struct string_list branch2 = STRING_LIST_INIT_DUP; + unsigned int include_merges = range_diff_opts->include_merges; if (range_diff_opts->left_only && range_diff_opts->right_only) res = error(_("options '%s' and '%s' cannot be used together"), "--left-only", "--right-only"); - if (!res && read_patches(range1, &branch1, range_diff_opts->other_arg)) + if (!res && read_patches(range1, &branch1, range_diff_opts->other_arg, include_merges)) res = error(_("could not parse log for '%s'"), range1); - if (!res && read_patches(range2, &branch2, range_diff_opts->other_arg)) + if (!res && read_patches(range2, &branch2, range_diff_opts->other_arg, include_merges)) res = error(_("could not parse log for '%s'"), range2); if (!res) { diff --git a/range-diff.h b/range-diff.h index 2f69f6a434..cd85000b5a 100644 --- a/range-diff.h +++ b/range-diff.h @@ -16,6 +16,7 @@ struct range_diff_options { int creation_factor; unsigned dual_color:1; unsigned left_only:1, right_only:1; + unsigned include_merges:1; const struct diff_options *diffopt; /* may be NULL */ const struct strvec *other_arg; /* may be NULL */ }; diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh index 86010931ab..c18a3fdab8 100755 --- a/t/t3206-range-diff.sh +++ b/t/t3206-range-diff.sh @@ -909,4 +909,20 @@ test_expect_success 'submodule changes are shown irrespective of diff.submodule' test_cmp expect actual ' +test_expect_success '--diff-merges' ' + renamed_oid=$(git rev-parse --short renamed-file) && + tree=$(git merge-tree unmodified renamed-file) && + clean=$(git commit-tree -m merge -p unmodified -p renamed-file $tree) && + clean_oid=$(git rev-parse --short $clean) && + conflict=$(git commit-tree -m merge -p unmodified -p renamed-file^ $tree) && + conflict_oid=$(git rev-parse --short $conflict) && + + git range-diff --diff-merges=1 $clean...$conflict >actual && + cat >expect <<-EOF && + 1: $renamed_oid < -: ------- s/12/B/ + 2: $clean_oid = 1: $conflict_oid merge + EOF + test_cmp expect actual +' + test_done -- cgit v1.2.3 From 4538338c7edb13a5e818abcfa5739f16ad3dda0c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Dec 2024 14:11:22 +0000 Subject: range-diff: introduce the convenience option `--remerge-diff` Just like `git log`, now also `git range-diff` has that option as a shortcut for the common operation that would otherwise require the quite unwieldy (if theoretically "more correct") `--diff-mode=remerge` option. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- Documentation/git-range-diff.txt | 4 ++++ builtin/range-diff.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/Documentation/git-range-diff.txt b/Documentation/git-range-diff.txt index 00c649b140..db0e4279b5 100644 --- a/Documentation/git-range-diff.txt +++ b/Documentation/git-range-diff.txt @@ -11,6 +11,7 @@ SYNOPSIS 'git range-diff' [--color=[]] [--no-color] [] [--no-dual-color] [--creation-factor=] [--left-only | --right-only] [--diff-merges=] + [--remerge-diff] ( | ... | ) [[--] ...] @@ -92,6 +93,9 @@ have produced. In other words, if a merge commit is the result of a non-conflicting `git merge`, the `remerge` mode will represent it with an empty diff. +--remerge-diff:: + Convenience option, equivalent to `--diff-merges=remerge`. + --[no-]notes[=]:: This flag is passed to the `git log` program (see linkgit:git-log[1]) that generates the patches. diff --git a/builtin/range-diff.c b/builtin/range-diff.c index 901de5d133..2452654347 100644 --- a/builtin/range-diff.c +++ b/builtin/range-diff.c @@ -39,6 +39,8 @@ int cmd_range_diff(int argc, PARSE_OPT_OPTARG), OPT_PASSTHRU_ARGV(0, "diff-merges", &diff_merges_arg, N_("style"), N_("passed to 'git log'"), 0), + OPT_PASSTHRU_ARGV(0, "remerge-diff", &diff_merges_arg, NULL, + N_("passed to 'git log'"), PARSE_OPT_NOARG), OPT_BOOL(0, "left-only", &left_only, N_("only emit output related to the first range")), OPT_BOOL(0, "right-only", &right_only, -- cgit v1.2.3 From 063bcebf0c917140ca0e705cbe0fdea127e90086 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 16 Dec 2024 08:54:04 -0800 Subject: Git 2.48-rc0 Signed-off-by: Junio C Hamano --- Documentation/RelNotes/2.48.0.txt | 22 ++++++++++++++++++++++ GIT-VERSION-GEN | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Documentation/RelNotes/2.48.0.txt b/Documentation/RelNotes/2.48.0.txt index 802e9a96e5..dc11ce58be 100644 --- a/Documentation/RelNotes/2.48.0.txt +++ b/Documentation/RelNotes/2.48.0.txt @@ -129,6 +129,11 @@ Performance, Internal Implementation, Development Support etc. * Yet another "pass the repository through the callchain" topic. + * "git describe" learned to stop digging the history needlessly + deeper. + + * Build procedure update plus introduction of Meson based builds. + Fixes since v2.47 ----------------- @@ -243,6 +248,23 @@ Fixes since v2.47 on the path, which was not documented, which has been corrected. (merge bc1a980759 kk/doc-ancestry-path later to maint). + + * "git tag" has been taught to refuse to create refs/tags/HEAD + as such a tag will be confusing in the context of UI provided by + the Git Porcelain commands. + (merge bbd445d5ef jc/forbid-head-as-tagname later to maint). + + * The advice messages now tell the newer 'git config set' command to + set the advice.token configuration variable to squelch a message. + (merge 6c397d0104 bf/explicit-config-set-in-advice-messages later to maint). + + * The syntax ":/" to name the latest commit with the matching + text was broken with a recent change, which has been corrected. + (merge 0ff919e87a ps/commit-with-message-syntax-fix later to maint). + + * Fix performance regression of a recent "fatten promisor pack with + local objects" protection against an unwanted gc. + * Other code cleanup, docfix, build fix, etc. (merge 77af53f56f aa/t7300-modernize later to maint). (merge dcd590a39d bf/t-readme-mention-reftable later to maint). diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index b4687784c1..de0e63bdfb 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,6 +1,6 @@ #!/bin/sh -DEF_VER=v2.47.GIT +DEF_VER=v2.48.0-rc0 LF=' ' -- cgit v1.2.3 From 1a83e26d72eb2601798dfc07e6f5112964dc9413 Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Mon, 16 Dec 2024 17:44:26 +0100 Subject: refs: include committer info in `ref_update` struct The reference backends obtain the committer information from `git_committer_info(0)` when adding a reflog. The upcoming patches introduce support for migrating reflogs between the reference backends. This requires an interface to creating reflogs, including custom committer information. Add a new field `committer_info` to the `ref_update` struct, which is then used by the reference backends. If there is no `committer_info` provided, the reference backends default to using `git_committer_info(0)`. The field itself cannot be set to `git_committer_info(0)` since the values are dynamic and must be obtained right when the reflog is being committed. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- refs.c | 1 + refs/files-backend.c | 24 ++++++++++++++---------- refs/refs-internal.h | 1 + refs/reftable-backend.c | 12 +++++++++++- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/refs.c b/refs.c index 762f3e324d..f003e51c6b 100644 --- a/refs.c +++ b/refs.c @@ -1151,6 +1151,7 @@ void ref_transaction_free(struct ref_transaction *transaction) for (i = 0; i < transaction->nr; i++) { free(transaction->updates[i]->msg); + free(transaction->updates[i]->committer_info); free((char *)transaction->updates[i]->new_target); free((char *)transaction->updates[i]->old_target); free(transaction->updates[i]); diff --git a/refs/files-backend.c b/refs/files-backend.c index 64f51f0da9..6078668c99 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -1858,6 +1858,9 @@ static int log_ref_write_fd(int fd, const struct object_id *old_oid, struct strbuf sb = STRBUF_INIT; int ret = 0; + if (!committer) + committer = git_committer_info(0); + strbuf_addf(&sb, "%s %s %s", oid_to_hex(old_oid), oid_to_hex(new_oid), committer); if (msg && *msg) { strbuf_addch(&sb, '\t'); @@ -1871,8 +1874,10 @@ static int log_ref_write_fd(int fd, const struct object_id *old_oid, } static int files_log_ref_write(struct files_ref_store *refs, - const char *refname, const struct object_id *old_oid, - const struct object_id *new_oid, const char *msg, + const char *refname, + const struct object_id *old_oid, + const struct object_id *new_oid, + const char *committer_info, const char *msg, int flags, struct strbuf *err) { int logfd, result; @@ -1889,8 +1894,7 @@ static int files_log_ref_write(struct files_ref_store *refs, if (logfd < 0) return 0; - result = log_ref_write_fd(logfd, old_oid, new_oid, - git_committer_info(0), msg); + result = log_ref_write_fd(logfd, old_oid, new_oid, committer_info, msg); if (result) { struct strbuf sb = STRBUF_INIT; int save_errno = errno; @@ -1974,8 +1978,7 @@ static int commit_ref_update(struct files_ref_store *refs, files_assert_main_repository(refs, "commit_ref_update"); clear_loose_ref_cache(refs); - if (files_log_ref_write(refs, lock->ref_name, - &lock->old_oid, oid, + if (files_log_ref_write(refs, lock->ref_name, &lock->old_oid, oid, NULL, logmsg, flags, err)) { char *old_msg = strbuf_detach(err, NULL); strbuf_addf(err, "cannot update the ref '%s': %s", @@ -2007,9 +2010,9 @@ static int commit_ref_update(struct files_ref_store *refs, if (head_ref && (head_flag & REF_ISSYMREF) && !strcmp(head_ref, lock->ref_name)) { struct strbuf log_err = STRBUF_INIT; - if (files_log_ref_write(refs, "HEAD", - &lock->old_oid, oid, - logmsg, flags, &log_err)) { + if (files_log_ref_write(refs, "HEAD", &lock->old_oid, + oid, NULL, logmsg, flags, + &log_err)) { error("%s", log_err.buf); strbuf_release(&log_err); } @@ -2969,7 +2972,8 @@ static int parse_and_write_reflog(struct files_ref_store *refs, } if (files_log_ref_write(refs, lock->ref_name, &lock->old_oid, - &update->new_oid, update->msg, update->flags, err)) { + &update->new_oid, update->committer_info, + update->msg, update->flags, err)) { char *old_msg = strbuf_detach(err, NULL); strbuf_addf(err, "cannot update the ref '%s': %s", diff --git a/refs/refs-internal.h b/refs/refs-internal.h index 58aa56d1b2..0fd95cdacd 100644 --- a/refs/refs-internal.h +++ b/refs/refs-internal.h @@ -113,6 +113,7 @@ struct ref_update { void *backend_data; unsigned int type; char *msg; + char *committer_info; /* * If this ref_update was split off of a symref update via diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c index 647ef9b05b..e882602487 100644 --- a/refs/reftable-backend.c +++ b/refs/reftable-backend.c @@ -1379,11 +1379,21 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data } if (create_reflog) { + struct ident_split c; + ALLOC_GROW(logs, logs_nr + 1, logs_alloc); log = &logs[logs_nr++]; memset(log, 0, sizeof(*log)); - fill_reftable_log_record(log, &committer_ident); + if (u->committer_info) { + if (split_ident_line(&c, u->committer_info, + strlen(u->committer_info))) + BUG("failed splitting committer info"); + } else { + c = committer_ident; + } + + fill_reftable_log_record(log, &c); log->update_index = ts; log->refname = xstrdup(u->refname); memcpy(log->value.update.new_hash, -- cgit v1.2.3 From a3582e2eacfae4328146b5142a0950fffcc05198 Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Mon, 16 Dec 2024 17:44:27 +0100 Subject: refs: add `index` field to `struct ref_udpate` The reftable backend, sorts its updates by refname before applying them, this ensures that the references are stored sorted. When migrating reflogs from one backend to another, the order of the reflogs must be maintained. Add a new `index` field to the `ref_update` struct to facilitate this. This field is used in the reftable backend's sort comparison function `transaction_update_cmp`, to ensure that indexed fields maintain their order. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- refs/refs-internal.h | 7 +++++++ refs/reftable-backend.c | 13 +++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/refs/refs-internal.h b/refs/refs-internal.h index 0fd95cdacd..f5c733d099 100644 --- a/refs/refs-internal.h +++ b/refs/refs-internal.h @@ -115,6 +115,13 @@ struct ref_update { char *msg; char *committer_info; + /* + * The index overrides the default sort algorithm. This is needed + * when migrating reflogs and we want to ensure we carry over the + * same order. + */ + unsigned int index; + /* * If this ref_update was split off of a symref update via * split_symref_update(), then this member points at that diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c index e882602487..c008f20be7 100644 --- a/refs/reftable-backend.c +++ b/refs/reftable-backend.c @@ -1279,8 +1279,17 @@ static int reftable_be_transaction_abort(struct ref_store *ref_store UNUSED, static int transaction_update_cmp(const void *a, const void *b) { - return strcmp(((struct reftable_transaction_update *)a)->update->refname, - ((struct reftable_transaction_update *)b)->update->refname); + struct reftable_transaction_update *update_a = (struct reftable_transaction_update *)a; + struct reftable_transaction_update *update_b = (struct reftable_transaction_update *)b; + + /* + * If there is an index set, it should take preference (default is 0). + * This ensures that updates with indexes are sorted amongst themselves. + */ + if (update_a->update->index || update_b->update->index) + return update_a->update->index - update_b->update->index; + + return strcmp(update_a->update->refname, update_b->update->refname); } static int write_transaction_table(struct reftable_writer *writer, void *cb_data) -- cgit v1.2.3 From 611986f3007d591731f56ad04cf3e00f0d2f163f Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Mon, 16 Dec 2024 17:44:28 +0100 Subject: refs/files: add count field to ref_lock When refs are updated in the files-backend, a lock is obtained for the corresponding file path. This is the case even for reflogs, i.e. a lock is obtained on the reference path instead of the reflog path. This works, since generally, reflogs are updated alongside the ref. The upcoming patches will add support for reflog updates in ref transaction. This means, in a particular transaction we want to have ref updates and reflog updates. For a given ref in a given transaction there can be at most one update. But we can theoretically have multiple reflog updates for a given ref in a given transaction. A great example of this would be when migrating reflogs from one backend to another. There we would batch all the reflog updates for a given reference in a single transaction. The current flow does not support this, because currently refs & reflogs are treated as a single entity and capture the lock together. To separate this, add a count field to ref_lock. With this, multiple updates can hold onto a single ref_lock and the lock will only be released when all of them release the lock. This patch only adds the `count` field to `ref_lock` and adds the logic to increment and decrement the lock. In a follow up commit, we'll separate the reflog update logic from ref updates and utilize this functionality. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- refs/files-backend.c | 58 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/refs/files-backend.c b/refs/files-backend.c index 6078668c99..02cb4907d8 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -71,6 +71,7 @@ struct ref_lock { char *ref_name; struct lock_file lk; struct object_id old_oid; + unsigned int count; /* track users of the lock (ref update + reflog updates) */ }; struct files_ref_store { @@ -638,9 +639,12 @@ int parse_loose_ref_contents(const struct git_hash_algo *algop, static void unlock_ref(struct ref_lock *lock) { - rollback_lock_file(&lock->lk); - free(lock->ref_name); - free(lock); + lock->count--; + if (!lock->count) { + rollback_lock_file(&lock->lk); + free(lock->ref_name); + free(lock); + } } /* @@ -696,6 +700,7 @@ static int lock_raw_ref(struct files_ref_store *refs, *lock_p = CALLOC_ARRAY(lock, 1); lock->ref_name = xstrdup(refname); + lock->count = 1; files_ref_path(refs, &ref_file, refname); retry: @@ -1169,6 +1174,7 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs, goto error_return; lock->ref_name = xstrdup(refname); + lock->count = 1; if (raceproof_create_file(ref_file.buf, create_reflock, &lock->lk)) { unable_to_lock_message(ref_file.buf, errno, err); @@ -2535,6 +2541,12 @@ static int check_old_oid(struct ref_update *update, struct object_id *oid, return -1; } +struct files_transaction_backend_data { + struct ref_transaction *packed_transaction; + int packed_refs_locked; + struct strmap ref_locks; +}; + /* * Prepare for carrying out update: * - Lock the reference referred to by update. @@ -2557,11 +2569,14 @@ static int lock_ref_for_update(struct files_ref_store *refs, { struct strbuf referent = STRBUF_INIT; int mustexist = ref_update_expects_existing_old_ref(update); + struct files_transaction_backend_data *backend_data; int ret = 0; struct ref_lock *lock; files_assert_main_repository(refs, "lock_ref_for_update"); + backend_data = transaction->backend_data; + if ((update->flags & REF_HAVE_NEW) && ref_update_has_null_new_value(update)) update->flags |= REF_DELETING; @@ -2572,18 +2587,25 @@ static int lock_ref_for_update(struct files_ref_store *refs, goto out; } - ret = lock_raw_ref(refs, update->refname, mustexist, - affected_refnames, - &lock, &referent, - &update->type, err); - if (ret) { - char *reason; + lock = strmap_get(&backend_data->ref_locks, update->refname); + if (lock) { + lock->count++; + } else { + ret = lock_raw_ref(refs, update->refname, mustexist, + affected_refnames, + &lock, &referent, + &update->type, err); + if (ret) { + char *reason; + + reason = strbuf_detach(err, NULL); + strbuf_addf(err, "cannot lock ref '%s': %s", + ref_update_original_update_refname(update), reason); + free(reason); + goto out; + } - reason = strbuf_detach(err, NULL); - strbuf_addf(err, "cannot lock ref '%s': %s", - ref_update_original_update_refname(update), reason); - free(reason); - goto out; + strmap_put(&backend_data->ref_locks, update->refname, lock); } update->backend_data = lock; @@ -2730,11 +2752,6 @@ out: return ret; } -struct files_transaction_backend_data { - struct ref_transaction *packed_transaction; - int packed_refs_locked; -}; - /* * Unlock any references in `transaction` that are still locked, and * mark the transaction closed. @@ -2767,6 +2784,8 @@ static void files_transaction_cleanup(struct files_ref_store *refs, if (backend_data->packed_refs_locked) packed_refs_unlock(refs->packed_ref_store); + strmap_clear(&backend_data->ref_locks, 0); + free(backend_data); } @@ -2796,6 +2815,7 @@ static int files_transaction_prepare(struct ref_store *ref_store, goto cleanup; CALLOC_ARRAY(backend_data, 1); + strmap_init(&backend_data->ref_locks); transaction->backend_data = backend_data; /* -- cgit v1.2.3 From add2c4f6e225083747e86c2e2e89e80c97b28733 Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Mon, 16 Dec 2024 17:44:29 +0100 Subject: refs: extract out refname verification in transactions Unless the `REF_SKIP_REFNAME_VERIFICATION` flag is set for an update, the refname of the update is verified for: - Ensuring it is not a pseudoref. - Checking the refname format. These checks will also be needed in a following commit where the function to add reflog updates to the transaction is introduced. Extract the code out into a new static function. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- refs.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/refs.c b/refs.c index f003e51c6b..9c9f4940c6 100644 --- a/refs.c +++ b/refs.c @@ -1196,6 +1196,28 @@ struct ref_update *ref_transaction_add_update( return update; } +static int transaction_refname_valid(const char *refname, + const struct object_id *new_oid, + unsigned int flags, struct strbuf *err) +{ + if (flags & REF_SKIP_REFNAME_VERIFICATION) + return 1; + + if (is_pseudo_ref(refname)) { + strbuf_addf(err, _("refusing to update pseudoref '%s'"), + refname); + return 0; + } else if ((new_oid && !is_null_oid(new_oid)) ? + check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) : + !refname_is_safe(refname)) { + strbuf_addf(err, _("refusing to update ref with bad name '%s'"), + refname); + return 0; + } + + return 1; +} + int ref_transaction_update(struct ref_transaction *transaction, const char *refname, const struct object_id *new_oid, @@ -1213,21 +1235,8 @@ int ref_transaction_update(struct ref_transaction *transaction, return -1; } - if (!(flags & REF_SKIP_REFNAME_VERIFICATION) && - ((new_oid && !is_null_oid(new_oid)) ? - check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) : - !refname_is_safe(refname))) { - strbuf_addf(err, _("refusing to update ref with bad name '%s'"), - refname); + if (!transaction_refname_valid(refname, new_oid, flags, err)) return -1; - } - - if (!(flags & REF_SKIP_REFNAME_VERIFICATION) && - is_pseudo_ref(refname)) { - strbuf_addf(err, _("refusing to update pseudoref '%s'"), - refname); - return -1; - } if (flags & ~REF_TRANSACTION_UPDATE_ALLOWED_FLAGS) BUG("illegal flags 0x%x passed to ref_transaction_update()", flags); -- cgit v1.2.3 From 4483be36f4477252f785df0c8c40677df8c18828 Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Mon, 16 Dec 2024 17:44:30 +0100 Subject: refs: add `committer_info` to `ref_transaction_add_update()` The `ref_transaction_add_update()` creates the `ref_update` struct. To facilitate addition of reflogs in the next commit, the function needs to accommodate setting the `committer_info` field in the struct. So modify the function to also take `committer_info` as an argument and set it accordingly. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- refs.c | 7 +++++-- refs/files-backend.c | 14 ++++++++------ refs/refs-internal.h | 1 + refs/reftable-backend.c | 6 ++++-- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/refs.c b/refs.c index 9c9f4940c6..782bf1090a 100644 --- a/refs.c +++ b/refs.c @@ -1166,6 +1166,7 @@ struct ref_update *ref_transaction_add_update( const struct object_id *new_oid, const struct object_id *old_oid, const char *new_target, const char *old_target, + const char *committer_info, const char *msg) { struct ref_update *update; @@ -1190,8 +1191,10 @@ struct ref_update *ref_transaction_add_update( oidcpy(&update->new_oid, new_oid); if ((flags & REF_HAVE_OLD) && old_oid) oidcpy(&update->old_oid, old_oid); - if (!(flags & REF_SKIP_CREATE_REFLOG)) + if (!(flags & REF_SKIP_CREATE_REFLOG)) { + update->committer_info = xstrdup_or_null(committer_info); update->msg = normalize_reflog_message(msg); + } return update; } @@ -1253,7 +1256,7 @@ int ref_transaction_update(struct ref_transaction *transaction, ref_transaction_add_update(transaction, refname, flags, new_oid, old_oid, new_target, - old_target, msg); + old_target, NULL, msg); return 0; } diff --git a/refs/files-backend.c b/refs/files-backend.c index 02cb4907d8..255fed8354 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -1270,7 +1270,7 @@ static void prune_ref(struct files_ref_store *refs, struct ref_to_prune *r) ref_transaction_add_update( transaction, r->name, REF_NO_DEREF | REF_HAVE_NEW | REF_HAVE_OLD | REF_IS_PRUNING, - null_oid(), &r->oid, NULL, NULL, NULL); + null_oid(), &r->oid, NULL, NULL, NULL, NULL); if (ref_transaction_commit(transaction, &err)) goto cleanup; @@ -2417,7 +2417,7 @@ static int split_head_update(struct ref_update *update, transaction, "HEAD", update->flags | REF_LOG_ONLY | REF_NO_DEREF, &update->new_oid, &update->old_oid, - NULL, NULL, update->msg); + NULL, NULL, update->committer_info, update->msg); /* * Add "HEAD". This insertion is O(N) in the transaction @@ -2481,7 +2481,8 @@ static int split_symref_update(struct ref_update *update, transaction, referent, new_flags, update->new_target ? NULL : &update->new_oid, update->old_target ? NULL : &update->old_oid, - update->new_target, update->old_target, update->msg); + update->new_target, update->old_target, NULL, + update->msg); new_update->parent_update = update; @@ -2914,7 +2915,7 @@ static int files_transaction_prepare(struct ref_store *ref_store, packed_transaction, update->refname, REF_HAVE_NEW | REF_NO_DEREF, &update->new_oid, NULL, - NULL, NULL, NULL); + NULL, NULL, NULL, NULL); } } @@ -3094,12 +3095,13 @@ static int files_transaction_finish_initial(struct files_ref_store *refs, ref_transaction_add_update(loose_transaction, update->refname, update->flags & ~REF_HAVE_OLD, update->new_target ? NULL : &update->new_oid, NULL, - update->new_target, NULL, NULL); + update->new_target, NULL, update->committer_info, + NULL); } else { ref_transaction_add_update(packed_transaction, update->refname, update->flags & ~REF_HAVE_OLD, &update->new_oid, &update->old_oid, - NULL, NULL, NULL); + NULL, NULL, update->committer_info, NULL); } } diff --git a/refs/refs-internal.h b/refs/refs-internal.h index f5c733d099..79b287c5ec 100644 --- a/refs/refs-internal.h +++ b/refs/refs-internal.h @@ -162,6 +162,7 @@ struct ref_update *ref_transaction_add_update( const struct object_id *new_oid, const struct object_id *old_oid, const char *new_target, const char *old_target, + const char *committer_info, const char *msg); /* diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c index c008f20be7..b2e3ba877d 100644 --- a/refs/reftable-backend.c +++ b/refs/reftable-backend.c @@ -1078,7 +1078,8 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store, new_update = ref_transaction_add_update( transaction, "HEAD", u->flags | REF_LOG_ONLY | REF_NO_DEREF, - &u->new_oid, &u->old_oid, NULL, NULL, u->msg); + &u->new_oid, &u->old_oid, NULL, NULL, NULL, + u->msg); string_list_insert(&affected_refnames, new_update->refname); } @@ -1161,7 +1162,8 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store, transaction, referent.buf, new_flags, u->new_target ? NULL : &u->new_oid, u->old_target ? NULL : &u->old_oid, - u->new_target, u->old_target, u->msg); + u->new_target, u->old_target, + u->committer_info, u->msg); new_update->parent_update = u; -- cgit v1.2.3 From 84675fa2717e08b39bf810eb9a439068ac915dfb Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Mon, 16 Dec 2024 17:44:31 +0100 Subject: refs: introduce the `ref_transaction_update_reflog` function Introduce a new function `ref_transaction_update_reflog`, for clients to add a reflog update to a transaction. While the existing function `ref_transaction_update` also allows clients to add a reflog entry, this function does a few things more, It: - Enforces that only a reflog entry is added and does not update the ref itself. - Allows the users to also provide the committer information. This means clients can add reflog entries with custom committer information. The `transaction_refname_valid()` function also modifies the error message selectively based on the type of the update. This change also affects reflog updates which go through `ref_transaction_update()`. A follow up commit will utilize this function to add reflog support to `git refs migrate`. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- refs.c | 39 +++++++++++++++++++++++++++++++++++---- refs.h | 14 ++++++++++++++ refs/files-backend.c | 24 ++++++++++++++++-------- 3 files changed, 65 insertions(+), 12 deletions(-) diff --git a/refs.c b/refs.c index 782bf1090a..8b3882cff1 100644 --- a/refs.c +++ b/refs.c @@ -1207,14 +1207,14 @@ static int transaction_refname_valid(const char *refname, return 1; if (is_pseudo_ref(refname)) { - strbuf_addf(err, _("refusing to update pseudoref '%s'"), - refname); + const char *what = flags & REF_LOG_ONLY ? "reflog for pseudoref" : "pseudoref"; + strbuf_addf(err, _("refusing to update %s '%s'"), what, refname); return 0; } else if ((new_oid && !is_null_oid(new_oid)) ? check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) : !refname_is_safe(refname)) { - strbuf_addf(err, _("refusing to update ref with bad name '%s'"), - refname); + const char *what = flags & REF_LOG_ONLY ? "reflog with bad name" : "ref with bad name"; + strbuf_addf(err, _("refusing to update %s '%s'"), what, refname); return 0; } @@ -1257,6 +1257,37 @@ int ref_transaction_update(struct ref_transaction *transaction, ref_transaction_add_update(transaction, refname, flags, new_oid, old_oid, new_target, old_target, NULL, msg); + + return 0; +} + +int ref_transaction_update_reflog(struct ref_transaction *transaction, + const char *refname, + const struct object_id *new_oid, + const struct object_id *old_oid, + const char *committer_info, unsigned int flags, + const char *msg, unsigned int index, + struct strbuf *err) +{ + struct ref_update *update; + + assert(err); + + flags |= REF_LOG_ONLY | REF_NO_DEREF; + + if (!transaction_refname_valid(refname, new_oid, flags, err)) + return -1; + + update = ref_transaction_add_update(transaction, refname, flags, + new_oid, old_oid, NULL, NULL, + committer_info, msg); + /* + * While we do set the old_oid value, we unset the flag to skip + * old_oid verification which only makes sense for refs. + */ + update->flags &= ~REF_HAVE_OLD; + update->index = index; + return 0; } diff --git a/refs.h b/refs.h index a5bedf48cf..b0dfc65ed2 100644 --- a/refs.h +++ b/refs.h @@ -727,6 +727,20 @@ int ref_transaction_update(struct ref_transaction *transaction, unsigned int flags, const char *msg, struct strbuf *err); +/* + * Similar to`ref_transaction_update`, but this function is only for adding + * a reflog update. Supports providing custom committer information. The index + * field can be utiltized to order updates as desired. When not used, the + * updates default to being ordered by refname. + */ +int ref_transaction_update_reflog(struct ref_transaction *transaction, + const char *refname, + const struct object_id *new_oid, + const struct object_id *old_oid, + const char *committer_info, unsigned int flags, + const char *msg, unsigned int index, + struct strbuf *err); + /* * Add a reference creation to transaction. new_oid is the value that * the reference should have after the update; it must not be diff --git a/refs/files-backend.c b/refs/files-backend.c index 255fed8354..c11213f520 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -3080,10 +3080,12 @@ static int files_transaction_finish_initial(struct files_ref_store *refs, } /* - * packed-refs don't support symbolic refs and root refs, so we - * have to queue these references via the loose transaction. + * packed-refs don't support symbolic refs, root refs and reflogs, + * so we have to queue these references via the loose transaction. */ - if (update->new_target || is_root_ref(update->refname)) { + if (update->new_target || + is_root_ref(update->refname) || + (update->flags & REF_LOG_ONLY)) { if (!loose_transaction) { loose_transaction = ref_store_transaction_begin(&refs->base, 0, err); if (!loose_transaction) { @@ -3092,11 +3094,17 @@ static int files_transaction_finish_initial(struct files_ref_store *refs, } } - ref_transaction_add_update(loose_transaction, update->refname, - update->flags & ~REF_HAVE_OLD, - update->new_target ? NULL : &update->new_oid, NULL, - update->new_target, NULL, update->committer_info, - NULL); + if (update->flags & REF_LOG_ONLY) + ref_transaction_add_update(loose_transaction, update->refname, + update->flags, &update->new_oid, + &update->old_oid, NULL, NULL, + update->committer_info, update->msg); + else + ref_transaction_add_update(loose_transaction, update->refname, + update->flags & ~REF_HAVE_OLD, + update->new_target ? NULL : &update->new_oid, NULL, + update->new_target, NULL, update->committer_info, + NULL); } else { ref_transaction_add_update(packed_transaction, update->refname, update->flags & ~REF_HAVE_OLD, -- cgit v1.2.3 From 297c09eabb1e8b44230bca86fc7fd344175e0be7 Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Mon, 16 Dec 2024 17:44:32 +0100 Subject: refs: allow multiple reflog entries for the same refname The reference transaction only allows a single update for a given reference to avoid conflicts. This, however, isn't an issue for reflogs. There are no conflicts to be resolved in reflogs and when migrating reflogs between backends we'd have multiple reflog entries for the same refname. So allow multiple reflog updates within a single transaction. Also the reflog creation logic isn't exposed to the end user. While this might change in the future, currently, this reduces the scope of issues to think about. In the reftable backend, the writer sorts all updates based on the update_index before writing to the block. When there are multiple reflogs for a given refname, it is essential that the order of the reflogs is maintained. So add the `index` value to the `update_index`. The `index` field is only set when multiple reflog entries for a given refname are added and as such in most scenarios the old behavior remains. This is required to add reflog migration support to `git refs migrate`. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- refs/files-backend.c | 15 +++++++++++---- refs/reftable-backend.c | 22 +++++++++++++++++++--- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/refs/files-backend.c b/refs/files-backend.c index c11213f520..8953d1c6d3 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -2611,6 +2611,9 @@ static int lock_ref_for_update(struct files_ref_store *refs, update->backend_data = lock; + if (update->flags & REF_LOG_ONLY) + goto out; + if (update->type & REF_ISSYMREF) { if (update->flags & REF_NO_DEREF) { /* @@ -2829,13 +2832,16 @@ static int files_transaction_prepare(struct ref_store *ref_store, */ for (i = 0; i < transaction->nr; i++) { struct ref_update *update = transaction->updates[i]; - struct string_list_item *item = - string_list_append(&affected_refnames, update->refname); + struct string_list_item *item; if ((update->flags & REF_IS_PRUNING) && !(update->flags & REF_NO_DEREF)) BUG("REF_IS_PRUNING set without REF_NO_DEREF"); + if (update->flags & REF_LOG_ONLY) + continue; + + item = string_list_append(&affected_refnames, update->refname); /* * We store a pointer to update in item->util, but at * the moment we never use the value of this field @@ -3035,8 +3041,9 @@ static int files_transaction_finish_initial(struct files_ref_store *refs, /* Fail if a refname appears more than once in the transaction: */ for (i = 0; i < transaction->nr; i++) - string_list_append(&affected_refnames, - transaction->updates[i]->refname); + if (!(transaction->updates[i]->flags & REF_LOG_ONLY)) + string_list_append(&affected_refnames, + transaction->updates[i]->refname); string_list_sort(&affected_refnames); if (ref_update_reject_duplicates(&affected_refnames, err)) { ret = TRANSACTION_GENERIC_ERROR; diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c index b2e3ba877d..bec5962deb 100644 --- a/refs/reftable-backend.c +++ b/refs/reftable-backend.c @@ -990,8 +990,9 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store, if (ret) goto done; - string_list_append(&affected_refnames, - transaction->updates[i]->refname); + if (!(transaction->updates[i]->flags & REF_LOG_ONLY)) + string_list_append(&affected_refnames, + transaction->updates[i]->refname); } /* @@ -1301,6 +1302,7 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data struct reftable_log_record *logs = NULL; struct ident_split committer_ident = {0}; size_t logs_nr = 0, logs_alloc = 0, i; + uint64_t max_update_index = ts; const char *committer_info; int ret = 0; @@ -1405,7 +1407,19 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data } fill_reftable_log_record(log, &c); - log->update_index = ts; + + /* + * Updates are sorted by the writer. So updates for the same + * refname need to contain different update indices. + */ + log->update_index = ts + u->index; + + /* + * Note the max update_index so the limit can be set later on. + */ + if (log->update_index > max_update_index) + max_update_index = log->update_index; + log->refname = xstrdup(u->refname); memcpy(log->value.update.new_hash, u->new_oid.hash, GIT_MAX_RAWSZ); @@ -1469,6 +1483,8 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data * and log blocks. */ if (logs) { + reftable_writer_set_limits(writer, ts, max_update_index); + ret = reftable_writer_add_logs(writer, logs, logs_nr); if (ret < 0) goto done; -- cgit v1.2.3 From 246cebe3205694ce19eceaa795d20f24ba762c49 Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Mon, 16 Dec 2024 17:44:33 +0100 Subject: refs: add support for migrating reflogs The `git refs migrate` command was introduced in 25a0023f28 (builtin/refs: new command to migrate ref storage formats, 2024-06-06) to support migrating from one reference backend to another. One limitation of the command was that it didn't support migrating repositories which contained reflogs. A previous commit, added support for adding reflog updates in ref transactions. Using the added functionality bake in reflog support for `git refs migrate`. To ensure that the order of the reflogs is maintained during the migration, we add the index for each reflog update as we iterate over the reflogs from the old reference backend. This is to ensure that the order is maintained in the new backend. Helped-by: Patrick Steinhardt Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- Documentation/git-refs.txt | 2 - refs.c | 92 ++++++++++++++++++++++++++++++++-------------- t/t1460-refs-migrate.sh | 73 +++++++++++++++++++++++++----------- 3 files changed, 115 insertions(+), 52 deletions(-) diff --git a/Documentation/git-refs.txt b/Documentation/git-refs.txt index ce31f93061..9829984b0a 100644 --- a/Documentation/git-refs.txt +++ b/Documentation/git-refs.txt @@ -57,8 +57,6 @@ KNOWN LIMITATIONS The ref format migration has several known limitations in its current form: -* It is not possible to migrate repositories that have reflogs. - * It is not possible to migrate repositories that have worktrees. * There is no way to block concurrent writes to the repository during an diff --git a/refs.c b/refs.c index 8b3882cff1..5d541ddc41 100644 --- a/refs.c +++ b/refs.c @@ -30,6 +30,7 @@ #include "date.h" #include "commit.h" #include "wildmatch.h" +#include "ident.h" /* * List of all available backends @@ -2673,6 +2674,7 @@ struct migration_data { struct ref_store *old_refs; struct ref_transaction *transaction; struct strbuf *errbuf; + struct strbuf sb; }; static int migrate_one_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid, @@ -2705,6 +2707,52 @@ done: return ret; } +struct reflog_migration_data { + unsigned int index; + const char *refname; + struct ref_store *old_refs; + struct ref_transaction *transaction; + struct strbuf *errbuf; + struct strbuf *sb; +}; + +static int migrate_one_reflog_entry(struct object_id *old_oid, + struct object_id *new_oid, + const char *committer, + timestamp_t timestamp, int tz, + const char *msg, void *cb_data) +{ + struct reflog_migration_data *data = cb_data; + const char *date; + int ret; + + date = show_date(timestamp, tz, DATE_MODE(NORMAL)); + strbuf_reset(data->sb); + /* committer contains name and email */ + strbuf_addstr(data->sb, fmt_ident("", committer, WANT_BLANK_IDENT, date, 0)); + + ret = ref_transaction_update_reflog(data->transaction, data->refname, + new_oid, old_oid, data->sb->buf, + REF_HAVE_NEW | REF_HAVE_OLD, msg, + data->index++, data->errbuf); + return ret; +} + +static int migrate_one_reflog(const char *refname, void *cb_data) +{ + struct migration_data *migration_data = cb_data; + struct reflog_migration_data data = { + .refname = refname, + .old_refs = migration_data->old_refs, + .transaction = migration_data->transaction, + .errbuf = migration_data->errbuf, + .sb = &migration_data->sb, + }; + + return refs_for_each_reflog_ent(migration_data->old_refs, refname, + migrate_one_reflog_entry, &data); +} + static int move_files(const char *from_path, const char *to_path, struct strbuf *errbuf) { struct strbuf from_buf = STRBUF_INIT, to_buf = STRBUF_INIT; @@ -2771,13 +2819,6 @@ done: return ret; } -static int count_reflogs(const char *reflog UNUSED, void *payload) -{ - size_t *reflog_count = payload; - (*reflog_count)++; - return 0; -} - static int has_worktrees(void) { struct worktree **worktrees = get_worktrees(); @@ -2802,8 +2843,9 @@ int repo_migrate_ref_storage_format(struct repository *repo, struct ref_store *old_refs = NULL, *new_refs = NULL; struct ref_transaction *transaction = NULL; struct strbuf new_gitdir = STRBUF_INIT; - struct migration_data data; - size_t reflog_count = 0; + struct migration_data data = { + .sb = STRBUF_INIT, + }; int did_migrate_refs = 0; int ret; @@ -2815,21 +2857,6 @@ int repo_migrate_ref_storage_format(struct repository *repo, old_refs = get_main_ref_store(repo); - /* - * We do not have any interfaces that would allow us to write many - * reflog entries. Once we have them we can remove this restriction. - */ - if (refs_for_each_reflog(old_refs, count_reflogs, &reflog_count) < 0) { - strbuf_addstr(errbuf, "cannot count reflogs"); - ret = -1; - goto done; - } - if (reflog_count) { - strbuf_addstr(errbuf, "migrating reflogs is not supported yet"); - ret = -1; - goto done; - } - /* * Worktrees complicate the migration because every worktree has a * separate ref storage. While it should be feasible to implement, this @@ -2855,17 +2882,21 @@ int repo_migrate_ref_storage_format(struct repository *repo, * This operation is safe as we do not yet modify the main * repository. * - * 3. If we're in dry-run mode then we are done and can hand over the + * 3. Enumerate all reflogs and write them into the new ref storage. + * This operation is safe as we do not yet modify the main + * repository. + * + * 4. If we're in dry-run mode then we are done and can hand over the * directory to the caller for inspection. If not, we now start * with the destructive part. * - * 4. Delete the old ref storage from disk. As we have a copy of refs + * 5. Delete the old ref storage from disk. As we have a copy of refs * in the new ref storage it's okay(ish) if we now get interrupted * as there is an equivalent copy of all refs available. * - * 5. Move the new ref storage files into place. + * 6. Move the new ref storage files into place. * - * 6. Change the repository format to the new ref format. + * 7. Change the repository format to the new ref format. */ strbuf_addf(&new_gitdir, "%s/%s", old_refs->gitdir, "ref_migration.XXXXXX"); if (!mkdtemp(new_gitdir.buf)) { @@ -2907,6 +2938,10 @@ int repo_migrate_ref_storage_format(struct repository *repo, if (ret < 0) goto done; + ret = refs_for_each_reflog(old_refs, migrate_one_reflog, &data); + if (ret < 0) + goto done; + ret = ref_transaction_commit(transaction, errbuf); if (ret < 0) goto done; @@ -2982,6 +3017,7 @@ done: } ref_transaction_free(transaction); strbuf_release(&new_gitdir); + strbuf_release(&data.sb); return ret; } diff --git a/t/t1460-refs-migrate.sh b/t/t1460-refs-migrate.sh index 1bfff3a7af..f59bc4860f 100755 --- a/t/t1460-refs-migrate.sh +++ b/t/t1460-refs-migrate.sh @@ -7,23 +7,44 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./test-lib.sh +# Migrate the provided repository from one format to the other and +# verify that the references and logs are migrated over correctly. +# Usage: test_migration +# is the relative path to the repo to be migrated. +# is the ref format to be migrated to. +# (true or false) whether to skip reflog verification. test_migration () { - git -C "$1" for-each-ref --include-root-refs \ + repo=$1 && + format=$2 && + skip_reflog_verify=${3:-false} && + git -C "$repo" for-each-ref --include-root-refs \ --format='%(refname) %(objectname) %(symref)' >expect && - git -C "$1" refs migrate --ref-format="$2" && - git -C "$1" for-each-ref --include-root-refs \ + if ! $skip_reflog_verify + then + git -C "$repo" reflog --all >expect_logs && + git -C "$repo" reflog list >expect_log_list + fi && + + git -C "$repo" refs migrate --ref-format="$2" && + + git -C "$repo" for-each-ref --include-root-refs \ --format='%(refname) %(objectname) %(symref)' >actual && test_cmp expect actual && + if ! $skip_reflog_verify + then + git -C "$repo" reflog --all >actual_logs && + git -C "$repo" reflog list >actual_log_list && + test_cmp expect_logs actual_logs && + test_cmp expect_log_list actual_log_list + fi && - git -C "$1" rev-parse --show-ref-format >actual && - echo "$2" >expect && + git -C "$repo" rev-parse --show-ref-format >actual && + echo "$format" >expect && test_cmp expect actual } test_expect_success 'setup' ' - rm -rf .git && - # The migration does not yet support reflogs. - git config --global core.logAllRefUpdates false + rm -rf .git ' test_expect_success "superfluous arguments" ' @@ -78,19 +99,6 @@ do test_cmp expect err ' - test_expect_success "$from_format -> $to_format: migration with reflog fails" ' - test_when_finished "rm -rf repo" && - git init --ref-format=$from_format repo && - test_config -C repo core.logAllRefUpdates true && - test_commit -C repo logged && - test_must_fail git -C repo refs migrate \ - --ref-format=$to_format 2>err && - cat >expect <<-EOF && - error: migrating reflogs is not supported yet - EOF - test_cmp expect err - ' - test_expect_success "$from_format -> $to_format: migration with worktree fails" ' test_when_finished "rm -rf repo" && git init --ref-format=$from_format repo && @@ -141,7 +149,7 @@ do test_commit -C repo initial && test-tool -C repo ref-store main update-ref "" refs/heads/broken \ "$(test_oid 001)" "$ZERO_OID" REF_SKIP_CREATE_REFLOG,REF_SKIP_OID_VERIFICATION && - test_migration repo "$to_format" && + test_migration repo "$to_format" true && test_oid 001 >expect && git -C repo rev-parse refs/heads/broken >actual && test_cmp expect actual @@ -195,6 +203,27 @@ do git -C repo rev-parse --show-ref-format >actual && test_cmp expect actual ' + + test_expect_success "$from_format -> $to_format: reflogs of symrefs with target deleted" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + test_commit -C repo initial && + git -C repo branch branch-1 HEAD && + git -C repo symbolic-ref refs/heads/symref refs/heads/branch-1 && + cat >input <<-EOF && + delete refs/heads/branch-1 + EOF + git -C repo update-ref --stdin $to_format: reflogs order is retained" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + test_commit --date "100005000 +0700" --no-tag -C repo initial && + test_commit --date "100003000 +0700" --no-tag -C repo second && + test_migration repo "$to_format" + ' done done -- cgit v1.2.3 From b30404dfc04a4b087b630aea4ab88a51cd3a7459 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 17 Dec 2024 12:52:04 +0000 Subject: mingw_rename: do support directory renames In 391bceae435 (compat/mingw: support POSIX semantics for atomic renames, 2024-10-27), we taught the `mingw_rename()` function to respect POSIX semantics, but we did so only as a fallback after `_wrename()` fails. This hid a bug in the implementation that was not caught by Git's test suite: The `CreateFileW()` function _can_ open handles to directories, but not when asked to use the `FILE_ATTRIBUTE_NORMAL` flag, as that flag only is allowed for files. Let's fix this by using the common `FILE_FLAG_BACKUP_SEMANTICS` flag that can be used for opening handles to directories, too. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index c4320769db..e8f491d03a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2273,7 +2273,7 @@ repeat: old_handle = CreateFileW(wpold, DELETE, FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (old_handle == INVALID_HANDLE_VALUE) { errno = err_win_to_posix(GetLastError()); return -1; -- cgit v1.2.3 From 55d62306eeada186154fd538cb79efd579f7d9f6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 17 Dec 2024 14:57:38 +0000 Subject: GitHub ci(windows): speed up initializing Git for Windows' minimal SDK again It used to be the case that initializing the minimal SDK (i.e. a radically slimmed-down subset of Git for Windows' development environment intended to perform the CI builds and little else) took a bit over one minute, would then be cached, and subsequent jobs would take at most half a dozen seconds to initialize said minimal SDK. It is important that this step is fast because we have to run the test suite in parallel, in a set of matrix jobs, to offset the slowness of the shell-based test suite, and each and every job has to initialize the very same minimal SDK. While it may sound as if parallelizing the jobs might only waste the generously-provided build minutes but at least the _wallclock_ time would pass quick, in reality it matters a lot: Frequently Git for Windows' or GitGitGadget PRs get stuck waiting for quite a while before CI builds start because other PRs' builds still spend substantial amounts of time to run, blocking due to the concurrency limit being reached. Since 91839a88277 (ci: create script to set up Git for Windows SDK, 2024-10-09), the situation has worsened: every job that requires the minimal Git for Windows SDK spends roughly two-and-a-half minutes doing so. With the switch away from the GitHub Action `setup-git-for-windows-sdk`, we incurred more downsides: - It is no longer possible for said Action to fix problems independently from the Git repository, e.g. when new rules about GitHub Actions require changes in the way the minimal SDK is initialized. - The minimal SDK was installed specifically outside of the worktree so as not to clutter it nor incur an additional cost to verify that the worktree is clean. Therefore, even if it would be nice to have a shared process between GitHub and GitLab based CI builds, let's switch the GitHub-based CI back to the tried-and-tested `setup-git-for-windows-sdk` Action. This commit partially reverts 91839a88277 (ci: create script to set up Git for Windows SDK, 2024-10-09). Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- .github/workflows/main.yml | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9301a1edd6..916a64b673 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -113,15 +113,13 @@ jobs: cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - uses: actions/checkout@v4 - - name: setup SDK - shell: powershell - run: ci/install-sdk.ps1 + - uses: git-for-windows/setup-git-for-windows-sdk@v1 - name: build - shell: powershell + shell: bash env: HOME: ${{runner.workspace}} NO_PERL: 1 - run: git-sdk/usr/bin/bash.exe -l -c 'ci/make-test-artifacts.sh artifacts' + run: . /etc/profile && ci/make-test-artifacts.sh artifacts - name: zip up tracked files run: git archive -o artifacts/tracked.tar.gz HEAD - name: upload tracked files and build artifacts @@ -149,12 +147,10 @@ jobs: - name: extract tracked files and build artifacts shell: bash run: tar xf artifacts.tar.gz && tar xf tracked.tar.gz - - name: setup SDK - shell: powershell - run: ci/install-sdk.ps1 + - uses: git-for-windows/setup-git-for-windows-sdk@v1 - name: test - shell: powershell - run: git-sdk/usr/bin/bash.exe -l -c 'ci/run-test-slice.sh ${{matrix.nr}} 10' + shell: bash + run: . /etc/profile && ci/run-test-slice.sh ${{matrix.nr}} 10 - name: print test failures if: failure() && env.FAILED_TEST_ARTIFACTS != '' shell: bash -- cgit v1.2.3 From c1c5b03afc156d502ec68e6bd7f69adf4cbe3367 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 17 Dec 2024 17:31:57 +0000 Subject: cmake: better support for out-of-tree builds follow-up In 7e0730c8baa (t: better support for out-of-tree builds, 2024-12-06), the `bin-wrappers/` strategy was changed so that it no longer hard-codes the template directory to be `@BUILD_DIR@/templates/blt`, but instead interpolates the `@TEMPLATE_DIR@` placeholder during the build. However, this commit only adjusted the `Makefile`-based build. Let's adjust the CMake-based build as well. This fixes t0000.15 which would otherwise fail with: ++ echo ''\''t1234-verbose/err'\'' is not empty, it contains:' 't1234-verbose/err' is not empty, it contains: ++ cat t1234-verbose/err warning: templates not found in @TEMPLATE_DIR@ Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- contrib/buildsystems/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 49904ca8a9..926f0d7b86 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -1087,6 +1087,7 @@ set(wrapper_test_scripts foreach(script ${wrapper_scripts}) file(STRINGS ${CMAKE_SOURCE_DIR}/bin-wrappers/wrap-for-bin.sh content NEWLINE_CONSUME) string(REPLACE "@BUILD_DIR@" "${CMAKE_BINARY_DIR}" content "${content}") + string(REPLACE "@TEMPLATE_DIR@" "'${CMAKE_BINARY_DIR}/templates/blt'" content "${content}") string(REPLACE "@PROG@" "${CMAKE_BINARY_DIR}/${script}${EXE_EXTENSION}" content "${content}") file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/${script} ${content}) endforeach() @@ -1094,12 +1095,14 @@ endforeach() foreach(script ${wrapper_test_scripts}) file(STRINGS ${CMAKE_SOURCE_DIR}/bin-wrappers/wrap-for-bin.sh content NEWLINE_CONSUME) string(REPLACE "@BUILD_DIR@" "${CMAKE_BINARY_DIR}" content "${content}") + string(REPLACE "@TEMPLATE_DIR@" "'${CMAKE_BINARY_DIR}/templates/blt'" content "${content}") string(REPLACE "@PROG@" "${CMAKE_BINARY_DIR}/t/helper/${script}${EXE_EXTENSION}" content "${content}") file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/${script} ${content}) endforeach() file(STRINGS ${CMAKE_SOURCE_DIR}/bin-wrappers/wrap-for-bin.sh content NEWLINE_CONSUME) string(REPLACE "@BUILD_DIR@" "${CMAKE_BINARY_DIR}" content "${content}") +string(REPLACE "@TEMPLATE_DIR@" "'${CMAKE_BINARY_DIR}/templates/blt'" content "${content}") string(REPLACE "@GIT_TEXTDOMAINDIR@" "${CMAKE_BINARY_DIR}/po/build/locale" content "${content}") string(REPLACE "@GITPERLLIB@" "${CMAKE_BINARY_DIR}/perl/build/lib" content "${content}") string(REPLACE "@MERGE_TOOLS_DIR@" "${CMAKE_SOURCE_DIR}/mergetools" content "${content}") -- cgit v1.2.3 From df87d53e941f8d7af4d60018b24eeb845a01c355 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 17 Dec 2024 17:31:58 +0000 Subject: cmake(mergetools): better support for out-of-tree builds In 7e0730c8baa (t: better support for out-of-tree builds, 2024-12-06) the strategy was changed from letting `t7609-mergetool--lib.sh` hard-code the directory where it expects to find the merge tools to hard-coding that value in the placeholder `@GIT_TEST_MERGE_TOOLS_DIR@` that is replaced during the build. However, likely due to a copy/paste mistake (and reviewers missed this, too), the CMake-based build was adjusted incorrectly, replacing that placeholder not with the path to the merge tools, but with a Boolean indicating whether to use a runtime-generated path prefix or not. Let's fix that, addressing this CMake-build's symptom: Initialized empty Git repository in D:/a/git/git/t/trash directory.t7609-mergetool--lib/.git/ ++ . true/vimdiff ./test-lib.sh: line 1021: true/vimdiff: No such file or directory Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- contrib/buildsystems/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 926f0d7b86..3dd6b3a130 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -1195,7 +1195,7 @@ string(REPLACE "@GIT_TEST_TEXTDOMAINDIR@" "'${CMAKE_BINARY_DIR}/po/build/locale' string(REPLACE "@GIT_TEST_POPATH@" "'${CMAKE_BINARY_DIR}/po'" git_build_options "${git_build_options}") string(REPLACE "@GIT_TEST_TEMPLATE_DIR@" "'${CMAKE_BINARY_DIR}/templates/blt'" git_build_options "${git_build_options}") string(REPLACE "@GIT_TEST_GITPERLLIB@" "'${CMAKE_BINARY_DIR}/perl/build/lib'" git_build_options "${git_build_options}") -string(REPLACE "@GIT_TEST_MERGE_TOOLS_DIR@" "'${RUNTIME_PREFIX}'" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_MERGE_TOOLS_DIR@" "'${CMAKE_BINARY_DIR}/mergetools'" git_build_options "${git_build_options}") string(REPLACE "@RUNTIME_PREFIX@" "'${RUNTIME_PREFIX}'" git_build_options "${git_build_options}") string(REPLACE "@GITWEBDIR@" "'${GITWEBDIR}'" git_build_options "${git_build_options}") string(REPLACE "@USE_GETTEXT_SCHEME@" "" git_build_options "${git_build_options}") -- cgit v1.2.3 From ca358e6bb2666446116974d72fbf7bf817fdc254 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 17 Dec 2024 17:31:59 +0000 Subject: cmake: use the correct file name for the Perl header In e4b488049a5 (Makefile: extract script to massage Perl scripts, 2024-12-06), the code was refactored that is used to transform the Perl scripts/modules to their final form. Even the CMake-based build was adjusted, but the change used the file name `PERL-HEADER` instead of the file name used by the Makefile-based build (same name but with the `GIT-` prefix). Let's adjust the former to the latter. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- contrib/buildsystems/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 3dd6b3a130..6f35cd66f3 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -867,7 +867,7 @@ list(TRANSFORM perl_modules REPLACE "${CMAKE_SOURCE_DIR}/" "") file(STRINGS ${CMAKE_SOURCE_DIR}/perl/header_templates/fixed_prefix.template.pl perl_header ) string(REPLACE "@PATHSEP@" ":" perl_header "${perl_header}") string(REPLACE "@INSTLIBDIR@" "${INSTLIBDIR}" perl_header "${perl_header}") -file(WRITE ${CMAKE_BINARY_DIR}/PERL-HEADER ${perl_header}) +file(WRITE ${CMAKE_BINARY_DIR}/GIT-PERL-HEADER ${perl_header}) add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/GIT-VERSION-FILE" COMMAND "${SH_EXE}" "${CMAKE_SOURCE_DIR}/GIT-VERSION-GEN" @@ -888,7 +888,7 @@ foreach(script ${git_perl_scripts} ${perl_modules}) COMMAND "${SH_EXE}" "${CMAKE_SOURCE_DIR}/generate-perl.sh" "${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS" "${CMAKE_BINARY_DIR}/GIT-VERSION-FILE" - "${CMAKE_BINARY_DIR}/PERL-HEADER" + "${CMAKE_BINARY_DIR}/GIT-PERL-HEADER" "${CMAKE_SOURCE_DIR}/${script}" "${CMAKE_BINARY_DIR}/${perl_gen_path}" DEPENDS "${CMAKE_SOURCE_DIR}/generate-perl.sh" -- cgit v1.2.3 From 1c01f0fb723b94130bd8aab31acf8b8f7a6439f6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 17 Dec 2024 17:32:00 +0000 Subject: cmake: put the Perl modules into the correct location again In ccfba9e0c45 (Makefile: use "generate-perl.sh" to massage Perl library, 2024-12-06), the previous strategy (which avoided spawning a shell script to transform the files) was replaced by the same `generate-perl.sh` invocation as for the Makefile-based build. The only difference is that now the transformation tries to handle the Perl modules in-place (which ends up in empty files because the same file is used as input and output via stdin/stdout redirection), and the Perl script cannot find them anymore because they are not in the expected place. Let's put them into the expected place again, i.e. into `perl/build/lib/` instead of `perl/`. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- contrib/buildsystems/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 6f35cd66f3..36f18ab2dd 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -882,6 +882,10 @@ foreach(script ${git_perl_scripts} ${perl_modules}) string(REPLACE ".perl" "" perl_gen_path "${script}") get_filename_component(perl_gen_dir "${perl_gen_path}" DIRECTORY) + if(script MATCHES "\.pm$") + string(REGEX REPLACE "^perl" "perl/build/lib" perl_gen_dir "${perl_gen_dir}") + string(REGEX REPLACE "^perl" "perl/build/lib" perl_gen_path "${perl_gen_path}") + endif() file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/${perl_gen_dir}") add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/${perl_gen_path}" -- cgit v1.2.3 From 2456374e782b83c4087cc819ea019ea92b535bf7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 17 Dec 2024 17:32:01 +0000 Subject: cmake/vcxproj: stop special-casing `remote-ext` When the `vcxproj` target was introduced in `config.mak.uname` to allow building Git with the Visual C toolchain, the `git remote-ext` command was always executed in its dashed form. Therefore, it was impossible to pass the test suite unless that command existed in its dashed form, and we had to special-case this. Later, when the `vcxproj` target got out of fashion because Visual Studio gained native support for CMake builds, this special-casing was copied without questioning it. But as of 675df192c5f (transport-helper: do not run git-remote-ext etc. in dashed form, 2020-08-26), the reason for this special-casing no longer exists. So let's just drop it. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- config.mak.uname | 4 ---- contrib/buildsystems/CMakeLists.txt | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/config.mak.uname b/config.mak.uname index d5112168a4..b12d4e168a 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -819,10 +819,6 @@ vcxproj: sed -i 's|\(git\)-\([-a-z]*\)\.exe"|\1.exe" \2|g' \ bin-wrappers/git-{receive-pack,upload-archive} git add -f $(test_bindir_programs) - # remote-ext is a builtin, but invoked as if it were external - sed 's|receive-pack|remote-ext|g' \ - bin-wrappers/git-remote-ext - git add -f bin-wrappers/git-remote-ext # Add templates $(MAKE) -C templates diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 36f18ab2dd..802445c1eb 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -1082,7 +1082,7 @@ endif() #wrapper scripts set(wrapper_scripts - git git-upload-pack git-receive-pack git-upload-archive git-shell git-remote-ext scalar) + git git-upload-pack git-receive-pack git-upload-archive git-shell scalar) set(wrapper_test_scripts test-fake-ssh test-tool) -- cgit v1.2.3 From a803b1e17160b51e3a0b2a7766955753fea22bf5 Mon Sep 17 00:00:00 2001 From: Kyle Lippincott Date: Wed, 18 Dec 2024 00:57:02 +0000 Subject: doc: remove extra quotes in generated docs Commit a38edab7c8 (Makefile: generate doc versions via GIT-VERSION-GEN, 2024-12-06) moved these variables from the Makefile to asciidoc.conf.in. When doing so, some extraneous quotes were added; these are visible in the generated .xml files, at least, and possibly in other locations: --- a/tmp/orig-git-bisect.xml +++ b/Documentation/git-bisect.xml @@ -5,14 +5,14 @@ git-bisect(1) - 2024-12-06 -2024-12-06 + '2024-12-06'^M +'2024-12-06'^M git-bisect 1 -Git 2.47.1.409.g9bb10d27e7 -Git Manual +'Git 2.47.1.410.ga38edab7c8'^M +'Git Manual'^M git-bisect Signed-off-by: Kyle Lippincott Signed-off-by: Junio C Hamano --- Documentation/asciidoc.conf.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/asciidoc.conf.in b/Documentation/asciidoc.conf.in index dbe36a52ea..b89bccf230 100644 --- a/Documentation/asciidoc.conf.in +++ b/Documentation/asciidoc.conf.in @@ -21,9 +21,9 @@ tilde=~ apostrophe=' backtick=` litdd=-- -manmanual='Git Manual' -mansource='Git @GIT_VERSION@' -revdate='@GIT_DATE@' +manmanual=Git Manual +mansource=Git @GIT_VERSION@ +revdate=@GIT_DATE@ ifdef::backend-docbook[] [linkgit-inlinemacro] -- cgit v1.2.3 From 62b3ec8a3f160cc9f1949b28644fc3947252db73 Mon Sep 17 00:00:00 2001 From: Taylor Blau Date: Fri, 13 Dec 2024 14:20:02 -0500 Subject: pack-bitmap.c: ensure pack validity for all reuse packs Commit 44f9fd6496 (pack-bitmap.c: check preferred pack validity when opening MIDX bitmap, 2022-05-24) prevents a race condition whereby the preferred pack disappears between opening the MIDX bitmap and attempting verbatim reuse out of its packs. That commit forces open_midx_bitmap_1() to ensure the validity of the MIDX's preferred pack, meaning that we have an open file handle on the *.pack, ensuring that we can reuse bytes out of verbatim later on in the process[^1]. But 44f9fd6496 was not extended to cover multi-pack reuse, meaning that this same race condition exists for non-preferred packs during verbatim reuse. Work around that race in the same way by only marking valid packs as reuse-able. For packs that aren't reusable, skip over them but include the number of objects they have to ensure we allocate a large enough 'reuse' bitmap (e.g. if a pack in the middle of the MIDX disappeared but we still want to reuse later packs). Since we're ensuring the validity of these packs within the verbatim reuse code, we no longer have to special-case the preferred pack and open it within the open_midx_bitmap_1() function. An alternative approach to the one taken here would be to open all MIDX'd packs from within open_midx_bitmap_1(). But that would be both slower and make the bitmaps less useful, since we can still perform some pack reuse among the packs that still exist when the *.bitmap is opened. After applying this patch, we can simulate the new behavior after instrumenting Git like so: diff --git a/packfile.c b/packfile.c index 9560f0a33c..aedce72524 100644 --- a/packfile.c +++ b/packfile.c @@ -557,6 +557,11 @@ static int open_packed_git_1(struct packed_git *p) ; /* nothing */ p->pack_fd = git_open(p->pack_name); + { + const char *delete = getenv("GIT_RACILY_DELETE"); + if (delete && !strcmp(delete, pack_basename(p))) + return -1; + } if (p->pack_fd < 0 || fstat(p->pack_fd, &st)) return -1; pack_open_fds++; and adding the following test: test_expect_success 'disappearing packs' ' git init disappearing-packs && ( cd disappearing-packs && git config pack.allowPackReuse multi && test_commit A && test_commit B && test_commit C && A="$(echo "A" | git pack-objects --revs $packdir/pack-A)" && B="$(echo "A..B" | git pack-objects --revs $packdir/pack-B)" && C="$(echo "B..C" | git pack-objects --revs $packdir/pack-C)" && git multi-pack-index write --bitmap --preferred-pack=pack-A-$A.idx && test_pack_objects_reused_all 9 3 && test_env GIT_RACILY_DELETE=pack-A-$A.pack \ test_pack_objects_reused_all 6 2 && test_env GIT_RACILY_DELETE=pack-B-$B.pack \ test_pack_objects_reused_all 6 2 && test_env GIT_RACILY_DELETE=pack-C-$C.pack \ test_pack_objects_reused_all 6 2 ) ' Note that we could relax the single-pack version of this which was most recently addressed in dc1daacdcc (pack-bitmap: check pack validity when opening bitmap, 2021-07-23), but only partially. Because we still need to know the object count in the pack, we'd still have to open the pack's *.idx, so the savings there are marginal. Note likewise that we add a new "if (!packs_nr)" early return in the pack reuse code to avoid a potentially expensive allocation on the 'reuse' bitmap in the case that no packs are available for reuse. [^1]: Unless we run out of open file handles. If that happens and we are forced to close the only open file handle of a file that has been removed from underneath us, there is nothing we can do. Signed-off-by: Taylor Blau Signed-off-by: Junio C Hamano --- pack-bitmap.c | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/pack-bitmap.c b/pack-bitmap.c index 9d9b8c4bfb..00c6a5396d 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -389,8 +389,7 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git, struct stat st; char *bitmap_name = midx_bitmap_filename(midx); int fd = git_open(bitmap_name); - uint32_t i, preferred_pack; - struct packed_git *preferred; + uint32_t i; if (fd < 0) { if (errno != ENOENT) @@ -445,18 +444,6 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git, } } - if (midx_preferred_pack(bitmap_git->midx, &preferred_pack) < 0) { - warning(_("could not determine MIDX preferred pack")); - goto cleanup; - } - - preferred = bitmap_git->midx->packs[preferred_pack]; - if (!is_pack_valid(preferred)) { - warning(_("preferred pack (%s) is invalid"), - preferred->pack_name); - goto cleanup; - } - return 0; cleanup: @@ -2285,8 +2272,10 @@ void reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git, if (!pack.bitmap_nr) continue; - ALLOC_GROW(packs, packs_nr + 1, packs_alloc); - memcpy(&packs[packs_nr++], &pack, sizeof(pack)); + if (is_pack_valid(pack.p)) { + ALLOC_GROW(packs, packs_nr + 1, packs_alloc); + memcpy(&packs[packs_nr++], &pack, sizeof(pack)); + } objects_nr += pack.p->num_objects; } @@ -2320,16 +2309,22 @@ void reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git, pack_int_id = -1; } - ALLOC_GROW(packs, packs_nr + 1, packs_alloc); - packs[packs_nr].p = pack; - packs[packs_nr].pack_int_id = pack_int_id; - packs[packs_nr].bitmap_nr = pack->num_objects; - packs[packs_nr].bitmap_pos = 0; - packs[packs_nr].from_midx = bitmap_git->midx; + if (is_pack_valid(pack)) { + ALLOC_GROW(packs, packs_nr + 1, packs_alloc); + packs[packs_nr].p = pack; + packs[packs_nr].pack_int_id = pack_int_id; + packs[packs_nr].bitmap_nr = pack->num_objects; + packs[packs_nr].bitmap_pos = 0; + packs[packs_nr].from_midx = bitmap_git->midx; + packs_nr++; + } - objects_nr = packs[packs_nr++].bitmap_nr; + objects_nr = pack->num_objects; } + if (!packs_nr) + return; + word_alloc = objects_nr / BITS_IN_EWORD; if (objects_nr % BITS_IN_EWORD) word_alloc++; -- cgit v1.2.3 From 1f7e6478dcd9e7462c70a5784ae0d41ab25ced11 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 17 Dec 2024 07:43:48 +0100 Subject: progress: stop using `the_repository` Stop using `the_repository` in the "progress" subsystem by passing in a repository when initializing `struct progress`. Furthermore, store a pointer to the repository in that struct so that we can pass it to the trace2 API when logging information. Adjust callers accordingly by using `the_repository`. While there may be some callers that have a repository available in their context, this trivial conversion allows for easier verification and bubbles up the use of `the_repository` by one level. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/blame.c | 4 +++- builtin/commit-graph.c | 1 + builtin/fsck.c | 12 ++++++++---- builtin/index-pack.c | 7 +++++-- builtin/log.c | 3 ++- builtin/pack-objects.c | 21 ++++++++++++++------- builtin/prune.c | 3 ++- builtin/remote.c | 3 ++- builtin/rev-list.c | 3 ++- builtin/unpack-objects.c | 3 ++- commit-graph.c | 20 +++++++++++++++++--- delta-islands.c | 3 ++- diffcore-rename.c | 1 + entry.c | 4 +++- midx-write.c | 11 ++++++++--- midx.c | 13 +++++++++---- pack-bitmap-write.c | 6 ++++-- pack-bitmap.c | 4 +++- preload-index.c | 4 +++- progress.c | 34 ++++++++++++++++++++-------------- progress.h | 13 +++++++++---- prune-packed.c | 3 ++- pseudo-merge.c | 3 ++- read-cache.c | 3 ++- t/helper/test-progress.c | 6 +++++- unpack-trees.c | 4 +++- walker.c | 3 ++- 27 files changed, 136 insertions(+), 59 deletions(-) diff --git a/builtin/blame.c b/builtin/blame.c index 867032e4c1..dd78288530 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -1193,7 +1193,9 @@ parse_done: sb.found_guilty_entry = &found_guilty_entry; sb.found_guilty_entry_data = π if (show_progress) - pi.progress = start_delayed_progress(_("Blaming lines"), num_lines); + pi.progress = start_delayed_progress(the_repository, + _("Blaming lines"), + num_lines); assign_blame(&sb, opt); diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c index bd70d052e7..8ca75262c5 100644 --- a/builtin/commit-graph.c +++ b/builtin/commit-graph.c @@ -305,6 +305,7 @@ static int graph_write(int argc, const char **argv, const char *prefix, oidset_init(&commits, 0); if (opts.progress) progress = start_delayed_progress( + the_repository, _("Collecting commits from input"), 0); while (strbuf_getline(&buf, stdin) != EOF) { diff --git a/builtin/fsck.c b/builtin/fsck.c index 0196c54eb6..7a4dcb0716 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -197,7 +197,8 @@ static int traverse_reachable(void) unsigned int nr = 0; int result = 0; if (show_progress) - progress = start_delayed_progress(_("Checking connectivity"), 0); + progress = start_delayed_progress(the_repository, + _("Checking connectivity"), 0); while (pending.nr) { result |= traverse_one_object(object_array_pop(&pending)); display_progress(progress, ++nr); @@ -703,7 +704,8 @@ static void fsck_object_dir(const char *path) fprintf_ln(stderr, _("Checking object directory")); if (show_progress) - progress = start_progress(_("Checking object directories"), 256); + progress = start_progress(the_repository, + _("Checking object directories"), 256); for_each_loose_file_in_objdir(path, fsck_loose, fsck_cruft, fsck_subdir, &cb_data); @@ -879,7 +881,8 @@ static int check_pack_rev_indexes(struct repository *r, int show_progress) if (show_progress) { for (struct packed_git *p = get_all_packs(r); p; p = p->next) pack_count++; - progress = start_delayed_progress("Verifying reverse pack-indexes", pack_count); + progress = start_delayed_progress(the_repository, + "Verifying reverse pack-indexes", pack_count); pack_count = 0; } @@ -989,7 +992,8 @@ int cmd_fsck(int argc, total += p->num_objects; } - progress = start_progress(_("Checking objects"), total); + progress = start_progress(the_repository, + _("Checking objects"), total); } for (p = get_all_packs(the_repository); p; p = p->next) { diff --git a/builtin/index-pack.c b/builtin/index-pack.c index d773809c4c..05691104c3 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -282,7 +282,8 @@ static unsigned check_objects(void) max = get_max_object_index(); if (verbose) - progress = start_delayed_progress(_("Checking objects"), max); + progress = start_delayed_progress(the_repository, + _("Checking objects"), max); for (i = 0; i < max; i++) { foreign_nr += check_object(get_indexed_object(i)); @@ -1249,6 +1250,7 @@ static void parse_pack_objects(unsigned char *hash) if (verbose) progress = start_progress( + the_repository, progress_title ? progress_title : from_stdin ? _("Receiving objects") : _("Indexing objects"), nr_objects); @@ -1329,7 +1331,8 @@ static void resolve_deltas(struct pack_idx_option *opts) QSORT(ref_deltas, nr_ref_deltas, compare_ref_delta_entry); if (verbose || show_resolving_progress) - progress = start_progress(_("Resolving deltas"), + progress = start_progress(the_repository, + _("Resolving deltas"), nr_ref_deltas + nr_ofs_deltas); nr_dispatched = 0; diff --git a/builtin/log.c b/builtin/log.c index cb41a035c6..317335e60d 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -2495,7 +2495,8 @@ int cmd_format_patch(int argc, rev.add_signoff = cfg.do_signoff; if (show_progress) - progress = start_delayed_progress(_("Generating patches"), total); + progress = start_delayed_progress(the_repository, + _("Generating patches"), total); while (0 <= --nr) { int shown; display_progress(progress, total - nr); diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 1c3b842651..d51c021d99 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -1264,7 +1264,8 @@ static void write_pack_file(void) struct object_entry **write_order; if (progress > pack_to_stdout) - progress_state = start_progress(_("Writing objects"), nr_result); + progress_state = start_progress(the_repository, + _("Writing objects"), nr_result); ALLOC_ARRAY(written_list, to_pack.nr_objects); write_order = compute_write_order(); @@ -2400,7 +2401,8 @@ static void get_object_details(void) struct object_entry **sorted_by_offset; if (progress) - progress_state = start_progress(_("Counting objects"), + progress_state = start_progress(the_repository, + _("Counting objects"), to_pack.nr_objects); CALLOC_ARRAY(sorted_by_offset, to_pack.nr_objects); @@ -3220,7 +3222,8 @@ static void prepare_pack(int window, int depth) unsigned nr_done = 0; if (progress) - progress_state = start_progress(_("Compressing objects"), + progress_state = start_progress(the_repository, + _("Compressing objects"), nr_deltas); QSORT(delta_list, n, type_size_sort); ll_find_deltas(delta_list, n, window+1, depth, &nr_done); @@ -3648,7 +3651,8 @@ static void add_objects_in_unpacked_packs(void); static void enumerate_cruft_objects(void) { if (progress) - progress_state = start_progress(_("Enumerating cruft objects"), 0); + progress_state = start_progress(the_repository, + _("Enumerating cruft objects"), 0); add_objects_in_unpacked_packs(); add_unreachable_loose_objects(); @@ -3674,7 +3678,8 @@ static void enumerate_and_traverse_cruft_objects(struct string_list *fresh_packs revs.ignore_missing_links = 1; if (progress) - progress_state = start_progress(_("Enumerating cruft objects"), 0); + progress_state = start_progress(the_repository, + _("Enumerating cruft objects"), 0); ret = add_unseen_recent_objects_to_traversal(&revs, cruft_expiration, set_cruft_mtime, 1); stop_progress(&progress_state); @@ -3693,7 +3698,8 @@ static void enumerate_and_traverse_cruft_objects(struct string_list *fresh_packs if (prepare_revision_walk(&revs)) die(_("revision walk setup failed")); if (progress) - progress_state = start_progress(_("Traversing cruft objects"), 0); + progress_state = start_progress(the_repository, + _("Traversing cruft objects"), 0); nr_seen = 0; traverse_commit_list(&revs, show_cruft_commit, show_cruft_object, NULL); @@ -4625,7 +4631,8 @@ int cmd_pack_objects(int argc, prepare_packing_data(the_repository, &to_pack); if (progress && !cruft) - progress_state = start_progress(_("Enumerating objects"), 0); + progress_state = start_progress(the_repository, + _("Enumerating objects"), 0); if (stdin_packs) { /* avoids adding objects in excluded packs */ ignore_packed_keep_in_core = 1; diff --git a/builtin/prune.c b/builtin/prune.c index aeff9ca1b3..1c357fffd8 100644 --- a/builtin/prune.c +++ b/builtin/prune.c @@ -64,7 +64,8 @@ static void perform_reachability_traversal(struct rev_info *revs) return; if (show_progress) - progress = start_delayed_progress(_("Checking connectivity"), 0); + progress = start_delayed_progress(the_repository, + _("Checking connectivity"), 0); mark_reachable_objects(revs, 1, expire, progress); stop_progress(&progress); initialized = 1; diff --git a/builtin/remote.c b/builtin/remote.c index b2b13a7dd2..95440bc9ff 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -820,7 +820,8 @@ static int mv(int argc, const char **argv, const char *prefix, * Count symrefs twice, since "renaming" them is done by * deleting and recreating them in two separate passes. */ - progress = start_progress(_("Renaming remote references"), + progress = start_progress(the_repository, + _("Renaming remote references"), rename.remote_branches->nr + rename.symrefs_nr); } for (i = 0; i < remote_branches.nr; i++) { diff --git a/builtin/rev-list.c b/builtin/rev-list.c index 3196da7b2d..8a7db9b546 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -735,7 +735,8 @@ int cmd_rev_list(int argc, revs.limited = 1; if (show_progress) - progress = start_delayed_progress(show_progress, 0); + progress = start_delayed_progress(the_repository, + show_progress, 0); if (use_bitmap_index) { if (!try_bitmap_count(&revs, filter_provided_objects)) diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c index 2197d6d933..842a90353a 100644 --- a/builtin/unpack-objects.c +++ b/builtin/unpack-objects.c @@ -590,7 +590,8 @@ static void unpack_all(void) use(sizeof(struct pack_header)); if (!quiet) - progress = start_progress(_("Unpacking objects"), nr_objects); + progress = start_progress(the_repository, + _("Unpacking objects"), nr_objects); CALLOC_ARRAY(obj_list, nr_objects); begin_odb_transaction(); for (i = 0; i < nr_objects; i++) { diff --git a/commit-graph.c b/commit-graph.c index 0df66e5a24..2a2999a6b8 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -1534,6 +1534,7 @@ static void close_reachable(struct write_commit_graph_context *ctx) if (ctx->report_progress) ctx->progress = start_delayed_progress( + the_repository, _("Loading known commits in commit graph"), ctx->oids.nr); for (i = 0; i < ctx->oids.nr; i++) { @@ -1551,6 +1552,7 @@ static void close_reachable(struct write_commit_graph_context *ctx) */ if (ctx->report_progress) ctx->progress = start_delayed_progress( + the_repository, _("Expanding reachable commits in commit graph"), 0); for (i = 0; i < ctx->oids.nr; i++) { @@ -1571,6 +1573,7 @@ static void close_reachable(struct write_commit_graph_context *ctx) if (ctx->report_progress) ctx->progress = start_delayed_progress( + the_repository, _("Clearing commit marks in commit graph"), ctx->oids.nr); for (i = 0; i < ctx->oids.nr; i++) { @@ -1688,6 +1691,7 @@ static void compute_topological_levels(struct write_commit_graph_context *ctx) if (ctx->report_progress) info.progress = ctx->progress = start_delayed_progress( + the_repository, _("Computing commit graph topological levels"), ctx->commits.nr); @@ -1722,6 +1726,7 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx) if (ctx->report_progress) info.progress = ctx->progress = start_delayed_progress( + the_repository, _("Computing commit graph generation numbers"), ctx->commits.nr); @@ -1798,6 +1803,7 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx) if (ctx->report_progress) progress = start_delayed_progress( + the_repository, _("Computing commit changed paths Bloom filters"), ctx->commits.nr); @@ -1877,6 +1883,7 @@ int write_commit_graph_reachable(struct object_directory *odb, data.commits = &commits; if (flags & COMMIT_GRAPH_WRITE_PROGRESS) data.progress = start_delayed_progress( + the_repository, _("Collecting referenced commits"), 0); refs_for_each_ref(get_main_ref_store(the_repository), add_ref_to_set, @@ -1908,7 +1915,8 @@ static int fill_oids_from_packs(struct write_commit_graph_context *ctx, "Finding commits for commit graph in %"PRIuMAX" packs", pack_indexes->nr), (uintmax_t)pack_indexes->nr); - ctx->progress = start_delayed_progress(progress_title.buf, 0); + ctx->progress = start_delayed_progress(the_repository, + progress_title.buf, 0); ctx->progress_done = 0; } for (i = 0; i < pack_indexes->nr; i++) { @@ -1959,6 +1967,7 @@ static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx) { if (ctx->report_progress) ctx->progress = start_delayed_progress( + the_repository, _("Finding commits for commit graph among packed objects"), ctx->approx_nr_objects); for_each_packed_object(ctx->r, add_packed_commits, ctx, @@ -1977,6 +1986,7 @@ static void copy_oids_to_commits(struct write_commit_graph_context *ctx) ctx->num_extra_edges = 0; if (ctx->report_progress) ctx->progress = start_delayed_progress( + the_repository, _("Finding extra edges in commit graph"), ctx->oids.nr); oid_array_sort(&ctx->oids); @@ -2136,6 +2146,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx) get_num_chunks(cf)), get_num_chunks(cf)); ctx->progress = start_delayed_progress( + the_repository, progress_title.buf, st_mult(get_num_chunks(cf), ctx->commits.nr)); } @@ -2348,6 +2359,7 @@ static void sort_and_scan_merged_commits(struct write_commit_graph_context *ctx) if (ctx->report_progress) ctx->progress = start_delayed_progress( + the_repository, _("Scanning merged commits"), ctx->commits.nr); @@ -2392,7 +2404,8 @@ static void merge_commit_graphs(struct write_commit_graph_context *ctx) current_graph_number--; if (ctx->report_progress) - ctx->progress = start_delayed_progress(_("Merging commit-graph"), 0); + ctx->progress = start_delayed_progress(the_repository, + _("Merging commit-graph"), 0); merge_commit_graph(ctx, g); stop_progress(&ctx->progress); @@ -2874,7 +2887,8 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags) if (!(flags & COMMIT_GRAPH_VERIFY_SHALLOW)) total += g->num_commits_in_base; - progress = start_progress(_("Verifying commits in commit graph"), + progress = start_progress(the_repository, + _("Verifying commits in commit graph"), total); } diff --git a/delta-islands.c b/delta-islands.c index 1c465a6041..3aec43fada 100644 --- a/delta-islands.c +++ b/delta-islands.c @@ -267,7 +267,8 @@ void resolve_tree_islands(struct repository *r, QSORT(todo, nr, tree_depth_compare); if (progress) - progress_state = start_progress(_("Propagating island marks"), nr); + progress_state = start_progress(the_repository, + _("Propagating island marks"), nr); for (i = 0; i < nr; i++) { struct object_entry *ent = todo[i].entry; diff --git a/diffcore-rename.c b/diffcore-rename.c index 10bb0321b1..91b77993c7 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -1567,6 +1567,7 @@ void diffcore_rename_extended(struct diff_options *options, trace2_region_enter("diff", "inexact renames", options->repo); if (options->show_rename_progress) { progress = start_delayed_progress( + the_repository, _("Performing inexact rename detection"), (uint64_t)num_destinations * (uint64_t)num_sources); } diff --git a/entry.c b/entry.c index 53a1c39358..81b321e53d 100644 --- a/entry.c +++ b/entry.c @@ -188,7 +188,9 @@ int finish_delayed_checkout(struct checkout *state, int show_progress) dco->state = CE_RETRY; if (show_progress) - progress = start_delayed_progress(_("Filtering content"), dco->paths.nr); + progress = start_delayed_progress(the_repository, + _("Filtering content"), + dco->paths.nr); while (dco->filters.nr > 0) { for_each_string_list_item(filter, &dco->filters) { struct string_list available_paths = STRING_LIST_INIT_DUP; diff --git a/midx-write.c b/midx-write.c index 0066594fa6..b3827b936b 100644 --- a/midx-write.c +++ b/midx-write.c @@ -1131,7 +1131,8 @@ static int write_midx_internal(struct repository *r, const char *object_dir, ctx.pack_paths_checked = 0; if (flags & MIDX_PROGRESS) - ctx.progress = start_delayed_progress(_("Adding packfiles to multi-pack-index"), 0); + ctx.progress = start_delayed_progress(r, + _("Adding packfiles to multi-pack-index"), 0); else ctx.progress = NULL; @@ -1539,7 +1540,9 @@ int expire_midx_packs(struct repository *r, const char *object_dir, unsigned fla CALLOC_ARRAY(count, m->num_packs); if (flags & MIDX_PROGRESS) - progress = start_delayed_progress(_("Counting referenced objects"), + progress = start_delayed_progress( + r, + _("Counting referenced objects"), m->num_objects); for (i = 0; i < m->num_objects; i++) { int pack_int_id = nth_midxed_pack_int_id(m, i); @@ -1549,7 +1552,9 @@ int expire_midx_packs(struct repository *r, const char *object_dir, unsigned fla stop_progress(&progress); if (flags & MIDX_PROGRESS) - progress = start_delayed_progress(_("Finding and deleting unreferenced packfiles"), + progress = start_delayed_progress( + r, + _("Finding and deleting unreferenced packfiles"), m->num_packs); for (i = 0; i < m->num_packs; i++) { char *pack_name; diff --git a/midx.c b/midx.c index f8a75cafd4..d91088efb8 100644 --- a/midx.c +++ b/midx.c @@ -907,7 +907,8 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag midx_report(_("incorrect checksum")); if (flags & MIDX_PROGRESS) - progress = start_delayed_progress(_("Looking for referenced packfiles"), + progress = start_delayed_progress(r, + _("Looking for referenced packfiles"), m->num_packs + m->num_packs_in_base); for (i = 0; i < m->num_packs + m->num_packs_in_base; i++) { if (prepare_midx_pack(r, m, i)) @@ -927,7 +928,8 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag } if (flags & MIDX_PROGRESS) - progress = start_sparse_progress(_("Verifying OID order in multi-pack-index"), + progress = start_sparse_progress(r, + _("Verifying OID order in multi-pack-index"), m->num_objects - 1); for (curr = m; curr; curr = curr->base_midx) { @@ -959,14 +961,17 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag } if (flags & MIDX_PROGRESS) - progress = start_sparse_progress(_("Sorting objects by packfile"), + progress = start_sparse_progress(r, + _("Sorting objects by packfile"), m->num_objects); display_progress(progress, 0); /* TODO: Measure QSORT() progress */ QSORT(pairs, m->num_objects, compare_pair_pos_vs_id); stop_progress(&progress); if (flags & MIDX_PROGRESS) - progress = start_sparse_progress(_("Verifying object offsets"), m->num_objects); + progress = start_sparse_progress(r, + _("Verifying object offsets"), + m->num_objects); for (i = 0; i < m->num_objects + m->num_objects_in_base; i++) { struct object_id oid; struct pack_entry e; diff --git a/pack-bitmap-write.c b/pack-bitmap-write.c index 4f8be53c2b..a06a1f35c6 100644 --- a/pack-bitmap-write.c +++ b/pack-bitmap-write.c @@ -590,7 +590,8 @@ int bitmap_writer_build(struct bitmap_writer *writer) int closed = 1; /* until proven otherwise */ if (writer->show_progress) - writer->progress = start_progress("Building bitmaps", + writer->progress = start_progress(the_repository, + "Building bitmaps", writer->selected_nr); trace2_region_enter("pack-bitmap-write", "building_bitmaps_total", the_repository); @@ -710,7 +711,8 @@ void bitmap_writer_select_commits(struct bitmap_writer *writer, } if (writer->show_progress) - writer->progress = start_progress("Selecting bitmap commits", 0); + writer->progress = start_progress(the_repository, + "Selecting bitmap commits", 0); for (;;) { struct commit *chosen = NULL; diff --git a/pack-bitmap.c b/pack-bitmap.c index bceb6da042..48e3b99efb 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -2578,7 +2578,9 @@ void test_bitmap_walk(struct rev_info *revs) tdata.trees = ewah_to_bitmap(bitmap_git->trees); tdata.blobs = ewah_to_bitmap(bitmap_git->blobs); tdata.tags = ewah_to_bitmap(bitmap_git->tags); - tdata.prg = start_progress("Verifying bitmap entries", result_popcnt); + tdata.prg = start_progress(revs->repo, + "Verifying bitmap entries", + result_popcnt); tdata.seen = 0; traverse_commit_list(revs, &test_show_commit, &test_show_object, &tdata); diff --git a/preload-index.c b/preload-index.c index ab94d6f399..40ab2abafb 100644 --- a/preload-index.c +++ b/preload-index.c @@ -132,7 +132,9 @@ void preload_index(struct index_state *index, memset(&pd, 0, sizeof(pd)); if (refresh_flags & REFRESH_PROGRESS && isatty(2)) { - pd.progress = start_delayed_progress(_("Refreshing index"), index->cache_nr); + pd.progress = start_delayed_progress(the_repository, + _("Refreshing index"), + index->cache_nr); pthread_mutex_init(&pd.mutex, NULL); } diff --git a/progress.c b/progress.c index a8fdfceb5c..8d5ae70f3a 100644 --- a/progress.c +++ b/progress.c @@ -9,7 +9,6 @@ */ #define GIT_TEST_PROGRESS_ONLY -#define USE_THE_REPOSITORY_VARIABLE #define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" @@ -37,6 +36,7 @@ struct throughput { }; struct progress { + struct repository *repo; const char *title; uint64_t last_value; uint64_t total; @@ -254,10 +254,12 @@ void display_progress(struct progress *progress, uint64_t n) display(progress, n, NULL); } -static struct progress *start_progress_delay(const char *title, uint64_t total, +static struct progress *start_progress_delay(struct repository *r, + const char *title, uint64_t total, unsigned delay, unsigned sparse) { struct progress *progress = xmalloc(sizeof(*progress)); + progress->repo = r; progress->title = title; progress->total = total; progress->last_value = -1; @@ -270,7 +272,7 @@ static struct progress *start_progress_delay(const char *title, uint64_t total, progress->title_len = utf8_strwidth(title); progress->split = 0; set_progress_signal(); - trace2_region_enter("progress", title, the_repository); + trace2_region_enter("progress", title, r); return progress; } @@ -284,14 +286,16 @@ static int get_default_delay(void) return delay_in_secs; } -struct progress *start_delayed_progress(const char *title, uint64_t total) +struct progress *start_delayed_progress(struct repository *r, + const char *title, uint64_t total) { - return start_progress_delay(title, total, get_default_delay(), 0); + return start_progress_delay(r, title, total, get_default_delay(), 0); } -struct progress *start_progress(const char *title, uint64_t total) +struct progress *start_progress(struct repository *r, + const char *title, uint64_t total) { - return start_progress_delay(title, total, 0, 0); + return start_progress_delay(r, title, total, 0, 0); } /* @@ -303,15 +307,17 @@ struct progress *start_progress(const char *title, uint64_t total) * When "sparse" is set, stop_progress() will automatically force the done * message to show 100%. */ -struct progress *start_sparse_progress(const char *title, uint64_t total) +struct progress *start_sparse_progress(struct repository *r, + const char *title, uint64_t total) { - return start_progress_delay(title, total, 0, 1); + return start_progress_delay(r, title, total, 0, 1); } -struct progress *start_delayed_sparse_progress(const char *title, +struct progress *start_delayed_sparse_progress(struct repository *r, + const char *title, uint64_t total) { - return start_progress_delay(title, total, get_default_delay(), 1); + return start_progress_delay(r, title, total, get_default_delay(), 1); } static void finish_if_sparse(struct progress *progress) @@ -341,14 +347,14 @@ static void force_last_update(struct progress *progress, const char *msg) static void log_trace2(struct progress *progress) { - trace2_data_intmax("progress", the_repository, "total_objects", + trace2_data_intmax("progress", progress->repo, "total_objects", progress->total); if (progress->throughput) - trace2_data_intmax("progress", the_repository, "total_bytes", + trace2_data_intmax("progress", progress->repo, "total_bytes", progress->throughput->curr_total); - trace2_region_leave("progress", progress->title, the_repository); + trace2_region_leave("progress", progress->title, progress->repo); } void stop_progress_msg(struct progress **p_progress, const char *msg) diff --git a/progress.h b/progress.h index 3a945637c8..ed068c7bab 100644 --- a/progress.h +++ b/progress.h @@ -3,6 +3,7 @@ #include "gettext.h" struct progress; +struct repository; #ifdef GIT_TEST_PROGRESS_ONLY @@ -14,10 +15,14 @@ void progress_test_force_update(void); void display_throughput(struct progress *progress, uint64_t total); void display_progress(struct progress *progress, uint64_t n); -struct progress *start_progress(const char *title, uint64_t total); -struct progress *start_sparse_progress(const char *title, uint64_t total); -struct progress *start_delayed_progress(const char *title, uint64_t total); -struct progress *start_delayed_sparse_progress(const char *title, +struct progress *start_progress(struct repository *r, + const char *title, uint64_t total); +struct progress *start_sparse_progress(struct repository *r, + const char *title, uint64_t total); +struct progress *start_delayed_progress(struct repository *r, + const char *title, uint64_t total); +struct progress *start_delayed_sparse_progress(struct repository *r, + const char *title, uint64_t total); void stop_progress_msg(struct progress **p_progress, const char *msg); static inline void stop_progress(struct progress **p_progress) diff --git a/prune-packed.c b/prune-packed.c index d1c65ab10e..7dad2fc0c1 100644 --- a/prune-packed.c +++ b/prune-packed.c @@ -37,7 +37,8 @@ static int prune_object(const struct object_id *oid, const char *path, void prune_packed_objects(int opts) { if (opts & PRUNE_PACKED_VERBOSE) - progress = start_delayed_progress(_("Removing duplicate objects"), 256); + progress = start_delayed_progress(the_repository, + _("Removing duplicate objects"), 256); for_each_loose_file_in_objdir(repo_get_object_directory(the_repository), prune_object, NULL, prune_subdir, &opts); diff --git a/pseudo-merge.c b/pseudo-merge.c index 971f54cfe1..893b763fe4 100644 --- a/pseudo-merge.c +++ b/pseudo-merge.c @@ -459,7 +459,8 @@ void select_pseudo_merges(struct bitmap_writer *writer) return; if (writer->show_progress) - progress = start_progress("Selecting pseudo-merge commits", + progress = start_progress(the_repository, + "Selecting pseudo-merge commits", writer->pseudo_merge_groups.nr); refs_for_each_ref(get_main_ref_store(the_repository), diff --git a/read-cache.c b/read-cache.c index 15d79839c2..38c36caa7f 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1523,7 +1523,8 @@ int refresh_index(struct index_state *istate, unsigned int flags, int t2_sum_scan = 0; if (flags & REFRESH_PROGRESS && isatty(2)) - progress = start_delayed_progress(_("Refresh index"), + progress = start_delayed_progress(the_repository, + _("Refresh index"), istate->cache_nr); trace_performance_enter(); diff --git a/t/helper/test-progress.c b/t/helper/test-progress.c index 44be2645e9..1f75b7bd19 100644 --- a/t/helper/test-progress.c +++ b/t/helper/test-progress.c @@ -17,10 +17,14 @@ * * See 't0500-progress-display.sh' for examples. */ + +#define USE_THE_REPOSITORY_VARIABLE #define GIT_TEST_PROGRESS_ONLY + #include "test-tool.h" #include "parse-options.h" #include "progress.h" +#include "repository.h" #include "strbuf.h" #include "string-list.h" @@ -64,7 +68,7 @@ int cmd__progress(int argc, const char **argv) else die("invalid input: '%s'", line.buf); - progress = start_progress(title, total); + progress = start_progress(the_repository, title, total); } else if (skip_prefix(line.buf, "progress ", (const char **) &end)) { uint64_t item_count = strtoull(end, &end, 10); if (*end != '\0') diff --git a/unpack-trees.c b/unpack-trees.c index b3be5d542f..334cb84f65 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -372,7 +372,8 @@ static struct progress *get_progress(struct unpack_trees_options *o, total++; } - return start_delayed_progress(_("Updating files"), total); + return start_delayed_progress(the_repository, + _("Updating files"), total); } static void setup_collided_checkout_detection(struct checkout *state, @@ -1773,6 +1774,7 @@ static int clear_ce_flags(struct index_state *istate, strbuf_reset(&prefix); if (show_progress) istate->progress = start_delayed_progress( + the_repository, _("Updating index flags"), istate->cache_nr); diff --git a/walker.c b/walker.c index 7cc9dbea46..1cf3da0219 100644 --- a/walker.c +++ b/walker.c @@ -172,7 +172,8 @@ static int loop(struct walker *walker) uint64_t nr = 0; if (walker->get_progress) - progress = start_delayed_progress(_("Fetching objects"), 0); + progress = start_delayed_progress(the_repository, + _("Fetching objects"), 0); while (process_queue) { struct object *obj = process_queue->item; -- cgit v1.2.3 From 59b6131a677b0b45fb7fd54ba60dbf689b0a1797 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 17 Dec 2024 07:43:49 +0100 Subject: pager: stop using `the_repository` Stop using `the_repository` in the "pager" subsystem by passing in a repository when setting up the pager and when configuring it. Adjust callers accordingly by using `the_repository`. While there may be some callers that have a repository available in their context, this trivial conversion allows for easier verification and bubbles up the use of `the_repository` by one level. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- add-patch.c | 2 +- builtin/am.c | 4 ++-- builtin/blame.c | 2 +- builtin/grep.c | 4 ++-- builtin/help.c | 4 ++-- builtin/log.c | 4 ++-- builtin/var.c | 2 +- diff.c | 4 ++-- git.c | 8 ++++---- pager.c | 14 ++++++-------- pager.h | 7 ++++--- 11 files changed, 27 insertions(+), 28 deletions(-) diff --git a/add-patch.c b/add-patch.c index 7b598e14df..95c67d8c80 100644 --- a/add-patch.c +++ b/add-patch.c @@ -1464,7 +1464,7 @@ static int patch_update_file(struct add_p_state *s, if (file_diff->hunk_nr) { if (rendered_hunk_index != hunk_index) { if (use_pager) { - setup_pager(); + setup_pager(the_repository); sigchain_push(SIGPIPE, SIG_IGN); } render_hunk(s, hunk, 0, colored, &s->buf); diff --git a/builtin/am.c b/builtin/am.c index 1338b606fe..27ccca8341 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -1786,7 +1786,7 @@ static int do_interactive(struct am_state *state) } strbuf_release(&msg); } else if (*reply == 'v' || *reply == 'V') { - const char *pager = git_pager(1); + const char *pager = git_pager(the_repository, 1); struct child_process cp = CHILD_PROCESS_INIT; if (!pager) @@ -2246,7 +2246,7 @@ static int show_patch(struct am_state *state, enum resume_type resume_mode) if (len < 0) die_errno(_("failed to read '%s'"), patch_path); - setup_pager(); + setup_pager(the_repository); write_in_full(1, sb.buf, sb.len); strbuf_release(&sb); return 0; diff --git a/builtin/blame.c b/builtin/blame.c index dd78288530..1f44c341c5 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -1202,7 +1202,7 @@ parse_done: stop_progress(&pi.progress); if (!incremental) - setup_pager(); + setup_pager(the_repository); else goto cleanup; diff --git a/builtin/grep.c b/builtin/grep.c index d00ee76f24..d1427290f7 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -1084,7 +1084,7 @@ int cmd_grep(int argc, } if (show_in_pager == default_pager) - show_in_pager = git_pager(1); + show_in_pager = git_pager(the_repository, 1); if (show_in_pager) { opt.color = 0; opt.name_only = 1; @@ -1246,7 +1246,7 @@ int cmd_grep(int argc, } if (!show_in_pager && !opt.status_only) - setup_pager(); + setup_pager(the_repository); die_for_incompatible_opt3(!use_index, "--no-index", untracked, "--untracked", diff --git a/builtin/help.c b/builtin/help.c index 05136279cf..c257079ceb 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -658,7 +658,7 @@ int cmd_help(int argc, case HELP_ACTION_ALL: opt_mode_usage(argc, "--all", help_format); if (verbose) { - setup_pager(); + setup_pager(the_repository); list_all_cmds_help(show_external_commands, show_aliases); return 0; @@ -692,7 +692,7 @@ int cmd_help(int argc, return 0; case HELP_ACTION_CONFIG: opt_mode_usage(argc, "--config", help_format); - setup_pager(); + setup_pager(the_repository); list_config_help(SHOW_CONFIG_HUMAN); printf("\n%s\n", _("'git help config' for more information")); return 0; diff --git a/builtin/log.c b/builtin/log.c index 317335e60d..3a6a3362f3 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -369,7 +369,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix, if (rev->line_level_traverse) line_log_init(rev, line_cb.prefix, &line_cb.args); - setup_pager(); + setup_pager(the_repository); } static void cmd_log_init(int argc, const char **argv, const char *prefix, @@ -2292,7 +2292,7 @@ int cmd_format_patch(int argc, rev.commit_format = CMIT_FMT_MBOXRD; if (use_stdout) { - setup_pager(); + setup_pager(the_repository); } else if (!rev.diffopt.close_file) { int saved; diff --git a/builtin/var.c b/builtin/var.c index 1449656cc9..50d024de66 100644 --- a/builtin/var.c +++ b/builtin/var.c @@ -42,7 +42,7 @@ static char *sequence_editor(int ident_flag UNUSED) static char *pager(int ident_flag UNUSED) { - const char *pgm = git_pager(1); + const char *pgm = git_pager(the_repository, 1); if (!pgm) pgm = "cat"; diff --git a/diff.c b/diff.c index d28b4114c8..0822ae4433 100644 --- a/diff.c +++ b/diff.c @@ -7386,6 +7386,6 @@ void setup_diff_pager(struct diff_options *opt) * --exit-code" in hooks and other scripts, we do not do so. */ if (!opt->flags.exit_with_status && - check_pager_config("diff") != 0) - setup_pager(); + check_pager_config(the_repository, "diff") != 0) + setup_pager(the_repository); } diff --git a/git.c b/git.c index 71d644dc1c..d977ebc84c 100644 --- a/git.c +++ b/git.c @@ -125,7 +125,7 @@ static void commit_pager_choice(void) setenv("GIT_PAGER", "cat", 1); break; case 1: - setup_pager(); + setup_pager(the_repository); break; default: break; @@ -136,7 +136,7 @@ void setup_auto_pager(const char *cmd, int def) { if (use_pager != -1 || pager_in_use()) return; - use_pager = check_pager_config(cmd); + use_pager = check_pager_config(the_repository, cmd); if (use_pager == -1) use_pager = def; commit_pager_choice(); @@ -462,7 +462,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv, struct precompose_argv_prefix(argc, argv, NULL); if (use_pager == -1 && run_setup && !(p->option & DELAY_PAGER_CONFIG)) - use_pager = check_pager_config(p->cmd); + use_pager = check_pager_config(the_repository, p->cmd); if (use_pager == -1 && p->option & USE_PAGER) use_pager = 1; if (run_setup && startup_info->have_repository) @@ -750,7 +750,7 @@ static void execv_dashed_external(const char **argv) int status; if (use_pager == -1 && !is_builtin(argv[0])) - use_pager = check_pager_config(argv[0]); + use_pager = check_pager_config(the_repository, argv[0]); commit_pager_choice(); strvec_pushf(&cmd.args, "git-%s", argv[0]); diff --git a/pager.c b/pager.c index 40b664f893..5531fff50e 100644 --- a/pager.c +++ b/pager.c @@ -1,5 +1,3 @@ -#define USE_THE_REPOSITORY_VARIABLE - #include "git-compat-util.h" #include "config.h" #include "editor.h" @@ -84,7 +82,7 @@ static int core_pager_config(const char *var, const char *value, return 0; } -const char *git_pager(int stdout_is_tty) +const char *git_pager(struct repository *r, int stdout_is_tty) { const char *pager; @@ -94,7 +92,7 @@ const char *git_pager(int stdout_is_tty) pager = getenv("GIT_PAGER"); if (!pager) { if (!pager_program) - read_early_config(the_repository, + read_early_config(r, core_pager_config, NULL); pager = pager_program; } @@ -143,10 +141,10 @@ void prepare_pager_args(struct child_process *pager_process, const char *pager) pager_process->trace2_child_class = "pager"; } -void setup_pager(void) +void setup_pager(struct repository *r) { static int once = 0; - const char *pager = git_pager(isatty(1)); + const char *pager = git_pager(r, isatty(1)); if (!pager) return; @@ -293,7 +291,7 @@ static int pager_command_config(const char *var, const char *value, } /* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */ -int check_pager_config(const char *cmd) +int check_pager_config(struct repository *r, const char *cmd) { struct pager_command_config_data data; @@ -301,7 +299,7 @@ int check_pager_config(const char *cmd) data.want = -1; data.value = NULL; - read_early_config(the_repository, pager_command_config, &data); + read_early_config(r, pager_command_config, &data); if (data.value) pager_program = data.value; diff --git a/pager.h b/pager.h index 103ecac476..d070be6348 100644 --- a/pager.h +++ b/pager.h @@ -2,15 +2,16 @@ #define PAGER_H struct child_process; +struct repository; -const char *git_pager(int stdout_is_tty); -void setup_pager(void); +const char *git_pager(struct repository *r, int stdout_is_tty); +void setup_pager(struct repository *r); void wait_for_pager(void); int pager_in_use(void); int term_columns(void); void term_clear_line(void); int decimal_width(uintmax_t); -int check_pager_config(const char *cmd); +int check_pager_config(struct repository *r, const char *cmd); void prepare_pager_args(struct child_process *, const char *pager); extern int pager_use_color; -- cgit v1.2.3 From bd0c0fb790dcb6cd32a585e1d9fcb0a4a4f7379b Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 17 Dec 2024 07:43:50 +0100 Subject: trace: stop using `the_repository` Stop using `the_repository` in the "trace" subsystem by passing in a repository when setting up tracing. Adjust the only caller accordingly. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- git.c | 2 +- trace.c | 9 ++++----- trace.h | 4 +++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/git.c b/git.c index d977ebc84c..a94dab3770 100644 --- a/git.c +++ b/git.c @@ -467,7 +467,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv, struct use_pager = 1; if (run_setup && startup_info->have_repository) /* get_git_dir() may set up repo, avoid that */ - trace_repo_setup(); + trace_repo_setup(the_repository); commit_pager_choice(); if (!help && p->option & NEED_WORK_TREE) diff --git a/trace.c b/trace.c index 2cfd25942e..9b99460db8 100644 --- a/trace.c +++ b/trace.c @@ -21,7 +21,6 @@ * along with this program; if not, see . */ -#define USE_THE_REPOSITORY_VARIABLE #define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" @@ -298,7 +297,7 @@ static const char *quote_crnl(const char *path) return new_path.buf; } -void trace_repo_setup(void) +void trace_repo_setup(struct repository *r) { const char *git_work_tree, *prefix = startup_info->prefix; char *cwd; @@ -308,14 +307,14 @@ void trace_repo_setup(void) cwd = xgetcwd(); - if (!(git_work_tree = repo_get_work_tree(the_repository))) + if (!(git_work_tree = repo_get_work_tree(r))) git_work_tree = "(null)"; if (!startup_info->prefix) prefix = "(null)"; - trace_printf_key(&trace_setup_key, "setup: git_dir: %s\n", quote_crnl(repo_get_git_dir(the_repository))); - trace_printf_key(&trace_setup_key, "setup: git_common_dir: %s\n", quote_crnl(repo_get_common_dir(the_repository))); + trace_printf_key(&trace_setup_key, "setup: git_dir: %s\n", quote_crnl(repo_get_git_dir(r))); + trace_printf_key(&trace_setup_key, "setup: git_common_dir: %s\n", quote_crnl(repo_get_common_dir(r))); trace_printf_key(&trace_setup_key, "setup: worktree: %s\n", quote_crnl(git_work_tree)); trace_printf_key(&trace_setup_key, "setup: cwd: %s\n", quote_crnl(cwd)); trace_printf_key(&trace_setup_key, "setup: prefix: %s\n", quote_crnl(prefix)); diff --git a/trace.h b/trace.h index d304d55aa1..9152fe9b3e 100644 --- a/trace.h +++ b/trace.h @@ -92,7 +92,9 @@ extern struct trace_key trace_default_key; extern struct trace_key trace_perf_key; extern struct trace_key trace_setup_key; -void trace_repo_setup(void); +struct repository; + +void trace_repo_setup(struct repository *r); /** * Checks whether the trace key is enabled. Used to prevent expensive -- cgit v1.2.3 From 395b584b5751b009d657d8c3aed371f2a233d919 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 17 Dec 2024 07:43:51 +0100 Subject: serve: stop using `the_repository` Stop using `the_repository` in the "serve" subsystem by passing in a repository when advertising capabilities or serving requests. Adjust callers accordingly by using `the_repository`. While there may be some callers that have a repository available in their context, this trivial conversion allows for easier verification and bubbles up the use of `the_repository` by one level. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/upload-pack.c | 6 ++++-- serve.c | 36 +++++++++++++++++------------------- serve.h | 6 ++++-- t/helper/test-serve-v2.c | 7 +++++-- 4 files changed, 30 insertions(+), 25 deletions(-) diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c index dd63d6eadf..c2bbc035ab 100644 --- a/builtin/upload-pack.c +++ b/builtin/upload-pack.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "builtin.h" #include "exec-cmd.h" #include "gettext.h" @@ -63,9 +65,9 @@ int cmd_upload_pack(int argc, switch (determine_protocol_version_server()) { case protocol_v2: if (advertise_refs) - protocol_v2_advertise_capabilities(); + protocol_v2_advertise_capabilities(the_repository); else - protocol_v2_serve_loop(stateless_rpc); + protocol_v2_serve_loop(the_repository, stateless_rpc); break; case protocol_v1: /* diff --git a/serve.c b/serve.c index c8694e3751..f6dfe34a2b 100644 --- a/serve.c +++ b/serve.c @@ -1,5 +1,3 @@ -#define USE_THE_REPOSITORY_VARIABLE - #include "git-compat-util.h" #include "repository.h" #include "config.h" @@ -159,7 +157,7 @@ static struct protocol_capability capabilities[] = { }, }; -void protocol_v2_advertise_capabilities(void) +void protocol_v2_advertise_capabilities(struct repository *r) { struct strbuf capability = STRBUF_INIT; struct strbuf value = STRBUF_INIT; @@ -170,7 +168,7 @@ void protocol_v2_advertise_capabilities(void) for (size_t i = 0; i < ARRAY_SIZE(capabilities); i++) { struct protocol_capability *c = &capabilities[i]; - if (c->advertise(the_repository, &value)) { + if (c->advertise(r, &value)) { strbuf_addstr(&capability, c->name); if (value.len) { @@ -214,20 +212,20 @@ static struct protocol_capability *get_capability(const char *key, const char ** return NULL; } -static int receive_client_capability(const char *key) +static int receive_client_capability(struct repository *r, const char *key) { const char *value; const struct protocol_capability *c = get_capability(key, &value); - if (!c || c->command || !c->advertise(the_repository, NULL)) + if (!c || c->command || !c->advertise(r, NULL)) return 0; if (c->receive) - c->receive(the_repository, value); + c->receive(r, value); return 1; } -static int parse_command(const char *key, struct protocol_capability **command) +static int parse_command(struct repository *r, const char *key, struct protocol_capability **command) { const char *out; @@ -238,7 +236,7 @@ static int parse_command(const char *key, struct protocol_capability **command) if (*command) die("command '%s' requested after already requesting command '%s'", out, (*command)->name); - if (!cmd || !cmd->advertise(the_repository, NULL) || !cmd->command || value) + if (!cmd || !cmd->advertise(r, NULL) || !cmd->command || value) die("invalid command '%s'", out); *command = cmd; @@ -253,7 +251,7 @@ enum request_state { PROCESS_REQUEST_DONE, }; -static int process_request(void) +static int process_request(struct repository *r) { enum request_state state = PROCESS_REQUEST_KEYS; struct packet_reader reader; @@ -278,8 +276,8 @@ static int process_request(void) case PACKET_READ_EOF: BUG("Should have already died when seeing EOF"); case PACKET_READ_NORMAL: - if (parse_command(reader.line, &command) || - receive_client_capability(reader.line)) + if (parse_command(r, reader.line, &command) || + receive_client_capability(r, reader.line)) seen_capability_or_command = 1; else die("unknown capability '%s'", reader.line); @@ -319,30 +317,30 @@ static int process_request(void) if (!command) die("no command requested"); - if (client_hash_algo != hash_algo_by_ptr(the_repository->hash_algo)) + if (client_hash_algo != hash_algo_by_ptr(r->hash_algo)) die("mismatched object format: server %s; client %s", - the_repository->hash_algo->name, + r->hash_algo->name, hash_algos[client_hash_algo].name); - command->command(the_repository, &reader); + command->command(r, &reader); return 0; } -void protocol_v2_serve_loop(int stateless_rpc) +void protocol_v2_serve_loop(struct repository *r, int stateless_rpc) { if (!stateless_rpc) - protocol_v2_advertise_capabilities(); + protocol_v2_advertise_capabilities(r); /* * If stateless-rpc was requested then exit after * a single request/response exchange */ if (stateless_rpc) { - process_request(); + process_request(r); } else { for (;;) - if (process_request()) + if (process_request(r)) break; } } diff --git a/serve.h b/serve.h index f946cf904a..85bf73cfe5 100644 --- a/serve.h +++ b/serve.h @@ -1,7 +1,9 @@ #ifndef SERVE_H #define SERVE_H -void protocol_v2_advertise_capabilities(void); -void protocol_v2_serve_loop(int stateless_rpc); +struct repository; + +void protocol_v2_advertise_capabilities(struct repository *r); +void protocol_v2_serve_loop(struct repository *r, int stateless_rpc); #endif /* SERVE_H */ diff --git a/t/helper/test-serve-v2.c b/t/helper/test-serve-v2.c index 054cbcf5d8..63a200b8d4 100644 --- a/t/helper/test-serve-v2.c +++ b/t/helper/test-serve-v2.c @@ -1,6 +1,9 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "gettext.h" #include "parse-options.h" +#include "repository.h" #include "serve.h" #include "setup.h" @@ -28,9 +31,9 @@ int cmd__serve_v2(int argc, const char **argv) PARSE_OPT_KEEP_UNKNOWN_OPT); if (advertise_capabilities) - protocol_v2_advertise_capabilities(); + protocol_v2_advertise_capabilities(the_repository); else - protocol_v2_serve_loop(stateless_rpc); + protocol_v2_serve_loop(the_repository, stateless_rpc); return 0; } -- cgit v1.2.3 From 5ee907bb3f12c630f78554ea9b4c605f4e1a5e92 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 17 Dec 2024 07:43:52 +0100 Subject: send-pack: stop using `the_repository` Stop using `the_repository` in the "send-pack" subsystem by passing in a repository when sending a packfile. Adjust callers accordingly by using `the_repository`. While there may be some callers that have a repository available in their context, this trivial conversion allows for easier verification and bubbles up the use of `the_repository` by one level. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/send-pack.c | 2 +- send-pack.c | 77 ++++++++++++++++++++++++++++------------------------- send-pack.h | 3 ++- transport.c | 2 +- 4 files changed, 44 insertions(+), 40 deletions(-) diff --git a/builtin/send-pack.c b/builtin/send-pack.c index 59b626aae8..8d461008e2 100644 --- a/builtin/send-pack.c +++ b/builtin/send-pack.c @@ -317,7 +317,7 @@ int cmd_send_pack(int argc, set_ref_status_for_push(remote_refs, args.send_mirror, args.force_update); - ret = send_pack(&args, fd, conn, remote_refs, &extra_have); + ret = send_pack(the_repository, &args, fd, conn, remote_refs, &extra_have); if (helper_status) print_helper_status(remote_refs); diff --git a/send-pack.c b/send-pack.c index 7e83213683..772c7683a0 100644 --- a/send-pack.c +++ b/send-pack.c @@ -1,5 +1,3 @@ -#define USE_THE_REPOSITORY_VARIABLE - #include "git-compat-util.h" #include "config.h" #include "commit.h" @@ -44,10 +42,11 @@ int option_parse_push_signed(const struct option *opt, die("bad %s argument: %s", opt->long_name, arg); } -static void feed_object(const struct object_id *oid, FILE *fh, int negative) +static void feed_object(struct repository *r, + const struct object_id *oid, FILE *fh, int negative) { if (negative && - !repo_has_object_file_with_flags(the_repository, oid, + !repo_has_object_file_with_flags(r, oid, OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK)) return; @@ -61,7 +60,8 @@ static void feed_object(const struct object_id *oid, FILE *fh, int negative) /* * Make a pack stream and spit it out into file descriptor fd */ -static int pack_objects(int fd, struct ref *refs, struct oid_array *advertised, +static int pack_objects(struct repository *r, + int fd, struct ref *refs, struct oid_array *advertised, struct oid_array *negotiated, struct send_pack_args *args) { @@ -74,7 +74,7 @@ static int pack_objects(int fd, struct ref *refs, struct oid_array *advertised, FILE *po_in; int rc; - trace2_region_enter("send_pack", "pack_objects", the_repository); + trace2_region_enter("send_pack", "pack_objects", r); strvec_push(&po.args, "pack-objects"); strvec_push(&po.args, "--all-progress-implied"); strvec_push(&po.args, "--revs"); @@ -87,7 +87,7 @@ static int pack_objects(int fd, struct ref *refs, struct oid_array *advertised, strvec_push(&po.args, "-q"); if (args->progress) strvec_push(&po.args, "--progress"); - if (is_repository_shallow(the_repository)) + if (is_repository_shallow(r)) strvec_push(&po.args, "--shallow"); if (args->disable_bitmaps) strvec_push(&po.args, "--no-use-bitmap-index"); @@ -104,15 +104,15 @@ static int pack_objects(int fd, struct ref *refs, struct oid_array *advertised, */ po_in = xfdopen(po.in, "w"); for (size_t i = 0; i < advertised->nr; i++) - feed_object(&advertised->oid[i], po_in, 1); + feed_object(r, &advertised->oid[i], po_in, 1); for (size_t i = 0; i < negotiated->nr; i++) - feed_object(&negotiated->oid[i], po_in, 1); + feed_object(r, &negotiated->oid[i], po_in, 1); while (refs) { if (!is_null_oid(&refs->old_oid)) - feed_object(&refs->old_oid, po_in, 1); + feed_object(r, &refs->old_oid, po_in, 1); if (!is_null_oid(&refs->new_oid)) - feed_object(&refs->new_oid, po_in, 0); + feed_object(r, &refs->new_oid, po_in, 0); refs = refs->next; } @@ -146,10 +146,10 @@ static int pack_objects(int fd, struct ref *refs, struct oid_array *advertised, */ if (rc > 128 && rc != 141) error("pack-objects died of signal %d", rc - 128); - trace2_region_leave("send_pack", "pack_objects", the_repository); + trace2_region_leave("send_pack", "pack_objects", r); return -1; } - trace2_region_leave("send_pack", "pack_objects", the_repository); + trace2_region_leave("send_pack", "pack_objects", r); return 0; } @@ -164,7 +164,8 @@ static int receive_unpack_status(struct packet_reader *reader) return 0; } -static int receive_status(struct packet_reader *reader, struct ref *refs) +static int receive_status(struct repository *r, + struct packet_reader *reader, struct ref *refs) { struct ref *hint; int ret; @@ -172,7 +173,7 @@ static int receive_status(struct packet_reader *reader, struct ref *refs) int new_report = 0; int once = 0; - trace2_region_enter("send_pack", "receive_status", the_repository); + trace2_region_enter("send_pack", "receive_status", r); hint = NULL; ret = receive_unpack_status(reader); while (1) { @@ -221,10 +222,10 @@ static int receive_status(struct packet_reader *reader, struct ref *refs) if (!strcmp(key, "refname")) report->ref_name = xstrdup_or_null(val); else if (!strcmp(key, "old-oid") && val && - !parse_oid_hex(val, &old_oid, &val)) + !parse_oid_hex_algop(val, &old_oid, &val, r->hash_algo)) report->old_oid = oiddup(&old_oid); else if (!strcmp(key, "new-oid") && val && - !parse_oid_hex(val, &new_oid, &val)) + !parse_oid_hex_algop(val, &new_oid, &val, r->hash_algo)) report->new_oid = oiddup(&new_oid); else if (!strcmp(key, "forced-update")) report->forced_update = 1; @@ -271,7 +272,7 @@ static int receive_status(struct packet_reader *reader, struct ref *refs) new_report = 1; } } - trace2_region_leave("send_pack", "receive_status", the_repository); + trace2_region_leave("send_pack", "receive_status", r); return ret; } @@ -293,9 +294,9 @@ static int advertise_shallow_grafts_cb(const struct commit_graft *graft, void *c return 0; } -static void advertise_shallow_grafts_buf(struct strbuf *sb) +static void advertise_shallow_grafts_buf(struct repository *r, struct strbuf *sb) { - if (!is_repository_shallow(the_repository)) + if (!is_repository_shallow(r)) return; for_each_commit_graft(advertise_shallow_grafts_cb, sb); } @@ -426,13 +427,14 @@ static void reject_invalid_nonce(const char *nonce, int len) } } -static void get_commons_through_negotiation(const char *url, +static void get_commons_through_negotiation(struct repository *r, + const char *url, const struct ref *remote_refs, struct oid_array *commons) { struct child_process child = CHILD_PROCESS_INIT; const struct ref *ref; - int len = the_hash_algo->hexsz + 1; /* hash + NL */ + int len = r->hash_algo->hexsz + 1; /* hash + NL */ int nr_negotiation_tip = 0; child.git_cmd = 1; @@ -466,7 +468,7 @@ static void get_commons_through_negotiation(const char *url, break; if (read_len != len) die("invalid length read %d", read_len); - if (parse_oid_hex(hex_hash, &oid, &end) || *end != '\n') + if (parse_oid_hex_algop(hex_hash, &oid, &end, r->hash_algo) || *end != '\n') die("invalid hash"); oid_array_append(commons, &oid); } while (1); @@ -480,7 +482,8 @@ static void get_commons_through_negotiation(const char *url, } } -int send_pack(struct send_pack_args *args, +int send_pack(struct repository *r, + struct send_pack_args *args, int fd[], struct child_process *conn, struct ref *remote_refs, struct oid_array *extra_have) @@ -518,17 +521,17 @@ int send_pack(struct send_pack_args *args, goto out; } - git_config_get_bool("push.negotiate", &push_negotiate); + repo_config_get_bool(r, "push.negotiate", &push_negotiate); if (push_negotiate) { - trace2_region_enter("send_pack", "push_negotiate", the_repository); - get_commons_through_negotiation(args->url, remote_refs, &commons); - trace2_region_leave("send_pack", "push_negotiate", the_repository); + trace2_region_enter("send_pack", "push_negotiate", r); + get_commons_through_negotiation(r, args->url, remote_refs, &commons); + trace2_region_leave("send_pack", "push_negotiate", r); } - if (!git_config_get_bool("push.usebitmaps", &use_bitmaps)) + if (!repo_config_get_bool(r, "push.usebitmaps", &use_bitmaps)) args->disable_bitmaps = !use_bitmaps; - git_config_get_bool("transfer.advertisesid", &advertise_sid); + repo_config_get_bool(r, "transfer.advertisesid", &advertise_sid); /* Does the other end support the reporting? */ if (server_supports("report-status-v2")) @@ -554,7 +557,7 @@ int send_pack(struct send_pack_args *args, if (server_supports("push-options")) push_options_supported = 1; - if (!server_supports_hash(the_hash_algo->name, &object_format_supported)) + if (!server_supports_hash(r->hash_algo->name, &object_format_supported)) die(_("the receiving end does not support this repository's hash algorithm")); if (args->push_cert != SEND_PACK_PUSH_CERT_NEVER) { @@ -596,7 +599,7 @@ int send_pack(struct send_pack_args *args, if (use_push_options) strbuf_addstr(&cap_buf, " push-options"); if (object_format_supported) - strbuf_addf(&cap_buf, " object-format=%s", the_hash_algo->name); + strbuf_addf(&cap_buf, " object-format=%s", r->hash_algo->name); if (agent_supported) strbuf_addf(&cap_buf, " agent=%s", git_user_agent_sanitized()); if (advertise_sid) @@ -646,7 +649,7 @@ int send_pack(struct send_pack_args *args, } if (!args->dry_run) - advertise_shallow_grafts_buf(&req_buf); + advertise_shallow_grafts_buf(r, &req_buf); /* * Finally, tell the other end! @@ -686,7 +689,7 @@ int send_pack(struct send_pack_args *args, } if (args->stateless_rpc) { - if (!args->dry_run && (cmds_sent || is_repository_shallow(the_repository))) { + if (!args->dry_run && (cmds_sent || is_repository_shallow(r))) { packet_buf_flush(&req_buf); send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX); } @@ -711,7 +714,7 @@ int send_pack(struct send_pack_args *args, PACKET_READ_DIE_ON_ERR_PACKET); if (need_pack_data && cmds_sent) { - if (pack_objects(out, remote_refs, extra_have, &commons, args) < 0) { + if (pack_objects(r, out, remote_refs, extra_have, &commons, args) < 0) { if (args->stateless_rpc) close(out); if (git_connection_is_socket(conn)) @@ -724,7 +727,7 @@ int send_pack(struct send_pack_args *args, * we get one). */ if (status_report) - receive_status(&reader, remote_refs); + receive_status(r, &reader, remote_refs); if (use_sideband) { close(demux.out); @@ -743,7 +746,7 @@ int send_pack(struct send_pack_args *args, packet_flush(out); if (status_report && cmds_sent) - ret = receive_status(&reader, remote_refs); + ret = receive_status(r, &reader, remote_refs); else ret = 0; if (args->stateless_rpc) diff --git a/send-pack.h b/send-pack.h index 7edb80596c..d256715681 100644 --- a/send-pack.h +++ b/send-pack.h @@ -6,6 +6,7 @@ struct child_process; struct oid_array; struct ref; +struct repository; /* Possible values for push_cert field in send_pack_args. */ #define SEND_PACK_PUSH_CERT_NEVER 0 @@ -35,7 +36,7 @@ struct option; int option_parse_push_signed(const struct option *opt, const char *arg, int unset); -int send_pack(struct send_pack_args *args, +int send_pack(struct repository *r, struct send_pack_args *args, int fd[], struct child_process *conn, struct ref *remote_refs, struct oid_array *extra_have); diff --git a/transport.c b/transport.c index 10d820c333..81ae8243b9 100644 --- a/transport.c +++ b/transport.c @@ -932,7 +932,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re break; case protocol_v1: case protocol_v0: - ret = send_pack(&args, data->fd, data->conn, remote_refs, + ret = send_pack(the_repository, &args, data->fd, data->conn, remote_refs, &data->extra_have); break; case protocol_unknown_version: -- cgit v1.2.3 From c365dbb44ec81fc60e9b7666a4384f8649d80b2a Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 17 Dec 2024 07:43:53 +0100 Subject: server-info: stop using `the_repository` Stop using `the_repository` in the "server-info" subsystem by passing in a repository when updating server info and storing the repository in the `update_info_ctx` structure to make it accessible to other functions. Adjust callers accordingly by using `the_repository`. While there may be some callers that have a repository available in their context, this trivial conversion allows for easier verification and bubbles up the use of `the_repository` by one level. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/receive-pack.c | 2 +- builtin/repack.c | 2 +- builtin/update-server-info.c | 2 +- server-info.c | 40 ++++++++++++++++++++++------------------ server-info.h | 4 +++- 5 files changed, 28 insertions(+), 22 deletions(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index c2e9103f11..191b5eeb34 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -2628,7 +2628,7 @@ int cmd_receive_pack(int argc, } } if (auto_update_server_info) - update_server_info(0); + update_server_info(the_repository, 0); clear_shallow_info(&si); } if (use_sideband) diff --git a/builtin/repack.c b/builtin/repack.c index 0c6dad7df4..81d13630ea 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -1565,7 +1565,7 @@ int cmd_repack(int argc, } if (run_update_server_info) - update_server_info(0); + update_server_info(the_repository, 0); if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0)) { unsigned flags = 0; diff --git a/builtin/update-server-info.c b/builtin/update-server-info.c index 6769611a02..47a3f0bdd9 100644 --- a/builtin/update-server-info.c +++ b/builtin/update-server-info.c @@ -27,5 +27,5 @@ int cmd_update_server_info(int argc, if (argc > 0) usage_with_options(update_server_info_usage, options); - return !!update_server_info(force); + return !!update_server_info(the_repository, force); } diff --git a/server-info.c b/server-info.c index ef2f3f4b5c..31c3fdc118 100644 --- a/server-info.c +++ b/server-info.c @@ -1,4 +1,3 @@ -#define USE_THE_REPOSITORY_VARIABLE #define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" @@ -18,6 +17,7 @@ #include "tempfile.h" struct update_info_ctx { + struct repository *repo; FILE *cur_fp; FILE *old_fp; /* becomes NULL if it differs from cur_fp */ struct strbuf cur_sb; @@ -73,7 +73,7 @@ static int uic_printf(struct update_info_ctx *uic, const char *fmt, ...) * it into place. The contents of the file come from "generate", which * should return non-zero if it encounters an error. */ -static int update_info_file(char *path, +static int update_info_file(struct repository *r, char *path, int (*generate)(struct update_info_ctx *), int force) { @@ -81,6 +81,7 @@ static int update_info_file(char *path, struct tempfile *f = NULL; int ret = -1; struct update_info_ctx uic = { + .repo = r, .cur_fp = NULL, .old_fp = NULL, .cur_sb = STRBUF_INIT, @@ -152,7 +153,7 @@ static int add_info_ref(const char *path, const char *referent UNUSED, const str void *cb_data) { struct update_info_ctx *uic = cb_data; - struct object *o = parse_object(the_repository, oid); + struct object *o = parse_object(uic->repo, oid); if (!o) return -1; @@ -160,7 +161,7 @@ static int add_info_ref(const char *path, const char *referent UNUSED, const str return -1; if (o->type == OBJ_TAG) { - o = deref_tag(the_repository, o, path, 0); + o = deref_tag(uic->repo, o, path, 0); if (o) if (uic_printf(uic, "%s %s^{}\n", oid_to_hex(&o->oid), path) < 0) @@ -171,14 +172,14 @@ static int add_info_ref(const char *path, const char *referent UNUSED, const str static int generate_info_refs(struct update_info_ctx *uic) { - return refs_for_each_ref(get_main_ref_store(the_repository), + return refs_for_each_ref(get_main_ref_store(uic->repo), add_info_ref, uic); } -static int update_info_refs(int force) +static int update_info_refs(struct repository *r, int force) { - char *path = git_pathdup("info/refs"); - int ret = update_info_file(path, generate_info_refs, force); + char *path = repo_git_path(r, "info/refs"); + int ret = update_info_file(r, path, generate_info_refs, force); free(path); return ret; } @@ -284,14 +285,14 @@ static int compare_info(const void *a_, const void *b_) return 1; } -static void init_pack_info(const char *infofile, int force) +static void init_pack_info(struct repository *r, const char *infofile, int force) { struct packed_git *p; int stale; int i; size_t alloc = 0; - for (p = get_all_packs(the_repository); p; p = p->next) { + for (p = get_all_packs(r); p; p = p->next) { /* we ignore things on alternate path since they are * not available to the pullers in general. */ @@ -340,33 +341,36 @@ static int write_pack_info_file(struct update_info_ctx *uic) return 0; } -static int update_info_packs(int force) +static int update_info_packs(struct repository *r, int force) { char *infofile = mkpathdup("%s/info/packs", - repo_get_object_directory(the_repository)); + repo_get_object_directory(r)); int ret; - init_pack_info(infofile, force); - ret = update_info_file(infofile, write_pack_info_file, force); + init_pack_info(r, infofile, force); + ret = update_info_file(r, infofile, write_pack_info_file, force); free_pack_info(); free(infofile); return ret; } /* public */ -int update_server_info(int force) +int update_server_info(struct repository *r, int force) { /* We would add more dumb-server support files later, * including index of available pack files and their * intended audiences. */ int errs = 0; + char *path; - errs = errs | update_info_refs(force); - errs = errs | update_info_packs(force); + errs = errs | update_info_refs(r, force); + errs = errs | update_info_packs(r, force); /* remove leftover rev-cache file if there is any */ - unlink_or_warn(git_path("info/rev-cache")); + path = repo_git_path(r, "info/rev-cache"); + unlink_or_warn(path); + free(path); return errs; } diff --git a/server-info.h b/server-info.h index 13bbde2c55..e634d1722b 100644 --- a/server-info.h +++ b/server-info.h @@ -1,7 +1,9 @@ #ifndef SERVER_INFO_H #define SERVER_INFO_H +struct repository; + /* Dumb servers support */ -int update_server_info(int); +int update_server_info(struct repository *r, int force); #endif /* SERVER_INFO_H */ -- cgit v1.2.3 From b4c476c43a1125300614d2e9ec9dedfa44355515 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 17 Dec 2024 07:43:54 +0100 Subject: diagnose: stop using `the_repository` Stop using `the_repository` in the "diagnose" subsystem by passing in a repository when generating a diagnostics archive. Adjust callers accordingly by using `the_repository`. While there may be some callers that have a repository available in their context, this trivial conversion allows for easier verification and bubbles up the use of `the_repository` by one level. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/bugreport.c | 2 +- builtin/diagnose.c | 4 +++- diagnose.c | 15 ++++++++------- diagnose.h | 5 ++++- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/builtin/bugreport.c b/builtin/bugreport.c index 7c2df035c9..0ac59cc8dc 100644 --- a/builtin/bugreport.c +++ b/builtin/bugreport.c @@ -167,7 +167,7 @@ int cmd_bugreport(int argc, strbuf_addftime(&zip_path, option_suffix, localtime_r(&now, &tm), 0, 0); strbuf_addstr(&zip_path, ".zip"); - if (create_diagnostics_archive(&zip_path, diagnose)) + if (create_diagnostics_archive(the_repository, &zip_path, diagnose)) die_errno(_("unable to create diagnostics archive %s"), zip_path.buf); strbuf_release(&zip_path); diff --git a/builtin/diagnose.c b/builtin/diagnose.c index 66a22d918e..33c39bd598 100644 --- a/builtin/diagnose.c +++ b/builtin/diagnose.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "builtin.h" #include "abspath.h" #include "gettext.h" @@ -58,7 +60,7 @@ int cmd_diagnose(int argc, } /* Prepare diagnostics */ - if (create_diagnostics_archive(&zip_path, mode)) + if (create_diagnostics_archive(the_repository, &zip_path, mode)) die_errno(_("unable to create diagnostics archive %s"), zip_path.buf); diff --git a/diagnose.c b/diagnose.c index b11931df86..bd485effea 100644 --- a/diagnose.c +++ b/diagnose.c @@ -1,5 +1,3 @@ -#define USE_THE_REPOSITORY_VARIABLE - #include "git-compat-util.h" #include "diagnose.h" #include "compat/disk.h" @@ -12,6 +10,7 @@ #include "object-store-ll.h" #include "packfile.h" #include "parse-options.h" +#include "repository.h" #include "write-or-die.h" struct archive_dir { @@ -179,7 +178,9 @@ static int add_directory_to_archiver(struct strvec *archiver_args, return res; } -int create_diagnostics_archive(struct strbuf *zip_path, enum diagnose_mode mode) +int create_diagnostics_archive(struct repository *r, + struct strbuf *zip_path, + enum diagnose_mode mode) { struct strvec archiver_args = STRVEC_INIT; char **argv_copy = NULL; @@ -218,7 +219,7 @@ int create_diagnostics_archive(struct strbuf *zip_path, enum diagnose_mode mode) strbuf_addstr(&buf, "Collecting diagnostic info\n\n"); get_version_info(&buf, 1); - strbuf_addf(&buf, "Repository root: %s\n", the_repository->worktree); + strbuf_addf(&buf, "Repository root: %s\n", r->worktree); get_disk_info(&buf); write_or_die(stdout_fd, buf.buf, buf.len); strvec_pushf(&archiver_args, @@ -227,7 +228,7 @@ int create_diagnostics_archive(struct strbuf *zip_path, enum diagnose_mode mode) strbuf_reset(&buf); strbuf_addstr(&buf, "--add-virtual-file=packs-local.txt:"); - dir_file_stats(the_repository->objects->odb, &buf); + dir_file_stats(r->objects->odb, &buf); foreach_alt_odb(dir_file_stats, &buf); strvec_push(&archiver_args, buf.buf); @@ -250,13 +251,13 @@ int create_diagnostics_archive(struct strbuf *zip_path, enum diagnose_mode mode) } strvec_pushl(&archiver_args, "--prefix=", - oid_to_hex(the_hash_algo->empty_tree), "--", NULL); + oid_to_hex(r->hash_algo->empty_tree), "--", NULL); /* `write_archive()` modifies the `argv` passed to it. Let it. */ argv_copy = xmemdupz(archiver_args.v, sizeof(char *) * archiver_args.nr); res = write_archive(archiver_args.nr, (const char **)argv_copy, NULL, - the_repository, NULL, 0); + r, NULL, 0); if (res) { error(_("failed to write archive")); goto diagnose_cleanup; diff --git a/diagnose.h b/diagnose.h index f525219ab0..f7b38f49f5 100644 --- a/diagnose.h +++ b/diagnose.h @@ -4,6 +4,7 @@ #include "strbuf.h" struct option; +struct repository; enum diagnose_mode { DIAGNOSE_NONE, @@ -13,6 +14,8 @@ enum diagnose_mode { int option_parse_diagnose(const struct option *opt, const char *arg, int unset); -int create_diagnostics_archive(struct strbuf *zip_path, enum diagnose_mode mode); +int create_diagnostics_archive(struct repository *r, + struct strbuf *zip_path, + enum diagnose_mode mode); #endif /* DIAGNOSE_H */ -- cgit v1.2.3 From 71e5afee8be62c9602838f859592539d8728cc56 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 17 Dec 2024 07:43:55 +0100 Subject: mailinfo: stop using `the_repository` Stop using `the_repository` in the "mailinfo" subsystem by passing in a repository when setting up the mailinfo structure. Adjust callers accordingly by using `the_repository`. While there may be some callers that have a repository available in their context, this trivial conversion allows for easier verification and bubbles up the use of `the_repository` by one level. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/am.c | 2 +- builtin/mailinfo.c | 2 +- mailinfo.c | 5 ++--- mailinfo.h | 4 +++- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/builtin/am.c b/builtin/am.c index 27ccca8341..e94d08e04b 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -1211,7 +1211,7 @@ static int parse_mail(struct am_state *state, const char *mail) int ret = 0; struct mailinfo mi; - setup_mailinfo(&mi); + setup_mailinfo(the_repository, &mi); if (state->utf8) mi.metainfo_charset = get_commit_output_encoding(); diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c index e17dec27b1..8de7ba7de1 100644 --- a/builtin/mailinfo.c +++ b/builtin/mailinfo.c @@ -83,7 +83,7 @@ int cmd_mailinfo(int argc, OPT_END() }; - setup_mailinfo(&mi); + setup_mailinfo(the_repository, &mi); meta_charset.policy = CHARSET_DEFAULT; argc = parse_options(argc, argv, prefix, options, mailinfo_usage, 0); diff --git a/mailinfo.c b/mailinfo.c index aa263bf490..7b001fa5db 100644 --- a/mailinfo.c +++ b/mailinfo.c @@ -1,4 +1,3 @@ -#define USE_THE_REPOSITORY_VARIABLE #define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" @@ -1269,7 +1268,7 @@ static int git_mailinfo_config(const char *var, const char *value, return 0; } -void setup_mailinfo(struct mailinfo *mi) +void setup_mailinfo(struct repository *r, struct mailinfo *mi) { memset(mi, 0, sizeof(*mi)); strbuf_init(&mi->name, 0); @@ -1281,7 +1280,7 @@ void setup_mailinfo(struct mailinfo *mi) mi->header_stage = 1; mi->use_inbody_headers = 1; mi->content_top = mi->content; - git_config(git_mailinfo_config, mi); + repo_config(r, git_mailinfo_config, mi); } void clear_mailinfo(struct mailinfo *mi) diff --git a/mailinfo.h b/mailinfo.h index f2ffd0349e..1f20664165 100644 --- a/mailinfo.h +++ b/mailinfo.h @@ -5,6 +5,8 @@ #define MAX_BOUNDARIES 5 +struct repository; + enum quoted_cr_action { quoted_cr_unset = -1, quoted_cr_nowarn, @@ -49,7 +51,7 @@ struct mailinfo { }; int mailinfo_parse_quoted_cr_action(const char *actionstr, int *action); -void setup_mailinfo(struct mailinfo *); +void setup_mailinfo(struct repository *r, struct mailinfo *); int mailinfo(struct mailinfo *, const char *msg, const char *patch); void clear_mailinfo(struct mailinfo *); -- cgit v1.2.3 From 6c27d22276b754e2214242de7a200b372aa611f6 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 17 Dec 2024 07:43:56 +0100 Subject: credential: stop using `the_repository` Stop using `the_repository` in the "credential" subsystem by passing in a repository when filling, approving or rejecting credentials. Adjust callers accordingly by using `the_repository`. While there may be some callers that have a repository available in their context, this trivial conversion allows for easier verification and bubbles up the use of `the_repository` by one level. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/credential.c | 6 +++--- credential.c | 34 +++++++++++++++++----------------- credential.h | 11 +++++++---- http.c | 24 ++++++++++++------------ imap-send.c | 10 +++++----- remote-curl.c | 4 ++-- 6 files changed, 46 insertions(+), 43 deletions(-) diff --git a/builtin/credential.c b/builtin/credential.c index 14c8c6608b..614b195b75 100644 --- a/builtin/credential.c +++ b/builtin/credential.c @@ -32,15 +32,15 @@ int cmd_credential(int argc, die("unable to read credential from stdin"); if (!strcmp(op, "fill")) { - credential_fill(&c, 0); + credential_fill(the_repository, &c, 0); credential_next_state(&c); credential_write(&c, stdout, CREDENTIAL_OP_RESPONSE); } else if (!strcmp(op, "approve")) { credential_set_all_capabilities(&c, CREDENTIAL_OP_HELPER); - credential_approve(&c); + credential_approve(the_repository, &c); } else if (!strcmp(op, "reject")) { credential_set_all_capabilities(&c, CREDENTIAL_OP_HELPER); - credential_reject(&c); + credential_reject(the_repository, &c); } else { usage(usage_msg); } diff --git a/credential.c b/credential.c index a995031c5f..b3f87b5b2f 100644 --- a/credential.c +++ b/credential.c @@ -1,4 +1,3 @@ -#define USE_THE_REPOSITORY_VARIABLE #define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" @@ -166,7 +165,7 @@ static int match_partial_url(const char *url, void *cb) return matches; } -static void credential_apply_config(struct credential *c) +static void credential_apply_config(struct repository *r, struct credential *c) { char *normalized_url; struct urlmatch_config config = URLMATCH_CONFIG_INIT; @@ -191,7 +190,7 @@ static void credential_apply_config(struct credential *c) credential_format(c, &url); normalized_url = url_normalize(url.buf, &config.url); - git_config(urlmatch_config_entry, &config); + repo_config(r, urlmatch_config_entry, &config); string_list_clear(&config.vars, 1); free(normalized_url); urlmatch_config_release(&config); @@ -254,34 +253,34 @@ static char *credential_ask_one(const char *what, struct credential *c, return xstrdup(r); } -static int credential_getpass(struct credential *c) +static int credential_getpass(struct repository *r, struct credential *c) { int interactive; char *value; - if (!git_config_get_maybe_bool("credential.interactive", &interactive) && + if (!repo_config_get_maybe_bool(r, "credential.interactive", &interactive) && !interactive) { - trace2_data_intmax("credential", the_repository, + trace2_data_intmax("credential", r, "interactive/skipped", 1); return -1; } - if (!git_config_get_string("credential.interactive", &value)) { + if (!repo_config_get_string(r, "credential.interactive", &value)) { int same = !strcmp(value, "never"); free(value); if (same) { - trace2_data_intmax("credential", the_repository, + trace2_data_intmax("credential", r, "interactive/skipped", 1); return -1; } } - trace2_region_enter("credential", "interactive", the_repository); + trace2_region_enter("credential", "interactive", r); if (!c->username) c->username = credential_ask_one("Username", c, PROMPT_ASKPASS|PROMPT_ECHO); if (!c->password) c->password = credential_ask_one("Password", c, PROMPT_ASKPASS); - trace2_region_leave("credential", "interactive", the_repository); + trace2_region_leave("credential", "interactive", r); return 0; } @@ -489,7 +488,8 @@ static int credential_do(struct credential *c, const char *helper, return r; } -void credential_fill(struct credential *c, int all_capabilities) +void credential_fill(struct repository *r, + struct credential *c, int all_capabilities) { int i; @@ -499,7 +499,7 @@ void credential_fill(struct credential *c, int all_capabilities) credential_next_state(c); c->multistage = 0; - credential_apply_config(c); + credential_apply_config(r, c); if (all_capabilities) credential_set_all_capabilities(c, CREDENTIAL_OP_INITIAL); @@ -526,12 +526,12 @@ void credential_fill(struct credential *c, int all_capabilities) c->helpers.items[i].string); } - if (credential_getpass(c) || + if (credential_getpass(r, c) || (!c->username && !c->password && !c->credential)) die("unable to get password from user"); } -void credential_approve(struct credential *c) +void credential_approve(struct repository *r, struct credential *c) { int i; @@ -542,20 +542,20 @@ void credential_approve(struct credential *c) credential_next_state(c); - credential_apply_config(c); + credential_apply_config(r, c); for (i = 0; i < c->helpers.nr; i++) credential_do(c, c->helpers.items[i].string, "store"); c->approved = 1; } -void credential_reject(struct credential *c) +void credential_reject(struct repository *r, struct credential *c) { int i; credential_next_state(c); - credential_apply_config(c); + credential_apply_config(r, c); for (i = 0; i < c->helpers.nr; i++) credential_do(c, c->helpers.items[i].string, "erase"); diff --git a/credential.h b/credential.h index 5f9e6ff2ef..1e6b0dc5b0 100644 --- a/credential.h +++ b/credential.h @@ -4,6 +4,8 @@ #include "string-list.h" #include "strvec.h" +struct repository; + /** * The credentials API provides an abstracted way of gathering * authentication credentials from the user. @@ -65,7 +67,7 @@ * // Fill in the username and password fields by contacting * // helpers and/or asking the user. The function will die if it * // fails. - * credential_fill(&c); + * credential_fill(repo, &c); * * // Otherwise, we have a username and password. Try to use it. * @@ -218,7 +220,8 @@ void credential_clear(struct credential *); * If all_capabilities is set, this is an internal user that is prepared * to deal with all known capabilities, and we should advertise that fact. */ -void credential_fill(struct credential *, int all_capabilities); +void credential_fill(struct repository *, struct credential *, + int all_capabilities); /** * Inform the credential subsystem that the provided credentials @@ -227,7 +230,7 @@ void credential_fill(struct credential *, int all_capabilities); * that they may store the result to be used again. Any errors * from helpers are ignored. */ -void credential_approve(struct credential *); +void credential_approve(struct repository *, struct credential *); /** * Inform the credential subsystem that the provided credentials @@ -239,7 +242,7 @@ void credential_approve(struct credential *); * for another call to `credential_fill`). Any errors from helpers * are ignored. */ -void credential_reject(struct credential *); +void credential_reject(struct repository *, struct credential *); /** * Enable all of the supported credential flags in this credential. diff --git a/http.c b/http.c index c8fc15aa11..f08b2ae474 100644 --- a/http.c +++ b/http.c @@ -609,7 +609,7 @@ static void init_curl_http_auth(CURL *result) } } - credential_fill(&http_auth, 1); + credential_fill(the_repository, &http_auth, 1); if (http_auth.password) { if (always_auth_proactively()) { @@ -652,7 +652,7 @@ static void init_curl_proxy_auth(CURL *result) { if (proxy_auth.username) { if (!proxy_auth.password && !proxy_auth.credential) - credential_fill(&proxy_auth, 1); + credential_fill(the_repository, &proxy_auth, 1); set_proxyauth_name_password(result); } @@ -686,7 +686,7 @@ static int has_cert_password(void) cert_auth.host = xstrdup(""); cert_auth.username = xstrdup(""); cert_auth.path = xstrdup(ssl_cert); - credential_fill(&cert_auth, 0); + credential_fill(the_repository, &cert_auth, 0); } return 1; } @@ -700,7 +700,7 @@ static int has_proxy_cert_password(void) proxy_cert_auth.host = xstrdup(""); proxy_cert_auth.username = xstrdup(""); proxy_cert_auth.path = xstrdup(http_proxy_ssl_cert); - credential_fill(&proxy_cert_auth, 0); + credential_fill(the_repository, &proxy_cert_auth, 0); } return 1; } @@ -1784,9 +1784,9 @@ static int handle_curl_result(struct slot_results *results) curl_errorstr, sizeof(curl_errorstr)); if (results->curl_result == CURLE_OK) { - credential_approve(&http_auth); - credential_approve(&proxy_auth); - credential_approve(&cert_auth); + credential_approve(the_repository, &http_auth); + credential_approve(the_repository, &proxy_auth); + credential_approve(the_repository, &cert_auth); return HTTP_OK; } else if (results->curl_result == CURLE_SSL_CERTPROBLEM) { /* @@ -1795,7 +1795,7 @@ static int handle_curl_result(struct slot_results *results) * with the certificate. So we reject the credential to * avoid caching or saving a bad password. */ - credential_reject(&cert_auth); + credential_reject(the_repository, &cert_auth); return HTTP_NOAUTH; } else if (results->curl_result == CURLE_SSL_PINNEDPUBKEYNOTMATCH) { return HTTP_NOMATCHPUBLICKEY; @@ -1808,7 +1808,7 @@ static int handle_curl_result(struct slot_results *results) credential_clear_secrets(&http_auth); return HTTP_REAUTH; } - credential_reject(&http_auth); + credential_reject(the_repository, &http_auth); if (always_auth_proactively()) http_proactive_auth = PROACTIVE_AUTH_NONE; return HTTP_NOAUTH; @@ -1822,7 +1822,7 @@ static int handle_curl_result(struct slot_results *results) } } else { if (results->http_connectcode == 407) - credential_reject(&proxy_auth); + credential_reject(the_repository, &proxy_auth); if (!curl_errorstr[0]) strlcpy(curl_errorstr, curl_easy_strerror(results->curl_result), @@ -2210,7 +2210,7 @@ static int http_request_reauth(const char *url, int ret; if (always_auth_proactively()) - credential_fill(&http_auth, 1); + credential_fill(the_repository, &http_auth, 1); ret = http_request(url, result, target, options); @@ -2251,7 +2251,7 @@ static int http_request_reauth(const char *url, BUG("Unknown http_request target"); } - credential_fill(&http_auth, 1); + credential_fill(the_repository, &http_auth, 1); ret = http_request(url, result, target, options); } diff --git a/imap-send.c b/imap-send.c index 68ab1aea83..6c8f84e836 100644 --- a/imap-send.c +++ b/imap-send.c @@ -922,7 +922,7 @@ static void server_fill_credential(struct imap_server_conf *srvc, struct credent cred->username = xstrdup_or_null(srvc->user); cred->password = xstrdup_or_null(srvc->pass); - credential_fill(cred, 1); + credential_fill(the_repository, cred, 1); if (!srvc->user) srvc->user = xstrdup(cred->username); @@ -1123,7 +1123,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c } /* !preauth */ if (cred.username) - credential_approve(&cred); + credential_approve(the_repository, &cred); credential_clear(&cred); /* check the target mailbox exists */ @@ -1150,7 +1150,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c bail: if (cred.username) - credential_reject(&cred); + credential_reject(the_repository, &cred); credential_clear(&cred); out: @@ -1492,9 +1492,9 @@ static int curl_append_msgs_to_imap(struct imap_server_conf *server, if (cred.username) { if (res == CURLE_OK) - credential_approve(&cred); + credential_approve(the_repository, &cred); else if (res == CURLE_LOGIN_DENIED) - credential_reject(&cred); + credential_reject(the_repository, &cred); } credential_clear(&cred); diff --git a/remote-curl.c b/remote-curl.c index a24e3a8b9a..1273507a96 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -942,7 +942,7 @@ static int post_rpc(struct rpc_state *rpc, int stateless_connect, int flush_rece do { err = probe_rpc(rpc, &results); if (err == HTTP_REAUTH) - credential_fill(&http_auth, 0); + credential_fill(the_repository, &http_auth, 0); } while (err == HTTP_REAUTH); if (err != HTTP_OK) return -1; @@ -1064,7 +1064,7 @@ retry: rpc->any_written = 0; err = run_slot(slot, NULL); if (err == HTTP_REAUTH && !large_request) { - credential_fill(&http_auth, 0); + credential_fill(the_repository, &http_auth, 0); curl_slist_free_all(headers); goto retry; } -- cgit v1.2.3 From b81093aeae557d56277773dee710eb363c720b6e Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 17 Dec 2024 07:43:57 +0100 Subject: resolve-undo: stop using `the_repository` Stop using `the_repository` in the "resolve-undo" subsystem by passing in the hash algorithm when reading or writing resolve-undo information. While we could trivially update the caller to pass in the hash algorithm used by the index itself, we instead pass in `the_hash_algo`. This is mostly done to stay consistent with the rest of the code in that file, which isn't prepared to handle arbitrary repositories, either. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- read-cache.c | 4 ++-- resolve-undo.c | 14 +++++++------- resolve-undo.h | 6 ++++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/read-cache.c b/read-cache.c index 38c36caa7f..d54be2c172 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1754,7 +1754,7 @@ static int read_index_extension(struct index_state *istate, istate->cache_tree = cache_tree_read(data, sz); break; case CACHE_EXT_RESOLVE_UNDO: - istate->resolve_undo = resolve_undo_read(data, sz); + istate->resolve_undo = resolve_undo_read(data, sz, the_hash_algo); break; case CACHE_EXT_LINK: if (read_link_extension(istate, data, sz)) @@ -3033,7 +3033,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, istate->resolve_undo) { strbuf_reset(&sb); - resolve_undo_write(&sb, istate->resolve_undo); + resolve_undo_write(&sb, istate->resolve_undo, the_hash_algo); err = write_index_ext_header(f, eoie_c, CACHE_EXT_RESOLVE_UNDO, sb.len) < 0; hashwrite(f, sb.buf, sb.len); diff --git a/resolve-undo.c b/resolve-undo.c index b5a9dfb4ac..52c45e5a49 100644 --- a/resolve-undo.c +++ b/resolve-undo.c @@ -1,4 +1,3 @@ -#define USE_THE_REPOSITORY_VARIABLE #define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" @@ -34,7 +33,8 @@ void record_resolve_undo(struct index_state *istate, struct cache_entry *ce) ui->mode[stage - 1] = ce->ce_mode; } -void resolve_undo_write(struct strbuf *sb, struct string_list *resolve_undo) +void resolve_undo_write(struct strbuf *sb, struct string_list *resolve_undo, + const struct git_hash_algo *algop) { struct string_list_item *item; for_each_string_list_item(item, resolve_undo) { @@ -50,18 +50,19 @@ void resolve_undo_write(struct strbuf *sb, struct string_list *resolve_undo) for (i = 0; i < 3; i++) { if (!ui->mode[i]) continue; - strbuf_add(sb, ui->oid[i].hash, the_hash_algo->rawsz); + strbuf_add(sb, ui->oid[i].hash, algop->rawsz); } } } -struct string_list *resolve_undo_read(const char *data, unsigned long size) +struct string_list *resolve_undo_read(const char *data, unsigned long size, + const struct git_hash_algo *algop) { struct string_list *resolve_undo; size_t len; char *endptr; int i; - const unsigned rawsz = the_hash_algo->rawsz; + const unsigned rawsz = algop->rawsz; CALLOC_ARRAY(resolve_undo, 1); resolve_undo->strdup_strings = 1; @@ -96,8 +97,7 @@ struct string_list *resolve_undo_read(const char *data, unsigned long size) continue; if (size < rawsz) goto error; - oidread(&ui->oid[i], (const unsigned char *)data, - the_repository->hash_algo); + oidread(&ui->oid[i], (const unsigned char *)data, algop); size -= rawsz; data += rawsz; } diff --git a/resolve-undo.h b/resolve-undo.h index 89a3227262..7ed11a1c59 100644 --- a/resolve-undo.h +++ b/resolve-undo.h @@ -14,8 +14,10 @@ struct resolve_undo_info { }; void record_resolve_undo(struct index_state *, struct cache_entry *); -void resolve_undo_write(struct strbuf *, struct string_list *); -struct string_list *resolve_undo_read(const char *, unsigned long); +void resolve_undo_write(struct strbuf *, struct string_list *, + const struct git_hash_algo *algop); +struct string_list *resolve_undo_read(const char *, unsigned long, + const struct git_hash_algo *algop); void resolve_undo_clear_index(struct index_state *); int unmerge_index_entry(struct index_state *, const char *, struct resolve_undo_info *, unsigned); void unmerge_index(struct index_state *, const struct pathspec *, unsigned); -- cgit v1.2.3 From 727c71a1121c2067223aad8d187409c9822a3f8d Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 17 Dec 2024 07:43:58 +0100 Subject: tmp-objdir: stop using `the_repository` Stop using `the_repository` in the "tmp-objdir" subsystem by passing in the repostiroy when creating a new temporary object directory. While we could trivially update the caller to pass in the hash algorithm used by the index itself, we instead pass in `the_hash_algo`. This is mostly done to stay consistent with the rest of the code in that file, which isn't prepared to handle arbitrary repositories, either. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/receive-pack.c | 2 +- bulk-checkin.c | 2 +- log-tree.c | 2 +- tmp-objdir.c | 15 ++++++++------- tmp-objdir.h | 5 +++-- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 191b5eeb34..56347a7963 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -2239,7 +2239,7 @@ static const char *unpack(int err_fd, struct shallow_info *si) strvec_push(&child.args, alt_shallow_file); } - tmp_objdir = tmp_objdir_create("incoming"); + tmp_objdir = tmp_objdir_create(the_repository, "incoming"); if (!tmp_objdir) { if (err_fd > 0) close(err_fd); diff --git a/bulk-checkin.c b/bulk-checkin.c index 4a70a70a95..f7b15e3999 100644 --- a/bulk-checkin.c +++ b/bulk-checkin.c @@ -333,7 +333,7 @@ void prepare_loose_object_bulk_checkin(void) if (!odb_transaction_nesting || bulk_fsync_objdir) return; - bulk_fsync_objdir = tmp_objdir_create("bulk-fsync"); + bulk_fsync_objdir = tmp_objdir_create(the_repository, "bulk-fsync"); if (bulk_fsync_objdir) tmp_objdir_replace_primary_odb(bulk_fsync_objdir, 0); } diff --git a/log-tree.c b/log-tree.c index d08eb672a9..8b184d6776 100644 --- a/log-tree.c +++ b/log-tree.c @@ -1042,7 +1042,7 @@ static int do_remerge_diff(struct rev_info *opt, * into the alternative object store list as the primary. */ if (opt->remerge_diff && !opt->remerge_objdir) { - opt->remerge_objdir = tmp_objdir_create("remerge-diff"); + opt->remerge_objdir = tmp_objdir_create(the_repository, "remerge-diff"); if (!opt->remerge_objdir) return error(_("unable to create temporary object directory")); tmp_objdir_replace_primary_odb(opt->remerge_objdir, 1); diff --git a/tmp-objdir.c b/tmp-objdir.c index 659fcdcc29..0ea078a5c5 100644 --- a/tmp-objdir.c +++ b/tmp-objdir.c @@ -1,5 +1,3 @@ -#define USE_THE_REPOSITORY_VARIABLE - #include "git-compat-util.h" #include "tmp-objdir.h" #include "abspath.h" @@ -16,6 +14,7 @@ #include "repository.h" struct tmp_objdir { + struct repository *repo; struct strbuf path; struct strvec env; struct object_directory *prev_odb; @@ -116,7 +115,8 @@ static int setup_tmp_objdir(const char *root) return ret; } -struct tmp_objdir *tmp_objdir_create(const char *prefix) +struct tmp_objdir *tmp_objdir_create(struct repository *r, + const char *prefix) { static int installed_handlers; struct tmp_objdir *t; @@ -125,6 +125,7 @@ struct tmp_objdir *tmp_objdir_create(const char *prefix) BUG("only one tmp_objdir can be used at a time"); t = xcalloc(1, sizeof(*t)); + t->repo = r; strbuf_init(&t->path, 0); strvec_init(&t->env); @@ -134,7 +135,7 @@ struct tmp_objdir *tmp_objdir_create(const char *prefix) * them. */ strbuf_addf(&t->path, "%s/tmp_objdir-%s-XXXXXX", - repo_get_object_directory(the_repository), prefix); + repo_get_object_directory(r), prefix); if (!mkdtemp(t->path.buf)) { /* free, not destroy, as we never touched the filesystem */ @@ -154,7 +155,7 @@ struct tmp_objdir *tmp_objdir_create(const char *prefix) } env_append(&t->env, ALTERNATE_DB_ENVIRONMENT, - absolute_path(repo_get_object_directory(the_repository))); + absolute_path(repo_get_object_directory(r))); env_replace(&t->env, DB_ENVIRONMENT, absolute_path(t->path.buf)); env_replace(&t->env, GIT_QUARANTINE_ENVIRONMENT, absolute_path(t->path.buf)); @@ -273,14 +274,14 @@ int tmp_objdir_migrate(struct tmp_objdir *t) return 0; if (t->prev_odb) { - if (the_repository->objects->odb->will_destroy) + if (t->repo->objects->odb->will_destroy) BUG("migrating an ODB that was marked for destruction"); restore_primary_odb(t->prev_odb, t->path.buf); t->prev_odb = NULL; } strbuf_addbuf(&src, &t->path); - strbuf_addstr(&dst, repo_get_object_directory(the_repository)); + strbuf_addstr(&dst, repo_get_object_directory(t->repo)); ret = migrate_paths(&src, &dst, 0); diff --git a/tmp-objdir.h b/tmp-objdir.h index 237d96b660..fceda14979 100644 --- a/tmp-objdir.h +++ b/tmp-objdir.h @@ -11,7 +11,7 @@ * Example: * * struct child_process child = CHILD_PROCESS_INIT; - * struct tmp_objdir *t = tmp_objdir_create("incoming"); + * struct tmp_objdir *t = tmp_objdir_create(repo, "incoming"); * strvec_push(&child.args, cmd); * strvec_pushv(&child.env, tmp_objdir_env(t)); * if (!run_command(&child)) && !tmp_objdir_migrate(t)) @@ -21,13 +21,14 @@ * */ +struct repository; struct tmp_objdir; /* * Create a new temporary object directory with the specified prefix; * returns NULL on failure. */ -struct tmp_objdir *tmp_objdir_create(const char *prefix); +struct tmp_objdir *tmp_objdir_create(struct repository *r, const char *prefix); /* * Return a list of environment strings, suitable for use with -- cgit v1.2.3 From 1b374ad71f702cd13f7395ccff54d5c4ee604b98 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 17 Dec 2024 07:43:59 +0100 Subject: add-interactive: stop using `the_repository` Stop using `the_repository` in the "add-interactive" subsystem by reusing the repository we already have available via parameters or in the `add_i_state` structure. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- add-interactive.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/add-interactive.c b/add-interactive.c index d0f8c10e6f..97ff35b6f1 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -1,4 +1,3 @@ -#define USE_THE_REPOSITORY_VARIABLE #define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" @@ -72,14 +71,14 @@ void init_add_i_state(struct add_i_state *s, struct repository *r) s->use_color ? GIT_COLOR_RESET : "", COLOR_MAXLEN); FREE_AND_NULL(s->interactive_diff_filter); - git_config_get_string("interactive.difffilter", - &s->interactive_diff_filter); + repo_config_get_string(r, "interactive.difffilter", + &s->interactive_diff_filter); FREE_AND_NULL(s->interactive_diff_algorithm); - git_config_get_string("diff.algorithm", - &s->interactive_diff_algorithm); + repo_config_get_string(r, "diff.algorithm", + &s->interactive_diff_algorithm); - git_config_get_bool("interactive.singlekey", &s->use_single_key); + repo_config_get_bool(r, "interactive.singlekey", &s->use_single_key); if (s->use_single_key) setbuf(stdin, NULL); } @@ -535,7 +534,7 @@ static int get_modified_files(struct repository *r, size_t *binary_count) { struct object_id head_oid; - int is_initial = !refs_resolve_ref_unsafe(get_main_ref_store(the_repository), + int is_initial = !refs_resolve_ref_unsafe(get_main_ref_store(r), "HEAD", RESOLVE_REF_READING, &head_oid, NULL); struct collection_status s = { 0 }; @@ -560,7 +559,7 @@ static int get_modified_files(struct repository *r, s.skip_unseen = filter && i; opt.def = is_initial ? - empty_tree_oid_hex(the_repository->hash_algo) : oid_to_hex(&head_oid); + empty_tree_oid_hex(r->hash_algo) : oid_to_hex(&head_oid); repo_init_revisions(r, &rev, NULL); setup_revisions(0, NULL, &rev, &opt); @@ -765,7 +764,7 @@ static int run_revert(struct add_i_state *s, const struct pathspec *ps, size_t count, i, j; struct object_id oid; - int is_initial = !refs_resolve_ref_unsafe(get_main_ref_store(the_repository), + int is_initial = !refs_resolve_ref_unsafe(get_main_ref_store(s->r), "HEAD", RESOLVE_REF_READING, &oid, NULL); @@ -996,7 +995,7 @@ static int run_diff(struct add_i_state *s, const struct pathspec *ps, ssize_t count, i; struct object_id oid; - int is_initial = !refs_resolve_ref_unsafe(get_main_ref_store(the_repository), + int is_initial = !refs_resolve_ref_unsafe(get_main_ref_store(s->r), "HEAD", RESOLVE_REF_READING, &oid, NULL); -- cgit v1.2.3 From e1335a940748d8e525b3a5e095f352c85644accf Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 17 Dec 2024 07:44:00 +0100 Subject: graph: stop using `the_repository` Stop using `the_repository` in the "graph" subsystem by reusing the repository we already have available via `struct rev_info`. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- graph.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/graph.c b/graph.c index 52205f75c3..26f6fbf000 100644 --- a/graph.c +++ b/graph.c @@ -1,4 +1,3 @@ -#define USE_THE_REPOSITORY_VARIABLE #define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" @@ -351,7 +350,7 @@ struct git_graph *graph_init(struct rev_info *opt) if (!column_colors) { char *string; - if (git_config_get_string("log.graphcolors", &string)) { + if (repo_config_get_string(opt->repo, "log.graphcolors", &string)) { /* not configured -- use default */ graph_set_column_colors(column_colors_ansi, column_colors_ansi_max); -- cgit v1.2.3 From d4cd757051d1c779f1d95557b7ac523a6e1803fc Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 17 Dec 2024 07:44:01 +0100 Subject: match-trees: stop using `the_repository` Stop using `the_repository` in the "match-trees" subsystem by passing down the already-available repository parameters to internal functions as required. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- match-trees.c | 50 +++++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/match-trees.c b/match-trees.c index a1c8b91eae..ef14ceb594 100644 --- a/match-trees.c +++ b/match-trees.c @@ -1,4 +1,3 @@ -#define USE_THE_REPOSITORY_VARIABLE #define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" @@ -8,6 +7,7 @@ #include "tree.h" #include "tree-walk.h" #include "object-store-ll.h" +#include "repository.h" static int score_missing(unsigned mode) { @@ -54,14 +54,15 @@ static int score_matches(unsigned mode1, unsigned mode2) return score; } -static void *fill_tree_desc_strict(struct tree_desc *desc, +static void *fill_tree_desc_strict(struct repository *r, + struct tree_desc *desc, const struct object_id *hash) { void *buffer; enum object_type type; unsigned long size; - buffer = repo_read_object_file(the_repository, hash, &type, &size); + buffer = repo_read_object_file(r, hash, &type, &size); if (!buffer) die("unable to read tree (%s)", oid_to_hex(hash)); if (type != OBJ_TREE) @@ -80,12 +81,13 @@ static int base_name_entries_compare(const struct name_entry *a, /* * Inspect two trees, and give a score that tells how similar they are. */ -static int score_trees(const struct object_id *hash1, const struct object_id *hash2) +static int score_trees(struct repository *r, + const struct object_id *hash1, const struct object_id *hash2) { struct tree_desc one; struct tree_desc two; - void *one_buf = fill_tree_desc_strict(&one, hash1); - void *two_buf = fill_tree_desc_strict(&two, hash2); + void *one_buf = fill_tree_desc_strict(r, &one, hash1); + void *two_buf = fill_tree_desc_strict(r, &two, hash2); int score = 0; for (;;) { @@ -133,7 +135,8 @@ static int score_trees(const struct object_id *hash1, const struct object_id *ha /* * Match one itself and its subtrees with two and pick the best match. */ -static void match_trees(const struct object_id *hash1, +static void match_trees(struct repository *r, + const struct object_id *hash1, const struct object_id *hash2, int *best_score, char **best_match, @@ -141,7 +144,7 @@ static void match_trees(const struct object_id *hash1, int recurse_limit) { struct tree_desc one; - void *one_buf = fill_tree_desc_strict(&one, hash1); + void *one_buf = fill_tree_desc_strict(r, &one, hash1); while (one.size) { const char *path; @@ -152,7 +155,7 @@ static void match_trees(const struct object_id *hash1, elem = tree_entry_extract(&one, &path, &mode); if (!S_ISDIR(mode)) goto next; - score = score_trees(elem, hash2); + score = score_trees(r, elem, hash2); if (*best_score < score) { free(*best_match); *best_match = xstrfmt("%s%s", base, path); @@ -160,7 +163,7 @@ static void match_trees(const struct object_id *hash1, } if (recurse_limit) { char *newbase = xstrfmt("%s%s/", base, path); - match_trees(elem, hash2, best_score, best_match, + match_trees(r, elem, hash2, best_score, best_match, newbase, recurse_limit - 1); free(newbase); } @@ -175,7 +178,8 @@ static void match_trees(const struct object_id *hash1, * A tree "oid1" has a subdirectory at "prefix". Come up with a tree object by * replacing it with another tree "oid2". */ -static int splice_tree(const struct object_id *oid1, const char *prefix, +static int splice_tree(struct repository *r, + const struct object_id *oid1, const char *prefix, const struct object_id *oid2, struct object_id *result) { char *subpath; @@ -194,7 +198,7 @@ static int splice_tree(const struct object_id *oid1, const char *prefix, if (*subpath) subpath++; - buf = repo_read_object_file(the_repository, oid1, &type, &sz); + buf = repo_read_object_file(r, oid1, &type, &sz); if (!buf) die("cannot read tree %s", oid_to_hex(oid1)); init_tree_desc(&desc, oid1, buf, sz); @@ -232,15 +236,15 @@ static int splice_tree(const struct object_id *oid1, const char *prefix, oid_to_hex(oid1)); if (*subpath) { struct object_id tree_oid; - oidread(&tree_oid, rewrite_here, the_repository->hash_algo); - status = splice_tree(&tree_oid, subpath, oid2, &subtree); + oidread(&tree_oid, rewrite_here, r->hash_algo); + status = splice_tree(r, &tree_oid, subpath, oid2, &subtree); if (status) return status; rewrite_with = &subtree; } else { rewrite_with = oid2; } - hashcpy(rewrite_here, rewrite_with->hash, the_repository->hash_algo); + hashcpy(rewrite_here, rewrite_with->hash, r->hash_algo); status = write_object_file(buf, sz, OBJ_TREE, result); free(buf); return status; @@ -271,7 +275,7 @@ void shift_tree(struct repository *r, if (!depth_limit) depth_limit = 2; - add_score = del_score = score_trees(hash1, hash2); + add_score = del_score = score_trees(r, hash1, hash2); add_prefix = xcalloc(1, 1); del_prefix = xcalloc(1, 1); @@ -279,13 +283,13 @@ void shift_tree(struct repository *r, * See if one's subtree resembles two; if so we need to prefix * two with a few fake trees to match the prefix. */ - match_trees(hash1, hash2, &add_score, &add_prefix, "", depth_limit); + match_trees(r, hash1, hash2, &add_score, &add_prefix, "", depth_limit); /* * See if two's subtree resembles one; if so we need to * pick only subtree of two. */ - match_trees(hash2, hash1, &del_score, &del_prefix, "", depth_limit); + match_trees(r, hash2, hash1, &del_score, &del_prefix, "", depth_limit); /* Assume we do not have to do any shifting */ oidcpy(shifted, hash2); @@ -306,7 +310,7 @@ void shift_tree(struct repository *r, if (!*add_prefix) goto out; - splice_tree(hash1, add_prefix, hash2, shifted); + splice_tree(r, hash1, add_prefix, hash2, shifted); out: free(add_prefix); @@ -340,16 +344,16 @@ void shift_tree_by(struct repository *r, if (candidate == 3) { /* Both are plausible -- we need to evaluate the score */ - int best_score = score_trees(hash1, hash2); + int best_score = score_trees(r, hash1, hash2); int score; candidate = 0; - score = score_trees(&sub1, hash2); + score = score_trees(r, &sub1, hash2); if (score > best_score) { candidate = 1; best_score = score; } - score = score_trees(&sub2, hash1); + score = score_trees(r, &sub2, hash1); if (score > best_score) candidate = 2; } @@ -365,7 +369,7 @@ void shift_tree_by(struct repository *r, * shift tree2 down by adding shift_prefix above it * to match tree1. */ - splice_tree(hash1, shift_prefix, hash2, shifted); + splice_tree(r, hash1, shift_prefix, hash2, shifted); else /* * shift tree2 up by removing shift_prefix from it -- cgit v1.2.3 From 7525cd8c3522827be57915941ebbba859c45ce0b Mon Sep 17 00:00:00 2001 From: Seija Kijin Date: Wed, 18 Dec 2024 16:48:32 +0000 Subject: git: use calloc instead of malloc + memset where possible Avoid calling malloc + memset by calling calloc. Signed-off-by: Seija Kijin Signed-off-by: Junio C Hamano --- remote.c | 4 ++-- submodule.c | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/remote.c b/remote.c index 10104d11e3..462ff10527 100644 --- a/remote.c +++ b/remote.c @@ -2854,9 +2854,9 @@ void apply_push_cas(struct push_cas_option *cas, struct remote_state *remote_state_new(void) { - struct remote_state *r = xmalloc(sizeof(*r)); + struct remote_state *r; - memset(r, 0, sizeof(*r)); + CALLOC_ARRAY(r, 1); hashmap_init(&r->remotes_hash, remotes_hash_cmp, NULL, 0); hashmap_init(&r->branches_hash, branches_hash_cmp, NULL, 0); diff --git a/submodule.c b/submodule.c index 7ec564854d..7707c6f48f 100644 --- a/submodule.c +++ b/submodule.c @@ -1489,14 +1489,13 @@ struct fetch_task { */ static const struct submodule *get_non_gitmodules_submodule(const char *path) { - struct submodule *ret = NULL; + struct submodule *ret; const char *name = default_name_or_path(path); if (!name) return NULL; - ret = xmalloc(sizeof(*ret)); - memset(ret, 0, sizeof(*ret)); + CALLOC_ARRAY(ret, 1); ret->path = name; ret->name = name; @@ -1536,8 +1535,9 @@ static struct fetch_task *fetch_task_create(struct submodule_parallel_fetch *spf const char *path, const struct object_id *treeish_name) { - struct fetch_task *task = xmalloc(sizeof(*task)); - memset(task, 0, sizeof(*task)); + struct fetch_task *task; + + CALLOC_ARRAY(task, 1); if (validate_submodule_path(path) < 0) exit(128); -- cgit v1.2.3 From ff795a5c5ed2e2d07c688c217a615d89e3f5733b Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 19 Dec 2024 10:57:38 -0800 Subject: Finishing touches before 2.48-rc1 Signed-off-by: Junio C Hamano --- Documentation/RelNotes/2.48.0.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Documentation/RelNotes/2.48.0.txt b/Documentation/RelNotes/2.48.0.txt index dc11ce58be..cc752d5466 100644 --- a/Documentation/RelNotes/2.48.0.txt +++ b/Documentation/RelNotes/2.48.0.txt @@ -28,6 +28,13 @@ UI, Workflows & Features both learned to trigger fsck over the new objects with configurable fck check levels. + * When "git fetch $remote" notices that refs/remotes/$remote/HEAD is + missing and discovers what branch the other side points with its + HEAD, refs/remotes/$remote/HEAD is updated to point to it. + + * "git fetch" honors "remote..followRemoteHEAD" settings to + tweak the remote-tracking HEAD in "refs/remotes//HEAD". + Performance, Internal Implementation, Development Support etc. -------------------------------------------------------------- @@ -265,6 +272,14 @@ Fixes since v2.47 * Fix performance regression of a recent "fatten promisor pack with local objects" protection against an unwanted gc. + * "git log -p --remerge-diff --reverse" was completely broken. + (merge f94bfa1516 js/log-remerge-keep-ancestry later to maint). + + * "git bundle create" with an annotated tag on the positive end of + the revision range had a workaround code for older limitation in + the revision walker, which has become unnecessary. + (merge dd1072dfa8 tc/bundle-with-tag-remove-workaround later to maint). + * Other code cleanup, docfix, build fix, etc. (merge 77af53f56f aa/t7300-modernize later to maint). (merge dcd590a39d bf/t-readme-mention-reftable later to maint). @@ -273,3 +288,4 @@ Fixes since v2.47 (merge 168ebb7159 jc/doc-error-message-guidelines later to maint). (merge 18693d7d65 kh/doc-bundle-typofix later to maint). (merge e2f5d3b491 kh/doc-update-ref-grammofix later to maint). + (merge 8525e92886 mh/doc-windows-home-env later to maint). -- cgit v1.2.3 From 62e745ced221263717d86d1d50ffcaa029d63c4c Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 20 Dec 2024 03:49:49 -0500 Subject: prio-queue: use size_t rather than int for size The alloc and nr fields of a prio-queue tell us how much memory is allocated and used in the array. So the natural type for them is size_t, which prevents overflow on 64-bit systems where "int" is still 32 bits. This is unlikely to happen in practice, as we typically use it for storing commits, and having 2^31 of those is rather a lot. But it's good to keep our generic data structures as flexible as possible. And as we start to enforce -Wsign-compare, it means that callers need to use "int", too, and the problem proliferates. Let's fix it at the source. The changes here can be put into a few groups: 1. Changing the alloc/nr fields in the struct to size_t. This requires swapping out int for size_t in negotiator/skipping.c, as well as in prio_queue_get(), because those all iterate over the array. Building with -Wsign-compare complains about these. 2. Other code that assigns or passes around indexes into the array (e.g., the swap() and compare() functions) won't trigger -Wsign-compare because we are simply truncating the values. These are caught by -Wconversion, but I've adjusted them here to future-proof us. 3. In prio_queue_reverse() we compute "queue->nr - 1" without checking if anything is in the queue, which underflows now that nr is unsigned. We can fix that by returning early when the queue is empty (there is nothing to reverse). 4. The insertion_ctr variable is currently unsigned, but can likewise grow (it is actually worse, because adding and removing an element many times will keep increasing the counter, even though "nr" does not). I've bumped that to size_t here, as well. But -Wconversion notes that computing the "cmp" result by subtracting the counters and assigning to "int" is a potential problem. And that's true even before this patch, since we use an unsigned counter (imagine comparing "2^32-1" and "0", which should be a high positive value, but instead is "-1" as a signed int). Since we only care about the sign (and not the magnitude) of the result, we could fix this by swapping out the subtraction for a ternary comparison. Probably the performance impact would be negligible, since we just called into a custom compare function and branched on its result anyway. But it's easy enough to do a branchless version by subtracting the comparison results. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- negotiator/skipping.c | 5 ++--- prio-queue.c | 15 +++++++++------ prio-queue.h | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/negotiator/skipping.c b/negotiator/skipping.c index abedb70a48..616df6bf3a 100644 --- a/negotiator/skipping.c +++ b/negotiator/skipping.c @@ -134,7 +134,6 @@ static int push_parent(struct data *data, struct entry *entry, struct entry *parent_entry; if (to_push->object.flags & SEEN) { - int i; if (to_push->object.flags & POPPED) /* * The entry for this commit has already been popped, @@ -145,7 +144,7 @@ static int push_parent(struct data *data, struct entry *entry, /* * Find the existing entry and use it. */ - for (i = 0; i < data->rev_list.nr; i++) { + for (size_t i = 0; i < data->rev_list.nr; i++) { parent_entry = data->rev_list.array[i].data; if (parent_entry->commit == to_push) goto parent_found; @@ -248,7 +247,7 @@ static int ack(struct fetch_negotiator *n, struct commit *c) static void release(struct fetch_negotiator *n) { struct data *data = n->data; - for (int i = 0; i < data->rev_list.nr; i++) + for (size_t i = 0; i < data->rev_list.nr; i++) free(data->rev_list.array[i].data); clear_prio_queue(&data->rev_list); FREE_AND_NULL(data); diff --git a/prio-queue.c b/prio-queue.c index 450775a374..ec33ac27db 100644 --- a/prio-queue.c +++ b/prio-queue.c @@ -1,26 +1,29 @@ #include "git-compat-util.h" #include "prio-queue.h" -static inline int compare(struct prio_queue *queue, int i, int j) +static inline int compare(struct prio_queue *queue, size_t i, size_t j) { int cmp = queue->compare(queue->array[i].data, queue->array[j].data, queue->cb_data); if (!cmp) - cmp = queue->array[i].ctr - queue->array[j].ctr; + cmp = (queue->array[i].ctr > queue->array[j].ctr) - + (queue->array[i].ctr < queue->array[j].ctr); return cmp; } -static inline void swap(struct prio_queue *queue, int i, int j) +static inline void swap(struct prio_queue *queue, size_t i, size_t j) { SWAP(queue->array[i], queue->array[j]); } void prio_queue_reverse(struct prio_queue *queue) { - int i, j; + size_t i, j; if (queue->compare) BUG("prio_queue_reverse() on non-LIFO queue"); + if (!queue->nr) + return; for (i = 0; i < (j = (queue->nr - 1) - i); i++) swap(queue, i, j); } @@ -35,7 +38,7 @@ void clear_prio_queue(struct prio_queue *queue) void prio_queue_put(struct prio_queue *queue, void *thing) { - int ix, parent; + size_t ix, parent; /* Append at the end */ ALLOC_GROW(queue->array, queue->nr + 1, queue->alloc); @@ -58,7 +61,7 @@ void prio_queue_put(struct prio_queue *queue, void *thing) void *prio_queue_get(struct prio_queue *queue) { void *result; - int ix, child; + size_t ix, child; if (!queue->nr) return NULL; diff --git a/prio-queue.h b/prio-queue.h index 4f9a37e6be..36f370625f 100644 --- a/prio-queue.h +++ b/prio-queue.h @@ -30,7 +30,7 @@ struct prio_queue { prio_queue_compare_fn compare; unsigned insertion_ctr; void *cb_data; - int alloc, nr; + size_t alloc, nr; struct prio_queue_entry *array; }; -- cgit v1.2.3 From 8ddcdc1bb33ccf803461dd2365146f9341bf9312 Mon Sep 17 00:00:00 2001 From: Karthik Nayak Date: Fri, 20 Dec 2024 13:58:37 +0100 Subject: refs: mark invalid refname message for translation The error message produced by `transaction_refname_valid()` changes based on whether the update is a ref update or a reflog update, with the use of a ternary operator. This breaks translation since the sub-msg is not marked for translation. Fix this by setting the entire message using a `if {} else {}` block and marking each message for translation. Signed-off-by: Karthik Nayak Signed-off-by: Junio C Hamano --- refs.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/refs.c b/refs.c index 5d541ddc41..c555839869 100644 --- a/refs.c +++ b/refs.c @@ -1208,14 +1208,22 @@ static int transaction_refname_valid(const char *refname, return 1; if (is_pseudo_ref(refname)) { - const char *what = flags & REF_LOG_ONLY ? "reflog for pseudoref" : "pseudoref"; - strbuf_addf(err, _("refusing to update %s '%s'"), what, refname); + const char *refusal_msg; + if (flags & REF_LOG_ONLY) + refusal_msg = _("refusing to update reflog for pseudoref '%s'"); + else + refusal_msg = _("refusing to update pseudoref '%s'"); + strbuf_addf(err, refusal_msg, refname); return 0; } else if ((new_oid && !is_null_oid(new_oid)) ? check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) : !refname_is_safe(refname)) { - const char *what = flags & REF_LOG_ONLY ? "reflog with bad name" : "ref with bad name"; - strbuf_addf(err, _("refusing to update %s '%s'"), what, refname); + const char *refusal_msg; + if (flags & REF_LOG_ONLY) + refusal_msg = _("refusing to update reflog with bad name '%s'"); + else + refusal_msg = _("refusing to update ref with bad name '%s'"); + strbuf_addf(err, refusal_msg, refname); return 0; } -- cgit v1.2.3 From 7d549fe317f8c4eea25f5212bc9f8e73b4b2608e Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 20 Dec 2024 17:30:35 +0100 Subject: meson: skip gitweb build when Perl is disabled It is possible to configure a Git build without Perl when disabling both our test suite and all Perl-based features. In Meson, this can be achieved with `meson setup -Dperl=disabled -Dtests=false`. It was reported by a user that this breaks the Meson build because gitweb gets built even if Perl was not discovered in such a build: $ meson setup .. -Dtests=false -Dperl=disabled ... ../gitweb/meson.build:2:43: ERROR: Unable to get the path of a not-found external program Fix this issue by introducing a new feature-option that allows the user to configure whether or not to build Gitweb. The feature is set to 'auto' by default and will be disabled automatically in case Perl was not found on the system. Reported-by: Daniel Engberg Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- meson.build | 13 +++++++++++-- meson_options.txt | 2 ++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 0dccebcdf1..8e34a895dc 100644 --- a/meson.build +++ b/meson.build @@ -740,7 +740,7 @@ endif # features. It is optional if you want to neither execute tests nor use any of # these optional features. perl_required = get_option('perl') -if get_option('tests') +if get_option('tests') or get_option('gitweb').enabled() perl_required = true endif @@ -1874,7 +1874,15 @@ if intl.found() subdir('po') endif subdir('contrib') -subdir('gitweb') + +# Gitweb requires Perl, so we disable the auto-feature if Perl was not found. +# We make sure further up that Perl is required in case the gitweb option is +# enabled. +gitweb_option = get_option('gitweb').disable_auto_if(not perl.found()) +if gitweb_option.enabled() + subdir('gitweb') +endif + subdir('templates') # Everything but the bin-wrappers need to come before this target such that we @@ -1893,6 +1901,7 @@ summary({ 'curl': curl.found(), 'expat': expat.found(), 'gettext': intl.found(), + 'gitweb': gitweb_option.enabled(), 'https': https_backend, 'iconv': iconv.found(), 'pcre2': pcre2.found(), diff --git a/meson_options.txt b/meson_options.txt index 32a72139ba..c374345b1a 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -23,6 +23,8 @@ option('expat', type: 'feature', value: 'enabled', description: 'Build helpers used to push to remotes with the HTTP transport.') option('gettext', type: 'feature', value: 'auto', description: 'Build translation files.') +option('gitweb', type: 'feature', value: 'auto', + description: 'Build Git web interface. Requires Perl.') option('iconv', type: 'feature', value: 'auto', description: 'Support reencoding strings with different encodings.') option('pcre2', type: 'feature', value: 'enabled', -- cgit v1.2.3 From b4d15f73e2819d9f4cbbdd1bc2bd007d962b053a Mon Sep 17 00:00:00 2001 From: Ethiraric Date: Mon, 21 Oct 2024 01:41:15 +0200 Subject: l10n: fr.po: Minor improvements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix an occurrence of "dpuis" to "depuis". * Add some entries in the translation index at the beginning of the file. * Harmonize the spelling of various items based on how common each spelling or translation is throughout the file. * superproject -> super-projet * patch -> rustine * regex / regexp -> regex * regular expression -> expression régulière * loose object -> objet esseulé * directory -> répertoire * Fix various typos (e.g.: trailing ".<" or ".", "mêm" -> "même") * Fix minor grammatical errors (e.g: "le valeur" -> "la valeur") * Remove old translations Signed-off-by: Florian Sabourin --- po/fr.po | 478 ++++++++++++++++++--------------------------------------------- 1 file changed, 133 insertions(+), 345 deletions(-) diff --git a/po/fr.po b/po/fr.po index 481e1bdc1d..b113e3870b 100644 --- a/po/fr.po +++ b/po/fr.po @@ -29,6 +29,7 @@ # to debug | déboguer # debugging | débogage # to deflate | compresser +# directory | répertoire # email | courriel # enlistment | enrôlement # entry | élément @@ -45,18 +46,23 @@ # hunk | section # to inflate | décompresser # to list | afficher +# loose object | objet esseulé # mapping | mise en correspondance # merge | fusion # pack | paquet -# patches | patchs +# patch (v) | appliquer une/des rustine(s) +# patches | rustines # pattern | motif # to prune | élaguer # to push | pousser # to rebase | rebaser # scheduler | planificateur # trailers | lignes terminales -# repository | dépôt +# regex | regex +# regular | +# expression | expression régulière # remote | distante (ou serveur distant) +# repository | dépôt # revision | révision # shallow | superficiel # shell | interpréteur de commandes @@ -64,6 +70,7 @@ # split (index) | index scindé # stash | remisage # to stash | remiser +# superproject | super-projet # tag | étiquette # template | modèle # thread | fil @@ -169,7 +176,7 @@ msgid "No changes.\n" msgstr "Aucune modification.\n" msgid "Patch update" -msgstr "Mise à jour par patch" +msgstr "Mise à jour par rustine" msgid "Review diff" msgstr "Réviser la différence" @@ -267,7 +274,7 @@ msgid "" "If the patch applies cleanly, the edited hunk will immediately be marked for " "staging." msgstr "" -"Si le patch s'applique proprement, la section éditée sera immédiatement " +"Si la rustine s'applique proprement, la section éditée sera immédiatement " "marquée comme indexée." msgid "" @@ -303,7 +310,7 @@ msgid "" "If the patch applies cleanly, the edited hunk will immediately be marked for " "stashing." msgstr "" -"Si le patch s'applique proprement, la section éditée sera immédiatement " +"Si la rustine s'applique proprement, la section éditée sera immédiatement " "marquée comme remisée." msgid "" @@ -339,7 +346,7 @@ msgid "" "If the patch applies cleanly, the edited hunk will immediately be marked for " "unstaging." msgstr "" -"Si le patch s'applique proprement, la section éditée sera immédiatement " +"Si la rustine s'applique proprement, la section éditée sera immédiatement " "marquée comme desindexée." msgid "" @@ -375,7 +382,7 @@ msgid "" "If the patch applies cleanly, the edited hunk will immediately be marked for " "applying." msgstr "" -"Si le patch s'applique proprement, la section éditée sera immédiatement " +"Si la rustine s'applique proprement, la section éditée sera immédiatement " "marquée comme appliquée." msgid "" @@ -411,7 +418,7 @@ msgid "" "If the patch applies cleanly, the edited hunk will immediately be marked for " "discarding." msgstr "" -"Si le patch s'applique proprement, la section éditée sera immédiatement " +"Si la rustine s'applique proprement, la section éditée sera immédiatement " "marquée comme éliminée." msgid "" @@ -893,7 +900,7 @@ msgstr "la rustine est trop grosse" #, c-format msgid "Cannot prepare timestamp regexp %s" -msgstr "Impossible de préparer la regexp d'horodatage %s" +msgstr "Impossible de préparer la regex d'horodatage %s" #, c-format msgid "regexec returned %d for input: %s" @@ -901,7 +908,7 @@ msgstr "regexec a retourné %d pour l'entrée : %s" #, c-format msgid "unable to find filename in patch at line %d" -msgstr "nom de fichier du patch introuvable à la ligne %d" +msgstr "nom de fichier de la rustine introuvable à la ligne %d" #, c-format msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d" @@ -912,13 +919,13 @@ msgstr "" #, c-format msgid "git apply: bad git-diff - inconsistent new filename on line %d" msgstr "" -"git apply : mauvais format de git-diff - nouveau nom de fichier inconsistant " +"git apply : mauvais format de git-diff - nouveau nom de fichier incohérent " "à la ligne %d" #, c-format msgid "git apply: bad git-diff - inconsistent old filename on line %d" msgstr "" -"git apply : mauvais format de git-diff - ancien nom de fichier inconsistant " +"git apply : mauvais format de git-diff - ancien nom de fichier incohérent " "à la ligne %d" #, c-format @@ -959,7 +966,7 @@ msgstr "recomptage : ligne inattendue : %.*s" #, c-format msgid "patch fragment without header at line %d: %.*s" -msgstr "fragment de patch sans en-tête à la ligne %d : %.*s" +msgstr "fragment de rustine sans en-tête à la ligne %d : %.*s" msgid "new file depends on old contents" msgstr "le nouveau fichier dépend de contenus anciens" @@ -969,7 +976,7 @@ msgstr "le fichier supprimé a encore du contenu" #, c-format msgid "corrupt patch at line %d" -msgstr "patch corrompu à la ligne %d" +msgstr "rustine corrompue à la ligne %d" #, c-format msgid "new file %s depends on old contents" @@ -985,15 +992,15 @@ msgstr "** attention : le fichier %s devient vide mais n'est pas supprimé" #, c-format msgid "corrupt binary patch at line %d: %.*s" -msgstr "patch binaire corrompu à la ligne %d : %.*s" +msgstr "rustine binaire corrompue à la ligne %d : %.*s" #, c-format msgid "unrecognized binary patch at line %d" -msgstr "patch binaire non reconnu à la ligne %d" +msgstr "rustine binaire non reconnue à la ligne %d" #, c-format msgid "patch with only garbage at line %d" -msgstr "patch totalement incompréhensible à la ligne %d" +msgstr "rustine totalement incompréhensible à la ligne %d" #, c-format msgid "unable to read symlink %s" @@ -1027,28 +1034,29 @@ msgstr "" #, c-format msgid "missing binary patch data for '%s'" -msgstr "données de patch binaire manquantes pour '%s'" +msgstr "données de rustine binaire manquantes pour '%s'" #, c-format msgid "cannot reverse-apply a binary patch without the reverse hunk to '%s'" msgstr "" -"impossible d'appliquer l'inverse d'un patch binaire à '%s' sans la section " +"impossible d'appliquer l'inverse d'une rustine binaire à '%s' sans la section " "inverse" #, c-format msgid "cannot apply binary patch to '%s' without full index line" msgstr "" -"impossible d'appliquer un patch binaire à '%s' sans la ligne complète d'index" +"impossible d'appliquer une rustine binaire à '%s' sans la ligne complète " +"d'index" #, c-format msgid "" "the patch applies to '%s' (%s), which does not match the current contents." msgstr "" -"le patch s'applique à '%s' (%s), ce qui ne correspond pas au contenu actuel." +"la rustine s'applique à '%s' (%s), ce qui ne correspond pas au contenu actuel." #, c-format msgid "the patch applies to an empty '%s' but it is not empty" -msgstr "le patch s'applique à un '%s' vide mais ce n'est pas vide" +msgstr "la rustine s'applique à un '%s' vide mais ce n'est pas vide" #, c-format msgid "the necessary postimage %s for '%s' cannot be read" @@ -1056,17 +1064,17 @@ msgstr "l'image postérieure nécessaire %s pour '%s' ne peut pas être lue" #, c-format msgid "binary patch does not apply to '%s'" -msgstr "le patch binaire ne s'applique par correctement à '%s'" +msgstr "la rustine binaire ne s'applique par correctement à '%s'" #, c-format msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)" msgstr "" -"le patch binaire sur '%s' crée un résultat incorrect (%s attendu, mais %s " +"la rustine binaire sur '%s' crée un résultat incorrect (%s attendu, mais %s " "trouvé)" #, c-format msgid "patch failed: %s:%ld" -msgstr "le patch a échoué : %s:%ld" +msgstr "l'application de la rustine a échoué : %s:%ld" #, c-format msgid "cannot checkout %s" @@ -1110,18 +1118,18 @@ msgstr "Échec de l'application de la fusion à 3 points…\n" #, c-format msgid "Applied patch to '%s' with conflicts.\n" -msgstr "Patch %s appliqué avec des conflits.\n" +msgstr "Rustine %s appliquée avec des conflits.\n" #, c-format msgid "Applied patch to '%s' cleanly.\n" -msgstr "Patch %s appliqué proprement.\n" +msgstr "Rustine %s appliquée proprement.\n" #, c-format msgid "Falling back to direct application...\n" msgstr "Retour à une application directe…\n" msgid "removal patch leaves file contents" -msgstr "le patch de suppression laisse un contenu dans le fichier" +msgstr "la rustine de suppression laisse un contenu dans le fichier" #, c-format msgid "%s: wrong type" @@ -1158,11 +1166,11 @@ msgstr "le fichier affecté '%s' est au-delà d'un lien symbolique" #, c-format msgid "%s: patch does not apply" -msgstr "%s : le patch ne s'applique pas" +msgstr "%s : la rustine ne s'applique pas" #, c-format msgid "Checking patch %s..." -msgstr "Vérification du patch %s..." +msgstr "Vérification de la rustine %s..." #, c-format msgid "sha1 information is lacking or useless for submodule %s" @@ -1191,7 +1199,7 @@ msgstr "suppression de %s dans l'index impossible" #, c-format msgid "corrupt patch for submodule %s" -msgstr "patch corrompu pour le sous-module %s" +msgstr "rustine corrompue pour le sous-module %s" #, c-format msgid "unable to stat newly created file '%s'" @@ -1221,7 +1229,7 @@ msgstr "écriture du fichier '%s' mode %o impossible" #, c-format msgid "Applied patch %s cleanly." -msgstr "Patch %s appliqué proprement." +msgstr "Rustine %s appliquée proprement." msgid "internal error" msgstr "erreur interne" @@ -1229,8 +1237,8 @@ msgstr "erreur interne" #, c-format msgid "Applying patch %%s with %d reject..." msgid_plural "Applying patch %%s with %d rejects..." -msgstr[0] "Application du patch %%s avec %d rejet..." -msgstr[1] "Application du patch %%s avec %d rejets..." +msgstr[0] "Application de la rustine %%s avec %d rejet..." +msgstr[1] "Application de la rustine %%s avec %d rejets..." #, c-format msgid "cannot open %s" @@ -1260,7 +1268,7 @@ msgstr "lecture du fichier d'index impossible" #, c-format msgid "can't open patch '%s': %s" -msgstr "ouverture impossible du patch '%s' :%s" +msgstr "ouverture impossible de la rustine '%s' :%s" #, c-format msgid "squelched %d whitespace error" @@ -1296,35 +1304,35 @@ msgid "remove leading slashes from traditional diff paths" msgstr "supprimer barres obliques des chemins traditionnels de diff" msgid "ignore additions made by the patch" -msgstr "ignorer les additions réalisées par le patch" +msgstr "ignorer les additions réalisées par la rustine" msgid "instead of applying the patch, output diffstat for the input" -msgstr "au lieu d'appliquer le patch, afficher le diffstat de l'entrée" +msgstr "au lieu d'appliquer la rustine, afficher le diffstat de l'entrée" msgid "show number of added and deleted lines in decimal notation" msgstr "" "afficher le nombre de lignes ajoutées et supprimées en notation décimale" msgid "instead of applying the patch, output a summary for the input" -msgstr "au lieu d'appliquer le patch, afficher un résumé de l'entrée" +msgstr "au lieu d'appliquer la rustine, afficher un résumé de l'entrée" msgid "instead of applying the patch, see if the patch is applicable" -msgstr "au lieu d'appliquer le patch, voir si le patch est applicable" +msgstr "au lieu d'appliquer la rustine, voir si la rustine est applicable" msgid "make sure the patch is applicable to the current index" -msgstr "s'assurer que le patch est applicable sur l'index actuel" +msgstr "s'assurer que la rustine est applicable sur l'index actuel" msgid "mark new files with `git add --intent-to-add`" msgstr "marquer les nouveaux fichiers `git add --intent-to-add`" msgid "apply a patch without touching the working tree" -msgstr "appliquer les patch sans toucher à la copie de travail" +msgstr "appliquer les rustines sans toucher à la copie de travail" msgid "accept a patch that touches outside the working area" -msgstr "accepter un patch qui touche hors de la copie de travail" +msgstr "accepter une rustine qui touche hors de la copie de travail" msgid "also apply the patch (use with --stat/--summary/--check)" -msgstr "appliquer aussi le patch (à utiliser avec --stat/--summary/--check)" +msgstr "appliquer aussi la rustine (à utiliser avec --stat/--summary/--check)" msgid "attempt three-way merge, fall back on normal patch if that fails" msgstr "" @@ -1361,7 +1369,7 @@ msgid "ignore changes in whitespace when finding context" msgstr "ignorer des modifications d'espace lors de la recherche de contexte" msgid "apply the patch in reverse" -msgstr "appliquer le patch en sens inverse" +msgstr "appliquer la rustine en sens inverse" msgid "don't expect at least one line of context" msgstr "ne pas s'attendre à au moins une ligne de contexte" @@ -1923,7 +1931,7 @@ msgid "could not read the index" msgstr "impossible de lire l'index" msgid "editing patch failed" -msgstr "échec de l'édition du patch" +msgstr "échec de l'édition de la rustine" #, c-format msgid "could not stat '%s'" @@ -2031,7 +2039,7 @@ msgid "adding embedded git repository: %s" msgstr "dépôt git embarqué ajouté : %s" msgid "Use -f if you really want to add them." -msgstr "Utilisez -f si vous voulez vraiment les ajouter<." +msgstr "Utilisez -f si vous voulez vraiment les ajouter." msgid "adding files failed" msgstr "échec de l'ajout de fichiers" @@ -2103,10 +2111,10 @@ msgstr "impossible d'ouvrir '%s' en écriture" #, c-format msgid "could not parse patch '%s'" -msgstr "impossible d'analyser le patch '%s'" +msgstr "impossible d'analyser la rustine '%s'" msgid "Only one StGIT patch series can be applied at once" -msgstr "Seulement une série de patchs StGIT peut être appliquée à la fois" +msgstr "Seulement une série de rustines StGIT peut être appliquée à la fois" msgid "invalid timestamp" msgstr "horodatage invalide" @@ -2118,14 +2126,14 @@ msgid "invalid timezone offset" msgstr "décalage horaire invalide" msgid "Patch format detection failed." -msgstr "Échec de détection du format du patch." +msgstr "Échec de détection du format de la rustine." #, c-format msgid "failed to create directory '%s'" msgstr "échec de la création du répertoire '%s'" msgid "Failed to split patches." -msgstr "Échec de découpage des patchs." +msgstr "Échec de découpage des rustines." #, c-format msgid "When you have resolved this problem, run \"%s --continue\".\n" @@ -2145,8 +2153,8 @@ msgstr "" #, c-format msgid "To restore the original branch and stop patching, run \"%s --abort\"." msgstr "" -"Pour restaurer la branche originale et arrêter de patcher, lancez \"%s --" -"abort\"." +"Pour restaurer la branche originale et arrêter d'appliquer des rustines, " +"lancez \"%s --abort\"." msgid "Patch sent with format=flowed; space at the end of lines might be lost." msgstr "" @@ -2178,11 +2186,11 @@ msgid "" "Did you hand edit your patch?\n" "It does not apply to blobs recorded in its index." msgstr "" -"Avez-vous édité le patch à la main ?\n" +"Avez-vous édité la rustine à la main ?\n" "Il ne s'applique pas aux blobs enregistrés dans son index." msgid "Falling back to patching base and 3-way merge..." -msgstr "Retour à un patch de la base et fusion à 3 points..." +msgstr "Retour à une rustine de la base et fusion à 3 points..." msgid "Failed to merge in the changes." msgstr "Échec d'intégration des modifications." @@ -2216,7 +2224,7 @@ msgstr "impossible d'écrire le fichier d'index" #, c-format msgid "Dirty index: cannot apply patches (dirty: %s)" -msgstr "Index sale : impossible d'appliquer des patchs (sales : %s)" +msgstr "Index sale : impossible d'appliquer des rustines (sales : %s)" #, c-format msgid "Skipping: %.*s" @@ -2227,7 +2235,7 @@ msgid "Creating an empty commit: %.*s" msgstr "Création d'un commit vide : %.*s" msgid "Patch is empty." -msgstr "Le patch actuel est vide." +msgstr "La rustine actuelle est vide." #, c-format msgid "Applying: %.*s" @@ -2242,7 +2250,8 @@ msgstr "l'application de la rustine a échoué à %s %.*s" msgid "Use 'git am --show-current-patch=diff' to see the failed patch" msgstr "" -"Utilisez 'git am --show-current-patch=diff' pour visualiser le patch en échec" +"Utilisez 'git am --show-current-patch=diff' pour visualiser la rustine en " +"échec" msgid "No changes - recorded it as an empty commit." msgstr "aucune modification - enregistré comme un commit vide." @@ -2254,8 +2263,8 @@ msgid "" msgstr "" "Aucun changement - avez-vous oublié d'utiliser 'git add' ?\n" "S'il n'y a plus rien à indexer, il se peut qu'autre chose ait déjà\n" -"introduit les mêmes changements ; vous pourriez avoir envie de sauter ce " -"patch." +"introduit les mêmes changements ; vous pourriez avoir envie de sauter cette " +"rustine." msgid "" "You still have unmerged paths in your index.\n" @@ -2342,28 +2351,30 @@ msgid "format" msgstr "format" msgid "format the patch(es) are in" -msgstr "format de présentation des patchs" +msgstr "format de présentation des rustines" msgid "override error message when patch failure occurs" -msgstr "surcharger le message d'erreur lors d'un échec d'application de patch" +msgstr "" +"surcharger le message d'erreur lors d'un échec d'application d'une rustine" msgid "continue applying patches after resolving a conflict" -msgstr "continuer à appliquer les patchs après résolution d'un conflit" +msgstr "continuer à appliquer les rustines après résolution d'un conflit" msgid "synonyms for --continue" msgstr "synonymes de --continue" msgid "skip the current patch" -msgstr "sauter le patch courant" +msgstr "sauter la rustine courante" msgid "restore the original branch and abort the patching operation" -msgstr "restaurer la branche originale et abandonner les applications de patch" +msgstr "" +"restaurer la branche originale et abandonner les applications de rustines" msgid "abort the patching operation but keep HEAD where it is" -msgstr "abandonne l'opération de patch mais garde HEAD où il est" +msgstr "abandonne l'opération de rustine mais garde HEAD où il est" msgid "show the patch being applied" -msgstr "afficher le patch en cours d'application" +msgstr "afficher la rustine en cours d'application" msgid "try to apply current patch again" msgstr "essayer d'appliquer de nouveau la rustine" @@ -3581,6 +3592,10 @@ msgstr "git check-mailmap [] ..." msgid "also read contacts from stdin" msgstr "lire aussi les contacts depuis l'entrée standard" +#, c-format +msgid "unable to parse contact: %s" +msgstr "impossible d'analyser le contact : %s" + msgid "read additional mailmap entries from file" msgstr "lire des entrées supplémentaires de mailmap depuis un fichier" @@ -4386,7 +4401,7 @@ msgstr "échec pour délier '%s'" #, c-format msgid "hardlink cannot be checked at '%s'" -msgstr "le lien dur ne peut pas être vérifier à '%s'" +msgstr "le lien dur ne peut pas être vérifié à '%s'" #, c-format msgid "hardlink different from source at '%s'" @@ -5486,7 +5501,7 @@ msgid "value" msgstr "valeur" msgid "use default value when missing entry" -msgstr "utiliser le valeur par défaut quand l'entrée n'existe pas" +msgstr "utiliser la valeur par défaut quand l'entrée n'existe pas" msgid "--fixed-value only applies with 'value-pattern'" msgstr "--fixed-value ne s'applique qu'à 'motif-de-valeur'" @@ -5523,7 +5538,7 @@ msgid "" " Use a regexp, --add or --replace-all to change %s." msgstr "" "impossible de surcharger des valeurs multiples avec une seule valeur\n" -" Utilisez une regexp, --add ou --replace-all pour modifier %s." +" Utilisez une regex, --add ou --replace-all pour modifier %s." #, c-format msgid "no such section: %s" @@ -5549,7 +5564,7 @@ msgid "get all values: key []" msgstr "obtenir toutes les valeurs : clé []" msgid "get values for regexp: name-regex []" -msgstr "obtenir les valeur pour la regexp : name-regex []" +msgstr "obtenir les valeurs pour la regex : name-regex []" msgid "get value specific for the URL: section[.var] URL" msgstr "obtenir la valeur spécifique pour l'URL : section[.var] URL" @@ -5586,7 +5601,7 @@ msgid "find the color setting: slot []" msgstr "trouver le réglage de la couleur : slot []" msgid "with --get, use default value when missing entry" -msgstr "avec --get, utiliser le valeur par défaut quand l'entrée n'existe pas" +msgstr "avec --get, utiliser la valeur par défaut quand l'entrée n'existe pas" msgid "--get-color and variable type are incoherent" msgstr "--get-color et le type de la variable sont incohérents" @@ -5623,7 +5638,7 @@ msgstr "" "Les permissions de votre répertoire de socket sont trop permissives ;\n" "les autres utilisateurs pourraient lire vos identifiants secrets. Lancez :\n" "\n" -" chmod 0700 %s" +"\tchmod 0700 %s" msgid "print debugging messages to stderr" msgstr "afficher les messages de debug sur stderr" @@ -6450,7 +6465,7 @@ msgid "config key storing a list of repository paths" msgstr "clé de config qui stocke la liste des chemins de dépôts" msgid "keep going even if command fails in a repository" -msgstr "continuer mêm si la commande échoue dans un dépôt" +msgstr "continuer même si la commande échoue dans un dépôt" msgid "missing --config=" msgstr "--config= manquant" @@ -6665,7 +6680,7 @@ msgid "check only connectivity" msgstr "ne vérifier que la connectivité" msgid "enable more strict checking" -msgstr "activer une vérification plus strict" +msgstr "activer une vérification plus stricte" msgid "write dangling objects in .git/lost-found" msgstr "écrire les objets en suspens dans .git/lost-found" @@ -6866,7 +6881,7 @@ msgstr "" msgid "" "There are too many unreachable loose objects; run 'git prune' to remove them." msgstr "" -"Il y a trop d'objets seuls inaccessibles ; lancez 'git prune' pour les " +"Il y a trop d'objets esseulés inaccessibles ; lancez 'git prune' pour les " "supprimer." msgid "" @@ -7890,7 +7905,7 @@ msgid "base commit shouldn't be in revision list" msgstr "le commit de base ne devrait pas faire partie de la liste de révisions" msgid "cannot get patch id" -msgstr "impossible d'obtenir l'id du patch" +msgstr "impossible d'obtenir l'id de la rustine" msgid "failed to infer range-diff origin of current series" msgstr "" @@ -7903,13 +7918,13 @@ msgstr "" "utilisation de '%s' comme une différence d'intervalle pour la série actuelle" msgid "use [PATCH n/m] even with a single patch" -msgstr "utiliser [PATCH n/m] même avec un patch unique" +msgstr "utiliser [PATCH n/m] même avec une rustine unique" msgid "use [PATCH] even with multiple patches" -msgstr "utiliser [PATCH] même avec des patchs multiples" +msgstr "utiliser [PATCH] même avec des rustines multiples" msgid "print patches to standard out" -msgstr "afficher les patchs sur la sortie standard" +msgstr "afficher les rustines sur la sortie standard" msgid "generate a cover letter" msgstr "générer une lettre de motivation" @@ -7925,7 +7940,7 @@ msgid "use instead of '.patch'" msgstr "utiliser au lieu de '.patch'" msgid "start numbering patches at instead of 1" -msgstr "démarrer la numérotation des patchs à au lieu de 1" +msgstr "démarrer la numérotation des rustines à au lieu de 1" msgid "reroll-count" msgstr "reroll-count" @@ -7969,10 +7984,10 @@ msgid "output all-zero hash in From header" msgstr "écrire une empreinte à zéro dans l'entête From" msgid "don't include a patch matching a commit upstream" -msgstr "ne pas inclure un patch correspondant à un commit amont" +msgstr "ne pas inclure de rustine correspondant à un commit amont" msgid "show patch format instead of default (patch + stat)" -msgstr "afficher le format du patch au lieu du défaut (patch + stat)" +msgstr "afficher le format de la rustine au lieu du défaut (rustine + stat)" msgid "Messaging" msgstr "Communication" @@ -8009,10 +8024,10 @@ msgid "boundary" msgstr "limite" msgid "attach the patch" -msgstr "attacher le patch" +msgstr "attacher la rustine" msgid "inline the patch" -msgstr "patch à l'intérieur" +msgstr "incorporer la rustine à l'intérieur" msgid "enable message threading, styles: shallow, deep" msgstr "" @@ -8028,17 +8043,17 @@ msgid "base-commit" msgstr "commit-de-base" msgid "add prerequisite tree info to the patch series" -msgstr "ajouter un arbre prérequis à la série de patchs" +msgstr "ajouter un arbre prérequis à la série de rustines" msgid "add a signature from a file" msgstr "ajouter une signature depuis un fichier" msgid "don't print the patch filenames" -msgstr "ne pas afficher les noms de fichiers des patchs" +msgstr "ne pas afficher les noms de fichiers des rustines" msgid "show progress while generating patches" msgstr "" -"afficher la barre de progression durant la phase de génération des patchs" +"afficher la barre de progression durant la phase de génération des rustines" msgid "show changes against in cover letter or single patch" msgstr "" @@ -8103,7 +8118,7 @@ msgid "unable to read signature file '%s'" msgstr "lecture du fichier de signature '%s' impossible" msgid "Generating patches" -msgstr "Génération des patchs" +msgstr "Génération des rustines" msgid "failed to create output files" msgstr "échec de création des fichiers en sortie" @@ -8221,7 +8236,7 @@ msgid "" " [-q | --quiet] [--exit-code] [--get-url] [--sort=]\n" " [--symref] [ [...]]" msgstr "" -"git ls-remote [--brances] [--tags] [--refs] [--upload-pack=]\n" +"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=]\n" " [-q | --quiet] [--exit-code] [--get-url] [--sort=]\n" " [--symref] [ [...]]" @@ -10548,7 +10563,7 @@ msgid "continue" msgstr "continuer" msgid "skip current patch and continue" -msgstr "sauter le patch courant et continuer" +msgstr "sauter la rustine courante et continuer" msgid "abort and check out the original branch" msgstr "abandonner et extraire la branche d'origine" @@ -10560,7 +10575,7 @@ msgid "edit the todo list during an interactive rebase" msgstr "éditer la liste à faire lors d'un rebasage interactif" msgid "show the patch file being applied or merged" -msgstr "afficher le patch en cours d'application ou de fusion" +msgstr "afficher la rustine en cours d'application ou de fusion" msgid "use apply strategies to rebase" msgstr "utiliser des stratégies d'application pour rebaser" @@ -10943,7 +10958,7 @@ msgid "repository already uses '%s' format" msgstr "le dépôt utilise déjà le format '%s'" msgid "enable strict checking" -msgstr "activer une vérification plus strict" +msgstr "activer une vérification plus stricte" msgid "'git refs verify' takes no arguments" msgstr "'git refs verify' n'accepte aucun argument" @@ -12454,7 +12469,7 @@ msgid "" "directory '%s' contains untracked files, but is not in the sparse-checkout " "cone" msgstr "" -"le dossier '%s' contient des fichiers non-suivis, mais n'est pas dans le " +"le répertoire '%s' contient des fichiers non-suivis, mais n'est pas dans le " "cone d'extraction clairsemée" #, c-format @@ -13191,7 +13206,7 @@ msgid "" "the superproject is not on any branch" msgstr "" "La branche du sous-module %s est configurée pour hériter de la branche du " -"superprojet, mais le superprojet n'est sur aucune branche" +"super-projet, mais le super-projet n'est sur aucune branche" #, c-format msgid "Unable to find current revision in submodule path '%s'" @@ -14409,13 +14424,13 @@ msgid "Add file contents to the index" msgstr "Ajouter le contenu de fichiers dans l'index" msgid "Apply a series of patches from a mailbox" -msgstr "Appliquer une série de patchs depuis une boîte mail" +msgstr "Appliquer une série de rustines depuis une boîte mail" msgid "Annotate file lines with commit information" msgstr "Annoter les lignes du fichier avec l'information de commit" msgid "Apply a patch to files and/or to the index" -msgstr "Appliquer une patch à des fichiers ou à l'index" +msgstr "Appliquer une rustine à des fichiers ou à l'index" msgid "Import a GNU Arch repository into Git" msgstr "Importer dans Git un dépôt GNU Arch" @@ -14567,7 +14582,7 @@ msgid "Run a Git command on a list of repositories" msgstr "Lance une commande Git sur une liste de dépôts" msgid "Prepare patches for e-mail submission" -msgstr "Préparer les patchs pour soumission par courriel" +msgstr "Préparer les rustines pour soumission par courriel" msgid "Verifies the connectivity and validity of the objects in the database" msgstr "" @@ -14637,7 +14652,7 @@ msgstr "Afficher le contenu d'un objet arbre" msgid "Extracts patch and authorship from a single e-mail message" msgstr "" -"Extraire le patch et l'information de d'auteur depuis un simple message de " +"Extraire la rustine et l'information de l'auteur depuis un simple message de " "courriel" msgid "Simple UNIX mbox splitter program" @@ -14700,7 +14715,7 @@ msgid "Pack heads and tags for efficient repository access" msgstr "Empaqueter les têtes et les étiquettes pour un accès efficace au dépôt" msgid "Compute unique ID for a patch" -msgstr "Calculer l'ID unique d'un patch" +msgstr "Calculer l'ID unique d'une rustine" msgid "Prune all unreachable objects from the object database" msgstr "Élaguer les objets inatteignables depuis la base de données des objets" @@ -14775,7 +14790,7 @@ msgid "Remove files from the working tree and from the index" msgstr "Supprimer des fichiers de la copie de travail et de l'index" msgid "Send a collection of patches as emails" -msgstr "Envoyer un ensemble de patchs comme courriels" +msgstr "Envoyer un ensemble de rustines comme courriels" msgid "Push objects over Git protocol to another repository" msgstr "Pousser les objets sur un autre dépôt via le protocole Git" @@ -15060,7 +15075,7 @@ msgid "" "disabling Bloom filters for commit-graph layer '%s' due to incompatible " "settings" msgstr "" -"désactivation des filtres de Bloom opur la couche de graphe de commits '%s' " +"désactivation des filtres de Bloom pour la couche de graphe de commits '%s' " "à cause de réglages incompatibles" msgid "commit-graph has no base graphs chunk" @@ -16211,7 +16226,7 @@ msgstr "impossible de charger la regex île pour '%s' : %s" #, c-format msgid "island regex from config has too many capture groups (max=%d)" msgstr "" -"l'expression rationnelle depuis la configuration a trop de groupes de " +"l'expression régulière depuis la configuration a trop de groupes de " "capture (max=%d)" #, c-format @@ -16736,7 +16751,7 @@ msgstr "" msgid "treat in -S as extended POSIX regular expression" msgstr "" -"traiter dans -S comme une expression rationnelle POSIX étendue" +"traiter dans -S comme une expression régulière POSIX étendue" msgid "control the order in which files appear in the output" msgstr "contrôler l'ordre dans lequel les fichiers apparaissent dans la sortie" @@ -18284,7 +18299,7 @@ msgstr "échec de l'écriture de l'index de multi-paquet" msgid "cannot expire packs from an incremental multi-pack-index" msgstr "" -"impossible d'expirer les paquets dpuis un index multi-paquet incrémental" +"impossible d'expirer les paquets depuis un index multi-paquet incrémental" msgid "Counting referenced objects" msgstr "Comptage des objets référencés" @@ -18293,7 +18308,7 @@ msgid "Finding and deleting unreferenced packfiles" msgstr "Recherche et effacement des fichiers paquets non-référencés" msgid "cannot repack an incremental multi-pack-index" -msgstr "impossible de ré-empaqueter un index multi-paquet" +msgstr "impossible de ré-empaqueter un index multi-paquet incrémental" msgid "could not start pack-objects" msgstr "impossible de démarrer le groupement d'objets" @@ -19270,7 +19285,7 @@ msgid "use digits to display object names" msgstr "utiliser chiffres pour afficher les noms des objets" msgid "prefixed path to initial superproject" -msgstr "chemin préfixé vers le superprojet initial" +msgstr "chemin préfixé vers le super-projet initial" msgid "how to strip spaces and #comments from message" msgstr "comment éliminer les espaces et les commentaires # du message" @@ -19484,7 +19499,7 @@ msgstr "" msgid "" "pseudo-merge regex from config has too many capture groups (max=%)" msgstr "" -"l'expression rationnelle de pseudo-fusion a trop de groupes de capture " +"l'expression régulière de pseudo-fusion a trop de groupes de capture " "(max=%)" #, c-format @@ -21359,7 +21374,7 @@ msgstr "impossible d'appliquer %s... %s" #, c-format msgid "dropping %s %s -- patch contents already upstream\n" -msgstr "abandon de %s %s -- le contenu de la rustine déjà en amont\n" +msgstr "abandon de %s %s -- le contenu de la rustine est déjà en amont\n" #, c-format msgid "git %s: failed to read the index" @@ -23266,13 +23281,13 @@ msgid "You are in the middle of an am session." msgstr "Vous êtes au milieu d'une session am." msgid "The current patch is empty." -msgstr "Le patch actuel est vide." +msgstr "La rustine actuelle est vide." msgid " (fix conflicts and then run \"git am --continue\")" msgstr " (réglez les conflits puis lancez \"git am --continue\")" msgid " (use \"git am --skip\" to skip this patch)" -msgstr " (utilisez \"git am --skip\" pour sauter ce patch)" +msgstr " (utilisez \"git am --skip\" pour sauter cette rustine)" msgid "" " (use \"git am --allow-empty\" to record this patch as an empty commit)" @@ -23322,7 +23337,7 @@ msgid " (fix conflicts and then run \"git rebase --continue\")" msgstr " (réglez les conflits puis lancez \"git rebase --continue\")" msgid " (use \"git rebase --skip\" to skip this patch)" -msgstr " (utilisez \"git rebase --skip\" pour sauter ce patch)" +msgstr " (utilisez \"git rebase --skip\" pour sauter cette rustine)" msgid " (use \"git rebase --abort\" to check out the original branch)" msgstr " (utilisez \"git rebase --abort\" pour extraire la branche d'origine)" @@ -23382,7 +23397,7 @@ msgstr "" " (tous les conflits sont réglés : lancez \"git cherry-pick --continue\")" msgid " (use \"git cherry-pick --skip\" to skip this patch)" -msgstr " (utilisez \"git cherry-pick --skip\" pour sauter ce patch)" +msgstr " (utilisez \"git cherry-pick --skip\" pour sauter cette rustine)" msgid " (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)" msgstr " (utilisez \"git cherry-pick --abort\" pour annuler le picorage)" @@ -23404,7 +23419,7 @@ msgid " (all conflicts fixed: run \"git revert --continue\")" msgstr " (tous les conflits sont réglés : lancez \"git revert --continue\")" msgid " (use \"git revert --skip\" to skip this patch)" -msgstr " (utilisez \"git revert --skip\" pour sauter ce patch)" +msgstr " (utilisez \"git revert --skip\" pour sauter cette rustine)" msgid " (use \"git revert --abort\" to cancel the revert operation)" msgstr " (utilisez \"git revert --abort\" pour annuler le rétablissement)" @@ -23728,7 +23743,7 @@ msgid "" "\n" msgstr "" "\n" -"Aucun fichier patch spécifié !\n" +"Aucun fichier de rustine spécifié !\n" "\n" #, perl-format @@ -23748,7 +23763,7 @@ msgid "" msgstr "" "Les lignes commençant par \"GIT:\" seront supprimées.\n" "Envisagez d'inclure un diffstat global ou une table des matières\n" -"pour le patch que vous êtes en train d'écrire.\n" +"pour la rustine que vous êtes en train d'écrire.\n" "\n" "Effacez le corps si vous ne souhaitez pas envoyer un résumé.\n" @@ -23785,7 +23800,7 @@ msgid "" "has the template subject '*** SUBJECT HERE ***'. Pass --force if you really " "want to send.\n" msgstr "" -"Envoi refusé parce que le patch\n" +"Envoi refusé parce que la rustine\n" "\t%s\n" "a un sujet modèle '*** SUBJECT HERE ***'. Passez --force is vous souhaitez " "vraiment envoyer.\n" @@ -23938,7 +23953,7 @@ msgid "" msgstr "" "fatal : %s : rejeté par le crochet %s\n" "%s\n" -"attention : aucun patch envoyé\n" +"attention : aucune rustine envoyée\n" #, perl-format msgid "unable to open %s: %s\n" @@ -23950,7 +23965,7 @@ msgid "" "warning: no patches were sent\n" msgstr "" "fatal : %s : %d est plus long que 998 caractères \n" -"attention : aucun patch envoyé\n" +"attention : aucune rustine envoyée\n" #, perl-format msgid "Skipping %s with backup suffix '%s'.\n" @@ -23960,230 +23975,3 @@ msgstr "%s sauté avec un suffix de sauvegarde '%s'.\n" #, perl-format msgid "Do you really want to send %s? [y|N]: " msgstr "Souhaitez-vous réellement envoyer %s ?[y|N] : " - -#~ msgid "revision walk setup failed\n" -#~ msgstr "échec de la préparation du parcours des révisions\n" - -#, c-format -#~ msgid "unable to parse contact: %s" -#~ msgstr "impossible d'analyser le contact : %s" - -#, c-format -#~ msgid "truncating .rej filename to %.*s.rej" -#~ msgstr "troncature du nom de fichier .rej en %.*s.rej" - -#~ msgid "" -#~ "the add.interactive.useBuiltin setting has been removed!\n" -#~ "See its entry in 'git help config' for details." -#~ msgstr "" -#~ "le réglage add.interactive.useBuiltin a été supprimé !\n" -#~ "Référez-vous à cette entrée dans 'git help config' pour plus de détails." - -#~ msgid "git archive: Remote with no URL" -#~ msgstr "git archive : Dépôt distant sans URL" - -#~ msgid "only one action at a time" -#~ msgstr "une seule action à la fois" - -#~ msgid "use [RFC PATCH] instead of [PATCH]" -#~ msgstr "utiliser [RFC PATCH] au lieu de [PATCH]" - -#, c-format -#~ msgid "no URLs configured for remote '%s'" -#~ msgstr "aucune URL configurée pour le dépôt distant '%s'" - -#, c-format -#~ msgid "remote '%s' has no configured URL" -#~ msgstr "le distant '%s' n'a pas d'URL configuré" - -#~ msgid "" -#~ "Use -f if you really want to add them.\n" -#~ "Turn this message off by running\n" -#~ "\"git config advice.addIgnoredFile false\"" -#~ msgstr "" -#~ "Utilisez -f si vous voulez vraiment les ajouter.\n" -#~ "Éliminez ce message en lançant\n" -#~ "\"git config advice.addIgnoredFile false\"" - -#~ msgid "" -#~ "Maybe you wanted to say 'git add .'?\n" -#~ "Turn this message off by running\n" -#~ "\"git config advice.addEmptyPathspec false\"" -#~ msgstr "" -#~ "Peut-être avez-vous voulu dire 'git add .' ?\n" -#~ "Éliminez ce message en lançant\n" -#~ "\"git config advice.addEmptyPathspec false\"" - -#~ msgid "" -#~ "clean.requireForce defaults to true and neither -i, -n, nor -f given; " -#~ "refusing to clean" -#~ msgstr "" -#~ "clean.requireForce à true par défaut et ni -i, -n ou -f fourni ; refus de " -#~ "nettoyer" - -#, c-format -#~ msgid "bad ls-files format: element '%s' does not start with '('" -#~ msgstr "mauvais format ls-files : l'élément '%s' ne commence pas par '('" - -#, c-format -#~ msgid "bad ls-files format: element '%s' does not end in ')'" -#~ msgstr "mauvais format ls-files : l'élément '%s' ne se termine pas par ')'" - -#, c-format -#~ msgid "bad ls-files format: %%%.*s" -#~ msgstr "mauvais format ls-files : %%%.*s" - -#~ msgid "keep redundant, empty commits" -#~ msgstr "garder les validations redondantes, vides" - -#~ msgid "core.commentChar should only be one ASCII character" -#~ msgstr "core.commentChar ne devrait être qu'un unique caractère ASCII" - -#~ msgid "" -#~ "--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-" -#~ "exclude" -#~ msgstr "" -#~ "--bundle-uri est incompatible avec --depth, --shallow-since, et --shallow-" -#~ "exclude" - -#~ msgid "--merge-base is incompatible with --stdin" -#~ msgstr "--merge-base est incompatible avec --stdin" - -#~ msgid "" -#~ "apply options are incompatible with rebase.autoSquash. Consider adding --" -#~ "no-autosquash" -#~ msgstr "" -#~ "les options d'application sont incompatibles avec rebase.autoSquash. " -#~ "Considérez l'ajout de --no-autosquash" - -#~ msgid "--exclude-hidden cannot be used together with --branches" -#~ msgstr "--exclude-hidden ne peut être utilisé avec --branches" - -#~ msgid "--exclude-hidden cannot be used together with --tags" -#~ msgstr "--exclude-hidden ne peut pas être utilisé avec --tags" - -#~ msgid "--exclude-hidden cannot be used together with --remotes" -#~ msgstr "--exclude-hidden ne peut pas être utilisé avec --remotes" - -#, c-format -#~ msgid "only one of '%s', '%s' or '%s' can be given" -#~ msgstr "les options '%s', '%s' et '%s' sont mutuellement exclusives" - -#, c-format -#~ msgid "'%s' and '%s' cannot be used together" -#~ msgstr "'%s' et '%s' ne peuvent pas être utilisées ensemble" - -#, c-format -#~ msgid "options '%s', and '%s' cannot be used together" -#~ msgstr "les options '%s' et '%s' ne peuvent pas être utilisées ensemble" - -#~ msgid "" -#~ msgstr "" - -#, c-format -#~ msgid "%s is incompatible with %s" -#~ msgstr "%s est incompatible avec %s" - -#~ msgid "unhandled options" -#~ msgstr "options non gérées" - -#, c-format -#~ msgid "options '%s=%s' and '%s=%s' cannot be used together" -#~ msgstr "" -#~ "les options '%s=%s' et '%s=%s' ne peuvent pas être utilisées ensemble" - -#, c-format -#~ msgid "%s : incompatible with something else" -#~ msgstr "%s est incompatible avec toute autre option" - -#~ msgid "Could not write patch" -#~ msgstr "Impossible d'écrire le patch" - -#, c-format -#~ msgid "Could not stat '%s'" -#~ msgstr "Stat de '%s' impossible" - -#, c-format -#~ msgid "Cannot delete branch '%s' checked out at '%s'" -#~ msgstr "Impossible de supprimer la branche '%s' extraite dans '%s'" - -#~ msgid "unable to write new_index file" -#~ msgstr "impossible d'écrire le fichier new_index" - -#~ msgid "do not apply config rules" -#~ msgstr "ne pas appliquer les règles de la configuration" - -#~ msgid "join whitespace-continued values" -#~ msgstr "joindre les valeurs continuées avec des caractères blancs" - -#~ msgid "set parsing options" -#~ msgstr "paramètres d'analyse" - -#~ msgid "cannot move directory over file" -#~ msgstr "impossible de déplacer un répertoire sur un fichier" - -#~ msgid "cannot use --filter without --stdout" -#~ msgstr "impossible d'utiliser --filter sans --stdout" - -#~ msgid "cannot use --max-pack-size with --cruft" -#~ msgstr "impossible d'utiliser --max-pack-size avec --cruft" - -#~ msgid "--strategy requires --merge or --interactive" -#~ msgstr "--strategy requiert --merge ou --interactive" - -#, c-format -#~ msgid "" -#~ "commit-graph has generation number zero for commit %s, but non-zero " -#~ "elsewhere" -#~ msgstr "" -#~ "le graphe de commit a un numéro de génération nul pour le commit %s, mais " -#~ "non-nul ailleurs" - -#~ msgid "--merge-base only works with commits" -#~ msgstr "--merge-base ne fonctionne qu'avec des commits" - -#~ msgid "scalar clone [] [--] []" -#~ msgstr "scalar clone [] [--] []" - -#, c-format -#~ msgid "could not rename '%s' to '%s'" -#~ msgstr "impossible de renommer '%s' en '%s'" - -#, c-format -#~ msgid "It is not possible to %s because you have unmerged files." -#~ msgstr "%s n'est pas possible car vous avez des fichiers non fusionnés." - -#~ msgid "do not pass --keep-cr flag to git-mailsplit independent of am.keepcr" -#~ msgstr "" -#~ "ne pas passer l'option --keep-cr à git-mailsplit indépendamment de am." -#~ "keepcr" - -#~ msgid "" -#~ "Updates were rejected because the tip of the remote-tracking\n" -#~ "branch has been updated since the last checkout. You may want\n" -#~ "to integrate those changes locally (e.g., 'git pull ...')\n" -#~ "before forcing an update.\n" -#~ msgstr "" -#~ "Les mises à jour ont été rejetées, car la pointe de la branche\n" -#~ "de suivi a été mise à jour depuis la dernière extraction. Intégrez\n" -#~ "ces changements localement (par exemple 'git pull ...') avant de\n" -#~ "forcer à nouveau une mise à jour.\n" - -#~ msgid "or do not fetch any tag at all (--no-tags)" -#~ msgstr "ou ne rapatrier aucune étiquette (--no-tags)" - -#~ msgid "current working directory is untracked" -#~ msgstr "l'arbre de travail actuel est non-suivi" - -#~ msgid "cannot use --contents with final commit object name" -#~ msgstr "on ne peut pas utiliser --contents avec un nom d'objet commit final" - -#~ msgid "please commit or stash them." -#~ msgstr "veuillez les valider ou les remiser." - -#, c-format -#~ msgid "Unknown mode: %s" -#~ msgstr "Mode inconnu : %s" - -#~ msgid "could not lock HEAD" -#~ msgstr "impossible de verrouiller HEAD" -- cgit v1.2.3 From 1b0882cba2f17ae126cba42bf58354f9290089d9 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 20 Dec 2024 20:44:21 +0100 Subject: Makefile: stop including "GIT-VERSION-FILE" in docs We include "GIT-VERSION-FILE" in our docs Makefile, but don't actually use the "GIT_VERSION" variable that it provides. This is a leftover from the conversion to make "GIT-VERSION-GEN" generate version information in-place by substituting placeholders in 4838deab65 (Makefile: refactor GIT-VERSION-GEN to be reusable, 2024-12-06) and subsequent commits, where all usages of the variable were removed. Stop including the file. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/Makefile | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Documentation/Makefile b/Documentation/Makefile index 3392e1ce7e..44c9e9369a 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -276,13 +276,6 @@ install-pdf: pdf install-html: html '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir) -../GIT-VERSION-FILE: FORCE - $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) GIT-VERSION-FILE - -ifneq ($(filter-out lint-docs clean,$(MAKECMDGOALS)),) --include ../GIT-VERSION-FILE -endif - mergetools_txt = mergetools-diff.txt mergetools-merge.txt # -- cgit v1.2.3 From b329f2eb002a53f2283b45de2ba5884f7b8cd5ba Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 20 Dec 2024 20:44:22 +0100 Subject: Makefile: drop unneeded indirection for GIT-VERSION-GEN outputs Some of the callsites of GIT-VERSION-GEN generate the target file with a "+" suffix first and then move the file into place when the new contents are different compared to the old contents. This allows us to avoid a needless rebuild by not updating timestamps of the target file when its contents will remain unchanged anyway. In fact though, this exact logic is already handled in GIT-VERSION-GEN, so doing this manually is pointless. This is a leftover from an earlier version of 4838deab65 (Makefile: refactor GIT-VERSION-GEN to be reusable, 2024-12-06), where the script didn't handle that logic for us. Drop the needless indirection. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/Makefile | 6 ++---- Makefile | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Documentation/Makefile b/Documentation/Makefile index 44c9e9369a..1a398d0dc3 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -211,12 +211,10 @@ XMLTO_EXTRA += --skip-validation XMLTO_EXTRA += -x manpage.xsl asciidoctor-extensions.rb: asciidoctor-extensions.rb.in FORCE - $(QUIET_GEN)GIT_USER_AGENT="$(GIT_USER_AGENT)" $(SHELL_PATH) ../GIT-VERSION-GEN "$(shell pwd)/.." $< $@+ - @if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi + $(QUIET_GEN)GIT_USER_AGENT="$(GIT_USER_AGENT)" $(SHELL_PATH) ../GIT-VERSION-GEN "$(shell pwd)/.." $< $@ else asciidoc.conf: asciidoc.conf.in FORCE - $(QUIET_GEN)GIT_USER_AGENT="$(GIT_USER_AGENT)" $(SHELL_PATH) ../GIT-VERSION-GEN "$(shell pwd)/.." $< $@+ - @if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi + $(QUIET_GEN)GIT_USER_AGENT="$(GIT_USER_AGENT)" $(SHELL_PATH) ../GIT-VERSION-GEN "$(shell pwd)/.." $< $@ endif ASCIIDOC_DEPS += docinfo.html diff --git a/Makefile b/Makefile index c4b9d2801a..fab398e885 100644 --- a/Makefile +++ b/Makefile @@ -2509,8 +2509,7 @@ pager.sp pager.s pager.o: EXTRA_CPPFLAGS = \ -DPAGER_ENV='$(PAGER_ENV_CQ_SQ)' version-def.h: version-def.h.in GIT-VERSION-GEN GIT-VERSION-FILE GIT-USER-AGENT - $(QUIET_GEN)GIT_USER_AGENT="$(GIT_USER_AGENT)" $(SHELL_PATH) ./GIT-VERSION-GEN "$(shell pwd)" $< $@+ - @if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi + $(QUIET_GEN)GIT_USER_AGENT="$(GIT_USER_AGENT)" $(SHELL_PATH) ./GIT-VERSION-GEN "$(shell pwd)" $< $@ version.sp version.s version.o: version-def.h @@ -2551,8 +2550,7 @@ $(SCRIPT_SH_GEN) $(SCRIPT_LIB) : % : %.sh generate-script.sh GIT-BUILD-OPTIONS G mv $@+ $@ git.rc: git.rc.in GIT-VERSION-GEN GIT-VERSION-FILE - $(QUIET_GEN)$(SHELL_PATH) ./GIT-VERSION-GEN "$(shell pwd)" $< $@+ - @if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi + $(QUIET_GEN)$(SHELL_PATH) ./GIT-VERSION-GEN "$(shell pwd)" $< $@ git.res: git.rc GIT-PREFIX $(QUIET_RC)$(RC) -i $< -o $@ -- cgit v1.2.3 From 114494ae2c6f473dd9c9745a9b4fc6c55b70f2e8 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 20 Dec 2024 20:44:23 +0100 Subject: Makefile: introduce template for GIT-VERSION-GEN Introduce a new template to call GIT-VERSION-GEN. This will allow us to iterate on how exactly the script is called in subsequent commits without having to adapt all call sites every time. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/Makefile | 4 ++-- Makefile | 6 +++--- shared.mak | 8 ++++++++ 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Documentation/Makefile b/Documentation/Makefile index 1a398d0dc3..ff30ab6c42 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -211,10 +211,10 @@ XMLTO_EXTRA += --skip-validation XMLTO_EXTRA += -x manpage.xsl asciidoctor-extensions.rb: asciidoctor-extensions.rb.in FORCE - $(QUIET_GEN)GIT_USER_AGENT="$(GIT_USER_AGENT)" $(SHELL_PATH) ../GIT-VERSION-GEN "$(shell pwd)/.." $< $@ + $(QUIET_GEN)$(call version_gen,"$(shell pwd)/..",$<,$@) else asciidoc.conf: asciidoc.conf.in FORCE - $(QUIET_GEN)GIT_USER_AGENT="$(GIT_USER_AGENT)" $(SHELL_PATH) ../GIT-VERSION-GEN "$(shell pwd)/.." $< $@ + $(QUIET_GEN)$(call version_gen,"$(shell pwd)/..",$<,$@) endif ASCIIDOC_DEPS += docinfo.html diff --git a/Makefile b/Makefile index fab398e885..c6973a720a 100644 --- a/Makefile +++ b/Makefile @@ -593,7 +593,7 @@ include shared.mak GIT-VERSION-FILE: FORCE @OLD=$$(cat $@ 2>/dev/null || :) && \ - $(SHELL_PATH) ./GIT-VERSION-GEN "$(shell pwd)" GIT-VERSION-FILE.in $@ && \ + $(call version_gen,"$(shell pwd)",GIT-VERSION-FILE.in,$@) && \ NEW=$$(cat $@ 2>/dev/null || :) && \ if test "$$OLD" != "$$NEW"; then echo "$$NEW" >&2; fi -include GIT-VERSION-FILE @@ -2509,7 +2509,7 @@ pager.sp pager.s pager.o: EXTRA_CPPFLAGS = \ -DPAGER_ENV='$(PAGER_ENV_CQ_SQ)' version-def.h: version-def.h.in GIT-VERSION-GEN GIT-VERSION-FILE GIT-USER-AGENT - $(QUIET_GEN)GIT_USER_AGENT="$(GIT_USER_AGENT)" $(SHELL_PATH) ./GIT-VERSION-GEN "$(shell pwd)" $< $@ + $(QUIET_GEN)$(call version_gen,"$(shell pwd)",$<,$@) version.sp version.s version.o: version-def.h @@ -2550,7 +2550,7 @@ $(SCRIPT_SH_GEN) $(SCRIPT_LIB) : % : %.sh generate-script.sh GIT-BUILD-OPTIONS G mv $@+ $@ git.rc: git.rc.in GIT-VERSION-GEN GIT-VERSION-FILE - $(QUIET_GEN)$(SHELL_PATH) ./GIT-VERSION-GEN "$(shell pwd)" $< $@ + $(QUIET_GEN)$(call version_gen,"$(shell pwd)",$<,$@) git.res: git.rc GIT-PREFIX $(QUIET_RC)$(RC) -i $< -o $@ diff --git a/shared.mak b/shared.mak index 29bebd30d8..b23c5505c9 100644 --- a/shared.mak +++ b/shared.mak @@ -116,3 +116,11 @@ endef define libpath_template -L$(1) $(if $(filter-out -L,$(CC_LD_DYNPATH)),$(CC_LD_DYNPATH)$(1)) endef + +# Populate build information into a file via GIT-VERSION-GEN. Requires the +# absolute path to the root source directory as well as input and output files +# as arguments, in that order. +define version_gen +GIT_USER_AGENT="$(GIT_USER_AGENT)" \ +$(SHELL_PATH) "$(1)/GIT-VERSION-GEN" "$(1)" "$(2)" "$(3)" +endef -- cgit v1.2.3 From 992bc5618f2879a8d7f00a60489e78c48e661820 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 20 Dec 2024 20:44:24 +0100 Subject: GIT-VERSION-GEN: fix overriding GIT_VERSION GIT-VERSION-GEN tries to derive the version that Git is being built from via multiple different sources in the following order: 1. A file called "version" in the source tree's root directory, if it exists. 2. The current commit in case Git is built from a Git repository. 3. Otherwise, we use a fallback version stored in a variable which is bumped whenever a new Git version is getting tagged. It used to be possible to override the version by overriding the `GIT_VERSION` Makefile variable (e.g. `make GIT_VERSION=foo`). This worked somewhat by chance, only: `GIT-VERSION-GEN` would write the actual Git version into `GIT-VERSION-FILE`, not the overridden value, but when including the file into our Makefile we would not override the `GIT_VERSION` variable because it has already been set by the user. And because our Makefile used the variable to propagate the version to our build tools instead of using `GIT-VERSION-FILE` the resulting build artifacts used the overridden version. But that subtle mechanism broke with 4838deab65 (Makefile: refactor GIT-VERSION-GEN to be reusable, 2024-12-06) and subsequent commits because the version information is not propagated via the Makefile variable anymore, but instead via the files that `GIT-VERSION-GEN` started to write. And as the script never knew about the `GIT_VERSION` environment variable in the first place it uses one of the values listed above instead of the overridden value. Fix this issue by making `GIT-VERSION-GEN` handle the case where `GIT_VERSION` has been set via the environment. Note that this requires us to introduce a new GIT_VERSION_OVERRIDE variable that stores a potential user-provided value, either via the environment or via "config.mak". Ideally we wouldn't need it and could just continue to use GIT_VERSION for this. But unfortunately, Makefiles will first include all sub-Makefiles before figuring out whether it needs to re-make any of them [1]. Consequently, if there already is a GIT-VERSION-FILE, we would have slurped in its value of GIT_VERSION before we call GIT-VERSION-GEN, and because GIT-VERSION-GEN now uses that value as an override it would mean that the first generated value for GIT_VERSION will remain unchanged. Furthermore we have to move the include for "GIT-VERSION-FILE" after the includes for "config.mak" and related so that GIT_VERSION_OVERRIDE can be set to the value provided by "config.mak". [1]: https://www.gnu.org/software/make/manual/html_node/Remaking-Makefiles.html Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/Makefile | 4 ++++ GIT-VERSION-GEN | 48 ++++++++++++++++++++++++++---------------------- Makefile | 19 ++++++++++++------- shared.mak | 1 + 4 files changed, 43 insertions(+), 29 deletions(-) diff --git a/Documentation/Makefile b/Documentation/Makefile index ff30ab6c42..a89823e1d1 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -181,6 +181,10 @@ endif -include ../config.mak.autogen -include ../config.mak +# Set GIT_VERSION_OVERRIDE such that version_gen knows to substitute +# GIT_VERSION in case it was set by the user. +GIT_VERSION_OVERRIDE := $(GIT_VERSION) + ifndef NO_MAN_BOLD_LITERAL XMLTO_EXTRA += -m manpage-bold-literal.xsl endif diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index b4687784c1..2fee5e7e80 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -27,31 +27,35 @@ fi GIT_CEILING_DIRECTORIES="$SOURCE_DIR/.." export GIT_CEILING_DIRECTORIES -# First see if there is a version file (included in release tarballs), -# then try git-describe, then default. -if test -f "$SOURCE_DIR"/version +if test -z "$GIT_VERSION" then - VN=$(cat "$SOURCE_DIR"/version) || VN="$DEF_VER" -elif { - test -d "$SOURCE_DIR/.git" || - test -d "${GIT_DIR:-.git}" || - test -f "$SOURCE_DIR"/.git; - } && - VN=$(git -C "$SOURCE_DIR" describe --match "v[0-9]*" HEAD 2>/dev/null) && - case "$VN" in - *$LF*) (exit 1) ;; - v[0-9]*) - git -C "$SOURCE_DIR" update-index -q --refresh - test -z "$(git -C "$SOURCE_DIR" diff-index --name-only HEAD --)" || - VN="$VN-dirty" ;; - esac -then - VN=$(echo "$VN" | sed -e 's/-/./g'); -else - VN="$DEF_VER" + # First see if there is a version file (included in release tarballs), + # then try git-describe, then default. + if test -f "$SOURCE_DIR"/version + then + VN=$(cat "$SOURCE_DIR"/version) || VN="$DEF_VER" + elif { + test -d "$SOURCE_DIR/.git" || + test -d "${GIT_DIR:-.git}" || + test -f "$SOURCE_DIR"/.git; + } && + VN=$(git -C "$SOURCE_DIR" describe --match "v[0-9]*" HEAD 2>/dev/null) && + case "$VN" in + *$LF*) (exit 1) ;; + v[0-9]*) + git -C "$SOURCE_DIR" update-index -q --refresh + test -z "$(git -C "$SOURCE_DIR" diff-index --name-only HEAD --)" || + VN="$VN-dirty" ;; + esac + then + VN=$(echo "$VN" | sed -e 's/-/./g'); + else + VN="$DEF_VER" + fi + + GIT_VERSION=$(expr "$VN" : v*'\(.*\)') fi -GIT_VERSION=$(expr "$VN" : v*'\(.*\)') GIT_BUILT_FROM_COMMIT=$(git -C "$SOURCE_DIR" rev-parse -q --verify HEAD 2>/dev/null) GIT_DATE=$(git -C "$SOURCE_DIR" show --quiet --format='%as' 2>/dev/null) if test -z "$GIT_USER_AGENT" diff --git a/Makefile b/Makefile index c6973a720a..5e14da0ae6 100644 --- a/Makefile +++ b/Makefile @@ -591,13 +591,6 @@ include shared.mak # # Disable -pedantic compilation. -GIT-VERSION-FILE: FORCE - @OLD=$$(cat $@ 2>/dev/null || :) && \ - $(call version_gen,"$(shell pwd)",GIT-VERSION-FILE.in,$@) && \ - NEW=$$(cat $@ 2>/dev/null || :) && \ - if test "$$OLD" != "$$NEW"; then echo "$$NEW" >&2; fi --include GIT-VERSION-FILE - # Set our default configuration. # # Among the variables below, these: @@ -1465,6 +1458,18 @@ ifdef DEVELOPER include config.mak.dev endif +GIT-VERSION-FILE: FORCE + @OLD=$$(cat $@ 2>/dev/null || :) && \ + $(call version_gen,"$(shell pwd)",GIT-VERSION-FILE.in,$@) && \ + NEW=$$(cat $@ 2>/dev/null || :) && \ + if test "$$OLD" != "$$NEW"; then echo "$$NEW" >&2; fi + +# We need to set GIT_VERSION_OVERRIDE before including the version file as +# otherwise any user-provided value for GIT_VERSION would have been overridden +# already. +GIT_VERSION_OVERRIDE := $(GIT_VERSION) +-include GIT-VERSION-FILE + # what 'all' will build and 'install' will install in gitexecdir, # excluding programs for built-in commands ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) diff --git a/shared.mak b/shared.mak index b23c5505c9..a66f46969e 100644 --- a/shared.mak +++ b/shared.mak @@ -122,5 +122,6 @@ endef # as arguments, in that order. define version_gen GIT_USER_AGENT="$(GIT_USER_AGENT)" \ +GIT_VERSION="$(GIT_VERSION_OVERRIDE)" \ $(SHELL_PATH) "$(1)/GIT-VERSION-GEN" "$(1)" "$(2)" "$(3)" endef -- cgit v1.2.3 From cfa01e6da515e409fdeaf39e50e8c3b7a70405b9 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 20 Dec 2024 20:44:25 +0100 Subject: GIT-VERSION-GEN: fix overriding GIT_BUILT_FROM_COMMIT and GIT_DATE Same as with the preceding commit, neither GIT_BUILT_FROM_COMMIT nor GIT_DATE can be overridden via the environment. Especially the latter is of importance given that we set it in our own "Documentation/doc-diff" script. Make the values of both variables overridable. Luckily we don't pull in these values via any included Makefiles, so the fix is trivial compared to the fix for GIT_VERSON. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- GIT-VERSION-GEN | 12 ++++++++++-- shared.mak | 2 ++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 2fee5e7e80..8dc54f6378 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -56,8 +56,16 @@ then GIT_VERSION=$(expr "$VN" : v*'\(.*\)') fi -GIT_BUILT_FROM_COMMIT=$(git -C "$SOURCE_DIR" rev-parse -q --verify HEAD 2>/dev/null) -GIT_DATE=$(git -C "$SOURCE_DIR" show --quiet --format='%as' 2>/dev/null) +if test -z "$GIT_BUILT_FROM_COMMIT" +then + GIT_BUILT_FROM_COMMIT=$(git -C "$SOURCE_DIR" rev-parse -q --verify HEAD 2>/dev/null) +fi + +if test -z "$GIT_DATE" +then + GIT_DATE=$(git -C "$SOURCE_DIR" show --quiet --format='%as' 2>/dev/null) +fi + if test -z "$GIT_USER_AGENT" then GIT_USER_AGENT="git/$GIT_VERSION" diff --git a/shared.mak b/shared.mak index a66f46969e..1a99848a95 100644 --- a/shared.mak +++ b/shared.mak @@ -121,6 +121,8 @@ endef # absolute path to the root source directory as well as input and output files # as arguments, in that order. define version_gen +GIT_BUILT_FROM_COMMIT="$(GIT_BUILT_FROM_COMMIT)" \ +GIT_DATE="$(GIT_DATE)" \ GIT_USER_AGENT="$(GIT_USER_AGENT)" \ GIT_VERSION="$(GIT_VERSION_OVERRIDE)" \ $(SHELL_PATH) "$(1)/GIT-VERSION-GEN" "$(1)" "$(2)" "$(3)" -- cgit v1.2.3 From 1bc815c3d0eff054c7a032130206d16839bb331a Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 20 Dec 2024 20:44:26 +0100 Subject: meson: add options to override build information We inject various different kinds of build information into build artifacts, like the version string or the commit from which Git was built. Add options to let users explicitly override this information with Meson. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/meson.build | 1 + meson.build | 13 +++++++++++++ meson_options.txt | 10 ++++++++++ 3 files changed, 24 insertions(+) diff --git a/Documentation/meson.build b/Documentation/meson.build index f2426ccaa3..fca3eab1f1 100644 --- a/Documentation/meson.build +++ b/Documentation/meson.build @@ -219,6 +219,7 @@ asciidoc_conf = custom_target( input: meson.current_source_dir() / 'asciidoc.conf.in', output: 'asciidoc.conf', depends: [git_version_file], + env: version_gen_environment, ) asciidoc_common_options = [ diff --git a/meson.build b/meson.build index 0dccebcdf1..be32d60e84 100644 --- a/meson.build +++ b/meson.build @@ -201,6 +201,16 @@ if get_option('sane_tool_path') != '' script_environment.prepend('PATH', get_option('sane_tool_path')) endif +# The environment used by GIT-VERSION-GEN. Note that we explicitly override +# environment variables that might be set by the user. This is by design so +# that we always use whatever Meson has configured instead of what is present +# in the environment. +version_gen_environment = script_environment +version_gen_environment.set('GIT_BUILT_FROM_COMMIT', get_option('built_from_commit')) +version_gen_environment.set('GIT_DATE', get_option('build_date')) +version_gen_environment.set('GIT_USER_AGENT', get_option('user_agent')) +version_gen_environment.set('GIT_VERSION', get_option('version')) + compiler = meson.get_compiler('c') libgit_sources = [ @@ -1485,6 +1495,7 @@ git_version_file = custom_target( ], input: meson.current_source_dir() / 'GIT-VERSION-FILE.in', output: 'GIT-VERSION-FILE', + env: version_gen_environment, build_always_stale: true, ) @@ -1501,6 +1512,7 @@ version_def_h = custom_target( # Depend on GIT-VERSION-FILE so that we don't always try to rebuild this # target for the same commit. depends: [git_version_file], + env: version_gen_environment, ) # Build a separate library for "version.c" so that we do not have to rebuild @@ -1544,6 +1556,7 @@ if host_machine.system() == 'windows' input: meson.current_source_dir() / 'git.rc.in', output: 'git.rc', depends: [git_version_file], + env: version_gen_environment, ) common_main_sources += import('windows').compile_resources(git_rc, diff --git a/meson_options.txt b/meson_options.txt index 32a72139ba..8ead134955 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -16,6 +16,16 @@ option('runtime_prefix', type: 'boolean', value: false, option('sane_tool_path', type: 'string', value: '', description: 'A colon-separated list of paths to prepend to PATH if your tools in /usr/bin are broken.') +# Build information compiled into Git and other parts like documentation. +option('build_date', type: 'string', value: '', + description: 'Build date reported by our documentation.') +option('built_from_commit', type: 'string', value: '', + description: 'Commit that Git was built from reported by git-version(1).') +option('user_agent', type: 'string', value: '', + description: 'User agent reported to remote servers.') +option('version', type: 'string', value: '', + description: 'Version string reported by git-version(1) and other tools.') + # Features supported by Git. option('curl', type: 'feature', value: 'enabled', description: 'Build helpers used to access remotes with the HTTP transport.') -- cgit v1.2.3 From 49edce4ff96d003e2b50202105107ef42e1f730e Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 20 Dec 2024 10:02:15 -0800 Subject: show-index: the short help should say the command reads from its input The short help text given by "git show-index -h" says $ git show-index -h usage: git show-index [--object-format=] --[no-]object-format specify the hash algorithm to use The command takes a pack .idx file from its standard input. The user has to _know_ this, as there is no indication from this output. Give a hint that the data to work on is fed from its standard input. Signed-off-by: Junio C Hamano --- Documentation/git-show-index.txt | 2 +- builtin/show-index.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/git-show-index.txt b/Documentation/git-show-index.txt index e49318a5a0..7e574ea243 100644 --- a/Documentation/git-show-index.txt +++ b/Documentation/git-show-index.txt @@ -9,7 +9,7 @@ git-show-index - Show packed archive index SYNOPSIS -------- [verse] -'git show-index' [--object-format=] +'git show-index' [--object-format=] < DESCRIPTION diff --git a/builtin/show-index.c b/builtin/show-index.c index f164c01bbe..8678b741a4 100644 --- a/builtin/show-index.c +++ b/builtin/show-index.c @@ -7,7 +7,7 @@ #include "parse-options.h" static const char *const show_index_usage[] = { - "git show-index [--object-format=]", + "git show-index [--object-format=] < ", NULL }; -- cgit v1.2.3 From 298805c823067ca32b1577662c87f77240e36aec Mon Sep 17 00:00:00 2001 From: Martin Ågren Date: Sat, 21 Dec 2024 00:18:16 +0100 Subject: asciidoctor-extensions.rb.in: delete existing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After the recent a38edab7c8 (Makefile: generate doc versions via GIT-VERSION-GEN, 2024-12-06), building with Asciidoctor results in manpages where the headers no longer contain "Git Manual" and the footers no longer identify the built Git version. Before a38edab7c8, we used to just provide a few attributes to Asciidoctor (and asciidoc). Commit 7a30134358 (asciidoctor-extensions: provide ``, 2019-09-16) noted that older versions of Asciidoctor didn't propagate those attributes into the built XML files, so we started injecting them ourselves from this script. With newer versions of Asciidoctor, we'd end up with some harmless duplication among the tags in the final XML. Post-a38edab7c8, we don't provide these attributes and Asciidoctor inserts empty-ish values. After our additions from 7a30134358, we get     2.47.1.[...] Git Manual When these are handled, it appears to be first come first served, meaning that our additions have no effect and we regress as described in the first paragraph. Remove existing "source" or "manual" tags before adding ours. I considered removing all to get a nice clean slate, instead of just those two that we want to replace to be a bit more precise. I opted for the latter. Maybe one day, Asciidoctor learns to insert something useful there which `xmlto` can pick up and make good use of -- let's not interfere. Signed-off-by: Martin Ågren Signed-off-by: Junio C Hamano --- Documentation/asciidoctor-extensions.rb.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/asciidoctor-extensions.rb.in b/Documentation/asciidoctor-extensions.rb.in index c4c200dace..d8d06f9a57 100644 --- a/Documentation/asciidoctor-extensions.rb.in +++ b/Documentation/asciidoctor-extensions.rb.in @@ -29,6 +29,8 @@ module Git class DocumentPostProcessor < Asciidoctor::Extensions::Postprocessor def process document, output if document.basebackend? 'docbook' + output = output.sub(/.*?<\/refmiscinfo>/, "") + output = output.sub(/.*?<\/refmiscinfo>/, "") new_tags = "" \ "@GIT_VERSION@\n" \ "Git Manual\n" -- cgit v1.2.3 From c683924d06e3c1f0166054450d4a7ecbabca0756 Mon Sep 17 00:00:00 2001 From: Martin Ågren Date: Sat, 21 Dec 2024 00:18:17 +0100 Subject: asciidoctor-extensions.rb.in: add missing word MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit a38edab7c8 (Makefile: generate doc versions via GIT-VERSION-GEN, 2024-12-06) stopped providing an attribute value "Git $(GIT_VERSION)" to asciidoc/Asciidoctor over the command line. Instead, we now provide the attribute to asciidoc through a generated asciidoc.conf, where the value is generated as "Git @GIT_VERSION@". In the similar mechanism for Asciidoctor, we forgot the "Git" prefix. Restore it. Signed-off-by: Martin Ågren Signed-off-by: Junio C Hamano --- Documentation/asciidoctor-extensions.rb.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/asciidoctor-extensions.rb.in b/Documentation/asciidoctor-extensions.rb.in index d8d06f9a57..fd1b84c2be 100644 --- a/Documentation/asciidoctor-extensions.rb.in +++ b/Documentation/asciidoctor-extensions.rb.in @@ -32,7 +32,7 @@ module Git output = output.sub(/.*?<\/refmiscinfo>/, "") output = output.sub(/.*?<\/refmiscinfo>/, "") new_tags = "" \ - "@GIT_VERSION@\n" \ + "Git @GIT_VERSION@\n" \ "Git Manual\n" output = output.sub(/<\/refmeta>/, new_tags + "") end -- cgit v1.2.3 From beb8081f3153fe17907131b94b4c7d32167ff26d Mon Sep 17 00:00:00 2001 From: Martin Ågren Date: Sat, 21 Dec 2024 00:18:18 +0100 Subject: asciidoctor-extensions.rb.in: inject GIT_DATE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After a38edab7c8 (Makefile: generate doc versions via GIT-VERSION-GEN, 2024-12-06), we no longer inject GIT_DATE when building with Asciidoctor. Replace the tag in the XML to inject the value of GIT_DATE. Unlike as handled in a recent commit, we have no reason to expect that this tag might be missing, so there's no need for "maybe remove, then add" and we can just outright replace the one that Asciidoctor has generated based on the mtime of the source file. Compared to pre-a38edab7c8, we now end up injecting this also in the build of Git.3pm, which until now has been using the mtime of Git.pm. That is arguably even a good change since it results in more reproducible builds. Signed-off-by: Martin Ågren Signed-off-by: Junio C Hamano --- Documentation/asciidoctor-extensions.rb.in | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/asciidoctor-extensions.rb.in b/Documentation/asciidoctor-extensions.rb.in index fd1b84c2be..2494f17a51 100644 --- a/Documentation/asciidoctor-extensions.rb.in +++ b/Documentation/asciidoctor-extensions.rb.in @@ -31,6 +31,7 @@ module Git if document.basebackend? 'docbook' output = output.sub(/.*?<\/refmiscinfo>/, "") output = output.sub(/.*?<\/refmiscinfo>/, "") + output = output.sub(/.*?<\/date>/, "@GIT_DATE@") new_tags = "" \ "Git @GIT_VERSION@\n" \ "Git Manual\n" -- cgit v1.2.3 From 8e27ee9220883cf5a0629c752e1642daaba4ce14 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Sun, 22 Dec 2024 08:24:28 +0100 Subject: reftable/stack: don't perform auto-compaction with less than two tables In order to compact tables we need at least two tables. Bail out early from `reftable_stack_auto_compact()` in case we have less than two tables. In the original, `stack_table_sizes_for_compaction()` yields an array that has the same length as the number of tables. This array is then passed on to `suggest_compaction_segment()`, which returns an empty segment in case we have less than two tables. The segment is then passed to `segment_size()`, which will return `0` because both start and end of the segment are `0`. And because we only call `stack_compact_range()` in case we have a positive segment size we don't perform auto-compaction at all. Consequently, this change does not result in a user-visible change in behaviour when called with a single table. But when called with no tables this protects us against a potential out-of-memory error: `stack_table_sizes_for_compaction()` would try to allocate a zero-byte object when there aren't any tables, and that may lead to a `NULL` pointer on some platforms like NonStop which causes us to bail out with an out-of-memory error. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- reftable/stack.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/reftable/stack.c b/reftable/stack.c index 63976e5cea..ae274cd51c 100644 --- a/reftable/stack.c +++ b/reftable/stack.c @@ -1552,6 +1552,9 @@ int reftable_stack_auto_compact(struct reftable_stack *st) struct segment seg; uint64_t *sizes; + if (st->merged->readers_len < 2) + return 0; + sizes = stack_table_sizes_for_compaction(st); if (!sizes) return REFTABLE_OUT_OF_MEMORY_ERROR; -- cgit v1.2.3 From 5ab83521cfe687e4295f5748f2c5d2aa7477efe5 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Sun, 22 Dec 2024 08:24:29 +0100 Subject: reftable/merged: fix zero-sized allocation when there are no readers It was reported [1] that Git started to fail with an out-of-memory error when initializing repositories with the reftable backend on NonStop platforms. A bisect led to 802c0646ac (reftable/merged: handle allocation failures in `merged_table_init_iter()`, 2024-10-02), which changed how we allocate memory when initializing a merged table. The root cause of this seems to be that NonStop returns a `NULL` pointer when doing a zero-sized allocation. This would've already happened before the above change, but we never noticed because we did not check the result. Now we do notice and thus return an out-of-memory error to the caller. Fix the issue by skipping the allocation altogether in case there are no readers. [1]: <00ad01db5017$aa9ce340$ffd6a9c0$@nexbridge.com> Reported-by: Randall S. Becker Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- reftable/merged.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/reftable/merged.c b/reftable/merged.c index 514d6facf4..5ff4bc35c2 100644 --- a/reftable/merged.c +++ b/reftable/merged.c @@ -238,14 +238,16 @@ int merged_table_init_iter(struct reftable_merged_table *mt, struct reftable_iterator *it, uint8_t typ) { - struct merged_subiter *subiters; + struct merged_subiter *subiters = NULL; struct merged_iter *mi = NULL; int ret; - REFTABLE_CALLOC_ARRAY(subiters, mt->readers_len); - if (!subiters) { - ret = REFTABLE_OUT_OF_MEMORY_ERROR; - goto out; + if (mt->readers_len) { + REFTABLE_CALLOC_ARRAY(subiters, mt->readers_len); + if (!subiters) { + ret = REFTABLE_OUT_OF_MEMORY_ERROR; + goto out; + } } for (size_t i = 0; i < mt->readers_len; i++) { -- cgit v1.2.3 From 2d3cb4b4b5401e2fd5a40600277f424032fc72f0 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Sun, 22 Dec 2024 08:24:30 +0100 Subject: reftable/stack: fix zero-sized allocation when there are no readers Similar as the preceding commit, we may try to do a zero-sized allocation when reloading a reftable stack that ain't got any tables. It is implementation-defined whether malloc(3p) returns a NULL pointer in that case or a zero-sized object. In case it does return a NULL pointer though it causes us to think we have run into an out-of-memory situation, and thus we return an error. Fix this by only allocating arrays when they have at least one entry. Reported-by: Randall S. Becker Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- reftable/stack.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/reftable/stack.c b/reftable/stack.c index ae274cd51c..f51d3ec9d9 100644 --- a/reftable/stack.c +++ b/reftable/stack.c @@ -254,9 +254,9 @@ static int reftable_stack_reload_once(struct reftable_stack *st, int reuse_open) { size_t cur_len = !st->merged ? 0 : st->merged->readers_len; - struct reftable_reader **cur; + struct reftable_reader **cur = NULL; struct reftable_reader **reused = NULL; - struct reftable_reader **new_readers; + struct reftable_reader **new_readers = NULL; size_t reused_len = 0, reused_alloc = 0, names_len; size_t new_readers_len = 0; struct reftable_merged_table *new_merged = NULL; @@ -264,18 +264,22 @@ static int reftable_stack_reload_once(struct reftable_stack *st, int err = 0; size_t i; - cur = stack_copy_readers(st, cur_len); - if (!cur) { - err = REFTABLE_OUT_OF_MEMORY_ERROR; - goto done; + if (cur_len) { + cur = stack_copy_readers(st, cur_len); + if (!cur) { + err = REFTABLE_OUT_OF_MEMORY_ERROR; + goto done; + } } names_len = names_length(names); - new_readers = reftable_calloc(names_len, sizeof(*new_readers)); - if (!new_readers) { - err = REFTABLE_OUT_OF_MEMORY_ERROR; - goto done; + if (names_len) { + new_readers = reftable_calloc(names_len, sizeof(*new_readers)); + if (!new_readers) { + err = REFTABLE_OUT_OF_MEMORY_ERROR; + goto done; + } } while (*names) { -- cgit v1.2.3 From d7282891f542b58410a209230009182b9057af79 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Sun, 22 Dec 2024 08:24:31 +0100 Subject: reftable/basics: return NULL on zero-sized allocations In the preceding commits we have fixed a couple of issues when allocating zero-sized objects. These issues were masked by implementation-defined behaviour. Quoting malloc(3p): If size is 0, either: * A null pointer shall be returned and errno may be set to an implementation-defined value, or * A pointer to the allocated space shall be returned. The application shall ensure that the pointer is not used to access an object. So it is perfectly valid that implementations of this function may or may not return a NULL pointer in such a case. Adapt both `reftable_malloc()` and `reftable_realloc()` so that they return NULL pointers on zero-sized allocations. This should remove any implementation-defined behaviour in our allocators and thus allows us to detect such platform-specific issues more easily going forward. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- reftable/basics.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/reftable/basics.c b/reftable/basics.c index 9a949e5cf8..eab5553d93 100644 --- a/reftable/basics.c +++ b/reftable/basics.c @@ -16,6 +16,8 @@ static void (*reftable_free_ptr)(void *); void *reftable_malloc(size_t sz) { + if (!sz) + return NULL; if (reftable_malloc_ptr) return (*reftable_malloc_ptr)(sz); return malloc(sz); @@ -23,6 +25,11 @@ void *reftable_malloc(size_t sz) void *reftable_realloc(void *p, size_t sz) { + if (!sz) { + reftable_free(p); + return NULL; + } + if (reftable_realloc_ptr) return (*reftable_realloc_ptr)(p, sz); return realloc(p, sz); -- cgit v1.2.3 From f37c6dd44e6cc403ff622b57d49348e4e1a6f640 Mon Sep 17 00:00:00 2001 From: Alexander Shopov Date: Sun, 22 Dec 2024 21:07:03 +0100 Subject: git-gui i18n: Updated Bulgarian translation (579t) Signed-off-by: Alexander Shopov Signed-off-by: Johannes Sixt --- po/bg.po | 3721 +++++++++++++++++++++++++++++++------------------------------- 1 file changed, 1890 insertions(+), 1831 deletions(-) diff --git a/po/bg.po b/po/bg.po index 5af78f15a8..27b05038e4 100644 --- a/po/bg.po +++ b/po/bg.po @@ -1,15 +1,15 @@ # Bulgarian translation of git-gui po-file. -# Copyright (C) 2012, 2013, 2014, 2015, 2016 Alexander Shopov . +# Copyright (C) 2012, 2013, 2014, 2015, 2016, 2024 Alexander Shopov . # This file is distributed under the same license as the git package. -# Alexander Shopov , 2012, 2013, 2014, 2015, 2016. +# Alexander Shopov , 2012, 2013, 2014, 2015, 2016, 2024. # # msgid "" msgstr "" "Project-Id-Version: git-gui master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-10-13 15:16+0300\n" -"PO-Revision-Date: 2016-10-13 15:16+0300\n" +"POT-Creation-Date: 2020-02-08 22:54+0100\n" +"PO-Revision-Date: 2024-12-22 15:44+0100\n" "Last-Translator: Alexander Shopov \n" "Language-Team: Bulgarian \n" "Language: bg\n" @@ -18,33 +18,33 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: git-gui.sh:865 +#: git-gui.sh:847 #, tcl-format msgid "Invalid font specified in %s:" msgstr "Указан е неправилен шрифт в „%s“:" -#: git-gui.sh:919 +#: git-gui.sh:901 msgid "Main Font" msgstr "Основен шрифт" -#: git-gui.sh:920 +#: git-gui.sh:902 msgid "Diff/Console Font" msgstr "Шрифт за разликите/конзолата" -#: git-gui.sh:935 git-gui.sh:949 git-gui.sh:962 git-gui.sh:1052 git-gui.sh:1071 -#: git-gui.sh:3147 +#: git-gui.sh:917 git-gui.sh:931 git-gui.sh:944 git-gui.sh:1034 git-gui.sh:1053 +#: git-gui.sh:3212 msgid "git-gui: fatal error" msgstr "git-gui: фатална грешка" -#: git-gui.sh:936 +#: git-gui.sh:918 msgid "Cannot find git in PATH." msgstr "Командата git липсва в пътя (PATH)." -#: git-gui.sh:963 +#: git-gui.sh:945 msgid "Cannot parse Git version string:" -msgstr "Низът с версията на Git не може да бъде интерпретиран:" +msgstr "Низът с версията на Git не може да се анализира:" -#: git-gui.sh:988 +#: git-gui.sh:970 #, tcl-format msgid "" "Git version cannot be determined.\n" @@ -55,7 +55,7 @@ msgid "" "\n" "Assume '%s' is version 1.5.0?\n" msgstr "" -"Версията на Git не може да бъде определена.\n" +"Версията на Git не може да се определи.\n" "\n" "Версията на „%s“ изглежда, че е „%s“.\n" "\n" @@ -63,506 +63,522 @@ msgstr "" "\n" "Да се приеме ли, че „%s“ е версия „1.5.0“?\n" -#: git-gui.sh:1285 +#: git-gui.sh:1267 msgid "Git directory not found:" msgstr "Директорията на Git не е открита:" -#: git-gui.sh:1319 +#: git-gui.sh:1301 msgid "Cannot move to top of working directory:" -msgstr "Не може да се премине към родителската директория." +msgstr "Не може да се премине към родителската директория." -#: git-gui.sh:1327 +#: git-gui.sh:1309 msgid "Cannot use bare repository:" msgstr "Голо хранилище не може да се използва:" -#: git-gui.sh:1335 +#: git-gui.sh:1317 msgid "No working directory" msgstr "Работната директория липсва" -#: git-gui.sh:1507 lib/checkout_op.tcl:306 +#: git-gui.sh:1491 lib/checkout_op.tcl:306 msgid "Refreshing file status..." msgstr "Обновяване на състоянието на файла…" -#: git-gui.sh:1567 +#: git-gui.sh:1551 msgid "Scanning for modified files ..." msgstr "Проверка за променени файлове…" -#: git-gui.sh:1645 +#: git-gui.sh:1629 msgid "Calling prepare-commit-msg hook..." msgstr "Куката „prepare-commit-msg“ се изпълнява в момента…" -#: git-gui.sh:1662 +#: git-gui.sh:1646 msgid "Commit declined by prepare-commit-msg hook." msgstr "Подаването е отхвърлено от куката „prepare-commit-msg“." -#: git-gui.sh:1820 lib/browser.tcl:252 +#: git-gui.sh:1804 lib/browser.tcl:252 msgid "Ready." msgstr "Готово." -#: git-gui.sh:1984 +#: git-gui.sh:1968 #, tcl-format msgid "" "Display limit (gui.maxfilesdisplayed = %s) reached, not showing all %s files." msgstr "" -"Достигнат е максималният размер на списъка за извеждане(gui." -"maxfilesdisplayed = %s), съответно не са показани всички %s файла." +"Достигнат е максималният размер на списъка за " +"извеждане(gui.maxfilesdisplayed = %s), съответно не са показани всички %s " +"файла." -#: git-gui.sh:2107 +#: git-gui.sh:2091 msgid "Unmodified" msgstr "Непроменен" -#: git-gui.sh:2109 +#: git-gui.sh:2093 msgid "Modified, not staged" msgstr "Променен, но не е в индекса" -#: git-gui.sh:2110 git-gui.sh:2122 +#: git-gui.sh:2094 git-gui.sh:2106 msgid "Staged for commit" msgstr "В индекса за подаване" -#: git-gui.sh:2111 git-gui.sh:2123 +#: git-gui.sh:2095 git-gui.sh:2107 msgid "Portions staged for commit" msgstr "Части са в индекса за подаване" -#: git-gui.sh:2112 git-gui.sh:2124 +#: git-gui.sh:2096 git-gui.sh:2108 msgid "Staged for commit, missing" msgstr "В индекса за подаване, но липсва" -#: git-gui.sh:2114 +#: git-gui.sh:2098 msgid "File type changed, not staged" msgstr "Видът на файла е сменен, но не е в индекса" -#: git-gui.sh:2115 git-gui.sh:2116 +#: git-gui.sh:2099 git-gui.sh:2100 msgid "File type changed, old type staged for commit" msgstr "Видът на файла е сменен, но новият вид не е в индекса" -#: git-gui.sh:2117 +#: git-gui.sh:2101 msgid "File type changed, staged" msgstr "Видът на файла е сменен и е в индекса" -#: git-gui.sh:2118 +#: git-gui.sh:2102 msgid "File type change staged, modification not staged" msgstr "Видът на файла е сменен в индекса, но не и съдържанието" -#: git-gui.sh:2119 +#: git-gui.sh:2103 msgid "File type change staged, file missing" msgstr "Видът на файла е сменен в индекса, но файлът липсва" -#: git-gui.sh:2121 +#: git-gui.sh:2105 msgid "Untracked, not staged" msgstr "Неследен" -#: git-gui.sh:2126 +#: git-gui.sh:2110 msgid "Missing" msgstr "Липсващ" -#: git-gui.sh:2127 +#: git-gui.sh:2111 msgid "Staged for removal" msgstr "В индекса за изтриване" -#: git-gui.sh:2128 +#: git-gui.sh:2112 msgid "Staged for removal, still present" msgstr "В индекса за изтриване, но още го има" -#: git-gui.sh:2130 git-gui.sh:2131 git-gui.sh:2132 git-gui.sh:2133 -#: git-gui.sh:2134 git-gui.sh:2135 +#: git-gui.sh:2114 git-gui.sh:2115 git-gui.sh:2116 git-gui.sh:2117 +#: git-gui.sh:2118 git-gui.sh:2119 msgid "Requires merge resolution" msgstr "Изисква коригиране при сливане" -#: git-gui.sh:2170 -msgid "Starting gitk... please wait..." -msgstr "Стартиране на „gitk“…, изчакайте…" - -#: git-gui.sh:2182 +#: git-gui.sh:2164 msgid "Couldn't find gitk in PATH" msgstr "Командата „gitk“ липсва в пътищата, определени от променливата PATH." -#: git-gui.sh:2241 +#: git-gui.sh:2210 git-gui.sh:2245 +#, tcl-format +msgid "Starting %s... please wait..." +msgstr "Стартиране на „%s“…, изчакайте…" + +#: git-gui.sh:2224 msgid "Couldn't find git gui in PATH" msgstr "" "Командата „git gui“ липсва в пътищата, определени от променливата PATH." -#: git-gui.sh:2676 lib/choose_repository.tcl:41 +#: git-gui.sh:2726 lib/choose_repository.tcl:53 msgid "Repository" msgstr "Хранилище" -#: git-gui.sh:2677 +#: git-gui.sh:2727 msgid "Edit" msgstr "Редактиране" -#: git-gui.sh:2679 lib/choose_rev.tcl:567 +#: git-gui.sh:2729 lib/choose_rev.tcl:567 msgid "Branch" msgstr "Клон" -#: git-gui.sh:2682 lib/choose_rev.tcl:554 +#: git-gui.sh:2732 lib/choose_rev.tcl:554 msgid "Commit@@noun" msgstr "Подаване" -#: git-gui.sh:2685 lib/merge.tcl:127 lib/merge.tcl:174 +#: git-gui.sh:2735 lib/merge.tcl:127 lib/merge.tcl:174 msgid "Merge" msgstr "Сливане" -#: git-gui.sh:2686 lib/choose_rev.tcl:563 +#: git-gui.sh:2736 lib/choose_rev.tcl:563 msgid "Remote" msgstr "Отдалечено хранилище" -#: git-gui.sh:2689 +#: git-gui.sh:2739 msgid "Tools" msgstr "Команди" -#: git-gui.sh:2698 +#: git-gui.sh:2748 msgid "Explore Working Copy" msgstr "Разглеждане на работното копие" -#: git-gui.sh:2704 +#: git-gui.sh:2763 msgid "Git Bash" msgstr "Bash за Git" -#: git-gui.sh:2714 +#: git-gui.sh:2772 msgid "Browse Current Branch's Files" msgstr "Разглеждане на файловете в текущия клон" -#: git-gui.sh:2718 +#: git-gui.sh:2776 msgid "Browse Branch Files..." msgstr "Разглеждане на текущия клон…" -#: git-gui.sh:2723 +#: git-gui.sh:2781 msgid "Visualize Current Branch's History" msgstr "Визуализация на историята на текущия клон" -#: git-gui.sh:2727 +#: git-gui.sh:2785 msgid "Visualize All Branch History" msgstr "Визуализация на историята на всички клонове" -#: git-gui.sh:2734 +#: git-gui.sh:2792 #, tcl-format msgid "Browse %s's Files" msgstr "Разглеждане на файловете в „%s“" -#: git-gui.sh:2736 +#: git-gui.sh:2794 #, tcl-format msgid "Visualize %s's History" msgstr "Визуализация на историята на „%s“" -#: git-gui.sh:2741 lib/database.tcl:40 +#: git-gui.sh:2799 lib/database.tcl:40 msgid "Database Statistics" msgstr "Статистика на базата от данни" -#: git-gui.sh:2744 lib/database.tcl:33 +#: git-gui.sh:2802 lib/database.tcl:33 msgid "Compress Database" msgstr "Компресиране на базата от данни" -#: git-gui.sh:2747 +#: git-gui.sh:2805 msgid "Verify Database" msgstr "Проверка на базата от данни" -#: git-gui.sh:2754 git-gui.sh:2758 git-gui.sh:2762 +#: git-gui.sh:2812 git-gui.sh:2816 git-gui.sh:2820 msgid "Create Desktop Icon" msgstr "Добавяне на икона на работния плот" -#: git-gui.sh:2770 lib/choose_repository.tcl:193 lib/choose_repository.tcl:201 +#: git-gui.sh:2828 lib/choose_repository.tcl:209 lib/choose_repository.tcl:217 msgid "Quit" msgstr "Спиране на програмата" -#: git-gui.sh:2778 +#: git-gui.sh:2836 msgid "Undo" msgstr "Отмяна" -#: git-gui.sh:2781 +#: git-gui.sh:2839 msgid "Redo" msgstr "Повторение" -#: git-gui.sh:2785 git-gui.sh:3399 +#: git-gui.sh:2843 git-gui.sh:3461 msgid "Cut" msgstr "Отрязване" -#: git-gui.sh:2788 git-gui.sh:3402 git-gui.sh:3476 git-gui.sh:3562 +#: git-gui.sh:2846 git-gui.sh:3464 git-gui.sh:3540 git-gui.sh:3633 #: lib/console.tcl:69 msgid "Copy" msgstr "Копиране" -#: git-gui.sh:2791 git-gui.sh:3405 +#: git-gui.sh:2849 git-gui.sh:3467 msgid "Paste" msgstr "Поставяне" -#: git-gui.sh:2794 git-gui.sh:3408 lib/branch_delete.tcl:28 -#: lib/remote_branch_delete.tcl:39 +#: git-gui.sh:2852 git-gui.sh:3470 lib/remote_branch_delete.tcl:39 +#: lib/branch_delete.tcl:28 msgid "Delete" msgstr "Изтриване" -#: git-gui.sh:2798 git-gui.sh:3412 git-gui.sh:3566 lib/console.tcl:71 +#: git-gui.sh:2856 git-gui.sh:3474 git-gui.sh:3637 lib/console.tcl:71 msgid "Select All" msgstr "Избиране на всичко" -#: git-gui.sh:2807 +#: git-gui.sh:2865 msgid "Create..." msgstr "Създаване…" -#: git-gui.sh:2813 +#: git-gui.sh:2871 msgid "Checkout..." msgstr "Изтегляне…" -#: git-gui.sh:2819 +#: git-gui.sh:2877 msgid "Rename..." msgstr "Преименуване…" -#: git-gui.sh:2824 +#: git-gui.sh:2882 msgid "Delete..." msgstr "Изтриване…" -#: git-gui.sh:2829 +#: git-gui.sh:2887 msgid "Reset..." msgstr "Отмяна на промените…" -#: git-gui.sh:2839 +#: git-gui.sh:2897 msgid "Done" msgstr "Готово" -#: git-gui.sh:2841 +#: git-gui.sh:2899 msgid "Commit@@verb" msgstr "Подаване" -#: git-gui.sh:2850 git-gui.sh:3335 -msgid "New Commit" -msgstr "Ново подаване" - -#: git-gui.sh:2858 git-gui.sh:3342 +#: git-gui.sh:2908 git-gui.sh:3400 msgid "Amend Last Commit" msgstr "Поправяне на последното подаване" -#: git-gui.sh:2868 git-gui.sh:3296 lib/remote_branch_delete.tcl:101 +#: git-gui.sh:2918 git-gui.sh:3361 lib/remote_branch_delete.tcl:101 msgid "Rescan" msgstr "Обновяване" -#: git-gui.sh:2874 +#: git-gui.sh:2924 msgid "Stage To Commit" msgstr "Към индекса за подаване" -#: git-gui.sh:2880 +#: git-gui.sh:2930 msgid "Stage Changed Files To Commit" msgstr "Всички променени файлове към индекса за подаване" -#: git-gui.sh:2886 +#: git-gui.sh:2936 msgid "Unstage From Commit" msgstr "Изваждане от индекса за подаване" -#: git-gui.sh:2892 lib/index.tcl:442 +#: git-gui.sh:2942 lib/index.tcl:521 msgid "Revert Changes" msgstr "Връщане на оригинала" -#: git-gui.sh:2900 git-gui.sh:3613 git-gui.sh:3644 +#: git-gui.sh:2950 git-gui.sh:3700 git-gui.sh:3731 msgid "Show Less Context" msgstr "По-малко контекст" -#: git-gui.sh:2904 git-gui.sh:3617 git-gui.sh:3648 +#: git-gui.sh:2954 git-gui.sh:3704 git-gui.sh:3735 msgid "Show More Context" msgstr "Повече контекст" -#: git-gui.sh:2911 git-gui.sh:3309 git-gui.sh:3423 +#: git-gui.sh:2961 git-gui.sh:3374 git-gui.sh:3485 msgid "Sign Off" msgstr "Подписване" -#: git-gui.sh:2927 +#: git-gui.sh:2977 msgid "Local Merge..." msgstr "Локално сливане…" -#: git-gui.sh:2932 +#: git-gui.sh:2982 msgid "Abort Merge..." msgstr "Преустановяване на сливане…" -#: git-gui.sh:2944 git-gui.sh:2972 +#: git-gui.sh:2994 git-gui.sh:3022 msgid "Add..." msgstr "Добавяне…" -#: git-gui.sh:2948 +#: git-gui.sh:2998 msgid "Push..." msgstr "Изтласкване…" -#: git-gui.sh:2952 +#: git-gui.sh:3002 msgid "Delete Branch..." msgstr "Изтриване на клон…" -#: git-gui.sh:2962 git-gui.sh:3595 +#: git-gui.sh:3012 git-gui.sh:3666 msgid "Options..." msgstr "Опции…" -#: git-gui.sh:2973 +#: git-gui.sh:3023 msgid "Remove..." msgstr "Премахване…" -#: git-gui.sh:2982 lib/choose_repository.tcl:55 +#: git-gui.sh:3032 lib/choose_repository.tcl:67 msgid "Help" msgstr "Помощ" -#: git-gui.sh:2986 git-gui.sh:2990 lib/about.tcl:14 -#: lib/choose_repository.tcl:49 lib/choose_repository.tcl:58 +#: git-gui.sh:3036 git-gui.sh:3040 lib/choose_repository.tcl:61 +#: lib/choose_repository.tcl:70 lib/about.tcl:14 #, tcl-format msgid "About %s" -msgstr "Относно %s" +msgstr "Относно „%s“" -#: git-gui.sh:3014 +#: git-gui.sh:3064 msgid "Online Documentation" msgstr "Документация в Интернет" -#: git-gui.sh:3017 lib/choose_repository.tcl:52 lib/choose_repository.tcl:61 +#: git-gui.sh:3067 lib/choose_repository.tcl:64 lib/choose_repository.tcl:73 msgid "Show SSH Key" msgstr "Показване на ключа за SSH" -#: git-gui.sh:3032 git-gui.sh:3164 +#: git-gui.sh:3097 git-gui.sh:3229 msgid "usage:" msgstr "употреба:" -#: git-gui.sh:3036 git-gui.sh:3168 +#: git-gui.sh:3101 git-gui.sh:3233 msgid "Usage" msgstr "Употреба" -#: git-gui.sh:3117 lib/blame.tcl:573 +#: git-gui.sh:3182 lib/blame.tcl:575 msgid "Error" msgstr "Грешка" -#: git-gui.sh:3148 +#: git-gui.sh:3213 #, tcl-format msgid "fatal: cannot stat path %s: No such file or directory" -msgstr "" -"ФАТАЛНА ГРЕШКА: пътят %s не може да бъде открит: такъв файл или директория " -"няма" +msgstr "ФАТАЛНА ГРЕШКА: пътят „%s“ липсва: такъв файл или директория няма" -#: git-gui.sh:3181 +#: git-gui.sh:3246 msgid "Current Branch:" msgstr "Текущ клон:" -#: git-gui.sh:3206 +#: git-gui.sh:3271 msgid "Unstaged Changes" msgstr "Промени извън индекса" -#: git-gui.sh:3228 +#: git-gui.sh:3293 msgid "Staged Changes (Will Commit)" msgstr "Промени в индекса (за подаване)" -#: git-gui.sh:3302 +#: git-gui.sh:3367 msgid "Stage Changed" msgstr "Индексът е променен" -#: git-gui.sh:3321 lib/transport.tcl:137 +#: git-gui.sh:3386 lib/transport.tcl:137 msgid "Push" msgstr "Изтласкване" -#: git-gui.sh:3356 +#: git-gui.sh:3413 msgid "Initial Commit Message:" msgstr "Първоначално съобщение при подаване:" -#: git-gui.sh:3357 +#: git-gui.sh:3414 msgid "Amended Commit Message:" msgstr "Поправено съобщение при подаване:" -#: git-gui.sh:3358 +#: git-gui.sh:3415 msgid "Amended Initial Commit Message:" msgstr "Поправено първоначално съобщение при подаване:" -#: git-gui.sh:3359 +#: git-gui.sh:3416 msgid "Amended Merge Commit Message:" msgstr "Поправено съобщение при подаване със сливане:" -#: git-gui.sh:3360 +#: git-gui.sh:3417 msgid "Merge Commit Message:" msgstr "Съобщение при подаване със сливане:" -#: git-gui.sh:3361 +#: git-gui.sh:3418 msgid "Commit Message:" msgstr "Съобщение при подаване:" -#: git-gui.sh:3415 git-gui.sh:3570 lib/console.tcl:73 +#: git-gui.sh:3477 git-gui.sh:3641 lib/console.tcl:73 msgid "Copy All" msgstr "Копиране на всичко" -#: git-gui.sh:3439 lib/blame.tcl:105 +#: git-gui.sh:3501 lib/blame.tcl:106 msgid "File:" msgstr "Файл:" -#: git-gui.sh:3558 +#: git-gui.sh:3549 lib/choose_repository.tcl:1100 +msgid "Open" +msgstr "Отваряне" + +#: git-gui.sh:3629 msgid "Refresh" msgstr "Обновяване" -#: git-gui.sh:3579 +#: git-gui.sh:3650 msgid "Decrease Font Size" -msgstr "По-едър шрифт" +msgstr "По-дребен шрифт" -#: git-gui.sh:3583 +#: git-gui.sh:3654 msgid "Increase Font Size" -msgstr "По-дребен шрифт" +msgstr "По-едър шрифт" -#: git-gui.sh:3591 lib/blame.tcl:294 +#: git-gui.sh:3662 lib/blame.tcl:296 msgid "Encoding" msgstr "Кодиране" -#: git-gui.sh:3602 +#: git-gui.sh:3673 msgid "Apply/Reverse Hunk" msgstr "Прилагане/връщане на парче" -#: git-gui.sh:3607 +#: git-gui.sh:3678 msgid "Apply/Reverse Line" msgstr "Прилагане/връщане на ред" -#: git-gui.sh:3626 +#: git-gui.sh:3684 git-gui.sh:3794 git-gui.sh:3805 +msgid "Revert Hunk" +msgstr "Връщане на парче" + +#: git-gui.sh:3689 git-gui.sh:3801 git-gui.sh:3812 +msgid "Revert Line" +msgstr "Връщане на ред" + +#: git-gui.sh:3694 git-gui.sh:3791 +msgid "Undo Last Revert" +msgstr "Отмяна на последното връщане" + +#: git-gui.sh:3713 msgid "Run Merge Tool" msgstr "Изпълнение на програмата за сливане" -#: git-gui.sh:3631 +#: git-gui.sh:3718 msgid "Use Remote Version" msgstr "Версия от отдалеченото хранилище" -#: git-gui.sh:3635 +#: git-gui.sh:3722 msgid "Use Local Version" msgstr "Локална версия" -#: git-gui.sh:3639 +#: git-gui.sh:3726 msgid "Revert To Base" msgstr "Връщане към родителската версия" -#: git-gui.sh:3657 +#: git-gui.sh:3744 msgid "Visualize These Changes In The Submodule" msgstr "Визуализиране на промените в подмодула" -#: git-gui.sh:3661 +#: git-gui.sh:3748 msgid "Visualize Current Branch History In The Submodule" msgstr "Визуализация на историята на текущия клон в историята за подмодула" -#: git-gui.sh:3665 +#: git-gui.sh:3752 msgid "Visualize All Branch History In The Submodule" msgstr "Визуализация на историята на всички клони в историята за подмодула" -#: git-gui.sh:3670 +#: git-gui.sh:3757 msgid "Start git gui In The Submodule" msgstr "Стартиране на „git gui“ за подмодула" -#: git-gui.sh:3705 +#: git-gui.sh:3793 msgid "Unstage Hunk From Commit" msgstr "Изваждане на парчето от подаването" -#: git-gui.sh:3707 +#: git-gui.sh:3797 msgid "Unstage Lines From Commit" msgstr "Изваждане на редовете от подаването" -#: git-gui.sh:3709 +#: git-gui.sh:3798 git-gui.sh:3809 +msgid "Revert Lines" +msgstr "Връщане на редовете" + +#: git-gui.sh:3800 msgid "Unstage Line From Commit" msgstr "Изваждане на реда от подаването" -#: git-gui.sh:3712 +#: git-gui.sh:3804 msgid "Stage Hunk For Commit" msgstr "Добавяне на парчето за подаване" -#: git-gui.sh:3714 +#: git-gui.sh:3808 msgid "Stage Lines For Commit" msgstr "Добавяне на редовете за подаване" -#: git-gui.sh:3716 +#: git-gui.sh:3811 msgid "Stage Line For Commit" msgstr "Добавяне на реда за подаване" -#: git-gui.sh:3741 +#: git-gui.sh:3861 msgid "Initializing..." msgstr "Инициализиране…" -#: git-gui.sh:3886 +#: git-gui.sh:4017 #, tcl-format msgid "" "Possible environment issues exist.\n" @@ -574,12 +590,12 @@ msgid "" msgstr "" "Възможно е да има проблем със средата.\n" "\n" -"Най-вероятно следните променливи няма да бъдат\n" -"взети под внимание от подпроцесите на Git\n" +"Най-вероятно следните променливи няма да се\n" +"вземат под внимание от подпроцесите на Git\n" "от %s:\n" "\n" -#: git-gui.sh:3915 +#: git-gui.sh:4046 msgid "" "\n" "This is due to a known issue with the\n" @@ -589,7 +605,7 @@ msgstr "" "Това е познат проблем и се дължи на\n" "версията на Tcl включена в Cygwin." -#: git-gui.sh:3920 +#: git-gui.sh:4051 #, tcl-format msgid "" "\n" @@ -605,389 +621,204 @@ msgstr "" "е да поставите настройките „user.name“ и\n" "„user.email“ в личния си файл „~/.gitconfig“.\n" -#: lib/about.tcl:26 -msgid "git-gui - a graphical user interface for Git." -msgstr "git-gui — графичен интерфейс за Git." +#: lib/spellcheck.tcl:57 +msgid "Unsupported spell checker" +msgstr "Тази програма за проверка на правописа не се поддържа" -#: lib/blame.tcl:73 -#, tcl-format -msgid "%s (%s): File Viewer" -msgstr "%s (%s): Преглед на файлове" +#: lib/spellcheck.tcl:65 +msgid "Spell checking is unavailable" +msgstr "Липсва програма за проверка на правописа" -#: lib/blame.tcl:79 -msgid "Commit:" -msgstr "Подаване:" +#: lib/spellcheck.tcl:68 +msgid "Invalid spell checking configuration" +msgstr "Неправилни настройки на проверката на правописа" -#: lib/blame.tcl:280 -msgid "Copy Commit" -msgstr "Копиране на подаване" +#: lib/spellcheck.tcl:70 +#, tcl-format +msgid "Reverting dictionary to %s." +msgstr "Ползване на речник за език „%s“." -#: lib/blame.tcl:284 -msgid "Find Text..." -msgstr "Търсене на текст…" +#: lib/spellcheck.tcl:73 +msgid "Spell checker silently failed on startup" +msgstr "Програмата за правопис даже не стартира успешно." -#: lib/blame.tcl:288 -msgid "Goto Line..." -msgstr "Към ред…" +#: lib/spellcheck.tcl:80 +msgid "Unrecognized spell checker" +msgstr "Непозната програма за проверка на правописа" -#: lib/blame.tcl:297 -msgid "Do Full Copy Detection" -msgstr "Пълно търсене на копиране" +#: lib/spellcheck.tcl:186 +msgid "No Suggestions" +msgstr "Няма предложения" -#: lib/blame.tcl:301 -msgid "Show History Context" -msgstr "Показване на контекста от историята" +#: lib/spellcheck.tcl:388 +msgid "Unexpected EOF from spell checker" +msgstr "Неочакван край на файл от програмата за проверка на правописа" -#: lib/blame.tcl:304 -msgid "Blame Parent Commit" -msgstr "Анотиране на родителското подаване" +#: lib/spellcheck.tcl:392 +msgid "Spell Checker Failed" +msgstr "Грешка в програмата за проверка на правописа" -#: lib/blame.tcl:466 +#: lib/transport.tcl:6 lib/remote_add.tcl:132 #, tcl-format -msgid "Reading %s..." -msgstr "Чете се „%s“…" +msgid "fetch %s" +msgstr "доставяне на „%s“" -#: lib/blame.tcl:594 -msgid "Loading copy/move tracking annotations..." -msgstr "Зареждане на анотациите за проследяване на копирането/преместването…" +#: lib/transport.tcl:7 +#, tcl-format +msgid "Fetching new changes from %s" +msgstr "Доставяне на промените от „%s“" -#: lib/blame.tcl:614 -msgid "lines annotated" -msgstr "реда анотирани" +#: lib/transport.tcl:18 +#, tcl-format +msgid "remote prune %s" +msgstr "окастряне на следящите клони към „%s“" -#: lib/blame.tcl:806 -msgid "Loading original location annotations..." -msgstr "Зареждане на анотациите за първоначалното местоположение…" +#: lib/transport.tcl:19 +#, tcl-format +msgid "Pruning tracking branches deleted from %s" +msgstr "Окастряне на следящите клони на изтритите клони от „%s“" -#: lib/blame.tcl:809 -msgid "Annotation complete." -msgstr "Анотирането завърши." +#: lib/transport.tcl:25 +msgid "fetch all remotes" +msgstr "доставяне от всички отдалечени" -#: lib/blame.tcl:839 -msgid "Busy" -msgstr "Операцията не е завършила" +#: lib/transport.tcl:26 +msgid "Fetching new changes from all remotes" +msgstr "Доставяне на промените от всички отдалечени хранилища" -#: lib/blame.tcl:840 -msgid "Annotation process is already running." -msgstr "В момента тече процес на анотиране." +#: lib/transport.tcl:40 +msgid "remote prune all remotes" +msgstr "окастряне на следящите изтрити" -#: lib/blame.tcl:879 -msgid "Running thorough copy detection..." -msgstr "Изпълнява се цялостен процес на откриване на копиране…" +#: lib/transport.tcl:41 +msgid "Pruning tracking branches deleted from all remotes" +msgstr "" +"Окастряне на следящите клони на изтритите клони от всички отдалечени " +"хранилища" -#: lib/blame.tcl:947 -msgid "Loading annotation..." -msgstr "Зареждане на анотации…" +#: lib/transport.tcl:54 lib/transport.tcl:92 lib/transport.tcl:110 +#: lib/remote_add.tcl:162 +#, tcl-format +msgid "push %s" +msgstr "изтласкване на „%s“" -#: lib/blame.tcl:1000 -msgid "Author:" -msgstr "Автор:" +#: lib/transport.tcl:55 +#, tcl-format +msgid "Pushing changes to %s" +msgstr "Изтласкване на промените към „%s“" -#: lib/blame.tcl:1004 -msgid "Committer:" -msgstr "Подал:" +#: lib/transport.tcl:93 +#, tcl-format +msgid "Mirroring to %s" +msgstr "Изтласкване на всичко към „%s“" -#: lib/blame.tcl:1009 -msgid "Original File:" -msgstr "Първоначален файл:" +#: lib/transport.tcl:111 +#, tcl-format +msgid "Pushing %s %s to %s" +msgstr "Изтласкване на %s „%s“ към „%s“" -#: lib/blame.tcl:1057 -msgid "Cannot find HEAD commit:" -msgstr "Подаването за връх „HEAD“ не може да се открие:" +#: lib/transport.tcl:132 +msgid "Push Branches" +msgstr "Клони за изтласкване" -#: lib/blame.tcl:1112 -msgid "Cannot find parent commit:" -msgstr "Родителското подаване не може да бъде открито" +#: lib/transport.tcl:141 lib/checkout_op.tcl:580 lib/remote_add.tcl:34 +#: lib/browser.tcl:292 lib/branch_checkout.tcl:30 lib/branch_rename.tcl:32 +#: lib/choose_font.tcl:45 lib/option.tcl:127 lib/tools_dlg.tcl:41 +#: lib/tools_dlg.tcl:202 lib/tools_dlg.tcl:345 lib/remote_branch_delete.tcl:43 +#: lib/branch_create.tcl:37 lib/branch_delete.tcl:34 lib/merge.tcl:178 +msgid "Cancel" +msgstr "Отказване" -#: lib/blame.tcl:1127 -msgid "Unable to display parent" -msgstr "Родителят не може да бъде показан" +#: lib/transport.tcl:147 +msgid "Source Branches" +msgstr "Клони-източници" -#: lib/blame.tcl:1128 lib/diff.tcl:358 -msgid "Error loading diff:" -msgstr "Грешка при зареждане на разлика:" +#: lib/transport.tcl:162 +msgid "Destination Repository" +msgstr "Целево хранилище" -#: lib/blame.tcl:1269 -msgid "Originally By:" -msgstr "Първоначално от:" +#: lib/transport.tcl:165 lib/remote_branch_delete.tcl:51 +msgid "Remote:" +msgstr "Отдалечено хранилище:" -#: lib/blame.tcl:1275 -msgid "In File:" -msgstr "Във файл:" +#: lib/transport.tcl:187 lib/remote_branch_delete.tcl:72 +msgid "Arbitrary Location:" +msgstr "Произволно местоположение:" -#: lib/blame.tcl:1280 -msgid "Copied Or Moved Here By:" -msgstr "Копирано или преместено тук от:" +#: lib/transport.tcl:205 +msgid "Transfer Options" +msgstr "Настройки при пренасянето" -#: lib/branch_checkout.tcl:16 -#, tcl-format -msgid "%s (%s): Checkout Branch" -msgstr "%s (%s): Клон за изтегляне" +#: lib/transport.tcl:207 +msgid "Force overwrite existing branch (may discard changes)" +msgstr "" +"Изрично презаписване на съществуващ клон (някои промени може да се загубят)" -#: lib/branch_checkout.tcl:21 -msgid "Checkout Branch" -msgstr "Клон за изтегляне" +#: lib/transport.tcl:211 +msgid "Use thin pack (for slow network connections)" +msgstr "Максимална компресия (за бавни мрежови връзки)" -#: lib/branch_checkout.tcl:26 -msgid "Checkout" -msgstr "Изтегляне" +#: lib/transport.tcl:215 +msgid "Include tags" +msgstr "Включване на етикетите" -#: lib/branch_checkout.tcl:30 lib/branch_create.tcl:37 lib/branch_delete.tcl:34 -#: lib/branch_rename.tcl:32 lib/browser.tcl:292 lib/checkout_op.tcl:579 -#: lib/choose_font.tcl:45 lib/merge.tcl:178 lib/option.tcl:127 -#: lib/remote_add.tcl:34 lib/remote_branch_delete.tcl:43 lib/tools_dlg.tcl:41 -#: lib/tools_dlg.tcl:202 lib/tools_dlg.tcl:345 lib/transport.tcl:141 -msgid "Cancel" -msgstr "Отказване" +#: lib/transport.tcl:229 +#, tcl-format +msgid "%s (%s): Push" +msgstr "%s (%s): Изтласкване" -#: lib/branch_checkout.tcl:35 lib/browser.tcl:297 lib/tools_dlg.tcl:321 -msgid "Revision" -msgstr "Версия" +#: lib/checkout_op.tcl:85 +#, tcl-format +msgid "Fetching %s from %s" +msgstr "Доставяне на „%s“ от „%s“" -#: lib/branch_checkout.tcl:39 lib/branch_create.tcl:69 lib/option.tcl:310 -msgid "Options" -msgstr "Опции" +#: lib/checkout_op.tcl:133 +#, tcl-format +msgid "fatal: Cannot resolve %s" +msgstr "фатална грешка: „%s“ не може да се открие" -#: lib/branch_checkout.tcl:42 lib/branch_create.tcl:92 -msgid "Fetch Tracking Branch" -msgstr "Изтегляне на промените от следения клон" +#: lib/checkout_op.tcl:146 lib/sshkey.tcl:58 lib/console.tcl:81 +#: lib/database.tcl:30 +msgid "Close" +msgstr "Затваряне" -#: lib/branch_checkout.tcl:47 -msgid "Detach From Local Branch" -msgstr "Изтриване от локалния клон" +#: lib/checkout_op.tcl:175 +#, tcl-format +msgid "Branch '%s' does not exist." +msgstr "Клонът „%s“ не съществува." -#: lib/branch_create.tcl:23 +#: lib/checkout_op.tcl:194 #, tcl-format -msgid "%s (%s): Create Branch" -msgstr "%s (%s): Създаване на клон" +msgid "Failed to configure simplified git-pull for '%s'." +msgstr "Неуспешно настройване на опростен git-pull за „%s“." -#: lib/branch_create.tcl:28 -msgid "Create New Branch" -msgstr "Създаване на нов клон" +#: lib/checkout_op.tcl:202 lib/branch_rename.tcl:102 +#, tcl-format +msgid "Branch '%s' already exists." +msgstr "Клонът „%s“ вече съществува." -#: lib/branch_create.tcl:33 lib/choose_repository.tcl:407 -msgid "Create" -msgstr "Създаване" +#: lib/checkout_op.tcl:229 +#, tcl-format +msgid "" +"Branch '%s' already exists.\n" +"\n" +"It cannot fast-forward to %s.\n" +"A merge is required." +msgstr "" +"Клонът „%s“ съществува.\n" +"\n" +"Той не може да се слее тривиално до „%s“.\n" +"Необходимо е сливане." -#: lib/branch_create.tcl:42 -msgid "Branch Name" -msgstr "Име на клона" +#: lib/checkout_op.tcl:243 +#, tcl-format +msgid "Merge strategy '%s' not supported." +msgstr "Стратегия за сливане „%s“ не се поддържа." -#: lib/branch_create.tcl:44 lib/remote_add.tcl:41 lib/tools_dlg.tcl:51 -msgid "Name:" -msgstr "Име:" - -#: lib/branch_create.tcl:57 -msgid "Match Tracking Branch Name" -msgstr "Съвпадане по името на следения клон" - -#: lib/branch_create.tcl:66 -msgid "Starting Revision" -msgstr "Начална версия" - -#: lib/branch_create.tcl:72 -msgid "Update Existing Branch:" -msgstr "Обновяване на съществуващ клон:" - -#: lib/branch_create.tcl:75 -msgid "No" -msgstr "Не" - -#: lib/branch_create.tcl:80 -msgid "Fast Forward Only" -msgstr "Само тривиално превъртащо сливане" - -#: lib/branch_create.tcl:85 lib/checkout_op.tcl:571 -msgid "Reset" -msgstr "Отначало" - -#: lib/branch_create.tcl:97 -msgid "Checkout After Creation" -msgstr "Преминаване към клона след създаването му" - -#: lib/branch_create.tcl:132 -msgid "Please select a tracking branch." -msgstr "Изберете клон за следени." - -#: lib/branch_create.tcl:141 -#, tcl-format -msgid "Tracking branch %s is not a branch in the remote repository." -msgstr "Следящият клон — „%s“, не съществува в отдалеченото хранилище." - -#: lib/branch_create.tcl:154 lib/branch_rename.tcl:92 -msgid "Please supply a branch name." -msgstr "Дайте име на клона." - -#: lib/branch_create.tcl:165 lib/branch_rename.tcl:112 -#, tcl-format -msgid "'%s' is not an acceptable branch name." -msgstr "„%s“ не може да се използва за име на клон." - -#: lib/branch_delete.tcl:16 -#, tcl-format -msgid "%s (%s): Delete Branch" -msgstr "%s (%s): Изтриване на клон" - -#: lib/branch_delete.tcl:21 -msgid "Delete Local Branch" -msgstr "Изтриване на локален клон" - -#: lib/branch_delete.tcl:39 -msgid "Local Branches" -msgstr "Локални клони" - -#: lib/branch_delete.tcl:51 -msgid "Delete Only If Merged Into" -msgstr "Изтриване, само ако промените са слети и другаде" - -#: lib/branch_delete.tcl:53 lib/remote_branch_delete.tcl:120 -msgid "Always (Do not perform merge checks)" -msgstr "Винаги (без проверка за сливане)" - -#: lib/branch_delete.tcl:103 -#, tcl-format -msgid "The following branches are not completely merged into %s:" -msgstr "Не всички промени в клоните са слети в „%s“:" - -#: lib/branch_delete.tcl:115 lib/remote_branch_delete.tcl:218 -msgid "" -"Recovering deleted branches is difficult.\n" -"\n" -"Delete the selected branches?" -msgstr "" -"Възстановяването на изтрити клони може да е трудно.\n" -"\n" -"Сигурни ли сте, че искате да триете?" - -#: lib/branch_delete.tcl:131 -#, tcl-format -msgid " - %s:" -msgstr " — „%s:“" - -#: lib/branch_delete.tcl:141 -#, tcl-format -msgid "" -"Failed to delete branches:\n" -"%s" -msgstr "" -"Неуспешно триене на клони:\n" -"%s" - -#: lib/branch_rename.tcl:15 -#, tcl-format -msgid "%s (%s): Rename Branch" -msgstr "%s (%s): Преименуване на клон" - -#: lib/branch_rename.tcl:23 -msgid "Rename Branch" -msgstr "Преименуване на клон" - -#: lib/branch_rename.tcl:28 -msgid "Rename" -msgstr "Преименуване" - -#: lib/branch_rename.tcl:38 -msgid "Branch:" -msgstr "Клон:" - -#: lib/branch_rename.tcl:46 -msgid "New Name:" -msgstr "Ново име:" - -#: lib/branch_rename.tcl:81 -msgid "Please select a branch to rename." -msgstr "Изберете клон за преименуване." - -#: lib/branch_rename.tcl:102 lib/checkout_op.tcl:202 -#, tcl-format -msgid "Branch '%s' already exists." -msgstr "Клонът „%s“ вече съществува." - -#: lib/branch_rename.tcl:123 -#, tcl-format -msgid "Failed to rename '%s'." -msgstr "Неуспешно преименуване на „%s“." - -#: lib/browser.tcl:17 -msgid "Starting..." -msgstr "Стартиране…" - -#: lib/browser.tcl:27 -#, tcl-format -msgid "%s (%s): File Browser" -msgstr "%s (%s): Файлов браузър" - -#: lib/browser.tcl:132 lib/browser.tcl:149 -#, tcl-format -msgid "Loading %s..." -msgstr "Зареждане на „%s“…" - -#: lib/browser.tcl:193 -msgid "[Up To Parent]" -msgstr "[Към родителя]" - -#: lib/browser.tcl:275 -#, tcl-format -msgid "%s (%s): Browse Branch Files" -msgstr "%s (%s): Разглеждане на файловете в клона" - -#: lib/browser.tcl:282 -msgid "Browse Branch Files" -msgstr "Разглеждане на файловете в клона" - -#: lib/browser.tcl:288 lib/choose_repository.tcl:422 -#: lib/choose_repository.tcl:509 lib/choose_repository.tcl:518 -#: lib/choose_repository.tcl:1074 -msgid "Browse" -msgstr "Разглеждане" - -#: lib/checkout_op.tcl:85 -#, tcl-format -msgid "Fetching %s from %s" -msgstr "Доставяне на „%s“ от „%s“" - -#: lib/checkout_op.tcl:133 -#, tcl-format -msgid "fatal: Cannot resolve %s" -msgstr "фатална грешка: „%s“ не може да се открие" - -#: lib/checkout_op.tcl:146 lib/console.tcl:81 lib/database.tcl:30 -#: lib/sshkey.tcl:55 -msgid "Close" -msgstr "Затваряне" - -#: lib/checkout_op.tcl:175 -#, tcl-format -msgid "Branch '%s' does not exist." -msgstr "Клонът „%s“ не съществува." - -#: lib/checkout_op.tcl:194 -#, tcl-format -msgid "Failed to configure simplified git-pull for '%s'." -msgstr "Неуспешно настройване на опростен git-pull за „%s“." - -#: lib/checkout_op.tcl:229 -#, tcl-format -msgid "" -"Branch '%s' already exists.\n" -"\n" -"It cannot fast-forward to %s.\n" -"A merge is required." -msgstr "" -"Клонът „%s“ съществува.\n" -"\n" -"Той не може да бъде тривиално слят до „%s“.\n" -"Необходимо е сливане." - -#: lib/checkout_op.tcl:243 -#, tcl-format -msgid "Merge strategy '%s' not supported." -msgstr "Стратегия за сливане „%s“ не се поддържа." - -#: lib/checkout_op.tcl:262 -#, tcl-format -msgid "Failed to update '%s'." -msgstr "Неуспешно обновяване на „%s“." +#: lib/checkout_op.tcl:262 +#, tcl-format +msgid "Failed to update '%s'." +msgstr "Неуспешно обновяване на „%s“." #: lib/checkout_op.tcl:274 msgid "Staging area (index) is already locked." @@ -1006,7 +837,7 @@ msgstr "" "хранилището.\n" "\n" "Някой друг процес за Git е променил хранилището междувременно. Състоянието " -"трябва да бъде проверено, преди да се премине към нов клон.\n" +"трябва да се провери, преди да се премине към нов клон.\n" "\n" "Автоматично ще започне нова проверка.\n" @@ -1019,22 +850,22 @@ msgstr "Работната директория се привежда към „ msgid "files checked out" msgstr "файла са изтеглени" -#: lib/checkout_op.tcl:376 +#: lib/checkout_op.tcl:377 #, tcl-format msgid "Aborted checkout of '%s' (file level merging is required)." msgstr "" "Преустановяване на изтеглянето на „%s“ (необходимо е пофайлово сливане)." -#: lib/checkout_op.tcl:377 +#: lib/checkout_op.tcl:378 msgid "File level merge required." msgstr "Необходимо е пофайлово сливане." -#: lib/checkout_op.tcl:381 +#: lib/checkout_op.tcl:382 #, tcl-format msgid "Staying on branch '%s'." msgstr "Оставане върху клона „%s“." -#: lib/checkout_op.tcl:452 +#: lib/checkout_op.tcl:453 msgid "" "You are no longer on a local branch.\n" "\n" @@ -1045,31 +876,35 @@ msgstr "" "\n" "Ако искате да сте на клон, създайте базиран на „Това несвързано изтегляне“." -#: lib/checkout_op.tcl:503 lib/checkout_op.tcl:507 +#: lib/checkout_op.tcl:504 lib/checkout_op.tcl:508 #, tcl-format msgid "Checked out '%s'." msgstr "„%s“ е изтеглен." -#: lib/checkout_op.tcl:535 +#: lib/checkout_op.tcl:536 #, tcl-format msgid "Resetting '%s' to '%s' will lose the following commits:" msgstr "" "Зануляването на „%s“ към „%s“ ще доведе до загубването на следните подавания:" -#: lib/checkout_op.tcl:557 +#: lib/checkout_op.tcl:558 msgid "Recovering lost commits may not be easy." msgstr "Възстановяването на загубените подавания може да е трудно." -#: lib/checkout_op.tcl:562 +#: lib/checkout_op.tcl:563 #, tcl-format msgid "Reset '%s'?" msgstr "Зануляване на „%s“?" -#: lib/checkout_op.tcl:567 lib/merge.tcl:170 lib/tools_dlg.tcl:336 +#: lib/checkout_op.tcl:568 lib/tools_dlg.tcl:336 lib/merge.tcl:170 msgid "Visualize" msgstr "Визуализация" -#: lib/checkout_op.tcl:635 +#: lib/checkout_op.tcl:572 lib/branch_create.tcl:85 +msgid "Reset" +msgstr "Отначало" + +#: lib/checkout_op.tcl:636 #, tcl-format msgid "" "Failed to set current branch.\n" @@ -1087,1721 +922,1945 @@ msgstr "" "Това състояние е аварийно и не трябва да се случва. Програмата „%s“ ще " "преустанови работа." -#: lib/choose_font.tcl:41 -msgid "Select" -msgstr "Избор" +#: lib/remote_add.tcl:20 +#, tcl-format +msgid "%s (%s): Add Remote" +msgstr "%s (%s): Добавяне на отдалечено хранилище" -#: lib/choose_font.tcl:55 -msgid "Font Family" -msgstr "Шрифт" +#: lib/remote_add.tcl:25 +msgid "Add New Remote" +msgstr "Добавяне на отдалечено хранилище" -#: lib/choose_font.tcl:76 -msgid "Font Size" -msgstr "Размер" +#: lib/remote_add.tcl:30 lib/tools_dlg.tcl:37 +msgid "Add" +msgstr "Добавяне" -#: lib/choose_font.tcl:93 -msgid "Font Example" -msgstr "Мостра" +#: lib/remote_add.tcl:39 +msgid "Remote Details" +msgstr "Данни за отдалеченото хранилище" -#: lib/choose_font.tcl:105 -msgid "" -"This is example text.\n" -"If you like this text, it can be your font." -msgstr "" -"Това е примерен текст.\n" -"Ако ви харесва как изглежда, изберете шрифта." +#: lib/remote_add.tcl:41 lib/tools_dlg.tcl:51 lib/branch_create.tcl:44 +msgid "Name:" +msgstr "Име:" -#: lib/choose_repository.tcl:33 -msgid "Git Gui" -msgstr "ГПИ на Git" +#: lib/remote_add.tcl:50 +msgid "Location:" +msgstr "Местоположение:" -#: lib/choose_repository.tcl:92 lib/choose_repository.tcl:412 -msgid "Create New Repository" -msgstr "Създаване на ново хранилище" +#: lib/remote_add.tcl:60 +msgid "Further Action" +msgstr "Следващо действие" -#: lib/choose_repository.tcl:98 -msgid "New..." -msgstr "Ново…" +#: lib/remote_add.tcl:63 +msgid "Fetch Immediately" +msgstr "Незабавно доставяне" -#: lib/choose_repository.tcl:105 lib/choose_repository.tcl:496 -msgid "Clone Existing Repository" -msgstr "Клониране на съществуващо хранилище" +#: lib/remote_add.tcl:69 +msgid "Initialize Remote Repository and Push" +msgstr "Инициализиране на отдалеченото хранилище и изтласкване на промените" -#: lib/choose_repository.tcl:116 -msgid "Clone..." -msgstr "Клониране…" +#: lib/remote_add.tcl:75 +msgid "Do Nothing Else Now" +msgstr "Да не се прави нищо" -#: lib/choose_repository.tcl:123 lib/choose_repository.tcl:1064 -msgid "Open Existing Repository" -msgstr "Отваряне на съществуващо хранилище" +#: lib/remote_add.tcl:100 +msgid "Please supply a remote name." +msgstr "Задайте име за отдалеченото хранилище." -#: lib/choose_repository.tcl:129 -msgid "Open..." -msgstr "Отваряне…" +#: lib/remote_add.tcl:113 +#, tcl-format +msgid "'%s' is not an acceptable remote name." +msgstr "Отдалечено хранилище не може да се казва „%s“." -#: lib/choose_repository.tcl:142 -msgid "Recent Repositories" -msgstr "Скоро ползвани" +#: lib/remote_add.tcl:124 +#, tcl-format +msgid "Failed to add remote '%s' of location '%s'." +msgstr "Неуспешно добавяне на отдалеченото хранилище „%s“ от адрес „%s“." -#: lib/choose_repository.tcl:148 -msgid "Open Recent Repository:" -msgstr "Отваряне на хранилище ползвано наскоро:" +#: lib/remote_add.tcl:133 +#, tcl-format +msgid "Fetching the %s" +msgstr "Доставяне на „%s“" -#: lib/choose_repository.tcl:316 lib/choose_repository.tcl:323 -#: lib/choose_repository.tcl:330 +#: lib/remote_add.tcl:156 #, tcl-format -msgid "Failed to create repository %s:" -msgstr "Неуспешно създаване на хранилището „%s“:" +msgid "Do not know how to initialize repository at location '%s'." +msgstr "Хранилището с местоположение „%s“ не може да се инициализира." -#: lib/choose_repository.tcl:417 -msgid "Directory:" -msgstr "Директория:" +#: lib/remote_add.tcl:163 +#, tcl-format +msgid "Setting up the %s (at %s)" +msgstr "Добавяне на хранилище „%s“ (с адрес „%s“)" -#: lib/choose_repository.tcl:447 lib/choose_repository.tcl:573 -#: lib/choose_repository.tcl:1098 -msgid "Git Repository" -msgstr "Хранилище на Git" +#: lib/browser.tcl:17 +msgid "Starting..." +msgstr "Стартиране…" -#: lib/choose_repository.tcl:472 +#: lib/browser.tcl:27 #, tcl-format -msgid "Directory %s already exists." -msgstr "Вече съществува директория „%s“." +msgid "%s (%s): File Browser" +msgstr "%s (%s): Файлов браузър" -#: lib/choose_repository.tcl:476 +#: lib/browser.tcl:132 lib/browser.tcl:149 #, tcl-format -msgid "File %s already exists." -msgstr "Вече съществува файл „%s“." +msgid "Loading %s..." +msgstr "Зареждане на „%s“…" -#: lib/choose_repository.tcl:491 -msgid "Clone" -msgstr "Клониране" +#: lib/browser.tcl:193 +msgid "[Up To Parent]" +msgstr "[Към родителя]" -#: lib/choose_repository.tcl:504 -msgid "Source Location:" -msgstr "Адрес на източника:" +#: lib/browser.tcl:275 +#, tcl-format +msgid "%s (%s): Browse Branch Files" +msgstr "%s (%s): Разглеждане на файловете в клона" -#: lib/choose_repository.tcl:513 -msgid "Target Directory:" -msgstr "Целева директория:" +#: lib/browser.tcl:282 +msgid "Browse Branch Files" +msgstr "Разглеждане на файловете в клона" -#: lib/choose_repository.tcl:523 -msgid "Clone Type:" -msgstr "Вид клониране:" +#: lib/browser.tcl:288 lib/choose_repository.tcl:437 +#: lib/choose_repository.tcl:524 lib/choose_repository.tcl:533 +#: lib/choose_repository.tcl:1115 +msgid "Browse" +msgstr "Разглеждане" -#: lib/choose_repository.tcl:528 -msgid "Standard (Fast, Semi-Redundant, Hardlinks)" -msgstr "Стандартно (бързо, частично споделяне на файлове, твърди връзки)" +#: lib/browser.tcl:297 lib/branch_checkout.tcl:35 lib/tools_dlg.tcl:321 +msgid "Revision" +msgstr "Версия" -#: lib/choose_repository.tcl:533 -msgid "Full Copy (Slower, Redundant Backup)" -msgstr "Пълно (бавно, пълноценно резервно копие)" +#: lib/index.tcl:6 +msgid "Unable to unlock the index." +msgstr "Индексът не може да се отключи." -#: lib/choose_repository.tcl:538 -msgid "Shared (Fastest, Not Recommended, No Backup)" -msgstr "Споделено (най-бързо, не се препоръчва, не прави резервно копие)" +#: lib/index.tcl:30 +msgid "Index Error" +msgstr "Грешка в индекса" -#: lib/choose_repository.tcl:545 -msgid "Recursively clone submodules too" -msgstr "Рекурсивно клониране и на подмодулите" +#: lib/index.tcl:32 +msgid "" +"Updating the Git index failed. A rescan will be automatically started to " +"resynchronize git-gui." +msgstr "" +"Неуспешно обновяване на индекса на Git. Автоматично ще започне нова проверка " +"за синхронизирането на git-gui." -#: lib/choose_repository.tcl:579 lib/choose_repository.tcl:626 -#: lib/choose_repository.tcl:772 lib/choose_repository.tcl:842 -#: lib/choose_repository.tcl:1104 lib/choose_repository.tcl:1112 -#, tcl-format -msgid "Not a Git repository: %s" -msgstr "Това не е хранилище на Git: %s" +#: lib/index.tcl:43 +msgid "Continue" +msgstr "Продължаване" -#: lib/choose_repository.tcl:615 -msgid "Standard only available for local repository." -msgstr "Само локални хранилища могат да се клонират стандартно" +#: lib/index.tcl:46 +msgid "Unlock Index" +msgstr "Отключване на индекса" -#: lib/choose_repository.tcl:619 -msgid "Shared only available for local repository." -msgstr "Само локални хранилища могат да се клонират споделено" +#: lib/index.tcl:77 lib/index.tcl:146 lib/index.tcl:220 lib/index.tcl:587 +#: lib/choose_repository.tcl:999 +msgid "files" +msgstr "файлове" -#: lib/choose_repository.tcl:640 -#, tcl-format -msgid "Location %s already exists." -msgstr "Местоположението „%s“ вече съществува." +#: lib/index.tcl:326 +msgid "Unstaging selected files from commit" +msgstr "Изваждане на избраните файлове от подаването" -#: lib/choose_repository.tcl:651 -msgid "Failed to configure origin" -msgstr "Неуспешно настройване на хранилището-източник" +#: lib/index.tcl:330 +#, tcl-format +msgid "Unstaging %s from commit" +msgstr "Изваждане на „%s“ от подаването" -#: lib/choose_repository.tcl:663 -msgid "Counting objects" -msgstr "Преброяване на обекти" +#: lib/index.tcl:369 +msgid "Ready to commit." +msgstr "Готовност за подаване." -#: lib/choose_repository.tcl:664 -msgid "buckets" -msgstr "клетки" +#: lib/index.tcl:378 +msgid "Adding selected files" +msgstr "Добавяне на избраните файлове" -#: lib/choose_repository.tcl:688 +#: lib/index.tcl:382 #, tcl-format -msgid "Unable to copy objects/info/alternates: %s" -msgstr "Обектите/информацията/синонимите не могат да бъдат копирани: %s" +msgid "Adding %s" +msgstr "Добавяне на „%s“" -#: lib/choose_repository.tcl:724 +#: lib/index.tcl:412 #, tcl-format -msgid "Nothing to clone from %s." -msgstr "Няма какво да се клонира от „%s“." +msgid "Stage %d untracked files?" +msgstr "Да се добавят ли %d неследени файла към индекса?" -#: lib/choose_repository.tcl:726 lib/choose_repository.tcl:940 -#: lib/choose_repository.tcl:952 -msgid "The 'master' branch has not been initialized." -msgstr "Основният клон — „master“ не е инициализиран." +#: lib/index.tcl:420 +msgid "Adding all changed files" +msgstr "Добавяне на всички променени файлове" -#: lib/choose_repository.tcl:739 -msgid "Hardlinks are unavailable. Falling back to copying." -msgstr "Не се поддържат твърди връзки. Преминава се към копиране." +#: lib/index.tcl:503 +#, tcl-format +msgid "Revert changes in file %s?" +msgstr "Да се махнат ли промените във файла „%s“?" -#: lib/choose_repository.tcl:751 +#: lib/index.tcl:508 #, tcl-format -msgid "Cloning from %s" -msgstr "Клониране на „%s“" +msgid "Revert changes in these %i files?" +msgstr "Да се махнат ли промените в тези %i файла?" -#: lib/choose_repository.tcl:782 -msgid "Copying objects" -msgstr "Копиране на обекти" +#: lib/index.tcl:517 +msgid "Any unstaged changes will be permanently lost by the revert." +msgstr "" +"Всички промени, които не са били добавени в индекса, ще се загубят " +"безвъзвратно." -#: lib/choose_repository.tcl:783 -msgid "KiB" -msgstr "KiB" +#: lib/index.tcl:520 lib/index.tcl:563 +msgid "Do Nothing" +msgstr "Нищо да не се прави" -#: lib/choose_repository.tcl:807 +#: lib/index.tcl:545 #, tcl-format -msgid "Unable to copy object: %s" -msgstr "Неуспешно копиране на обект: %s" - -#: lib/choose_repository.tcl:817 -msgid "Linking objects" -msgstr "Създаване на връзки към обектите" - -#: lib/choose_repository.tcl:818 -msgid "objects" -msgstr "обекти" +msgid "Delete untracked file %s?" +msgstr "Да се изтрие ли неследеният файл „%s“?" -#: lib/choose_repository.tcl:826 +#: lib/index.tcl:550 #, tcl-format -msgid "Unable to hardlink object: %s" -msgstr "Неуспешно създаване на твърда връзка към обект: %s" +msgid "Delete these %i untracked files?" +msgstr "Да се изтрият ли тези %d неследени файла?" -#: lib/choose_repository.tcl:881 -msgid "Cannot fetch branches and objects. See console output for details." -msgstr "" -"Клоните и обектите не могат да бъдат изтеглени. За повече информация " -"погледнете изхода на конзолата." +#: lib/index.tcl:560 +msgid "Files will be permanently deleted." +msgstr "Файловете ще се изтрият окончателно." -#: lib/choose_repository.tcl:892 -msgid "Cannot fetch tags. See console output for details." -msgstr "" -"Етикетите не могат да бъдат изтеглени. За повече информация погледнете " -"изхода на конзолата." +#: lib/index.tcl:564 +msgid "Delete Files" +msgstr "Изтриване на файлове" -#: lib/choose_repository.tcl:916 -msgid "Cannot determine HEAD. See console output for details." -msgstr "" -"Върхът „HEAD“ не може да бъде определен. За повече информация погледнете " -"изхода на конзолата." +#: lib/index.tcl:586 +msgid "Deleting" +msgstr "Изтриване" -#: lib/choose_repository.tcl:925 +#: lib/index.tcl:665 +msgid "Encountered errors deleting files:\n" +msgstr "Грешки при изтриване на файловете:\n" + +#: lib/index.tcl:674 #, tcl-format -msgid "Unable to cleanup %s" -msgstr "„%s“ не може да се зачисти" +msgid "None of the %d selected files could be deleted." +msgstr "Никой от избраните %d файла не бе изтрит." -#: lib/choose_repository.tcl:931 -msgid "Clone failed." -msgstr "Неуспешно клониране." +#: lib/index.tcl:679 +#, tcl-format +msgid "%d of the %d selected files could not be deleted." +msgstr "%d от избраните %d файла не бяха изтрити." -#: lib/choose_repository.tcl:938 -msgid "No default branch obtained." -msgstr "Не е получен клон по подразбиране." +#: lib/index.tcl:726 +msgid "Reverting selected files" +msgstr "Махане на промените в избраните файлове" -#: lib/choose_repository.tcl:949 +#: lib/index.tcl:730 #, tcl-format -msgid "Cannot resolve %s as a commit." -msgstr "Няма подаване отговарящо на „%s“." - -#: lib/choose_repository.tcl:961 -msgid "Creating working directory" -msgstr "Създаване на работната директория" +msgid "Reverting %s" +msgstr "Махане на промените в „%s“" -#: lib/choose_repository.tcl:962 lib/index.tcl:70 lib/index.tcl:136 -#: lib/index.tcl:207 -msgid "files" -msgstr "файлове" +#: lib/branch_checkout.tcl:16 +#, tcl-format +msgid "%s (%s): Checkout Branch" +msgstr "%s (%s): Клон за изтегляне" -#: lib/choose_repository.tcl:981 -msgid "Cannot clone submodules." -msgstr "Подмодулите не могат да се клонират." +#: lib/branch_checkout.tcl:21 +msgid "Checkout Branch" +msgstr "Клон за изтегляне" -#: lib/choose_repository.tcl:990 -msgid "Cloning submodules" -msgstr "Клониране на подмодули" +#: lib/branch_checkout.tcl:26 +msgid "Checkout" +msgstr "Изтегляне" -#: lib/choose_repository.tcl:1015 -msgid "Initial file checkout failed." -msgstr "Неуспешно първоначално изтегляне." +#: lib/branch_checkout.tcl:39 lib/option.tcl:310 lib/branch_create.tcl:69 +msgid "Options" +msgstr "Опции" -#: lib/choose_repository.tcl:1059 -msgid "Open" -msgstr "Отваряне" +#: lib/branch_checkout.tcl:42 lib/branch_create.tcl:92 +msgid "Fetch Tracking Branch" +msgstr "Изтегляне на промените от следения клон" -#: lib/choose_repository.tcl:1069 -msgid "Repository:" -msgstr "Хранилище:" +#: lib/branch_checkout.tcl:47 +msgid "Detach From Local Branch" +msgstr "Изтриване от локалния клон" -#: lib/choose_repository.tcl:1118 +#: lib/status_bar.tcl:263 #, tcl-format -msgid "Failed to open repository %s:" -msgstr "Неуспешно отваряне на хранилището „%s“:" +msgid "%s ... %*i of %*i %s (%3i%%)" +msgstr "%s… %*i от общо %*i %s (%3i%%)" -#: lib/choose_rev.tcl:52 -msgid "This Detached Checkout" -msgstr "Това несвързано изтегляне" +#: lib/remote.tcl:200 +msgid "Push to" +msgstr "Изтласкване към" -#: lib/choose_rev.tcl:60 -msgid "Revision Expression:" -msgstr "Израз за версия:" +#: lib/remote.tcl:218 +msgid "Remove Remote" +msgstr "Премахване на отдалечено хранилище" -#: lib/choose_rev.tcl:72 -msgid "Local Branch" -msgstr "Локален клон" +#: lib/remote.tcl:223 +msgid "Prune from" +msgstr "Окастряне от" -#: lib/choose_rev.tcl:77 -msgid "Tracking Branch" -msgstr "Следящ клон" +#: lib/remote.tcl:228 +msgid "Fetch from" +msgstr "Доставяне от" -#: lib/choose_rev.tcl:82 lib/choose_rev.tcl:544 -msgid "Tag" -msgstr "Етикет" +#: lib/remote.tcl:249 lib/remote.tcl:253 lib/remote.tcl:258 lib/remote.tcl:264 +msgid "All" +msgstr "Всички" -#: lib/choose_rev.tcl:321 +#: lib/branch_rename.tcl:15 #, tcl-format -msgid "Invalid revision: %s" -msgstr "Неправилна версия: %s" - -#: lib/choose_rev.tcl:342 -msgid "No revision selected." -msgstr "Не е избрана версия." +msgid "%s (%s): Rename Branch" +msgstr "%s (%s): Преименуване на клон" -#: lib/choose_rev.tcl:350 -msgid "Revision expression is empty." -msgstr "Изразът за версия е празен." +#: lib/branch_rename.tcl:23 +msgid "Rename Branch" +msgstr "Преименуване на клон" -#: lib/choose_rev.tcl:537 -msgid "Updated" -msgstr "Обновен" +#: lib/branch_rename.tcl:28 +msgid "Rename" +msgstr "Преименуване" -#: lib/choose_rev.tcl:565 -msgid "URL" -msgstr "Адрес" +#: lib/branch_rename.tcl:38 +msgid "Branch:" +msgstr "Клон:" -#: lib/commit.tcl:9 -msgid "" -"There is nothing to amend.\n" -"\n" -"You are about to create the initial commit. There is no commit before this " -"to amend.\n" -msgstr "" -"Няма какво да се поправи.\n" -"\n" -"Ще създадете първоначалното подаване. Преди него няма други подавания, които " -"да поправите.\n" +#: lib/branch_rename.tcl:46 +msgid "New Name:" +msgstr "Ново име:" -#: lib/commit.tcl:18 +#: lib/branch_rename.tcl:81 +msgid "Please select a branch to rename." +msgstr "Изберете клон за преименуване." + +#: lib/branch_rename.tcl:92 lib/branch_create.tcl:154 +msgid "Please supply a branch name." +msgstr "Дайте име на клона." + +#: lib/branch_rename.tcl:112 lib/branch_create.tcl:165 +#, tcl-format +msgid "'%s' is not an acceptable branch name." +msgstr "„%s“ не може да се използва за име на клон." + +#: lib/branch_rename.tcl:123 +#, tcl-format +msgid "Failed to rename '%s'." +msgstr "Неуспешно преименуване на „%s“." + +#: lib/choose_font.tcl:41 +msgid "Select" +msgstr "Избор" + +#: lib/choose_font.tcl:55 +msgid "Font Family" +msgstr "Шрифт" + +#: lib/choose_font.tcl:76 +msgid "Font Size" +msgstr "Размер" + +#: lib/choose_font.tcl:93 +msgid "Font Example" +msgstr "Мостра" + +#: lib/choose_font.tcl:105 msgid "" -"Cannot amend while merging.\n" -"\n" -"You are currently in the middle of a merge that has not been fully " -"completed. You cannot amend the prior commit unless you first abort the " -"current merge activity.\n" +"This is example text.\n" +"If you like this text, it can be your font." msgstr "" -"По време на сливане не може да поправяте.\n" -"\n" -"В момента все още не сте завършили операция по сливане. Не може да поправите " -"предишното подаване, освен ако първо не преустановите текущото сливане.\n" +"Това е примерен текст.\n" +"Ако ви харесва как изглежда, изберете шрифта." -#: lib/commit.tcl:48 -msgid "Error loading commit data for amend:" -msgstr "Грешка при зареждане на данните от подаване, които да се поправят:" +#: lib/option.tcl:11 +#, tcl-format +msgid "Invalid global encoding '%s'" +msgstr "Неправилно глобално кодиране „%s“" -#: lib/commit.tcl:75 -msgid "Unable to obtain your identity:" -msgstr "Идентификацията ви не може да бъде определена:" +#: lib/option.tcl:19 +#, tcl-format +msgid "Invalid repo encoding '%s'" +msgstr "Неправилно кодиране „%s“ на хранилището" -#: lib/commit.tcl:80 -msgid "Invalid GIT_COMMITTER_IDENT:" -msgstr "Неправилно поле „GIT_COMMITTER_IDENT“:" +#: lib/option.tcl:119 +msgid "Restore Defaults" +msgstr "Стандартни настройки" -#: lib/commit.tcl:129 +#: lib/option.tcl:123 +msgid "Save" +msgstr "Запазване" + +#: lib/option.tcl:133 #, tcl-format -msgid "warning: Tcl does not support encoding '%s'." -msgstr "предупреждение: Tcl не поддържа кодирането „%s“." +msgid "%s Repository" +msgstr "Хранилище „%s“" -#: lib/commit.tcl:149 -msgid "" -"Last scanned state does not match repository state.\n" -"\n" -"Another Git program has modified this repository since the last scan. A " -"rescan must be performed before another commit can be created.\n" -"\n" -"The rescan will be automatically started now.\n" -msgstr "" -"Състоянието при последната проверка не отговаря на състоянието на " -"хранилището.\n" -"\n" -"Някой друг процес за Git е променил хранилището междувременно. Състоянието " -"трябва да бъде проверено преди ново подаване.\n" -"\n" -"Автоматично ще започне нова проверка.\n" +#: lib/option.tcl:134 +msgid "Global (All Repositories)" +msgstr "Глобално (за всички хранилища)" + +#: lib/option.tcl:140 +msgid "User Name" +msgstr "Потребителско име" + +#: lib/option.tcl:141 +msgid "Email Address" +msgstr "Адрес на е-поща" + +#: lib/option.tcl:143 +msgid "Summarize Merge Commits" +msgstr "Обобщаване на подаванията при сливане" + +#: lib/option.tcl:144 +msgid "Merge Verbosity" +msgstr "Подробности при сливанията" + +#: lib/option.tcl:145 +msgid "Show Diffstat After Merge" +msgstr "Извеждане на статистика след сливанията" + +#: lib/option.tcl:146 +msgid "Use Merge Tool" +msgstr "Използване на програма за сливане" + +#: lib/option.tcl:148 +msgid "Trust File Modification Timestamps" +msgstr "Доверие във времето на промяна на файловете" + +#: lib/option.tcl:149 +msgid "Prune Tracking Branches During Fetch" +msgstr "Окастряне на следящите клонове при доставяне" + +#: lib/option.tcl:150 +msgid "Match Tracking Branches" +msgstr "Напасване на следящите клонове" + +#: lib/option.tcl:151 +msgid "Use Textconv For Diffs and Blames" +msgstr "Използване на „textconv“ за разликите и анотирането" + +#: lib/option.tcl:152 +msgid "Blame Copy Only On Changed Files" +msgstr "Анотиране на копието само по променените файлове" + +#: lib/option.tcl:153 +msgid "Maximum Length of Recent Repositories List" +msgstr "Максимален брой на списъка „Скоро ползвани“ хранилища" + +#: lib/option.tcl:154 +msgid "Minimum Letters To Blame Copy On" +msgstr "Минимален брой знаци за анотиране на копието" + +#: lib/option.tcl:155 +msgid "Blame History Context Radius (days)" +msgstr "Исторически обхват за анотиране в дни" + +#: lib/option.tcl:156 +msgid "Number of Diff Context Lines" +msgstr "Брой редове за контекста на разликите" + +#: lib/option.tcl:157 +msgid "Additional Diff Parameters" +msgstr "Аргументи към командата за разликите" + +#: lib/option.tcl:158 +msgid "Commit Message Text Width" +msgstr "Широчина на текста на съобщението при подаване" + +#: lib/option.tcl:159 +msgid "New Branch Name Template" +msgstr "Шаблон за името на новите клони" + +#: lib/option.tcl:160 +msgid "Default File Contents Encoding" +msgstr "Кодиране на файловете" + +#: lib/option.tcl:161 +msgid "Warn before committing to a detached head" +msgstr "Предупреждаване при подаване към несвързан указател" -#: lib/commit.tcl:173 +#: lib/option.tcl:162 +msgid "Staging of untracked files" +msgstr "Добавяне на неследените файлове към индекса" + +#: lib/option.tcl:163 +msgid "Show untracked files" +msgstr "Показване на неследените файлове" + +#: lib/option.tcl:164 +msgid "Tab spacing" +msgstr "Ширина на табулацията" + +#: lib/option.tcl:182 lib/option.tcl:197 lib/option.tcl:220 lib/option.tcl:282 +#: lib/database.tcl:57 #, tcl-format -msgid "" -"Unmerged files cannot be committed.\n" -"\n" -"File %s has merge conflicts. You must resolve them and stage the file " -"before committing.\n" -msgstr "" -"Неслетите файлове не могат да бъдат подавани.\n" -"\n" -"Във файла „%s“ има конфликти при сливане. За да го подадете, трябва първо да " -"коригирате конфликтите и да добавите файла към индекса за подаване.\n" +msgid "%s:" +msgstr "%s:" + +#: lib/option.tcl:210 +msgid "Change" +msgstr "Смяна" + +#: lib/option.tcl:254 +msgid "Spelling Dictionary:" +msgstr "Правописен речник:" + +#: lib/option.tcl:284 +msgid "Change Font" +msgstr "Смяна на шрифта" -#: lib/commit.tcl:181 +#: lib/option.tcl:288 #, tcl-format -msgid "" -"Unknown file state %s detected.\n" -"\n" -"File %s cannot be committed by this program.\n" -msgstr "" -"Непознато състояние на файл „%s“.\n" -"\n" -"Файлът „%s“ не може да бъде подаден чрез текущата програма.\n" +msgid "Choose %s" +msgstr "Избор на „%s“" -#: lib/commit.tcl:189 -msgid "" -"No changes to commit.\n" -"\n" -"You must stage at least 1 file before you can commit.\n" -msgstr "" -"Няма промени за подаване.\n" -"\n" -"Трябва да добавите поне един файл към индекса, за да подадете.\n" +#: lib/option.tcl:294 +msgid "pt." +msgstr "тчк." + +#: lib/option.tcl:308 +msgid "Preferences" +msgstr "Настройки" + +#: lib/option.tcl:345 +msgid "Failed to completely save options:" +msgstr "Неуспешно запазване на настройките:" + +#: lib/encoding.tcl:443 +msgid "Default" +msgstr "Стандартното" + +#: lib/encoding.tcl:448 +#, tcl-format +msgid "System (%s)" +msgstr "Системното (%s)" + +#: lib/encoding.tcl:459 lib/encoding.tcl:465 +msgid "Other" +msgstr "Друго" + +#: lib/tools.tcl:76 +#, tcl-format +msgid "Running %s requires a selected file." +msgstr "За изпълнението на „%s“ трябва да изберете файл." + +#: lib/tools.tcl:92 +#, tcl-format +msgid "Are you sure you want to run %1$s on file \"%2$s\"?" +msgstr "Сигурни ли сте, че искате да изпълните „%1$s“ върху файла „%2$s“?" + +#: lib/tools.tcl:96 +#, tcl-format +msgid "Are you sure you want to run %s?" +msgstr "Сигурни ли сте, че искате да изпълните „%s“?" + +#: lib/tools.tcl:118 +#, tcl-format +msgid "Tool: %s" +msgstr "Команда: %s" + +#: lib/tools.tcl:119 +#, tcl-format +msgid "Running: %s" +msgstr "Изпълнение: %s" + +#: lib/tools.tcl:158 +#, tcl-format +msgid "Tool completed successfully: %s" +msgstr "Командата завърши успешно: %s" + +#: lib/tools.tcl:160 +#, tcl-format +msgid "Tool failed: %s" +msgstr "Командата върна грешка: %s" + +#: lib/mergetool.tcl:8 +msgid "Force resolution to the base version?" +msgstr "Да се използва базовата версия" + +#: lib/mergetool.tcl:9 +msgid "Force resolution to this branch?" +msgstr "Да се използва версията от този клон" + +#: lib/mergetool.tcl:10 +msgid "Force resolution to the other branch?" +msgstr "Да се използва версията от другия клон" -#: lib/commit.tcl:204 +#: lib/mergetool.tcl:14 +#, tcl-format msgid "" -"Please supply a commit message.\n" +"Note that the diff shows only conflicting changes.\n" "\n" -"A good commit message has the following format:\n" +"%s will be overwritten.\n" "\n" -"- First line: Describe in one sentence what you did.\n" -"- Second line: Blank\n" -"- Remaining lines: Describe why this change is good.\n" +"This operation can be undone only by restarting the merge." msgstr "" -"Задайте добро съобщение при подаване.\n" +"Разликата показва само разликите с конфликт.\n" "\n" -"Използвайте следния формат:\n" +"Файлът „%s“ ще се презапише.\n" "\n" -"● Първи ред: описание в едно изречение на промяната.\n" -"● Втори ред: празен.\n" -"● Останалите редове: опишете защо се налага тази промяна.\n" - -#: lib/commit.tcl:235 -msgid "Calling pre-commit hook..." -msgstr "Изпълняване на куката преди подаване…" - -#: lib/commit.tcl:250 -msgid "Commit declined by pre-commit hook." -msgstr "Подаването е отхвърлено от куката преди подаване." +"Тази операция може да се отмени само чрез започване на сливането наново." -#: lib/commit.tcl:269 -msgid "" -"You are about to commit on a detached head. This is a potentially dangerous " -"thing to do because if you switch to another branch you will lose your " -"changes and it can be difficult to retrieve them later from the reflog. You " -"should probably cancel this commit and create a new branch to continue.\n" -" \n" -" Do you really want to proceed with your Commit?" +#: lib/mergetool.tcl:45 +#, tcl-format +msgid "File %s seems to have unresolved conflicts, still stage?" msgstr "" -"Ще подадете към несвързан, отделѐн указател „HEAD“. Това е опасно, защото " -"при преминаването към клон ще загубите промените си, като единственият начин " -"да ги върнете ще е чрез журнала на указателите (reflog). Най-вероятно трябва " -"да не правите това подаване, а да създадете нов клон, преди да продължите.\n" -" \n" -"Сигурни ли сте, че искате да извършите текущото подаване?" +"Изглежда, че все още има некоригирани конфликти във файла „%s“. Да се добави " +"ли файлът към индекса?" -#: lib/commit.tcl:290 -msgid "Calling commit-msg hook..." -msgstr "Изпълняване на куката за съобщението при подаване…" +#: lib/mergetool.tcl:60 +#, tcl-format +msgid "Adding resolution for %s" +msgstr "Добавяне на корекция на конфликтите в „%s“" -#: lib/commit.tcl:305 -msgid "Commit declined by commit-msg hook." -msgstr "Подаването е отхвърлено от куката за съобщението при подаване." +#: lib/mergetool.tcl:141 +msgid "Cannot resolve deletion or link conflicts using a tool" +msgstr "" +"Конфликтите при символни връзки или изтриване не може да се коригират с " +"външна програма." -#: lib/commit.tcl:318 -msgid "Committing changes..." -msgstr "Подаване на промените…" +#: lib/mergetool.tcl:146 +msgid "Conflict file does not exist" +msgstr "Файлът, в който е конфликтът, не съществува" -#: lib/commit.tcl:334 -msgid "write-tree failed:" -msgstr "неуспешно запазване на дървото (write-tree):" +#: lib/mergetool.tcl:246 +#, tcl-format +msgid "Not a GUI merge tool: '%s'" +msgstr "Това не е графична програма за сливане: „%s“" -#: lib/commit.tcl:335 lib/commit.tcl:382 lib/commit.tcl:403 -msgid "Commit failed." -msgstr "Неуспешно подаване." +#: lib/mergetool.tcl:275 +#, tcl-format +msgid "Unsupported merge tool '%s'" +msgstr "Неподдържана програма за сливане: „%s“" + +#: lib/mergetool.tcl:310 +msgid "Merge tool is already running, terminate it?" +msgstr "Програмата за сливане вече е стартирана. Да се изключи ли?" -#: lib/commit.tcl:352 +#: lib/mergetool.tcl:330 #, tcl-format -msgid "Commit %s appears to be corrupt" -msgstr "Подаването „%s“ изглежда повредено" +msgid "" +"Error retrieving versions:\n" +"%s" +msgstr "" +"Грешка при изтеглянето на версии:\n" +"%s" -#: lib/commit.tcl:357 +#: lib/mergetool.tcl:350 +#, tcl-format msgid "" -"No changes to commit.\n" -"\n" -"No files were modified by this commit and it was not a merge commit.\n" +"Could not start the merge tool:\n" "\n" -"A rescan will be automatically started now.\n" +"%s" msgstr "" -"Няма промени за подаване.\n" +"Програмата за сливане не може да се стартира:\n" "\n" -"В това подаване не са променяни никакви файлове, а и не е подаване със " -"сливане.\n" -"\n" -"Автоматично ще започне нова проверка.\n" - -#: lib/commit.tcl:364 -msgid "No changes to commit." -msgstr "Няма промени за подаване." +"%s" -#: lib/commit.tcl:381 -msgid "commit-tree failed:" -msgstr "неуспешно подаване на дървото (commit-tree):" +#: lib/mergetool.tcl:354 +msgid "Running merge tool..." +msgstr "Стартиране на програмата за сливане…" -#: lib/commit.tcl:402 -msgid "update-ref failed:" -msgstr "неуспешно обновяване на указателите (update-ref):" +#: lib/mergetool.tcl:382 lib/mergetool.tcl:390 +msgid "Merge tool failed." +msgstr "Грешка в програмата за сливане." -#: lib/commit.tcl:495 +#: lib/tools_dlg.tcl:22 #, tcl-format -msgid "Created commit %s: %s" -msgstr "Успешно подаване %s: %s" +msgid "%s (%s): Add Tool" +msgstr "%s (%s): Добавяне на команда" -#: lib/console.tcl:59 -msgid "Working... please wait..." -msgstr "В момента се извършва действие, изчакайте…" +#: lib/tools_dlg.tcl:28 +msgid "Add New Tool Command" +msgstr "Добавяне на команда" -#: lib/console.tcl:186 -msgid "Success" -msgstr "Успех" +#: lib/tools_dlg.tcl:34 +msgid "Add globally" +msgstr "Глобално добавяне" -#: lib/console.tcl:200 -msgid "Error: Command Failed" -msgstr "Грешка: неуспешно изпълнение на команда" +#: lib/tools_dlg.tcl:46 +msgid "Tool Details" +msgstr "Подробности за командата" -#: lib/database.tcl:42 -msgid "Number of loose objects" -msgstr "Брой непакетирани обекти" +#: lib/tools_dlg.tcl:49 +msgid "Use '/' separators to create a submenu tree:" +msgstr "За създаване на подменюта използвайте знака „/“ за разделител:" -#: lib/database.tcl:43 -msgid "Disk space used by loose objects" -msgstr "Дисково пространство заето от непакетирани обекти" +#: lib/tools_dlg.tcl:60 +msgid "Command:" +msgstr "Команда:" -#: lib/database.tcl:44 -msgid "Number of packed objects" -msgstr "Брой пакетирани обекти" +#: lib/tools_dlg.tcl:71 +msgid "Show a dialog before running" +msgstr "Преди изпълнение да се извежда диалогов прозорец" -#: lib/database.tcl:45 -msgid "Number of packs" -msgstr "Брой пакети" +#: lib/tools_dlg.tcl:77 +msgid "Ask the user to select a revision (sets $REVISION)" +msgstr "Потребителят да укаже версия (задаване на променливата $REVISION)" -#: lib/database.tcl:46 -msgid "Disk space used by packed objects" -msgstr "Дисково пространство заето от пакетирани обекти" +#: lib/tools_dlg.tcl:82 +msgid "Ask the user for additional arguments (sets $ARGS)" +msgstr "" +"Потребителят да укаже допълнителни аргументи (задаване на променливата $ARGS)" -#: lib/database.tcl:47 -msgid "Packed objects waiting for pruning" -msgstr "Пакетирани обекти за окастряне" +#: lib/tools_dlg.tcl:89 +msgid "Don't show the command output window" +msgstr "Без показване на прозорец с изхода от командата" -#: lib/database.tcl:48 -msgid "Garbage files" -msgstr "Файлове за боклука" +#: lib/tools_dlg.tcl:94 +msgid "Run only if a diff is selected ($FILENAME not empty)" +msgstr "" +"Стартиране само след избор на разлика (променливата $FILENAME не е празна)" -#: lib/database.tcl:57 lib/option.tcl:182 lib/option.tcl:197 lib/option.tcl:220 -#: lib/option.tcl:282 -#, tcl-format -msgid "%s:" -msgstr "%s:" +#: lib/tools_dlg.tcl:118 +msgid "Please supply a name for the tool." +msgstr "Задайте име за командата." -#: lib/database.tcl:66 +#: lib/tools_dlg.tcl:126 #, tcl-format -msgid "%s (%s): Database Statistics" -msgstr "%s (%s): Статистика на базата от данни" - -#: lib/database.tcl:72 -msgid "Compressing the object database" -msgstr "Компресиране на базата с данни за обектите" - -#: lib/database.tcl:83 -msgid "Verifying the object database with fsck-objects" -msgstr "Проверка на базата с данни за обектите с програмата „fsck-objects“" +msgid "Tool '%s' already exists." +msgstr "Командата „%s“ вече съществува." -#: lib/database.tcl:107 +#: lib/tools_dlg.tcl:148 #, tcl-format msgid "" -"This repository currently has approximately %i loose objects.\n" -"\n" -"To maintain optimal performance it is strongly recommended that you compress " -"the database.\n" -"\n" -"Compress the database now?" +"Could not add tool:\n" +"%s" msgstr "" -"В това хранилище в момента има към %i непакетирани обекти.\n" -"\n" -"За добра производителност се препоръчва да компресирате базата с данни за " -"обектите.\n" -"\n" -"Да се започне ли компресирането?" +"Командата не може да се добави:\n" +"%s" -#: lib/date.tcl:25 +#: lib/tools_dlg.tcl:187 #, tcl-format -msgid "Invalid date from Git: %s" -msgstr "Неправилни данни от Git: %s" +msgid "%s (%s): Remove Tool" +msgstr "%s (%s): Премахване на команда" -#: lib/diff.tcl:77 +#: lib/tools_dlg.tcl:193 +msgid "Remove Tool Commands" +msgstr "Премахване на команди" + +#: lib/tools_dlg.tcl:198 +msgid "Remove" +msgstr "Премахване" + +#: lib/tools_dlg.tcl:231 +msgid "(Blue denotes repository-local tools)" +msgstr "(командите към локалното хранилище са обозначени в синьо)" + +#: lib/tools_dlg.tcl:283 #, tcl-format -msgid "" -"No differences detected.\n" -"\n" -"%s has no changes.\n" -"\n" -"The modification date of this file was updated by another application, but " -"the content within the file was not changed.\n" -"\n" -"A rescan will be automatically started to find other files which may have " -"the same state." -msgstr "" -"Не са открити разлики.\n" -"\n" -"Няма промени в „%s“.\n" -"\n" -"Времето на промяна на файла е бил зададен от друга програма, но съдържанието " -"му не е променено.\n" -"\n" -"Автоматично ще започне нова проверка дали няма други файлове в това " -"състояние." +msgid "%s (%s):" +msgstr "%s (%s):" -#: lib/diff.tcl:117 +#: lib/tools_dlg.tcl:292 #, tcl-format -msgid "Loading diff of %s..." -msgstr "Зареждане на разликите в „%s“…" +msgid "Run Command: %s" +msgstr "Изпълнение на командата „%s“" -#: lib/diff.tcl:143 -msgid "" -"LOCAL: deleted\n" -"REMOTE:\n" -msgstr "" -"ЛОКАЛНО: изтрит\n" -"ОТДАЛЕЧЕНО:\n" +#: lib/tools_dlg.tcl:306 +msgid "Arguments" +msgstr "Аргументи" -#: lib/diff.tcl:148 -msgid "" -"REMOTE: deleted\n" -"LOCAL:\n" -msgstr "" -"ОТДАЛЕЧЕНО: изтрит\n" -"ЛОКАЛНО:\n" +#: lib/tools_dlg.tcl:341 +msgid "OK" +msgstr "Добре" + +#: lib/search.tcl:48 +msgid "Find:" +msgstr "Търсене:" + +#: lib/search.tcl:50 +msgid "Next" +msgstr "Следваща поява" + +#: lib/search.tcl:51 +msgid "Prev" +msgstr "Предишна поява" + +#: lib/search.tcl:52 +msgid "RegExp" +msgstr "РегИзр" + +#: lib/search.tcl:54 +msgid "Case" +msgstr "Главни/Малки" + +#: lib/shortcut.tcl:8 lib/shortcut.tcl:43 lib/shortcut.tcl:75 +#, tcl-format +msgid "%s (%s): Create Desktop Icon" +msgstr "%s (%s): Добавяне на икона на работния плот" -#: lib/diff.tcl:155 -msgid "LOCAL:\n" -msgstr "ЛОКАЛНО:\n" +#: lib/shortcut.tcl:24 lib/shortcut.tcl:65 +msgid "Cannot write shortcut:" +msgstr "Клавишната комбинация не може да се запази:" -#: lib/diff.tcl:158 -msgid "REMOTE:\n" -msgstr "ОТДАЛЕЧЕНО:\n" +#: lib/shortcut.tcl:140 +msgid "Cannot write icon:" +msgstr "Иконата не може да се запази:" -#: lib/diff.tcl:220 lib/diff.tcl:357 +#: lib/remote_branch_delete.tcl:29 #, tcl-format -msgid "Unable to display %s" -msgstr "Файлът „%s“ не може да бъде показан" +msgid "%s (%s): Delete Branch Remotely" +msgstr "%s (%s): Изтриване на отдалечения клон" -#: lib/diff.tcl:221 -msgid "Error loading file:" -msgstr "Грешка при зареждане на файл:" +#: lib/remote_branch_delete.tcl:34 +msgid "Delete Branch Remotely" +msgstr "Изтриване на отдалечения клон" -#: lib/diff.tcl:227 -msgid "Git Repository (subproject)" -msgstr "Хранилище на Git (подмодул)" +#: lib/remote_branch_delete.tcl:48 +msgid "From Repository" +msgstr "От хранилище" -#: lib/diff.tcl:239 -msgid "* Binary file (not showing content)." -msgstr "● Двоичен файл (съдържанието не се показва)." +#: lib/remote_branch_delete.tcl:88 +msgid "Branches" +msgstr "Клони" -#: lib/diff.tcl:244 -#, tcl-format -msgid "" -"* Untracked file is %d bytes.\n" -"* Showing only first %d bytes.\n" -msgstr "" -"● Неследеният файл е %d байта.\n" -"● Показват се само първите %d байта.\n" +#: lib/remote_branch_delete.tcl:110 +msgid "Delete Only If" +msgstr "Изтриване, само ако" -#: lib/diff.tcl:250 +#: lib/remote_branch_delete.tcl:112 +msgid "Merged Into:" +msgstr "Слят в:" + +#: lib/remote_branch_delete.tcl:120 lib/branch_delete.tcl:53 +msgid "Always (Do not perform merge checks)" +msgstr "Винаги (без проверка за сливане)" + +#: lib/remote_branch_delete.tcl:153 +msgid "A branch is required for 'Merged Into'." +msgstr "За данните „Слят в“ е необходимо да зададете клон." + +#: lib/remote_branch_delete.tcl:185 #, tcl-format msgid "" +"The following branches are not completely merged into %s:\n" "\n" -"* Untracked file clipped here by %s.\n" -"* To see the entire file, use an external editor.\n" +" - %s" msgstr "" +"Следните клони не са слети напълно в „%s“:\n" "\n" -"● Неследеният файл е отрязан дотук от програмата „%s“.\n" -"● Използвайте външен редактор, за да видите целия файл.\n" - -#: lib/diff.tcl:580 -msgid "Failed to unstage selected hunk." -msgstr "Избраното парче не може да бъде извадено от индекса." - -#: lib/diff.tcl:587 -msgid "Failed to stage selected hunk." -msgstr "Избраното парче не може да бъде добавено към индекса." +" ● %s" -#: lib/diff.tcl:666 -msgid "Failed to unstage selected line." -msgstr "Избраният ред не може да бъде изваден от индекса." +#: lib/remote_branch_delete.tcl:190 +#, tcl-format +msgid "" +"One or more of the merge tests failed because you have not fetched the " +"necessary commits. Try fetching from %s first." +msgstr "" +"Поне една от пробите за сливане е неуспешна, защото не сте доставили всички " +"необходими подавания. Пробвайте първо да доставите подаванията от „%s“." -#: lib/diff.tcl:674 -msgid "Failed to stage selected line." -msgstr "Избраният ред не може да бъде добавен към индекса." +#: lib/remote_branch_delete.tcl:208 +msgid "Please select one or more branches to delete." +msgstr "Изберете поне един клон за изтриване." -#: lib/encoding.tcl:443 -msgid "Default" -msgstr "Стандартното" +#: lib/remote_branch_delete.tcl:218 lib/branch_delete.tcl:115 +msgid "" +"Recovering deleted branches is difficult.\n" +"\n" +"Delete the selected branches?" +msgstr "" +"Възстановяването на изтрити клони може да е трудно.\n" +"\n" +"Сигурни ли сте, че искате да триете?" -#: lib/encoding.tcl:448 +#: lib/remote_branch_delete.tcl:227 #, tcl-format -msgid "System (%s)" -msgstr "Системното (%s)" - -#: lib/encoding.tcl:459 lib/encoding.tcl:465 -msgid "Other" -msgstr "Друго" +msgid "Deleting branches from %s" +msgstr "Изтриване на клони от „%s“" -#: lib/error.tcl:20 -#, tcl-format -msgid "%s: error" -msgstr "%s: грешка" +#: lib/remote_branch_delete.tcl:300 +msgid "No repository selected." +msgstr "Не е избрано хранилище." -#: lib/error.tcl:36 +#: lib/remote_branch_delete.tcl:305 #, tcl-format -msgid "%s: warning" -msgstr "%s: предупреждение" +msgid "Scanning %s..." +msgstr "Претърсване на „%s“…" -#: lib/error.tcl:80 -#, tcl-format -msgid "%s hook failed:" -msgstr "%s: грешка от куката" +#: lib/choose_repository.tcl:45 +msgid "Git Gui" +msgstr "ГПИ на Git" -#: lib/error.tcl:96 -msgid "You must correct the above errors before committing." -msgstr "Преди да можете да подадете, коригирайте горните грешки." +#: lib/choose_repository.tcl:104 lib/choose_repository.tcl:427 +msgid "Create New Repository" +msgstr "Създаване на ново хранилище" -#: lib/error.tcl:116 -#, tcl-format -msgid "%s (%s): error" -msgstr "%s (%s): грешка" +#: lib/choose_repository.tcl:110 +msgid "New..." +msgstr "Ново…" -#: lib/index.tcl:6 -msgid "Unable to unlock the index." -msgstr "Индексът не може да бъде отключен." +#: lib/choose_repository.tcl:117 lib/choose_repository.tcl:511 +msgid "Clone Existing Repository" +msgstr "Клониране на съществуващо хранилище" -#: lib/index.tcl:17 -msgid "Index Error" -msgstr "Грешка в индекса" +#: lib/choose_repository.tcl:128 +msgid "Clone..." +msgstr "Клониране…" -#: lib/index.tcl:19 -msgid "" -"Updating the Git index failed. A rescan will be automatically started to " -"resynchronize git-gui." -msgstr "" -"Неуспешно обновяване на индекса на Git. Автоматично ще започне нова проверка " -"за синхронизирането на git-gui." +#: lib/choose_repository.tcl:135 lib/choose_repository.tcl:1105 +msgid "Open Existing Repository" +msgstr "Отваряне на съществуващо хранилище" -#: lib/index.tcl:30 -msgid "Continue" -msgstr "Продължаване" +#: lib/choose_repository.tcl:141 +msgid "Open..." +msgstr "Отваряне…" -#: lib/index.tcl:33 -msgid "Unlock Index" -msgstr "Отключване на индекса" +#: lib/choose_repository.tcl:154 +msgid "Recent Repositories" +msgstr "Скоро ползвани" -#: lib/index.tcl:294 -msgid "Unstaging selected files from commit" -msgstr "Изваждане на избраните файлове от подаването" +#: lib/choose_repository.tcl:164 +msgid "Open Recent Repository:" +msgstr "Отваряне на хранилище ползвано наскоро:" -#: lib/index.tcl:298 +#: lib/choose_repository.tcl:331 lib/choose_repository.tcl:338 +#: lib/choose_repository.tcl:345 #, tcl-format -msgid "Unstaging %s from commit" -msgstr "Изваждане на „%s“ от подаването" +msgid "Failed to create repository %s:" +msgstr "Неуспешно създаване на хранилището „%s“:" -#: lib/index.tcl:337 -msgid "Ready to commit." -msgstr "Готовност за подаване." +#: lib/choose_repository.tcl:422 lib/branch_create.tcl:33 +msgid "Create" +msgstr "Създаване" -#: lib/index.tcl:346 -msgid "Adding selected files" -msgstr "Добавяне на избраните файлове" +#: lib/choose_repository.tcl:432 +msgid "Directory:" +msgstr "Директория:" + +#: lib/choose_repository.tcl:462 lib/choose_repository.tcl:588 +#: lib/choose_repository.tcl:1139 +msgid "Git Repository" +msgstr "Хранилище на Git" -#: lib/index.tcl:350 +#: lib/choose_repository.tcl:487 #, tcl-format -msgid "Adding %s" -msgstr "Добавяне на „%s“" +msgid "Directory %s already exists." +msgstr "Вече съществува директория „%s“." -#: lib/index.tcl:380 +#: lib/choose_repository.tcl:491 #, tcl-format -msgid "Stage %d untracked files?" -msgstr "Да се добавят ли %d неследени файла към индекса?" +msgid "File %s already exists." +msgstr "Вече съществува файл „%s“." -#: lib/index.tcl:388 -msgid "Adding all changed files" -msgstr "Добавяне на всички променени файлове" +#: lib/choose_repository.tcl:506 +msgid "Clone" +msgstr "Клониране" -#: lib/index.tcl:428 -#, tcl-format -msgid "Revert changes in file %s?" -msgstr "Да се махнат ли промените във файла „%s“?" +#: lib/choose_repository.tcl:519 +msgid "Source Location:" +msgstr "Адрес на източника:" -#: lib/index.tcl:430 -#, tcl-format -msgid "Revert changes in these %i files?" -msgstr "Да се махнат ли промените в тези %i файла?" +#: lib/choose_repository.tcl:528 +msgid "Target Directory:" +msgstr "Целева директория:" -#: lib/index.tcl:438 -msgid "Any unstaged changes will be permanently lost by the revert." -msgstr "" -"Всички промени, които не са били вкарани в индекса, ще бъдат безвъзвратно " -"загубени." +#: lib/choose_repository.tcl:538 +msgid "Clone Type:" +msgstr "Вид клониране:" -#: lib/index.tcl:441 -msgid "Do Nothing" -msgstr "Нищо да не се прави" +#: lib/choose_repository.tcl:543 +msgid "Standard (Fast, Semi-Redundant, Hardlinks)" +msgstr "Стандартно (бързо, частично споделяне на файлове, твърди връзки)" -#: lib/index.tcl:459 -msgid "Reverting selected files" -msgstr "Махане на промените в избраните файлове" +#: lib/choose_repository.tcl:548 +msgid "Full Copy (Slower, Redundant Backup)" +msgstr "Пълно (бавно, пълноценно резервно копие)" -#: lib/index.tcl:463 -#, tcl-format -msgid "Reverting %s" -msgstr "Махане на промените в „%s“" +#: lib/choose_repository.tcl:553 +msgid "Shared (Fastest, Not Recommended, No Backup)" +msgstr "Споделено (най-бързо, не се препоръчва, не прави резервно копие)" -#: lib/line.tcl:17 -msgid "Goto Line:" -msgstr "Към ред:" +#: lib/choose_repository.tcl:560 +msgid "Recursively clone submodules too" +msgstr "Рекурсивно клониране и на подмодулите" -#: lib/line.tcl:23 -msgid "Go" -msgstr "Придвижване" +#: lib/choose_repository.tcl:594 lib/choose_repository.tcl:641 +#: lib/choose_repository.tcl:790 lib/choose_repository.tcl:864 +#: lib/choose_repository.tcl:1145 lib/choose_repository.tcl:1153 +#, tcl-format +msgid "Not a Git repository: %s" +msgstr "Това не е хранилище на Git: %s" -#: lib/merge.tcl:13 -msgid "" -"Cannot merge while amending.\n" -"\n" -"You must finish amending this commit before starting any type of merge.\n" -msgstr "" -"По време на поправяне не може да сливане.\n" -"\n" -"Трябва да завършите поправянето на текущото подаване, преди да започнете " -"сливане.\n" +#: lib/choose_repository.tcl:630 +msgid "Standard only available for local repository." +msgstr "Само локални хранилища може да се клонират стандартно" -#: lib/merge.tcl:27 -msgid "" -"Last scanned state does not match repository state.\n" -"\n" -"Another Git program has modified this repository since the last scan. A " -"rescan must be performed before a merge can be performed.\n" -"\n" -"The rescan will be automatically started now.\n" -msgstr "" -"Последно установеното състояние не отговаря на това в хранилището.\n" -"\n" -"Някой друг процес за Git е променил хранилището междувременно. Състоянието " -"трябва да бъде проверено, преди да се извърши сливане.\n" -"\n" -"Автоматично ще започне нова проверка.\n" -"\n" +#: lib/choose_repository.tcl:634 +msgid "Shared only available for local repository." +msgstr "Само локални хранилища може да се клонират споделено" -#: lib/merge.tcl:45 +#: lib/choose_repository.tcl:655 #, tcl-format -msgid "" -"You are in the middle of a conflicted merge.\n" -"\n" -"File %s has merge conflicts.\n" -"\n" -"You must resolve them, stage the file, and commit to complete the current " -"merge. Only then can you begin another merge.\n" -msgstr "" -"В момента тече сливане, но има конфликти.\n" -"\n" -"Погледнете файла „%s“.\n" -"\n" -"Трябва да коригирате конфликтите в него, да го добавите към индекса и да " -"завършите текущото сливане чрез подаване. Чак тогава може да започнете ново " -"сливане.\n" +msgid "Location %s already exists." +msgstr "Местоположението „%s“ вече съществува." -#: lib/merge.tcl:55 -#, tcl-format -msgid "" -"You are in the middle of a change.\n" -"\n" -"File %s is modified.\n" -"\n" -"You should complete the current commit before starting a merge. Doing so " -"will help you abort a failed merge, should the need arise.\n" -msgstr "" -"В момента тече подаване.\n" -"\n" -"Файлът „%s“ е променен.\n" -"\n" -"Трябва да завършите текущото подаване, преди да започнете сливане. Така ще " -"можете лесно да преустановите сливането, ако възникне нужда.\n" +#: lib/choose_repository.tcl:666 +msgid "Failed to configure origin" +msgstr "Неуспешно настройване на хранилището-източник" -#: lib/merge.tcl:108 +#: lib/choose_repository.tcl:678 +msgid "Counting objects" +msgstr "Преброяване на обекти" + +#: lib/choose_repository.tcl:679 +msgid "buckets" +msgstr "клетки" + +#: lib/choose_repository.tcl:703 #, tcl-format -msgid "%s of %s" -msgstr "%s от общо %s" +msgid "Unable to copy objects/info/alternates: %s" +msgstr "Обектите/Информацията/Синонимите не може да се копират: %s" -#: lib/merge.tcl:126 +#: lib/choose_repository.tcl:740 #, tcl-format -msgid "Merging %s and %s..." -msgstr "Сливане на „%s“ и „%s“…" +msgid "Nothing to clone from %s." +msgstr "Няма какво да се клонира от „%s“." -#: lib/merge.tcl:137 -msgid "Merge completed successfully." -msgstr "Сливането завърши успешно." +#: lib/choose_repository.tcl:742 lib/choose_repository.tcl:962 +#: lib/choose_repository.tcl:974 +msgid "The 'master' branch has not been initialized." +msgstr "Основният клон — „master“ не е инициализиран." -#: lib/merge.tcl:139 -msgid "Merge failed. Conflict resolution is required." -msgstr "Неуспешно сливане — има конфликти за коригиране." +#: lib/choose_repository.tcl:755 +msgid "Hardlinks are unavailable. Falling back to copying." +msgstr "Не се поддържат твърди връзки. Преминава се към копиране." -#: lib/merge.tcl:156 +#: lib/choose_repository.tcl:769 #, tcl-format -msgid "%s (%s): Merge" -msgstr "%s (%s): Сливане" +msgid "Cloning from %s" +msgstr "Клониране на „%s“" -#: lib/merge.tcl:164 +#: lib/choose_repository.tcl:800 +msgid "Copying objects" +msgstr "Копиране на обекти" + +#: lib/choose_repository.tcl:801 +msgid "KiB" +msgstr "KiB" + +#: lib/choose_repository.tcl:825 #, tcl-format -msgid "Merge Into %s" -msgstr "Сливане в „%s“" +msgid "Unable to copy object: %s" +msgstr "Неуспешно копиране на обект: %s" -#: lib/merge.tcl:183 -msgid "Revision To Merge" -msgstr "Версия за сливане" +#: lib/choose_repository.tcl:837 +msgid "Linking objects" +msgstr "Създаване на връзки към обектите" -#: lib/merge.tcl:218 -msgid "" -"Cannot abort while amending.\n" -"\n" -"You must finish amending this commit.\n" +#: lib/choose_repository.tcl:838 +msgid "objects" +msgstr "обекти" + +#: lib/choose_repository.tcl:846 +#, tcl-format +msgid "Unable to hardlink object: %s" +msgstr "Неуспешно създаване на твърда връзка към обект: %s" + +#: lib/choose_repository.tcl:903 +msgid "Cannot fetch branches and objects. See console output for details." msgstr "" -"Поправянето не може да бъде преустановено.\n" -"\n" -"Трябва да завършите поправката на това подаване.\n" +"Клоните и обектите не може да се изтеглят. За повече информация погледнете " +"изхода на конзолата." -#: lib/merge.tcl:228 -msgid "" -"Abort merge?\n" -"\n" -"Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" -"\n" -"Continue with aborting the current merge?" +#: lib/choose_repository.tcl:914 +msgid "Cannot fetch tags. See console output for details." msgstr "" -"Да се преустанови ли сливането?\n" -"\n" -"В такъв случай ●ВСИЧКИ● неподадени промени ще бъдат безвъзвратно загубени.\n" -"\n" -"Наистина ли да се преустанови сливането?" +"Етикетите не може да се изтеглят. За повече информация погледнете изхода на " +"конзолата." -#: lib/merge.tcl:234 -msgid "" -"Reset changes?\n" -"\n" -"Resetting the changes will cause *ALL* uncommitted changes to be lost.\n" -"\n" -"Continue with resetting the current changes?" +#: lib/choose_repository.tcl:938 +msgid "Cannot determine HEAD. See console output for details." msgstr "" -"Да се занулят ли промените?\n" -"\n" -"В такъв случай ●ВСИЧКИ● неподадени промени ще бъдат безвъзвратно загубени.\n" -"\n" -"Наистина ли да се занулят промените?" +"Върхът „HEAD“ не може да се определи. За повече информация погледнете изхода " +"на конзолата." -#: lib/merge.tcl:245 -msgid "Aborting" -msgstr "Преустановяване" +#: lib/choose_repository.tcl:947 +#, tcl-format +msgid "Unable to cleanup %s" +msgstr "„%s“ не може да се изчисти" -#: lib/merge.tcl:245 -msgid "files reset" -msgstr "файла със занулени промени" +#: lib/choose_repository.tcl:953 +msgid "Clone failed." +msgstr "Неуспешно клониране." -#: lib/merge.tcl:273 -msgid "Abort failed." -msgstr "Неуспешно преустановяване." +#: lib/choose_repository.tcl:960 +msgid "No default branch obtained." +msgstr "Не е получен клон по подразбиране." -#: lib/merge.tcl:275 -msgid "Abort completed. Ready." -msgstr "Успешно преустановяване. Готовност за следващо действие." +#: lib/choose_repository.tcl:971 +#, tcl-format +msgid "Cannot resolve %s as a commit." +msgstr "Няма подаване отговарящо на „%s“." -#: lib/mergetool.tcl:8 -msgid "Force resolution to the base version?" -msgstr "Да се използва базовата версия" +#: lib/choose_repository.tcl:998 +msgid "Creating working directory" +msgstr "Създаване на работната директория" -#: lib/mergetool.tcl:9 -msgid "Force resolution to this branch?" -msgstr "Да се използва версията от този клон" +#: lib/choose_repository.tcl:1028 +msgid "Initial file checkout failed." +msgstr "Неуспешно първоначално изтегляне." -#: lib/mergetool.tcl:10 -msgid "Force resolution to the other branch?" -msgstr "Да се използва версията от другия клон" +#: lib/choose_repository.tcl:1072 +msgid "Cloning submodules" +msgstr "Клониране на подмодули" -#: lib/mergetool.tcl:14 -#, tcl-format -msgid "" -"Note that the diff shows only conflicting changes.\n" -"\n" -"%s will be overwritten.\n" -"\n" -"This operation can be undone only by restarting the merge." -msgstr "" -"Разликата показва само разликите с конфликт.\n" -"\n" -"Файлът „%s“ ще бъде презаписан.\n" -"\n" -"Тази операция може да бъде отменена само чрез започване на сливането наново." +#: lib/choose_repository.tcl:1087 +msgid "Cannot clone submodules." +msgstr "Подмодулите не може да се клонират." -#: lib/mergetool.tcl:45 +#: lib/choose_repository.tcl:1110 +msgid "Repository:" +msgstr "Хранилище:" + +#: lib/choose_repository.tcl:1159 #, tcl-format -msgid "File %s seems to have unresolved conflicts, still stage?" -msgstr "" -"Изглежда, че все още има некоригирани конфликти във файла „%s“. Да се добави " -"ли файлът към индекса?" +msgid "Failed to open repository %s:" +msgstr "Неуспешно отваряне на хранилището „%s“:" -#: lib/mergetool.tcl:60 +#: lib/about.tcl:26 +msgid "git-gui - a graphical user interface for Git." +msgstr "git-gui — графичен интерфейс за Git." + +#: lib/blame.tcl:74 #, tcl-format -msgid "Adding resolution for %s" -msgstr "Добавяне на корекция на конфликтите в „%s“" +msgid "%s (%s): File Viewer" +msgstr "%s (%s): Преглед на файлове" -#: lib/mergetool.tcl:141 -msgid "Cannot resolve deletion or link conflicts using a tool" -msgstr "" -"Конфликтите при символни връзки или изтриване не могат да бъдат коригирани с " -"външна програма." +#: lib/blame.tcl:80 +msgid "Commit:" +msgstr "Подаване:" -#: lib/mergetool.tcl:146 -msgid "Conflict file does not exist" -msgstr "Файлът, в който е конфликтът, не съществува" +#: lib/blame.tcl:282 +msgid "Copy Commit" +msgstr "Копиране на подаване" -#: lib/mergetool.tcl:246 -#, tcl-format -msgid "Not a GUI merge tool: '%s'" -msgstr "Това не е графична програма за сливане: „%s“" +#: lib/blame.tcl:286 +msgid "Find Text..." +msgstr "Търсене на текст…" -#: lib/mergetool.tcl:275 -#, tcl-format -msgid "Unsupported merge tool '%s'" -msgstr "Неподдържана програма за сливане: „%s“" +#: lib/blame.tcl:290 +msgid "Goto Line..." +msgstr "Към ред…" -#: lib/mergetool.tcl:310 -msgid "Merge tool is already running, terminate it?" -msgstr "Програмата за сливане вече е стартирана. Да бъде ли изключена?" +#: lib/blame.tcl:299 +msgid "Do Full Copy Detection" +msgstr "Пълно търсене на копиране" -#: lib/mergetool.tcl:330 -#, tcl-format -msgid "" -"Error retrieving versions:\n" -"%s" -msgstr "" -"Грешка при изтеглянето на версии:\n" -"%s" +#: lib/blame.tcl:303 +msgid "Show History Context" +msgstr "Показване на контекста от историята" -#: lib/mergetool.tcl:350 +#: lib/blame.tcl:306 +msgid "Blame Parent Commit" +msgstr "Анотиране на родителското подаване" + +#: lib/blame.tcl:468 #, tcl-format -msgid "" -"Could not start the merge tool:\n" -"\n" -"%s" -msgstr "" -"Програмата за сливане не може да бъде стартирана:\n" -"\n" -"%s" +msgid "Reading %s..." +msgstr "Чете се „%s“…" -#: lib/mergetool.tcl:354 -msgid "Running merge tool..." -msgstr "Стартиране на програмата за сливане…" +#: lib/blame.tcl:596 +msgid "Loading copy/move tracking annotations..." +msgstr "Зареждане на анотациите за проследяване на копирането/преместването…" -#: lib/mergetool.tcl:382 lib/mergetool.tcl:390 -msgid "Merge tool failed." -msgstr "Грешка в програмата за сливане." +#: lib/blame.tcl:613 +msgid "lines annotated" +msgstr "реда анотирани" + +#: lib/blame.tcl:815 +msgid "Loading original location annotations..." +msgstr "Зареждане на анотациите за първоначалното местоположение…" + +#: lib/blame.tcl:818 +msgid "Annotation complete." +msgstr "Анотирането завърши." + +#: lib/blame.tcl:849 +msgid "Busy" +msgstr "Операцията не е завършила" -#: lib/option.tcl:11 -#, tcl-format -msgid "Invalid global encoding '%s'" -msgstr "Неправилно глобално кодиране „%s“" +#: lib/blame.tcl:850 +msgid "Annotation process is already running." +msgstr "В момента тече процес на анотиране." -#: lib/option.tcl:19 -#, tcl-format -msgid "Invalid repo encoding '%s'" -msgstr "Неправилно кодиране „%s“ на хранилището" +#: lib/blame.tcl:889 +msgid "Running thorough copy detection..." +msgstr "Изпълнява се цялостен процес на откриване на копиране…" -#: lib/option.tcl:119 -msgid "Restore Defaults" -msgstr "Стандартни настройки" +#: lib/blame.tcl:957 +msgid "Loading annotation..." +msgstr "Зареждане на анотации…" -#: lib/option.tcl:123 -msgid "Save" -msgstr "Запазване" +#: lib/blame.tcl:1010 +msgid "Author:" +msgstr "Автор:" -#: lib/option.tcl:133 -#, tcl-format -msgid "%s Repository" -msgstr "Хранилище „%s“" +#: lib/blame.tcl:1014 +msgid "Committer:" +msgstr "Подал:" -#: lib/option.tcl:134 -msgid "Global (All Repositories)" -msgstr "Глобално (за всички хранилища)" +#: lib/blame.tcl:1019 +msgid "Original File:" +msgstr "Първоначален файл:" -#: lib/option.tcl:140 -msgid "User Name" -msgstr "Потребителско име" +#: lib/blame.tcl:1067 +msgid "Cannot find HEAD commit:" +msgstr "Подаването за връх „HEAD“ не може да се открие:" -#: lib/option.tcl:141 -msgid "Email Address" -msgstr "Адрес на е-поща" +#: lib/blame.tcl:1122 +msgid "Cannot find parent commit:" +msgstr "Родителското подаване не може да се открие" -#: lib/option.tcl:143 -msgid "Summarize Merge Commits" -msgstr "Обобщаване на подаванията при сливане" +#: lib/blame.tcl:1137 +msgid "Unable to display parent" +msgstr "Родителят не може да се покаже" -#: lib/option.tcl:144 -msgid "Merge Verbosity" -msgstr "Подробности при сливанията" +#: lib/blame.tcl:1138 lib/diff.tcl:345 +msgid "Error loading diff:" +msgstr "Грешка при зареждане на разлика:" -#: lib/option.tcl:145 -msgid "Show Diffstat After Merge" -msgstr "Извеждане на статистика след сливанията" +#: lib/blame.tcl:1279 +msgid "Originally By:" +msgstr "Първоначално от:" -#: lib/option.tcl:146 -msgid "Use Merge Tool" -msgstr "Използване на програма за сливане" +#: lib/blame.tcl:1285 +msgid "In File:" +msgstr "Във файл:" -#: lib/option.tcl:148 -msgid "Trust File Modification Timestamps" -msgstr "Доверие във времето на промяна на файловете" +#: lib/blame.tcl:1290 +msgid "Copied Or Moved Here By:" +msgstr "Копирано или преместено тук от:" -#: lib/option.tcl:149 -msgid "Prune Tracking Branches During Fetch" -msgstr "Окастряне на следящите клонове при доставяне" +#: lib/diff.tcl:77 +#, tcl-format +msgid "" +"No differences detected.\n" +"\n" +"%s has no changes.\n" +"\n" +"The modification date of this file was updated by another application, but " +"the content within the file was not changed.\n" +"\n" +"A rescan will be automatically started to find other files which may have " +"the same state." +msgstr "" +"Не са открити разлики.\n" +"\n" +"Няма промени в „%s“.\n" +"\n" +"Времето на промяна на файла е бил зададен от друга програма, но съдържанието " +"му не е променено.\n" +"\n" +"Автоматично ще започне нова проверка дали няма други файлове в това " +"състояние." -#: lib/option.tcl:150 -msgid "Match Tracking Branches" -msgstr "Напасване на следящите клонове" +#: lib/diff.tcl:117 +#, tcl-format +msgid "Loading diff of %s..." +msgstr "Зареждане на разликите в „%s“…" -#: lib/option.tcl:151 -msgid "Use Textconv For Diffs and Blames" -msgstr "Използване на „textconv“ за разликите и анотирането" +#: lib/diff.tcl:143 +msgid "" +"LOCAL: deleted\n" +"REMOTE:\n" +msgstr "" +"ЛОКАЛНО: изтрит\n" +"ОТДАЛЕЧЕНО:\n" -#: lib/option.tcl:152 -msgid "Blame Copy Only On Changed Files" -msgstr "Анотиране на копието само по променените файлове" +#: lib/diff.tcl:148 +msgid "" +"REMOTE: deleted\n" +"LOCAL:\n" +msgstr "" +"ОТДАЛЕЧЕНО: изтрит\n" +"ЛОКАЛНО:\n" -#: lib/option.tcl:153 -msgid "Maximum Length of Recent Repositories List" -msgstr "Максимален брой на списъка „Скоро ползвани“ хранилища" +#: lib/diff.tcl:155 +msgid "LOCAL:\n" +msgstr "ЛОКАЛНО:\n" -#: lib/option.tcl:154 -msgid "Minimum Letters To Blame Copy On" -msgstr "Минимален брой знаци за анотиране на копието" +#: lib/diff.tcl:158 +msgid "REMOTE:\n" +msgstr "ОТДАЛЕЧЕНО:\n" -#: lib/option.tcl:155 -msgid "Blame History Context Radius (days)" -msgstr "Исторически обхват за анотиране в дни" +#: lib/diff.tcl:220 lib/diff.tcl:344 +#, tcl-format +msgid "Unable to display %s" +msgstr "Файлът „%s“ не може да се покаже" -#: lib/option.tcl:156 -msgid "Number of Diff Context Lines" -msgstr "Брой редове за контекста на разликите" +#: lib/diff.tcl:221 +msgid "Error loading file:" +msgstr "Грешка при зареждане на файл:" -#: lib/option.tcl:157 -msgid "Additional Diff Parameters" -msgstr "Аргументи към командата за разликите" +#: lib/diff.tcl:227 +msgid "Git Repository (subproject)" +msgstr "Хранилище на Git (подмодул)" -#: lib/option.tcl:158 -msgid "Commit Message Text Width" -msgstr "Широчина на текста на съобщението при подаване" +#: lib/diff.tcl:239 +msgid "* Binary file (not showing content)." +msgstr "● Двоичен файл (съдържанието не се показва)." -#: lib/option.tcl:159 -msgid "New Branch Name Template" -msgstr "Шаблон за името на новите клони" +#: lib/diff.tcl:244 +#, tcl-format +msgid "" +"* Untracked file is %d bytes.\n" +"* Showing only first %d bytes.\n" +msgstr "" +"● Неследеният файл е %d байта.\n" +"● Показват се само първите %d байта.\n" -#: lib/option.tcl:160 -msgid "Default File Contents Encoding" -msgstr "Кодиране на файловете" +#: lib/diff.tcl:250 +#, tcl-format +msgid "" +"\n" +"* Untracked file clipped here by %s.\n" +"* To see the entire file, use an external editor.\n" +msgstr "" +"\n" +"● Неследеният файл е отрязан дотук от програмата „%s“.\n" +"● Използвайте външен редактор, за да видите целия файл.\n" -#: lib/option.tcl:161 -msgid "Warn before committing to a detached head" -msgstr "Предупреждаване при подаване към несвързан указател" +#: lib/diff.tcl:583 +msgid "Failed to unstage selected hunk." +msgstr "Избраното парче не може да се извади от индекса." -#: lib/option.tcl:162 -msgid "Staging of untracked files" -msgstr "Добавяне на неследените файлове към индекса" +#: lib/diff.tcl:591 +msgid "Failed to revert selected hunk." +msgstr "Избраното парче не може да се върне." -#: lib/option.tcl:163 -msgid "Show untracked files" -msgstr "Показване на неследените файлове" +#: lib/diff.tcl:594 +msgid "Failed to stage selected hunk." +msgstr "Избраното парче не може да се добави към индекса." -#: lib/option.tcl:164 -msgid "Tab spacing" -msgstr "Ширина на табулацията" +#: lib/diff.tcl:687 +msgid "Failed to unstage selected line." +msgstr "Избраният ред не може да се извади от индекса." -#: lib/option.tcl:210 -msgid "Change" -msgstr "Смяна" +#: lib/diff.tcl:696 +msgid "Failed to revert selected line." +msgstr "Избраният ред не може да се върне." -#: lib/option.tcl:254 -msgid "Spelling Dictionary:" -msgstr "Правописен речник:" +#: lib/diff.tcl:700 +msgid "Failed to stage selected line." +msgstr "Избраният ред не може да се добави към индекса." -#: lib/option.tcl:284 -msgid "Change Font" -msgstr "Смяна на шрифта" +#: lib/diff.tcl:889 +msgid "Failed to undo last revert." +msgstr "Неуспешна отмяна на последното връщане." -#: lib/option.tcl:288 +#: lib/sshkey.tcl:34 +msgid "No keys found." +msgstr "Не са открити ключове." + +#: lib/sshkey.tcl:37 #, tcl-format -msgid "Choose %s" -msgstr "Избор на „%s“" +msgid "Found a public key in: %s" +msgstr "Открит е публичен ключ в „%s“" -#: lib/option.tcl:294 -msgid "pt." -msgstr "тчк." +#: lib/sshkey.tcl:43 +msgid "Generate Key" +msgstr "Генериране на ключ" -#: lib/option.tcl:308 -msgid "Preferences" -msgstr "Настройки" +#: lib/sshkey.tcl:61 +msgid "Copy To Clipboard" +msgstr "Копиране към системния буфер" -#: lib/option.tcl:345 -msgid "Failed to completely save options:" -msgstr "Неуспешно запазване на настройките:" +#: lib/sshkey.tcl:75 +msgid "Your OpenSSH Public Key" +msgstr "Публичният ви ключ за OpenSSH" -#: lib/remote.tcl:200 -msgid "Push to" -msgstr "Изтласкване към" +#: lib/sshkey.tcl:83 +msgid "Generating..." +msgstr "Генериране…" -#: lib/remote.tcl:218 -msgid "Remove Remote" -msgstr "Премахване на отдалечено хранилище" +#: lib/sshkey.tcl:89 +#, tcl-format +msgid "" +"Could not start ssh-keygen:\n" +"\n" +"%s" +msgstr "" +"Програмата „ssh-keygen“ не може да се стартира:\n" +"\n" +"%s" -#: lib/remote.tcl:223 -msgid "Prune from" -msgstr "Окастряне от" +#: lib/sshkey.tcl:116 +msgid "Generation failed." +msgstr "Неуспешно генериране." -#: lib/remote.tcl:228 -msgid "Fetch from" -msgstr "Доставяне от" +#: lib/sshkey.tcl:123 +msgid "Generation succeeded, but no keys found." +msgstr "Генерирането завърши успешно, а не са намерени ключове." -#: lib/remote.tcl:253 lib/remote.tcl:258 -msgid "All" -msgstr "Всички" +#: lib/sshkey.tcl:126 +#, tcl-format +msgid "Your key is in: %s" +msgstr "Ключът ви е в „%s“" -#: lib/remote_add.tcl:20 +#: lib/branch_create.tcl:23 #, tcl-format -msgid "%s (%s): Add Remote" -msgstr "%s (%s): Добавяне на отдалечено хранилище" +msgid "%s (%s): Create Branch" +msgstr "%s (%s): Създаване на клон" -#: lib/remote_add.tcl:25 -msgid "Add New Remote" -msgstr "Добавяне на отдалечено хранилище" +#: lib/branch_create.tcl:28 +msgid "Create New Branch" +msgstr "Създаване на нов клон" -#: lib/remote_add.tcl:30 lib/tools_dlg.tcl:37 -msgid "Add" -msgstr "Добавяне" +#: lib/branch_create.tcl:42 +msgid "Branch Name" +msgstr "Име на клона" -#: lib/remote_add.tcl:39 -msgid "Remote Details" -msgstr "Данни за отдалеченото хранилище" +#: lib/branch_create.tcl:57 +msgid "Match Tracking Branch Name" +msgstr "Съвпадане по името на следения клон" -#: lib/remote_add.tcl:50 -msgid "Location:" -msgstr "Местоположение:" +#: lib/branch_create.tcl:66 +msgid "Starting Revision" +msgstr "Начална версия" -#: lib/remote_add.tcl:60 -msgid "Further Action" -msgstr "Следващо действие" +#: lib/branch_create.tcl:72 +msgid "Update Existing Branch:" +msgstr "Обновяване на съществуващ клон:" -#: lib/remote_add.tcl:63 -msgid "Fetch Immediately" -msgstr "Незабавно доставяне" +#: lib/branch_create.tcl:75 +msgid "No" +msgstr "Не" -#: lib/remote_add.tcl:69 -msgid "Initialize Remote Repository and Push" -msgstr "Инициализиране на отдалеченото хранилище и изтласкване на промените" +#: lib/branch_create.tcl:80 +msgid "Fast Forward Only" +msgstr "Само тривиално превъртащо сливане" -#: lib/remote_add.tcl:75 -msgid "Do Nothing Else Now" -msgstr "Да не се прави нищо" +#: lib/branch_create.tcl:97 +msgid "Checkout After Creation" +msgstr "Преминаване към клона след създаването му" -#: lib/remote_add.tcl:100 -msgid "Please supply a remote name." -msgstr "Задайте име за отдалеченото хранилище." +#: lib/branch_create.tcl:132 +msgid "Please select a tracking branch." +msgstr "Изберете клон за следени." -#: lib/remote_add.tcl:113 +#: lib/branch_create.tcl:141 #, tcl-format -msgid "'%s' is not an acceptable remote name." -msgstr "Отдалечено хранилище не може да се казва „%s“." +msgid "Tracking branch %s is not a branch in the remote repository." +msgstr "Следящият клон — „%s“, не съществува в отдалеченото хранилище." -#: lib/remote_add.tcl:124 -#, tcl-format -msgid "Failed to add remote '%s' of location '%s'." -msgstr "Неуспешно добавяне на отдалеченото хранилище „%s“ от адрес „%s“." +#: lib/console.tcl:59 +msgid "Working... please wait..." +msgstr "В момента се извършва действие, изчакайте…" -#: lib/remote_add.tcl:132 lib/transport.tcl:6 -#, tcl-format -msgid "fetch %s" -msgstr "доставяне на „%s“" +#: lib/console.tcl:186 +msgid "Success" +msgstr "Успех" -#: lib/remote_add.tcl:133 -#, tcl-format -msgid "Fetching the %s" -msgstr "Доставяне на „%s“" +#: lib/console.tcl:200 +msgid "Error: Command Failed" +msgstr "Грешка: неуспешно изпълнение на команда" -#: lib/remote_add.tcl:156 -#, tcl-format -msgid "Do not know how to initialize repository at location '%s'." -msgstr "Хранилището с местоположение „%s“ не може да бъде инициализирано." +#: lib/line.tcl:17 +msgid "Goto Line:" +msgstr "Към ред:" -#: lib/remote_add.tcl:162 lib/transport.tcl:54 lib/transport.tcl:92 -#: lib/transport.tcl:110 -#, tcl-format -msgid "push %s" -msgstr "изтласкване на „%s“" +#: lib/line.tcl:23 +msgid "Go" +msgstr "Към" -#: lib/remote_add.tcl:163 -#, tcl-format -msgid "Setting up the %s (at %s)" -msgstr "Добавяне на хранилище „%s“ (с адрес „%s“)" +#: lib/choose_rev.tcl:52 +msgid "This Detached Checkout" +msgstr "Това несвързано изтегляне" -#: lib/remote_branch_delete.tcl:29 -#, tcl-format -msgid "%s (%s): Delete Branch Remotely" -msgstr "%s (%s): Изтриване на отдалечения клон" +#: lib/choose_rev.tcl:60 +msgid "Revision Expression:" +msgstr "Израз за версия:" -#: lib/remote_branch_delete.tcl:34 -msgid "Delete Branch Remotely" -msgstr "Изтриване на отдалечения клон" +#: lib/choose_rev.tcl:72 +msgid "Local Branch" +msgstr "Локален клон" -#: lib/remote_branch_delete.tcl:48 -msgid "From Repository" -msgstr "От хранилище" +#: lib/choose_rev.tcl:77 +msgid "Tracking Branch" +msgstr "Следящ клон" -#: lib/remote_branch_delete.tcl:51 lib/transport.tcl:165 -msgid "Remote:" -msgstr "Отдалечено хранилище:" +#: lib/choose_rev.tcl:82 lib/choose_rev.tcl:544 +msgid "Tag" +msgstr "Етикет" -#: lib/remote_branch_delete.tcl:72 lib/transport.tcl:187 -msgid "Arbitrary Location:" -msgstr "Произволно местоположение:" +#: lib/choose_rev.tcl:321 +#, tcl-format +msgid "Invalid revision: %s" +msgstr "Неправилна версия: %s" -#: lib/remote_branch_delete.tcl:88 -msgid "Branches" -msgstr "Клони" +#: lib/choose_rev.tcl:342 +msgid "No revision selected." +msgstr "Не е избрана версия." -#: lib/remote_branch_delete.tcl:110 -msgid "Delete Only If" -msgstr "Изтриване, само ако" +#: lib/choose_rev.tcl:350 +msgid "Revision expression is empty." +msgstr "Изразът за версия е празен." -#: lib/remote_branch_delete.tcl:112 -msgid "Merged Into:" -msgstr "Слят в:" +#: lib/choose_rev.tcl:537 +msgid "Updated" +msgstr "Обновен" -#: lib/remote_branch_delete.tcl:153 -msgid "A branch is required for 'Merged Into'." -msgstr "За данните „Слят в“ е необходимо да зададете клон." +#: lib/choose_rev.tcl:565 +msgid "URL" +msgstr "Адрес" -#: lib/remote_branch_delete.tcl:185 -#, tcl-format +#: lib/commit.tcl:9 msgid "" -"The following branches are not completely merged into %s:\n" +"There is nothing to amend.\n" "\n" -" - %s" +"You are about to create the initial commit. There is no commit before this " +"to amend.\n" msgstr "" -"Следните клони не са слети напълно в „%s“:\n" +"Няма какво да се поправи.\n" "\n" -" ● %s" +"Ще създадете първоначалното подаване. Преди него няма други подавания, които " +"да поправите.\n" -#: lib/remote_branch_delete.tcl:190 -#, tcl-format +#: lib/commit.tcl:18 msgid "" -"One or more of the merge tests failed because you have not fetched the " -"necessary commits. Try fetching from %s first." +"Cannot amend while merging.\n" +"\n" +"You are currently in the middle of a merge that has not been fully " +"completed. You cannot amend the prior commit unless you first abort the " +"current merge activity.\n" msgstr "" -"Поне една от пробите за сливане е неуспешна, защото не сте доставили всички " -"необходими подавания. Пробвайте първо да доставите подаванията от „%s“." - -#: lib/remote_branch_delete.tcl:208 -msgid "Please select one or more branches to delete." -msgstr "Изберете поне един клон за изтриване." - -#: lib/remote_branch_delete.tcl:227 -#, tcl-format -msgid "Deleting branches from %s" -msgstr "Изтриване на клони от „%s“" - -#: lib/remote_branch_delete.tcl:300 -msgid "No repository selected." -msgstr "Не е избрано хранилище." - -#: lib/remote_branch_delete.tcl:305 -#, tcl-format -msgid "Scanning %s..." -msgstr "Претърсване на „%s“…" - -#: lib/search.tcl:48 -msgid "Find:" -msgstr "Търсене:" - -#: lib/search.tcl:50 -msgid "Next" -msgstr "Следваща поява" +"По време на сливане не може да поправяте.\n" +"\n" +"В момента все още не сте завършили операция по сливане. Не може да поправите " +"предишното подаване, освен ако първо не преустановите текущото сливане.\n" -#: lib/search.tcl:51 -msgid "Prev" -msgstr "Предишна поява" +#: lib/commit.tcl:56 +msgid "Error loading commit data for amend:" +msgstr "Грешка при зареждане на данните от подаване, които да се поправят:" -#: lib/search.tcl:52 -msgid "RegExp" -msgstr "РегИзр" +#: lib/commit.tcl:83 +msgid "Unable to obtain your identity:" +msgstr "Идентификацията ви не може да се определи:" -#: lib/search.tcl:54 -msgid "Case" -msgstr "Главни/малки" +#: lib/commit.tcl:88 +msgid "Invalid GIT_COMMITTER_IDENT:" +msgstr "Неправилно поле „GIT_COMMITTER_IDENT“:" -#: lib/shortcut.tcl:8 lib/shortcut.tcl:43 lib/shortcut.tcl:75 +#: lib/commit.tcl:138 #, tcl-format -msgid "%s (%s): Create Desktop Icon" -msgstr "%s (%s): Добавяне на икона на работния плот" - -#: lib/shortcut.tcl:24 lib/shortcut.tcl:65 -msgid "Cannot write shortcut:" -msgstr "Клавишната комбинация не може да бъде запазена:" - -#: lib/shortcut.tcl:140 -msgid "Cannot write icon:" -msgstr "Иконата не може да бъде запазена:" - -#: lib/spellcheck.tcl:57 -msgid "Unsupported spell checker" -msgstr "Тази програма за проверка на правописа не се поддържа" - -#: lib/spellcheck.tcl:65 -msgid "Spell checking is unavailable" -msgstr "Липсва програма за проверка на правописа" +msgid "warning: Tcl does not support encoding '%s'." +msgstr "предупреждение: Tcl не поддържа кодирането „%s“." -#: lib/spellcheck.tcl:68 -msgid "Invalid spell checking configuration" -msgstr "Неправилни настройки на проверката на правописа" +#: lib/commit.tcl:158 +msgid "" +"Last scanned state does not match repository state.\n" +"\n" +"Another Git program has modified this repository since the last scan. A " +"rescan must be performed before another commit can be created.\n" +"\n" +"The rescan will be automatically started now.\n" +msgstr "" +"Състоянието при последната проверка не отговаря на състоянието на " +"хранилището.\n" +"\n" +"Някой друг процес за Git е променил хранилището междувременно. Състоянието " +"трябва да се провери преди ново подаване.\n" +"\n" +"Автоматично ще започне нова проверка.\n" -#: lib/spellcheck.tcl:70 +#: lib/commit.tcl:182 #, tcl-format -msgid "Reverting dictionary to %s." -msgstr "Ползване на речник за език „%s“." +msgid "" +"Unmerged files cannot be committed.\n" +"\n" +"File %s has merge conflicts. You must resolve them and stage the file " +"before committing.\n" +msgstr "" +"Неслетите файлове не може да се подадат.\n" +"\n" +"Във файла „%s“ има конфликти при сливане. За да го подадете, трябва първо да " +"коригирате конфликтите и да добавите файла към индекса за подаване.\n" -#: lib/spellcheck.tcl:73 -msgid "Spell checker silently failed on startup" -msgstr "Програмата за правопис даже не стартира успешно." +#: lib/commit.tcl:190 +#, tcl-format +msgid "" +"Unknown file state %s detected.\n" +"\n" +"File %s cannot be committed by this program.\n" +msgstr "" +"Непознато състояние на файл „%s“.\n" +"\n" +"Файлът „%s“ не може да се подаде чрез текущата програма.\n" -#: lib/spellcheck.tcl:80 -msgid "Unrecognized spell checker" -msgstr "Непозната програма за проверка на правописа" +#: lib/commit.tcl:198 +msgid "" +"No changes to commit.\n" +"\n" +"You must stage at least 1 file before you can commit.\n" +msgstr "" +"Няма промени за подаване.\n" +"\n" +"Трябва да добавите поне един файл към индекса, за да подадете.\n" -#: lib/spellcheck.tcl:186 -msgid "No Suggestions" -msgstr "Няма предложения" +#: lib/commit.tcl:213 +msgid "" +"Please supply a commit message.\n" +"\n" +"A good commit message has the following format:\n" +"\n" +"- First line: Describe in one sentence what you did.\n" +"- Second line: Blank\n" +"- Remaining lines: Describe why this change is good.\n" +msgstr "" +"Задайте добро съобщение при подаване.\n" +"\n" +"Използвайте следния формат:\n" +"\n" +"● Първи ред: описание в едно изречение на промяната.\n" +"● Втори ред: празен.\n" +"● Останалите редове: опишете защо се налага тази промяна.\n" -#: lib/spellcheck.tcl:388 -msgid "Unexpected EOF from spell checker" -msgstr "Неочакван край на файл от програмата за проверка на правописа" +#: lib/commit.tcl:244 +msgid "Calling pre-commit hook..." +msgstr "Изпълняване на куката преди подаване…" -#: lib/spellcheck.tcl:392 -msgid "Spell Checker Failed" -msgstr "Грешка в програмата за проверка на правописа" +#: lib/commit.tcl:259 +msgid "Commit declined by pre-commit hook." +msgstr "Подаването е отхвърлено от куката преди подаване." -#: lib/sshkey.tcl:31 -msgid "No keys found." -msgstr "Не са открити ключове." +#: lib/commit.tcl:278 +msgid "" +"You are about to commit on a detached head. This is a potentially dangerous " +"thing to do because if you switch to another branch you will lose your " +"changes and it can be difficult to retrieve them later from the reflog. You " +"should probably cancel this commit and create a new branch to continue.\n" +" \n" +" Do you really want to proceed with your Commit?" +msgstr "" +"Ще подадете към несвързан, отделѐн указател „HEAD“. Това е опасно, защото " +"при преминаването към клон ще загубите промените си, като единственият начин " +"да ги върнете ще е чрез журнала на указателите (reflog). Най-вероятно трябва " +"да не правите това подаване, а да създадете нов клон, преди да продължите.\n" +" \n" +"Сигурни ли сте, че искате да извършите текущото подаване?" -#: lib/sshkey.tcl:34 -#, tcl-format -msgid "Found a public key in: %s" -msgstr "Открит е публичен ключ в „%s“" +#: lib/commit.tcl:299 +msgid "Calling commit-msg hook..." +msgstr "Изпълняване на куката за съобщението при подаване…" -#: lib/sshkey.tcl:40 -msgid "Generate Key" -msgstr "Генериране на ключ" +#: lib/commit.tcl:314 +msgid "Commit declined by commit-msg hook." +msgstr "Подаването е отхвърлено от куката за съобщението при подаване." -#: lib/sshkey.tcl:58 -msgid "Copy To Clipboard" -msgstr "Копиране към системния буфер" +#: lib/commit.tcl:327 +msgid "Committing changes..." +msgstr "Подаване на промените…" -#: lib/sshkey.tcl:72 -msgid "Your OpenSSH Public Key" -msgstr "Публичният ви ключ за OpenSSH" +#: lib/commit.tcl:344 +msgid "write-tree failed:" +msgstr "неуспешно запазване на дървото (write-tree):" -#: lib/sshkey.tcl:80 -msgid "Generating..." -msgstr "Генериране…" +#: lib/commit.tcl:345 lib/commit.tcl:395 lib/commit.tcl:422 +msgid "Commit failed." +msgstr "Неуспешно подаване." -#: lib/sshkey.tcl:86 +#: lib/commit.tcl:362 #, tcl-format +msgid "Commit %s appears to be corrupt" +msgstr "Подаването „%s“ изглежда повредено" + +#: lib/commit.tcl:367 msgid "" -"Could not start ssh-keygen:\n" +"No changes to commit.\n" "\n" -"%s" +"No files were modified by this commit and it was not a merge commit.\n" +"\n" +"A rescan will be automatically started now.\n" msgstr "" -"Програмата „ssh-keygen“ не може да бъде стартирана:\n" +"Няма промени за подаване.\n" "\n" -"%s" +"В това подаване не са променяни никакви файлове, а и не е подаване със " +"сливане.\n" +"\n" +"Автоматично ще започне нова проверка.\n" -#: lib/sshkey.tcl:113 -msgid "Generation failed." -msgstr "Неуспешно генериране." +#: lib/commit.tcl:374 +msgid "No changes to commit." +msgstr "Няма промени за подаване." -#: lib/sshkey.tcl:120 -msgid "Generation succeeded, but no keys found." -msgstr "Генерирането завърши успешно, а не са намерени ключове." +#: lib/commit.tcl:394 +msgid "commit-tree failed:" +msgstr "неуспешно подаване на дървото (commit-tree):" -#: lib/sshkey.tcl:123 -#, tcl-format -msgid "Your key is in: %s" -msgstr "Ключът ви е в „%s“" +#: lib/commit.tcl:421 +msgid "update-ref failed:" +msgstr "неуспешно обновяване на указателите (update-ref):" -#: lib/status_bar.tcl:87 +#: lib/commit.tcl:514 #, tcl-format -msgid "%s ... %*i of %*i %s (%3i%%)" -msgstr "%s… %*i от общо %*i %s (%3i%%)" +msgid "Created commit %s: %s" +msgstr "Успешно подаване %s: %s" -#: lib/tools.tcl:76 +#: lib/branch_delete.tcl:16 #, tcl-format -msgid "Running %s requires a selected file." -msgstr "За изпълнението на „%s“ трябва да изберете файл." +msgid "%s (%s): Delete Branch" +msgstr "%s (%s): Изтриване на клон" -#: lib/tools.tcl:92 -#, tcl-format -msgid "Are you sure you want to run %1$s on file \"%2$s\"?" -msgstr "Сигурни ли сте, че искате да изпълните „%1$s“ върху файла „%2$s“?" +#: lib/branch_delete.tcl:21 +msgid "Delete Local Branch" +msgstr "Изтриване на локален клон" -#: lib/tools.tcl:96 -#, tcl-format -msgid "Are you sure you want to run %s?" -msgstr "Сигурни ли сте, че искате да изпълните „%s“?" +#: lib/branch_delete.tcl:39 +msgid "Local Branches" +msgstr "Локални клони" -#: lib/tools.tcl:118 -#, tcl-format -msgid "Tool: %s" -msgstr "Команда: %s" +#: lib/branch_delete.tcl:51 +msgid "Delete Only If Merged Into" +msgstr "Изтриване, само ако промените са слети и другаде" -#: lib/tools.tcl:119 +#: lib/branch_delete.tcl:103 #, tcl-format -msgid "Running: %s" -msgstr "Изпълнение: %s" +msgid "The following branches are not completely merged into %s:" +msgstr "Не всички промени в клоните са слети в „%s“:" -#: lib/tools.tcl:158 +#: lib/branch_delete.tcl:131 #, tcl-format -msgid "Tool completed successfully: %s" -msgstr "Командата завърши успешно: %s" +msgid " - %s:" +msgstr " — „%s:“" -#: lib/tools.tcl:160 +#: lib/branch_delete.tcl:141 #, tcl-format -msgid "Tool failed: %s" -msgstr "Командата върна грешка: %s" +msgid "" +"Failed to delete branches:\n" +"%s" +msgstr "" +"Неуспешно триене на клони:\n" +"%s" -#: lib/tools_dlg.tcl:22 +#: lib/date.tcl:25 #, tcl-format -msgid "%s (%s): Add Tool" -msgstr "%s (%s): Добавяне на команда" - -#: lib/tools_dlg.tcl:28 -msgid "Add New Tool Command" -msgstr "Добавяне на команда" - -#: lib/tools_dlg.tcl:34 -msgid "Add globally" -msgstr "Глобално добавяне" - -#: lib/tools_dlg.tcl:46 -msgid "Tool Details" -msgstr "Подробности за командата" - -#: lib/tools_dlg.tcl:49 -msgid "Use '/' separators to create a submenu tree:" -msgstr "За създаване на подменюта използвайте знака „/“ за разделител:" - -#: lib/tools_dlg.tcl:60 -msgid "Command:" -msgstr "Команда:" +msgid "Invalid date from Git: %s" +msgstr "Неправилни данни от Git: %s" -#: lib/tools_dlg.tcl:71 -msgid "Show a dialog before running" -msgstr "Преди изпълнение да се извежда диалогов прозорец" +#: lib/database.tcl:42 +msgid "Number of loose objects" +msgstr "Брой непакетирани обекти" -#: lib/tools_dlg.tcl:77 -msgid "Ask the user to select a revision (sets $REVISION)" -msgstr "Потребителят да укаже версия (задаване на променливата $REVISION)" +#: lib/database.tcl:43 +msgid "Disk space used by loose objects" +msgstr "Дисково пространство заето от непакетирани обекти" -#: lib/tools_dlg.tcl:82 -msgid "Ask the user for additional arguments (sets $ARGS)" -msgstr "" -"Потребителят да укаже допълнителни аргументи (задаване на променливата $ARGS)" +#: lib/database.tcl:44 +msgid "Number of packed objects" +msgstr "Брой пакетирани обекти" -#: lib/tools_dlg.tcl:89 -msgid "Don't show the command output window" -msgstr "Без показване на прозорец с изхода от командата" +#: lib/database.tcl:45 +msgid "Number of packs" +msgstr "Брой пакети" -#: lib/tools_dlg.tcl:94 -msgid "Run only if a diff is selected ($FILENAME not empty)" -msgstr "" -"Стартиране само след избор на разлика (променливата $FILENAME не е празна)" +#: lib/database.tcl:46 +msgid "Disk space used by packed objects" +msgstr "Дисково пространство заето от пакетирани обекти" -#: lib/tools_dlg.tcl:118 -msgid "Please supply a name for the tool." -msgstr "Задайте име за командата." +#: lib/database.tcl:47 +msgid "Packed objects waiting for pruning" +msgstr "Пакетирани обекти за окастряне" -#: lib/tools_dlg.tcl:126 +#: lib/database.tcl:48 +msgid "Garbage files" +msgstr "Файлове за боклука" + +#: lib/database.tcl:66 #, tcl-format -msgid "Tool '%s' already exists." -msgstr "Командата „%s“ вече съществува." +msgid "%s (%s): Database Statistics" +msgstr "%s (%s): Статистика на базата от данни" -#: lib/tools_dlg.tcl:148 +#: lib/database.tcl:72 +msgid "Compressing the object database" +msgstr "Компресиране на базата с данни за обектите" + +#: lib/database.tcl:83 +msgid "Verifying the object database with fsck-objects" +msgstr "Проверка на базата с данни за обектите с програмата „fsck-objects“" + +#: lib/database.tcl:107 #, tcl-format msgid "" -"Could not add tool:\n" -"%s" +"This repository currently has approximately %i loose objects.\n" +"\n" +"To maintain optimal performance it is strongly recommended that you compress " +"the database.\n" +"\n" +"Compress the database now?" msgstr "" -"Командата не може да бъде добавена:\n" -"%s" +"В това хранилище в момента има към %i непакетирани обекти.\n" +"\n" +"За добра производителност се препоръчва да компресирате базата с данни за " +"обектите.\n" +"\n" +"Да се започне ли компресирането?" -#: lib/tools_dlg.tcl:187 +#: lib/error.tcl:20 #, tcl-format -msgid "%s (%s): Remove Tool" -msgstr "%s (%s): Премахване на команда" - -#: lib/tools_dlg.tcl:193 -msgid "Remove Tool Commands" -msgstr "Премахване на команди" - -#: lib/tools_dlg.tcl:198 -msgid "Remove" -msgstr "Премахване" +msgid "%s: error" +msgstr "%s: грешка" -#: lib/tools_dlg.tcl:231 -msgid "(Blue denotes repository-local tools)" -msgstr "(командите към локалното хранилище са обозначени в синьо)" +#: lib/error.tcl:36 +#, tcl-format +msgid "%s: warning" +msgstr "%s: предупреждение" -#: lib/tools_dlg.tcl:283 +#: lib/error.tcl:80 #, tcl-format -msgid "%s (%s):" -msgstr "%s (%s):" +msgid "%s hook failed:" +msgstr "%s: грешка от куката" -#: lib/tools_dlg.tcl:292 +#: lib/error.tcl:96 +msgid "You must correct the above errors before committing." +msgstr "Преди да можете да подадете, коригирайте горните грешки." + +#: lib/error.tcl:116 #, tcl-format -msgid "Run Command: %s" -msgstr "Изпълнение на командата „%s“" +msgid "%s (%s): error" +msgstr "%s (%s): грешка" -#: lib/tools_dlg.tcl:306 -msgid "Arguments" -msgstr "Аргументи" +#: lib/merge.tcl:13 +msgid "" +"Cannot merge while amending.\n" +"\n" +"You must finish amending this commit before starting any type of merge.\n" +msgstr "" +"По време на поправяне не може да сливане.\n" +"\n" +"Трябва да завършите поправянето на текущото подаване, преди да започнете " +"сливане.\n" -#: lib/tools_dlg.tcl:341 -msgid "OK" -msgstr "Добре" +#: lib/merge.tcl:27 +msgid "" +"Last scanned state does not match repository state.\n" +"\n" +"Another Git program has modified this repository since the last scan. A " +"rescan must be performed before a merge can be performed.\n" +"\n" +"The rescan will be automatically started now.\n" +msgstr "" +"Последно установеното състояние не отговаря на това в хранилището.\n" +"\n" +"Някой друг процес за Git е променил хранилището междувременно. Състоянието " +"трябва да се провери, преди да се извърши сливане.\n" +"\n" +"Автоматично ще започне нова проверка.\n" +"\n" -#: lib/transport.tcl:7 +#: lib/merge.tcl:45 #, tcl-format -msgid "Fetching new changes from %s" -msgstr "Доставяне на промените от „%s“" +msgid "" +"You are in the middle of a conflicted merge.\n" +"\n" +"File %s has merge conflicts.\n" +"\n" +"You must resolve them, stage the file, and commit to complete the current " +"merge. Only then can you begin another merge.\n" +msgstr "" +"В момента тече сливане, но има конфликти.\n" +"\n" +"Погледнете файла „%s“.\n" +"\n" +"Трябва да коригирате конфликтите в него, да го добавите към индекса и да " +"завършите текущото сливане чрез подаване. Чак тогава може да започнете ново " +"сливане.\n" -#: lib/transport.tcl:18 +#: lib/merge.tcl:55 #, tcl-format -msgid "remote prune %s" -msgstr "окастряне на следящите клони към „%s“" +msgid "" +"You are in the middle of a change.\n" +"\n" +"File %s is modified.\n" +"\n" +"You should complete the current commit before starting a merge. Doing so " +"will help you abort a failed merge, should the need arise.\n" +msgstr "" +"В момента тече подаване.\n" +"\n" +"Файлът „%s“ е променен.\n" +"\n" +"Трябва да завършите текущото подаване, преди да започнете сливане. Така ще " +"можете лесно да преустановите сливането, ако възникне нужда.\n" -#: lib/transport.tcl:19 +#: lib/merge.tcl:108 #, tcl-format -msgid "Pruning tracking branches deleted from %s" -msgstr "Окастряне на следящите клони на изтритите клони от „%s“" - -#: lib/transport.tcl:25 -msgid "fetch all remotes" -msgstr "доставяне от всички отдалечени" - -#: lib/transport.tcl:26 -msgid "Fetching new changes from all remotes" -msgstr "Доставяне на промените от всички отдалечени хранилища" +msgid "%s of %s" +msgstr "%s от общо %s" -#: lib/transport.tcl:40 -msgid "remote prune all remotes" -msgstr "окастряне на следящите изтрити" +#: lib/merge.tcl:126 +#, tcl-format +msgid "Merging %s and %s..." +msgstr "Сливане на „%s“ и „%s“…" -#: lib/transport.tcl:41 -msgid "Pruning tracking branches deleted from all remotes" -msgstr "" -"Окастряне на следящите клони на изтритите клони от всички отдалечени " -"хранилища" +#: lib/merge.tcl:137 +msgid "Merge completed successfully." +msgstr "Сливането завърши успешно." -#: lib/transport.tcl:55 -#, tcl-format -msgid "Pushing changes to %s" -msgstr "Изтласкване на промените към „%s“" +#: lib/merge.tcl:139 +msgid "Merge failed. Conflict resolution is required." +msgstr "Неуспешно сливане — има конфликти за коригиране." -#: lib/transport.tcl:93 +#: lib/merge.tcl:156 #, tcl-format -msgid "Mirroring to %s" -msgstr "Изтласкване на всичко към „%s“" +msgid "%s (%s): Merge" +msgstr "%s (%s): Сливане" -#: lib/transport.tcl:111 +#: lib/merge.tcl:164 #, tcl-format -msgid "Pushing %s %s to %s" -msgstr "Изтласкване на %s „%s“ към „%s“" - -#: lib/transport.tcl:132 -msgid "Push Branches" -msgstr "Клони за изтласкване" +msgid "Merge Into %s" +msgstr "Сливане в „%s“" -#: lib/transport.tcl:147 -msgid "Source Branches" -msgstr "Клони-източници" +#: lib/merge.tcl:183 +msgid "Revision To Merge" +msgstr "Версия за сливане" -#: lib/transport.tcl:162 -msgid "Destination Repository" -msgstr "Целево хранилище" +#: lib/merge.tcl:218 +msgid "" +"Cannot abort while amending.\n" +"\n" +"You must finish amending this commit.\n" +msgstr "" +"Поправянето не може да се преустанови.\n" +"\n" +"Трябва да завършите поправката на това подаване.\n" -#: lib/transport.tcl:205 -msgid "Transfer Options" -msgstr "Настройки при пренасянето" +#: lib/merge.tcl:228 +msgid "" +"Abort merge?\n" +"\n" +"Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" +"\n" +"Continue with aborting the current merge?" +msgstr "" +"Да се преустанови ли сливането?\n" +"\n" +"В такъв случай ●ВСИЧКИ● неподадени промени ще се загубят безвъзвратно.\n" +"\n" +"Наистина ли да се преустанови сливането?" -#: lib/transport.tcl:207 -msgid "Force overwrite existing branch (may discard changes)" +#: lib/merge.tcl:234 +msgid "" +"Reset changes?\n" +"\n" +"Resetting the changes will cause *ALL* uncommitted changes to be lost.\n" +"\n" +"Continue with resetting the current changes?" msgstr "" -"Изрично презаписване на съществуващ клон (някои промени може да бъдат " -"загубени)" +"Да се занулят ли промените?\n" +"\n" +"В такъв случай ●ВСИЧКИ● неподадени промени ще се загубят безвъзвратно.\n" +"\n" +"Наистина ли да се занулят промените?" -#: lib/transport.tcl:211 -msgid "Use thin pack (for slow network connections)" -msgstr "Максимална компресия (за бавни мрежови връзки)" +#: lib/merge.tcl:246 +msgid "Aborting" +msgstr "Преустановяване" -#: lib/transport.tcl:215 -msgid "Include tags" -msgstr "Включване на етикетите" +#: lib/merge.tcl:247 +msgid "files reset" +msgstr "файла със занулени промени" -#: lib/transport.tcl:229 -#, tcl-format -msgid "%s (%s): Push" -msgstr "%s (%s): Изтласкване" +#: lib/merge.tcl:277 +msgid "Abort failed." +msgstr "Неуспешно преустановяване." + +#: lib/merge.tcl:279 +msgid "Abort completed. Ready." +msgstr "Успешно преустановяване. Готовност за следващо действие." -- cgit v1.2.3 From 996f0c583b36aa5d6c6308285aea1421eb7efae7 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 23 Dec 2024 08:45:57 -0800 Subject: Hopefully the final batch before 2.48-rc1 Let's wait for git-gui, gitk, and possibly po/ and delay the tagging of the -rc1. Many people are already offline for the end-of-year holidays and it is a slow week, and 'master' front has too many new things graduated from 'next' a bit too early for me to feel comfortable. Signed-off-by: Junio C Hamano --- Documentation/RelNotes/2.48.0.txt | 27 +++++++++++++++++++++++++++ GIT-VERSION-GEN | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/Documentation/RelNotes/2.48.0.txt b/Documentation/RelNotes/2.48.0.txt index cc752d5466..33c11e742f 100644 --- a/Documentation/RelNotes/2.48.0.txt +++ b/Documentation/RelNotes/2.48.0.txt @@ -35,6 +35,10 @@ UI, Workflows & Features * "git fetch" honors "remote..followRemoteHEAD" settings to tweak the remote-tracking HEAD in "refs/remotes//HEAD". + * "git range-diff" learned to optionally show and compare merge + commits in the ranges being compared, with the --diff-merges + option. + Performance, Internal Implementation, Development Support etc. -------------------------------------------------------------- @@ -141,6 +145,22 @@ Performance, Internal Implementation, Development Support etc. * Build procedure update plus introduction of Meson based builds. + * Recent reftable updates mistook a NULL return from a request for + 0-byte allocation as OOM and died unnecessarily, which has been + corrected. + + * Reftable backend adds check for upper limit of log's update_index. + + * Start working to make the codebase buildable with -Wsign-compare. + + * Regression fix for 'show-index' when run outside of a repository. + + * The meson-build procedure is integrated into CI to catch and + prevent bitrotting. + + * "git refs migrate" learned to also migrate the reflog data across + backends. + Fixes since v2.47 ----------------- @@ -280,6 +300,13 @@ Fixes since v2.47 the revision walker, which has become unnecessary. (merge dd1072dfa8 tc/bundle-with-tag-remove-workaround later to maint). + * GitLab CI updates. + (merge c6b43f663e ps/ci-gitlab-update later to maint). + + * Code to reuse objects based on bitmap contents have been tightened + to avoid race condition even when multiple packs are involved. + (merge 62b3ec8a3f tb/bitmap-fix-pack-reuse later to maint). + * Other code cleanup, docfix, build fix, etc. (merge 77af53f56f aa/t7300-modernize later to maint). (merge dcd590a39d bf/t-readme-mention-reftable later to maint). diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 497b4e48d2..194ec0f9ad 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,6 +1,6 @@ #!/bin/sh -DEF_VER=v2.48.0-rc0 +DEF_VER=v2.48.0-rc1 LF=' ' -- cgit v1.2.3 From e76b53ef23871ff81ab305822eb605baf0cc5bd3 Mon Sep 17 00:00:00 2001 From: Alexander Shopov Date: Tue, 24 Dec 2024 11:17:58 +0100 Subject: gitk: Update Bulgarian translation (327t) Signed-off-by: Alexander Shopov Signed-off-by: Johannes Sixt --- po/bg.po | 730 +++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 385 insertions(+), 345 deletions(-) diff --git a/po/bg.po b/po/bg.po index 87ab1fac24..773a049831 100644 --- a/po/bg.po +++ b/po/bg.po @@ -1,15 +1,15 @@ # Bulgarian translation of gitk po-file. -# Copyright (C) 2014, 2015, 2019 Alexander Shopov . +# Copyright (C) 2014, 2015, 2019, 2020, 2024 Alexander Shopov . # This file is distributed under the same license as the git package. -# Alexander Shopov , 2014, 2015, 2019. +# Alexander Shopov , 2014, 2015, 2019, 2020, 2024. # # msgid "" msgstr "" "Project-Id-Version: gitk master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-03-04 11:27+0100\n" -"PO-Revision-Date: 2019-03-04 11:39+0100\n" +"POT-Creation-Date: 2024-12-24 11:01+0100\n" +"PO-Revision-Date: 2024-12-24 11:05+0100\n" "Last-Translator: Alexander Shopov \n" "Language-Team: Bulgarian \n" "Language: bg\n" @@ -18,32 +18,32 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: gitk:140 +#: gitk:139 msgid "Couldn't get list of unmerged files:" -msgstr "Списъкът с неслети файлове не може да бъде получен:" +msgstr "Списъкът с неслети файлове не може да се получи:" -#: gitk:212 gitk:2403 +#: gitk:211 gitk:2430 msgid "Color words" msgstr "Оцветяване на думите" -#: gitk:217 gitk:2403 gitk:8249 gitk:8282 +#: gitk:216 gitk:2430 gitk:8335 gitk:8368 msgid "Markup words" msgstr "Отбелязване на думите" -#: gitk:324 +#: gitk:323 msgid "Error parsing revisions:" msgstr "Грешка при анализ на версиите:" -#: gitk:380 +#: gitk:389 msgid "Error executing --argscmd command:" msgstr "Грешка при изпълнение на командата с „--argscmd“." -#: gitk:393 +#: gitk:402 msgid "No files selected: --merge specified but no files are unmerged." msgstr "" "Не са избрани файлове — указана е опцията „--merge“, но няма неслети файлове." -#: gitk:396 +#: gitk:405 msgid "" "No files selected: --merge specified but no unmerged files are within file " "limit." @@ -51,326 +51,326 @@ msgstr "" "Не са избрани файлове — указана е опцията „--merge“, но няма неслети файлове " "в ограниченията." -#: gitk:418 gitk:566 +#: gitk:430 gitk:585 msgid "Error executing git log:" msgstr "Грешка при изпълнение на „git log“:" -#: gitk:436 gitk:582 +#: gitk:448 gitk:601 msgid "Reading" msgstr "Прочитане" -#: gitk:496 gitk:4549 +#: gitk:508 gitk:4596 msgid "Reading commits..." msgstr "Прочитане на подаванията…" -#: gitk:499 gitk:1641 gitk:4552 +#: gitk:511 gitk:1660 gitk:4599 msgid "No commits selected" msgstr "Не са избрани подавания" -#: gitk:1449 gitk:4069 gitk:12583 +#: gitk:1468 gitk:4116 gitk:12738 msgid "Command line" msgstr "Команден ред" -#: gitk:1515 +#: gitk:1534 msgid "Can't parse git log output:" msgstr "Изходът от „git log“ не може да се анализира:" -#: gitk:1744 +#: gitk:1763 msgid "No commit information available" msgstr "Липсва информация за подавания" -#: gitk:1907 gitk:1936 gitk:4339 gitk:9789 gitk:11388 gitk:11668 +#: gitk:1930 gitk:1959 gitk:4386 gitk:9875 gitk:11485 gitk:11805 msgid "OK" msgstr "Добре" -#: gitk:1938 gitk:4341 gitk:9225 gitk:9304 gitk:9434 gitk:9520 gitk:9791 -#: gitk:11389 gitk:11669 +#: gitk:1961 gitk:4388 gitk:9311 gitk:9390 gitk:9520 gitk:9606 gitk:9877 +#: gitk:11486 gitk:11806 msgid "Cancel" msgstr "Отказ" -#: gitk:2087 +#: gitk:2114 msgid "&Update" msgstr "&Обновяване" -#: gitk:2088 +#: gitk:2115 msgid "&Reload" msgstr "&Презареждане" -#: gitk:2089 +#: gitk:2116 msgid "Reread re&ferences" -msgstr "&Наново прочитане" +msgstr "Прочитане &наново" -#: gitk:2090 +#: gitk:2117 msgid "&List references" msgstr "&Изброяване на указателите" -#: gitk:2092 +#: gitk:2119 msgid "Start git &gui" msgstr "&Стартиране на „git gui“" -#: gitk:2094 +#: gitk:2121 msgid "&Quit" msgstr "&Спиране на програмата" -#: gitk:2086 +#: gitk:2113 msgid "&File" msgstr "&Файл" -#: gitk:2098 +#: gitk:2125 msgid "&Preferences" msgstr "&Настройки" -#: gitk:2097 +#: gitk:2124 msgid "&Edit" msgstr "&Редактиране" -#: gitk:2102 +#: gitk:2129 msgid "&New view..." msgstr "&Нов изглед…" -#: gitk:2103 +#: gitk:2130 msgid "&Edit view..." msgstr "&Редактиране на изгледа…" -#: gitk:2104 +#: gitk:2131 msgid "&Delete view" msgstr "&Изтриване на изгледа" -#: gitk:2106 +#: gitk:2133 msgid "&All files" msgstr "&Всички файлове" -#: gitk:2101 +#: gitk:2128 msgid "&View" msgstr "&Изглед" -#: gitk:2111 gitk:2121 +#: gitk:2138 gitk:2148 msgid "&About gitk" msgstr "&Относно gitk" -#: gitk:2112 gitk:2126 +#: gitk:2139 gitk:2153 msgid "&Key bindings" msgstr "&Клавишни комбинации" -#: gitk:2110 gitk:2125 +#: gitk:2137 gitk:2152 msgid "&Help" msgstr "Помо&щ" -#: gitk:2203 gitk:8681 -msgid "SHA1 ID:" -msgstr "SHA1:" +#: gitk:2230 gitk:8767 +msgid "Commit ID:" +msgstr "Подаване:" -#: gitk:2247 +#: gitk:2274 msgid "Row" msgstr "Ред" -#: gitk:2285 +#: gitk:2312 msgid "Find" msgstr "Търсене" -#: gitk:2313 +#: gitk:2340 msgid "commit" msgstr "подаване" -#: gitk:2317 gitk:2319 gitk:4711 gitk:4734 gitk:4758 gitk:6779 gitk:6851 -#: gitk:6936 +#: gitk:2344 gitk:2346 gitk:4758 gitk:4781 gitk:4805 gitk:6826 gitk:6898 +#: gitk:6983 msgid "containing:" msgstr "съдържащо:" -#: gitk:2320 gitk:3550 gitk:3555 gitk:4787 +#: gitk:2347 gitk:3597 gitk:3602 gitk:4834 msgid "touching paths:" msgstr "в пътищата:" -#: gitk:2321 gitk:4801 +#: gitk:2348 gitk:4848 msgid "adding/removing string:" msgstr "добавящо/премахващо низ" -#: gitk:2322 gitk:4803 +#: gitk:2349 gitk:4850 msgid "changing lines matching:" msgstr "променящо редове напасващи:" -#: gitk:2331 gitk:2333 gitk:4790 +#: gitk:2358 gitk:2360 gitk:4837 msgid "Exact" msgstr "Точно" -#: gitk:2333 gitk:4878 gitk:6747 +#: gitk:2360 gitk:4925 gitk:6794 msgid "IgnCase" msgstr "Без регистър" -#: gitk:2333 gitk:4760 gitk:4876 gitk:6743 +#: gitk:2360 gitk:4807 gitk:4923 gitk:6790 msgid "Regexp" msgstr "Рег. израз" -#: gitk:2335 gitk:2336 gitk:4898 gitk:4928 gitk:4935 gitk:6872 gitk:6940 +#: gitk:2362 gitk:2363 gitk:4945 gitk:4975 gitk:4982 gitk:6919 gitk:6987 msgid "All fields" msgstr "Всички полета" -#: gitk:2336 gitk:4895 gitk:4928 gitk:6810 +#: gitk:2363 gitk:4942 gitk:4975 gitk:6857 msgid "Headline" msgstr "Първи ред" -#: gitk:2337 gitk:4895 gitk:6810 gitk:6940 gitk:7413 +#: gitk:2364 gitk:4942 gitk:6857 gitk:6987 gitk:7499 msgid "Comments" msgstr "Коментари" -#: gitk:2337 gitk:4895 gitk:4900 gitk:4935 gitk:6810 gitk:7348 gitk:8859 -#: gitk:8874 +#: gitk:2364 gitk:4942 gitk:4947 gitk:4982 gitk:6857 gitk:7434 gitk:8945 +#: gitk:8960 msgid "Author" msgstr "Автор" -#: gitk:2337 gitk:4895 gitk:6810 gitk:7350 +#: gitk:2364 gitk:4942 gitk:6857 gitk:7436 msgid "Committer" msgstr "Подаващ" -#: gitk:2371 +#: gitk:2398 msgid "Search" msgstr "Търсене" -#: gitk:2379 +#: gitk:2406 msgid "Diff" msgstr "Разлики" -#: gitk:2381 +#: gitk:2408 msgid "Old version" msgstr "Стара версия" -#: gitk:2383 +#: gitk:2410 msgid "New version" msgstr "Нова версия" -#: gitk:2386 +#: gitk:2413 msgid "Lines of context" msgstr "Контекст в редове" -#: gitk:2396 +#: gitk:2423 msgid "Ignore space change" msgstr "Празните знаци без значение" -#: gitk:2400 gitk:2402 gitk:7983 gitk:8235 +#: gitk:2427 gitk:2429 gitk:8069 gitk:8321 msgid "Line diff" msgstr "Поредови разлики" -#: gitk:2467 +#: gitk:2502 msgid "Patch" msgstr "Кръпка" -#: gitk:2469 +#: gitk:2504 msgid "Tree" msgstr "Дърво" -#: gitk:2639 gitk:2660 +#: gitk:2674 gitk:2695 msgid "Diff this -> selected" msgstr "Разлики между това и избраното" -#: gitk:2640 gitk:2661 +#: gitk:2675 gitk:2696 msgid "Diff selected -> this" msgstr "Разлики между избраното и това" -#: gitk:2641 gitk:2662 +#: gitk:2676 gitk:2697 msgid "Make patch" msgstr "Създаване на кръпка" -#: gitk:2642 gitk:9283 +#: gitk:2677 gitk:9369 msgid "Create tag" msgstr "Създаване на етикет" -#: gitk:2643 -msgid "Copy commit summary" -msgstr "Копиране на информацията за подаване" +#: gitk:2678 +msgid "Copy commit reference" +msgstr "Копиране на указателя на подаване" -#: gitk:2644 gitk:9414 +#: gitk:2679 gitk:9500 msgid "Write commit to file" msgstr "Запазване на подаването във файл" -#: gitk:2645 +#: gitk:2680 msgid "Create new branch" msgstr "Създаване на нов клон" -#: gitk:2646 +#: gitk:2681 msgid "Cherry-pick this commit" msgstr "Отбиране на това подаване" -#: gitk:2647 +#: gitk:2682 msgid "Reset HEAD branch to here" msgstr "Привеждане на върха на клона към текущото подаване" -#: gitk:2648 +#: gitk:2683 msgid "Mark this commit" msgstr "Отбелязване на това подаване" -#: gitk:2649 +#: gitk:2684 msgid "Return to mark" msgstr "Връщане към отбелязаното подаване" -#: gitk:2650 +#: gitk:2685 msgid "Find descendant of this and mark" msgstr "Откриване и отбелязване на наследниците" -#: gitk:2651 +#: gitk:2686 msgid "Compare with marked commit" msgstr "Сравнение с отбелязаното подаване" -#: gitk:2652 gitk:2663 +#: gitk:2687 gitk:2698 msgid "Diff this -> marked commit" msgstr "Разлики между това и отбелязаното" -#: gitk:2653 gitk:2664 +#: gitk:2688 gitk:2699 msgid "Diff marked commit -> this" msgstr "Разлики между отбелязаното и това" -#: gitk:2654 +#: gitk:2689 msgid "Revert this commit" msgstr "Отмяна на това подаване" -#: gitk:2670 +#: gitk:2705 msgid "Check out this branch" msgstr "Изтегляне на този клон" -#: gitk:2671 +#: gitk:2706 msgid "Rename this branch" msgstr "Преименуване на този клон" -#: gitk:2672 +#: gitk:2707 msgid "Remove this branch" msgstr "Изтриване на този клон" -#: gitk:2673 +#: gitk:2708 msgid "Copy branch name" msgstr "Копиране на името на клона" -#: gitk:2680 +#: gitk:2715 msgid "Highlight this too" msgstr "Отбелязване и на това" -#: gitk:2681 +#: gitk:2716 msgid "Highlight this only" msgstr "Отбелязване само на това" -#: gitk:2682 +#: gitk:2717 msgid "External diff" msgstr "Външна програма за разлики" -#: gitk:2683 +#: gitk:2718 msgid "Blame parent commit" msgstr "Анотиране на родителското подаване" -#: gitk:2684 +#: gitk:2719 msgid "Copy path" msgstr "Копиране на пътя" -#: gitk:2691 +#: gitk:2726 msgid "Show origin of this line" msgstr "Показване на произхода на този ред" -#: gitk:2692 +#: gitk:2727 msgid "Run git gui blame on this line" msgstr "Изпълнение на „git gui blame“ върху този ред" -#: gitk:3036 +#: gitk:3081 msgid "About gitk" msgstr "Относно gitk" -#: gitk:3038 +#: gitk:3083 msgid "" "\n" "Gitk - a commit viewer for git\n" @@ -386,324 +386,324 @@ msgstr "" "\n" "Използвайте и разпространявайте при условията на ОПЛ на ГНУ" -#: gitk:3046 gitk:3113 gitk:10004 +#: gitk:3091 gitk:3158 gitk:10090 msgid "Close" msgstr "Затваряне" -#: gitk:3067 +#: gitk:3112 msgid "Gitk key bindings" msgstr "Клавишни комбинации" -#: gitk:3070 +#: gitk:3115 msgid "Gitk key bindings:" msgstr "Клавишни комбинации:" -#: gitk:3072 +#: gitk:3117 #, tcl-format msgid "<%s-Q>\t\tQuit" msgstr "<%s-Q>\t\tСпиране на програмата" -#: gitk:3073 +#: gitk:3118 #, tcl-format msgid "<%s-W>\t\tClose window" msgstr "<%s-W>\t\tЗатваряне на прозореца" -#: gitk:3074 +#: gitk:3119 msgid "\t\tMove to first commit" msgstr "\t\tКъм първото подаване" -#: gitk:3075 +#: gitk:3120 msgid "\t\tMove to last commit" msgstr "\t\tКъм последното подаване" -#: gitk:3076 +#: gitk:3121 msgid ", p, k\tMove up one commit" msgstr ", p, k\tЕдно подаване нагоре" -#: gitk:3077 +#: gitk:3122 msgid ", n, j\tMove down one commit" msgstr ", n, j\tЕдно подаване надолу" -#: gitk:3078 +#: gitk:3123 msgid ", z, h\tGo back in history list" msgstr ", z, h\tНазад в историята" -#: gitk:3079 +#: gitk:3124 msgid ", x, l\tGo forward in history list" msgstr ", x, l\tНапред в историята" -#: gitk:3080 +#: gitk:3125 #, tcl-format msgid "<%s-n>\tGo to n-th parent of current commit in history list" msgstr "<%s-n>\tКъм n-тия родител на текущото подаване в историята" -#: gitk:3081 +#: gitk:3126 msgid "\tMove up one page in commit list" msgstr "\tСтраница нагоре в списъка с подаванията" -#: gitk:3082 +#: gitk:3127 msgid "\tMove down one page in commit list" msgstr "\tСтраница надолу в списъка с подаванията" -#: gitk:3083 +#: gitk:3128 #, tcl-format msgid "<%s-Home>\tScroll to top of commit list" msgstr "<%s-Home>\tКъм началото на списъка с подаванията" -#: gitk:3084 +#: gitk:3129 #, tcl-format msgid "<%s-End>\tScroll to bottom of commit list" msgstr "<%s-End>\tКъм края на списъка с подаванията" -#: gitk:3085 +#: gitk:3130 #, tcl-format msgid "<%s-Up>\tScroll commit list up one line" msgstr "<%s-Up>\tРед нагоре в списъка с подавания" -#: gitk:3086 +#: gitk:3131 #, tcl-format msgid "<%s-Down>\tScroll commit list down one line" msgstr "<%s-Down>\tРед надолу в списъка с подавания" -#: gitk:3087 +#: gitk:3132 #, tcl-format msgid "<%s-PageUp>\tScroll commit list up one page" msgstr "<%s-PageUp>\tСтраница нагоре в списъка с подавания" -#: gitk:3088 +#: gitk:3133 #, tcl-format msgid "<%s-PageDown>\tScroll commit list down one page" msgstr "<%s-PageDown>\tСтраница надолу в списъка с подавания" -#: gitk:3089 +#: gitk:3134 msgid "\tFind backwards (upwards, later commits)" msgstr "\tТърсене назад (визуално нагоре, исторически — последващи)" -#: gitk:3090 +#: gitk:3135 msgid "\tFind forwards (downwards, earlier commits)" msgstr "" "\tТърсене напред (визуално надолу, исторически — предхождащи)" -#: gitk:3091 +#: gitk:3136 msgid ", b\tScroll diff view up one page" msgstr ", b\tСтраница нагоре в изгледа за разлики" -#: gitk:3092 +#: gitk:3137 msgid "\tScroll diff view up one page" msgstr "\tСтраница надолу в изгледа за разлики" -#: gitk:3093 +#: gitk:3138 msgid "\t\tScroll diff view down one page" msgstr "\t\tСтраница надолу в изгледа за разлики" -#: gitk:3094 +#: gitk:3139 msgid "u\t\tScroll diff view up 18 lines" msgstr "u\t\t18 реда нагоре в изгледа за разлики" -#: gitk:3095 +#: gitk:3140 msgid "d\t\tScroll diff view down 18 lines" msgstr "d\t\t18 реда надолу в изгледа за разлики" -#: gitk:3096 +#: gitk:3141 #, tcl-format msgid "<%s-F>\t\tFind" msgstr "<%s-F>\t\tТърсене" -#: gitk:3097 +#: gitk:3142 #, tcl-format msgid "<%s-G>\t\tMove to next find hit" msgstr "<%s-G>\t\tКъм следващата поява" -#: gitk:3098 +#: gitk:3143 msgid "\tMove to next find hit" msgstr "\tКъм следващата поява" -#: gitk:3099 +#: gitk:3144 msgid "g\t\tGo to commit" msgstr "g\t\tКъм последното подаване" -#: gitk:3100 +#: gitk:3145 msgid "/\t\tFocus the search box" msgstr "/\t\tФокус върху полето за търсене" -#: gitk:3101 +#: gitk:3146 msgid "?\t\tMove to previous find hit" msgstr "?\t\tКъм предишната поява" -#: gitk:3102 +#: gitk:3147 msgid "f\t\tScroll diff view to next file" msgstr "f\t\tСледващ файл в изгледа за разлики" -#: gitk:3103 +#: gitk:3148 #, tcl-format msgid "<%s-S>\t\tSearch for next hit in diff view" msgstr "<%s-S>\t\tТърсене на следващата поява в изгледа за разлики" -#: gitk:3104 +#: gitk:3149 #, tcl-format msgid "<%s-R>\t\tSearch for previous hit in diff view" msgstr "<%s-R>\t\tТърсене на предишната поява в изгледа за разлики" -#: gitk:3105 +#: gitk:3150 #, tcl-format msgid "<%s-KP+>\tIncrease font size" msgstr "<%s-KP+>\tПо-голям размер на шрифта" -#: gitk:3106 +#: gitk:3151 #, tcl-format msgid "<%s-plus>\tIncrease font size" msgstr "<%s-plus>\tПо-голям размер на шрифта" -#: gitk:3107 +#: gitk:3152 #, tcl-format msgid "<%s-KP->\tDecrease font size" msgstr "<%s-KP->\tПо-малък размер на шрифта" -#: gitk:3108 +#: gitk:3153 #, tcl-format msgid "<%s-minus>\tDecrease font size" msgstr "<%s-minus>\tПо-малък размер на шрифта" -#: gitk:3109 +#: gitk:3154 msgid "\t\tUpdate" msgstr "\t\tОбновяване" -#: gitk:3574 gitk:3583 +#: gitk:3621 gitk:3630 #, tcl-format msgid "Error creating temporary directory %s:" msgstr "Грешка при създаването на временната директория „%s“:" -#: gitk:3596 +#: gitk:3643 #, tcl-format msgid "Error getting \"%s\" from %s:" msgstr "Грешка при получаването на „%s“ от %s:" -#: gitk:3659 +#: gitk:3706 msgid "command failed:" msgstr "неуспешно изпълнение на команда:" -#: gitk:3808 +#: gitk:3855 msgid "No such commit" msgstr "Такова подаване няма" -#: gitk:3822 +#: gitk:3869 msgid "git gui blame: command failed:" msgstr "„git gui blame“: неуспешно изпълнение на команда:" -#: gitk:3853 +#: gitk:3900 #, tcl-format msgid "Couldn't read merge head: %s" -msgstr "Върхът за сливане не може да бъде прочетен: %s" +msgstr "Върхът за сливане не може да се прочете: %s" -#: gitk:3861 +#: gitk:3908 #, tcl-format msgid "Error reading index: %s" msgstr "Грешка при прочитане на индекса: %s" -#: gitk:3886 +#: gitk:3933 #, tcl-format msgid "Couldn't start git blame: %s" -msgstr "Командата „git blame“ не може да бъде стартирана: %s" +msgstr "Командата „git blame“ не може да се стартира: %s" -#: gitk:3889 gitk:6778 +#: gitk:3936 gitk:6825 msgid "Searching" msgstr "Търсене" -#: gitk:3921 +#: gitk:3968 #, tcl-format msgid "Error running git blame: %s" msgstr "Грешка при изпълнението на „git blame“: %s" -#: gitk:3949 +#: gitk:3996 #, tcl-format msgid "That line comes from commit %s, which is not in this view" msgstr "Този ред идва от подаването %s, което не е в изгледа" -#: gitk:3963 +#: gitk:4010 msgid "External diff viewer failed:" msgstr "Неуспешно изпълнение на външната програма за разлики:" -#: gitk:4067 +#: gitk:4114 msgid "All files" msgstr "Всички файлове" -#: gitk:4091 +#: gitk:4138 msgid "View" msgstr "Изглед" -#: gitk:4094 +#: gitk:4141 msgid "Gitk view definition" msgstr "Дефиниция на изглед в Gitk" -#: gitk:4098 +#: gitk:4145 msgid "Remember this view" msgstr "Запазване на този изглед" -#: gitk:4099 +#: gitk:4146 msgid "References (space separated list):" msgstr "Указатели (списък с разделител интервал):" -#: gitk:4100 +#: gitk:4147 msgid "Branches & tags:" msgstr "Клони и етикети:" -#: gitk:4101 +#: gitk:4148 msgid "All refs" msgstr "Всички указатели" -#: gitk:4102 +#: gitk:4149 msgid "All (local) branches" msgstr "Всички (локални) клони" -#: gitk:4103 +#: gitk:4150 msgid "All tags" msgstr "Всички етикети" -#: gitk:4104 +#: gitk:4151 msgid "All remote-tracking branches" msgstr "Всички следящи клони" -#: gitk:4105 +#: gitk:4152 msgid "Commit Info (regular expressions):" msgstr "Информация за подаване (рег. изр.):" -#: gitk:4106 +#: gitk:4153 msgid "Author:" msgstr "Автор:" -#: gitk:4107 +#: gitk:4154 msgid "Committer:" msgstr "Подал:" -#: gitk:4108 +#: gitk:4155 msgid "Commit Message:" msgstr "Съобщение при подаване:" -#: gitk:4109 +#: gitk:4156 msgid "Matches all Commit Info criteria" msgstr "Съвпадение по всички характеристики на подаването" -#: gitk:4110 +#: gitk:4157 msgid "Matches no Commit Info criteria" msgstr "Не съвпада по никоя от характеристиките на подаването" -#: gitk:4111 +#: gitk:4158 msgid "Changes to Files:" msgstr "Промени по файловете:" -#: gitk:4112 +#: gitk:4159 msgid "Fixed String" msgstr "Дословен низ" -#: gitk:4113 +#: gitk:4160 msgid "Regular Expression" msgstr "Регулярен израз" -#: gitk:4114 +#: gitk:4161 msgid "Search string:" msgstr "Низ за търсене:" -#: gitk:4115 +#: gitk:4162 msgid "" "Commit Dates (\"2 weeks ago\", \"2009-03-17 15:27:38\", \"March 17, 2009 " "15:27:38\"):" @@ -711,204 +711,208 @@ msgstr "" "Дата на подаване („2 weeks ago“ (преди 2 седмици), „2009-03-17 15:27:38“, " "„March 17, 2009 15:27:38“):" -#: gitk:4116 +#: gitk:4163 msgid "Since:" msgstr "От:" -#: gitk:4117 +#: gitk:4164 msgid "Until:" msgstr "До:" -#: gitk:4118 +#: gitk:4165 msgid "Limit and/or skip a number of revisions (positive integer):" msgstr "" "Ограничаване и/или прескачане на определен брой версии (неотрицателно цяло " "число):" -#: gitk:4119 +#: gitk:4166 msgid "Number to show:" msgstr "Брой показани:" -#: gitk:4120 +#: gitk:4167 msgid "Number to skip:" msgstr "Брой прескочени:" -#: gitk:4121 +#: gitk:4168 msgid "Miscellaneous options:" msgstr "Разни:" -#: gitk:4122 +#: gitk:4169 msgid "Strictly sort by date" msgstr "Подреждане по дата" -#: gitk:4123 +#: gitk:4170 msgid "Mark branch sides" msgstr "Отбелязване на страните по клона" -#: gitk:4124 +#: gitk:4171 msgid "Limit to first parent" msgstr "Само първия родител" -#: gitk:4125 +#: gitk:4172 msgid "Simple history" msgstr "Опростена история" -#: gitk:4126 +#: gitk:4173 msgid "Additional arguments to git log:" msgstr "Допълнителни аргументи към „git log“:" -#: gitk:4127 +#: gitk:4174 msgid "Enter files and directories to include, one per line:" msgstr "Въведете файловете и директориите за включване, по елемент на ред" -#: gitk:4128 +#: gitk:4175 msgid "Command to generate more commits to include:" msgstr "" -"Команда за генерирането на допълнителни подавания, които да бъдат включени:" +"Команда за генерирането на допълнителни подавания, които да се включат:" -#: gitk:4252 +#: gitk:4299 msgid "Gitk: edit view" msgstr "Gitk: редактиране на изглед" -#: gitk:4260 +#: gitk:4307 msgid "-- criteria for selecting revisions" msgstr "— критерии за избор на версии" -#: gitk:4265 +#: gitk:4312 msgid "View Name" msgstr "Име на изглед" -#: gitk:4340 +#: gitk:4387 msgid "Apply (F5)" msgstr "Прилагане (F5)" -#: gitk:4378 +#: gitk:4425 msgid "Error in commit selection arguments:" msgstr "Грешка в аргументите за избор на подавания:" -#: gitk:4433 gitk:4486 gitk:4948 gitk:4962 gitk:6232 gitk:12524 gitk:12525 +#: gitk:4480 gitk:4533 gitk:4995 gitk:5009 gitk:6279 gitk:12679 gitk:12680 msgid "None" msgstr "Няма" -#: gitk:5045 gitk:5050 +#: gitk:5092 gitk:5097 msgid "Descendant" msgstr "Наследник" -#: gitk:5046 +#: gitk:5093 msgid "Not descendant" msgstr "Не е наследник" -#: gitk:5053 gitk:5058 +#: gitk:5100 gitk:5105 msgid "Ancestor" msgstr "Предшественик" -#: gitk:5054 +#: gitk:5101 msgid "Not ancestor" msgstr "Не е предшественик" -#: gitk:5348 +#: gitk:5395 msgid "Local changes checked in to index but not committed" msgstr "Локални промени добавени към индекса, но неподадени" -#: gitk:5384 +#: gitk:5431 msgid "Local uncommitted changes, not checked in to index" msgstr "Локални промени извън индекса" -#: gitk:7158 +#: gitk:7179 +msgid "Error starting web browser:" +msgstr "Грешка при стартирането на уеб браузър:" + +#: gitk:7240 msgid "and many more" msgstr "и още много" -#: gitk:7161 +#: gitk:7243 msgid "many" msgstr "много" -#: gitk:7352 +#: gitk:7438 msgid "Tags:" msgstr "Етикети:" -#: gitk:7369 gitk:7375 gitk:8854 +#: gitk:7455 gitk:7461 gitk:8940 msgid "Parent" msgstr "Родител" -#: gitk:7380 +#: gitk:7466 msgid "Child" msgstr "Дете" -#: gitk:7389 +#: gitk:7475 msgid "Branch" msgstr "Клон" -#: gitk:7392 +#: gitk:7478 msgid "Follows" msgstr "Следва" -#: gitk:7395 +#: gitk:7481 msgid "Precedes" msgstr "Предшества" -#: gitk:7990 +#: gitk:8076 #, tcl-format msgid "Error getting diffs: %s" msgstr "Грешка при получаването на разликите: %s" -#: gitk:8679 +#: gitk:8765 msgid "Goto:" msgstr "Към ред:" -#: gitk:8700 +#: gitk:8786 #, tcl-format -msgid "Short SHA1 id %s is ambiguous" -msgstr "Съкратената сума по SHA1 %s не е еднозначна" +msgid "Short commit ID %s is ambiguous" +msgstr "Съкратената контролна сума %s не е еднозначна" -#: gitk:8707 +#: gitk:8793 #, tcl-format msgid "Revision %s is not known" msgstr "Непозната версия %s" -#: gitk:8717 +#: gitk:8803 #, tcl-format -msgid "SHA1 id %s is not known" -msgstr "Непозната сума по SHA1 %s" +msgid "Commit ID %s is not known" +msgstr "Непозната контролна сума %s" -#: gitk:8719 +#: gitk:8805 #, tcl-format msgid "Revision %s is not in the current view" msgstr "Версия %s не е в текущия изглед" -#: gitk:8861 gitk:8876 +#: gitk:8947 gitk:8962 msgid "Date" msgstr "Дата" -#: gitk:8864 +#: gitk:8950 msgid "Children" msgstr "Деца" -#: gitk:8927 +#: gitk:9013 #, tcl-format msgid "Reset %s branch to here" msgstr "Зануляване на клона „%s“ към текущото подаване" -#: gitk:8929 +#: gitk:9015 msgid "Detached head: can't reset" msgstr "Несвързан връх: невъзможно зануляване" -#: gitk:9034 gitk:9040 +#: gitk:9120 gitk:9126 msgid "Skipping merge commit " msgstr "Пропускане на подаването на сливането" -#: gitk:9049 gitk:9054 +#: gitk:9135 gitk:9140 msgid "Error getting patch ID for " msgstr "Грешка при получаването на идентификатора на " -#: gitk:9050 gitk:9055 +#: gitk:9136 gitk:9141 msgid " - stopping\n" msgstr " — спиране\n" -#: gitk:9060 gitk:9063 gitk:9071 gitk:9085 gitk:9094 +#: gitk:9146 gitk:9149 gitk:9157 gitk:9171 gitk:9180 msgid "Commit " msgstr "Подаване" -#: gitk:9064 +#: gitk:9150 msgid "" " is the same patch as\n" " " @@ -916,7 +920,7 @@ msgstr "" " е същата кръпка като\n" " " -#: gitk:9072 +#: gitk:9158 msgid "" " differs from\n" " " @@ -924,7 +928,7 @@ msgstr "" " се различава от\n" " " -#: gitk:9074 +#: gitk:9160 msgid "" "Diff of commits:\n" "\n" @@ -932,147 +936,147 @@ msgstr "" "Разлика между подаванията:\n" "\n" -#: gitk:9086 gitk:9095 +#: gitk:9172 gitk:9181 #, tcl-format msgid " has %s children - stopping\n" msgstr " има %s деца — спиране\n" -#: gitk:9114 +#: gitk:9200 #, tcl-format msgid "Error writing commit to file: %s" msgstr "Грешка при запазването на подаването във файл: %s" -#: gitk:9120 +#: gitk:9206 #, tcl-format msgid "Error diffing commits: %s" msgstr "Грешка при изчисляването на разликите между подаванията: %s" -#: gitk:9166 +#: gitk:9252 msgid "Top" msgstr "Най-горе" -#: gitk:9167 +#: gitk:9253 msgid "From" msgstr "От" -#: gitk:9172 +#: gitk:9258 msgid "To" msgstr "До" -#: gitk:9196 +#: gitk:9282 msgid "Generate patch" msgstr "Генериране на кръпка" -#: gitk:9198 +#: gitk:9284 msgid "From:" msgstr "От:" -#: gitk:9207 +#: gitk:9293 msgid "To:" msgstr "До:" -#: gitk:9216 +#: gitk:9302 msgid "Reverse" msgstr "Обръщане" -#: gitk:9218 gitk:9428 +#: gitk:9304 gitk:9514 msgid "Output file:" msgstr "Запазване във файла:" -#: gitk:9224 +#: gitk:9310 msgid "Generate" msgstr "Генериране" -#: gitk:9262 +#: gitk:9348 msgid "Error creating patch:" msgstr "Грешка при създаването на кръпка:" -#: gitk:9285 gitk:9416 gitk:9504 +#: gitk:9371 gitk:9502 gitk:9590 msgid "ID:" msgstr "Идентификатор:" -#: gitk:9294 +#: gitk:9380 msgid "Tag name:" msgstr "Име на етикет:" -#: gitk:9297 +#: gitk:9383 msgid "Tag message is optional" msgstr "Съобщението за етикет е незадължително" -#: gitk:9299 +#: gitk:9385 msgid "Tag message:" msgstr "Съобщение за етикет:" -#: gitk:9303 gitk:9474 +#: gitk:9389 gitk:9560 msgid "Create" msgstr "Създаване" -#: gitk:9321 +#: gitk:9407 msgid "No tag name specified" msgstr "Липсва име на етикет" -#: gitk:9325 +#: gitk:9411 #, tcl-format msgid "Tag \"%s\" already exists" msgstr "Етикетът „%s“ вече съществува" -#: gitk:9335 +#: gitk:9421 msgid "Error creating tag:" msgstr "Грешка при създаването на етикет:" -#: gitk:9425 +#: gitk:9511 msgid "Command:" msgstr "Команда:" -#: gitk:9433 +#: gitk:9519 msgid "Write" msgstr "Запазване" -#: gitk:9451 +#: gitk:9537 msgid "Error writing commit:" msgstr "Грешка при запазването на подаването:" -#: gitk:9473 +#: gitk:9559 msgid "Create branch" msgstr "Създаване на клон" -#: gitk:9489 +#: gitk:9575 #, tcl-format msgid "Rename branch %s" msgstr "Преименуване на клона „%s“" -#: gitk:9490 +#: gitk:9576 msgid "Rename" msgstr "Преименуване" -#: gitk:9514 +#: gitk:9600 msgid "Name:" msgstr "Име:" -#: gitk:9538 +#: gitk:9624 msgid "Please specify a name for the new branch" msgstr "Укажете име за новия клон" -#: gitk:9543 +#: gitk:9629 #, tcl-format msgid "Branch '%s' already exists. Overwrite?" -msgstr "Клонът „%s“ вече съществува. Да бъде ли презаписан?" +msgstr "Клонът „%s“ вече съществува. Да се презапише ли?" -#: gitk:9587 +#: gitk:9673 msgid "Please specify a new name for the branch" msgstr "Укажете ново име за клона" -#: gitk:9650 +#: gitk:9736 #, tcl-format msgid "Commit %s is already included in branch %s -- really re-apply it?" msgstr "" -"Подаването „%s“ вече е включено в клона „%s“ — да бъде ли приложено отново?" +"Подаването „%s“ вече е включено в клона „%s“ — да се приложи ли отново?" -#: gitk:9655 +#: gitk:9741 msgid "Cherry-picking" msgstr "Отбиране" -#: gitk:9664 +#: gitk:9750 #, tcl-format msgid "" "Cherry-pick failed because of local changes to file '%s'.\n" @@ -1081,7 +1085,7 @@ msgstr "" "Неуспешно отбиране, защото във файла „%s“ има локални промени.\n" "Подайте, занулете или ги скатайте и пробвайте отново." -#: gitk:9670 +#: gitk:9756 msgid "" "Cherry-pick failed because of merge conflict.\n" "Do you wish to run git citool to resolve it?" @@ -1089,20 +1093,20 @@ msgstr "" "Неуспешно отбиране поради конфликти при сливане.\n" "Искате ли да ги коригирате чрез „git citool“?" -#: gitk:9686 gitk:9744 +#: gitk:9772 gitk:9830 msgid "No changes committed" msgstr "Не са подадени промени" -#: gitk:9713 +#: gitk:9799 #, tcl-format msgid "Commit %s is not included in branch %s -- really revert it?" -msgstr "Подаването „%s“ не е включено в клона „%s“. Да бъде ли отменено?" +msgstr "Подаването „%s“ не е включено в клона „%s“. Да се отменени ли?" -#: gitk:9718 +#: gitk:9804 msgid "Reverting" msgstr "Отмяна" -#: gitk:9726 +#: gitk:9812 #, tcl-format msgid "" "Revert failed because of local changes to the following files:%s Please " @@ -1111,7 +1115,7 @@ msgstr "" "Неуспешна отмяна, защото във файла „%s“ има локални промени.\n" "Подайте, занулете или ги скатайте и пробвайте отново." -#: gitk:9730 +#: gitk:9816 msgid "" "Revert failed because of merge conflict.\n" " Do you wish to run git citool to resolve it?" @@ -1119,53 +1123,53 @@ msgstr "" "Неуспешно отмяна поради конфликти при сливане.\n" "Искате ли да ги коригирате чрез „git citool“?" -#: gitk:9773 +#: gitk:9859 msgid "Confirm reset" msgstr "Потвърждаване на зануляването" -#: gitk:9775 +#: gitk:9861 #, tcl-format msgid "Reset branch %s to %s?" msgstr "Да се занули ли клонът „%s“ към „%s“?" -#: gitk:9777 +#: gitk:9863 msgid "Reset type:" msgstr "Вид зануляване:" -#: gitk:9780 +#: gitk:9866 msgid "Soft: Leave working tree and index untouched" msgstr "Слабо: работното дърво и индекса остават същите" -#: gitk:9783 +#: gitk:9869 msgid "Mixed: Leave working tree untouched, reset index" msgstr "Смесено: работното дърво остава същото, индексът се занулява" -#: gitk:9786 +#: gitk:9872 msgid "" "Hard: Reset working tree and index\n" "(discard ALL local changes)" msgstr "" "Силно: зануляване и на работното дърво, и на индекса\n" -"(ВСИЧКИ локални промени ще бъдат безвъзвратно загубени)" +"(ВСИЧКИ локални промени ще се загубят безвъзвратно)" -#: gitk:9803 +#: gitk:9889 msgid "Resetting" msgstr "Зануляване" -#: gitk:9876 +#: gitk:9962 #, tcl-format msgid "A local branch named %s exists already" msgstr "Вече съществува локален клон „%s“." -#: gitk:9884 +#: gitk:9970 msgid "Checking out" msgstr "Изтегляне" -#: gitk:9943 +#: gitk:10029 msgid "Cannot delete the currently checked-out branch" -msgstr "Текущо изтегленият клон не може да бъде изтрит" +msgstr "Текущо изтегленият клон не може да се изтрие" -#: gitk:9949 +#: gitk:10035 #, tcl-format msgid "" "The commits on branch %s aren't on any other branch.\n" @@ -1174,16 +1178,16 @@ msgstr "" "Подаванията на клона „%s“ не са на никой друг клон.\n" "Наистина ли искате да изтриете клона „%s“?" -#: gitk:9980 +#: gitk:10066 #, tcl-format msgid "Tags and heads: %s" msgstr "Етикети и върхове: %s" -#: gitk:9997 +#: gitk:10083 msgid "Filter" msgstr "Филтриране" -#: gitk:10293 +#: gitk:10390 msgid "" "Error reading commit topology information; branch and preceding/following " "tag information will be incomplete." @@ -1191,201 +1195,237 @@ msgstr "" "Грешка при прочитането на топологията на подаванията. Информацията за клона " "и предшестващите/следващите етикети ще е непълна." -#: gitk:11270 +#: gitk:11367 msgid "Tag" msgstr "Етикет" -#: gitk:11274 +#: gitk:11371 msgid "Id" msgstr "Идентификатор" -#: gitk:11357 +#: gitk:11454 msgid "Gitk font chooser" msgstr "Избор на шрифт за Gitk" -#: gitk:11374 +#: gitk:11471 msgid "B" msgstr "Ч" -#: gitk:11377 +#: gitk:11474 msgid "I" msgstr "К" -#: gitk:11495 +#: gitk:11593 msgid "Commit list display options" msgstr "Настройки на списъка с подавания" -#: gitk:11498 +#: gitk:11596 msgid "Maximum graph width (lines)" msgstr "Максимална широчина на графа (в редове)" -#: gitk:11502 +#: gitk:11600 #, no-tcl-format msgid "Maximum graph width (% of pane)" msgstr "Максимална широчина на графа (% от панела)" -#: gitk:11505 +#: gitk:11603 msgid "Show local changes" msgstr "Показване на локалните промени" -#: gitk:11508 -msgid "Auto-select SHA1 (length)" -msgstr "Автоматично избиране на SHA1 (дължина)" - -#: gitk:11512 +#: gitk:11606 msgid "Hide remote refs" msgstr "Скриване на отдалечените указатели" -#: gitk:11516 +#: gitk:11610 +msgid "Copy commit ID to clipboard" +msgstr "Копиране на контролната сума към буфера за обмен" + +#: gitk:11614 +msgid "Copy commit ID to X11 selection" +msgstr "Копиране на контролната сума в селекцията на X11" + +#: gitk:11619 +msgid "Length of commit ID to copy" +msgstr "Дължина на контролната сума, която се копира" + +#: gitk:11622 msgid "Diff display options" msgstr "Настройки на показването на разликите" -#: gitk:11518 +#: gitk:11624 msgid "Tab spacing" msgstr "Широчина на табулатора" -#: gitk:11521 +#: gitk:11628 +msgid "Wrap comment text" +msgstr "Пренасяне на думите в коментарите" + +#: gitk:11633 +msgid "Wrap other text" +msgstr "Пренасяне на другия текст" + +#: gitk:11638 msgid "Display nearby tags/heads" msgstr "Извеждане на близките етикети и върхове" -#: gitk:11524 +#: gitk:11641 msgid "Maximum # tags/heads to show" msgstr "Максимален брой етикети/върхове за показване" -#: gitk:11527 +#: gitk:11644 msgid "Limit diffs to listed paths" msgstr "Разлика само в избраните пътища" -#: gitk:11530 +#: gitk:11647 msgid "Support per-file encodings" msgstr "Поддръжка на различни кодирания за всеки файл" -#: gitk:11536 gitk:11683 +#: gitk:11653 gitk:11820 msgid "External diff tool" msgstr "Външен инструмент за разлики" -#: gitk:11537 +#: gitk:11654 msgid "Choose..." msgstr "Избор…" -#: gitk:11542 +#: gitk:11661 +msgid "Web browser" +msgstr "Уеб браузър" + +#: gitk:11666 msgid "General options" msgstr "Общи настройки" -#: gitk:11545 +#: gitk:11669 msgid "Use themed widgets" msgstr "Използване на тема за графичните обекти" -#: gitk:11547 +#: gitk:11671 msgid "(change requires restart)" msgstr "(промяната изисква рестартиране на Gitk)" -#: gitk:11549 +#: gitk:11673 msgid "(currently unavailable)" msgstr "(в момента недостъпно)" -#: gitk:11560 +#: gitk:11685 msgid "Colors: press to choose" msgstr "Цветове: избира се с натискане" -#: gitk:11563 +#: gitk:11688 msgid "Interface" msgstr "Интерфейс" -#: gitk:11564 +#: gitk:11689 msgid "interface" msgstr "интерфейс" -#: gitk:11567 +#: gitk:11692 msgid "Background" msgstr "Фон" -#: gitk:11568 gitk:11598 +#: gitk:11693 gitk:11735 msgid "background" msgstr "фон" -#: gitk:11571 +#: gitk:11696 msgid "Foreground" msgstr "Знаци" -#: gitk:11572 +#: gitk:11697 msgid "foreground" msgstr "знаци" -#: gitk:11575 +#: gitk:11700 msgid "Diff: old lines" msgstr "Разлика: стари редове" -#: gitk:11576 +#: gitk:11701 msgid "diff old lines" msgstr "разлика, стари редове" -#: gitk:11580 +#: gitk:11705 +msgid "Diff: old lines bg" +msgstr "Разлика: фон на стари редове" + +#: gitk:11707 +msgid "diff old lines bg" +msgstr "разлика, фон на стари редове" + +#: gitk:11711 msgid "Diff: new lines" msgstr "Разлика: нови редове" -#: gitk:11581 +#: gitk:11712 msgid "diff new lines" msgstr "разлика, нови редове" -#: gitk:11585 +#: gitk:11716 +msgid "Diff: new lines bg" +msgstr "Разлика: фон на нови редове" + +#: gitk:11718 +msgid "diff new lines bg" +msgstr "разлика, фон на нови редове" + +#: gitk:11722 msgid "Diff: hunk header" msgstr "Разлика: начало на парче" -#: gitk:11587 +#: gitk:11724 msgid "diff hunk header" msgstr "разлика, начало на парче" -#: gitk:11591 +#: gitk:11728 msgid "Marked line bg" msgstr "Фон на отбелязан ред" -#: gitk:11593 +#: gitk:11730 msgid "marked line background" msgstr "фон на отбелязан ред" -#: gitk:11597 +#: gitk:11734 msgid "Select bg" msgstr "Избор на фон" -#: gitk:11606 +#: gitk:11743 msgid "Fonts: press to choose" msgstr "Шрифтове: избира се с натискане" -#: gitk:11608 +#: gitk:11745 msgid "Main font" msgstr "Основен шрифт" -#: gitk:11609 +#: gitk:11746 msgid "Diff display font" msgstr "Шрифт за разликите" -#: gitk:11610 +#: gitk:11747 msgid "User interface font" msgstr "Шрифт на интерфейса" -#: gitk:11632 +#: gitk:11769 msgid "Gitk preferences" msgstr "Настройки на Gitk" -#: gitk:11641 +#: gitk:11778 msgid "General" msgstr "Общи" -#: gitk:11642 +#: gitk:11779 msgid "Colors" msgstr "Цветове" -#: gitk:11643 +#: gitk:11780 msgid "Fonts" msgstr "Шрифтове" -#: gitk:11693 +#: gitk:11830 #, tcl-format msgid "Gitk: choose color for %s" msgstr "Gitk: избор на цвят на „%s“" -#: gitk:12206 +#: gitk:12350 msgid "" "Sorry, gitk cannot run with this version of Tcl/Tk.\n" " Gitk requires at least Tcl/Tk 8.4." @@ -1393,15 +1433,15 @@ msgstr "" "Тази версия на Tcl/Tk не се поддържа от Gitk.\n" " Необходима ви е поне Tcl/Tk 8.4." -#: gitk:12416 +#: gitk:12571 msgid "Cannot find a git repository here." msgstr "Тук липсва хранилище на Git." -#: gitk:12463 +#: gitk:12618 #, tcl-format msgid "Ambiguous argument '%s': both revision and filename" msgstr "Нееднозначен аргумент „%s“: има и такава версия, и такъв файл" -#: gitk:12475 +#: gitk:12630 msgid "Bad arguments to gitk:" msgstr "Неправилни аргументи на gitk:" -- cgit v1.2.3 From b59358100c203b104e53523e1a4e3c2ad426334c Mon Sep 17 00:00:00 2001 From: Alexander Shopov Date: Tue, 24 Dec 2024 13:29:09 +0100 Subject: Update the official repo of gitk Point out: - current maintaner - contribution flow is via the mailing list Signed-off-by: Alexander Shopov Signed-off-by: Junio C Hamano --- Documentation/SubmittingPatches | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index d8a8caa791..3968abcc4c 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -692,16 +692,17 @@ rebase when I receive your patches). Some parts of the system have dedicated maintainers with their own repositories. -- `git-gui/` comes from git-gui project, maintained by Johannes Sixt: +- `git-gui/` comes from the git-gui project, maintained by Johannes Sixt: https://github.com/j6t/git-gui -- `gitk-git/` comes from Paul Mackerras's gitk project: + Contibutions should go via the git mailing list. - git://git.ozlabs.org/~paulus/gitk +- `gitk-git/` comes from the gitk project, maintained by Johannes Sixt: - Those who are interested in improving gitk can volunteer to help Paul - maintain it, cf. . + https://github.com/j6t/gitk + + Contibutions should go via the git mailing list. - `po/` comes from the localization coordinator, Jiang Xin: -- cgit v1.2.3 From d11d003ba5e98c036fb94204df6dcef28aafe2f8 Mon Sep 17 00:00:00 2001 From: Sören Krecker Date: Mon, 23 Dec 2024 12:04:05 +0100 Subject: date.c: Fix type missmatch warings from msvc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix compiler warings from msvc in date.c for value truncation from 64 bit to 32 bit integers. Also switch from int to size_t for all variables with result of strlen() which cannot become negative. Signed-off-by: Sören Krecker Signed-off-by: Junio C Hamano --- date.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/date.c b/date.c index a1b26a8dce..17a95077cf 100644 --- a/date.c +++ b/date.c @@ -1244,7 +1244,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm } for (s = special; s->name; s++) { - int len = strlen(s->name); + size_t len = strlen(s->name); if (match_string(date, s->name) == len) { s->fn(tm, now, num); *touched = 1; @@ -1254,7 +1254,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm if (!*num) { for (i = 1; i < 11; i++) { - int len = strlen(number_name[i]); + size_t len = strlen(number_name[i]); if (match_string(date, number_name[i]) == len) { *num = i; *touched = 1; @@ -1270,7 +1270,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm tl = typelen; while (tl->type) { - int len = strlen(tl->type); + size_t len = strlen(tl->type); if (match_string(date, tl->type) >= len-1) { update_tm(tm, now, tl->length * *num); *num = 0; -- cgit v1.2.3 From 44945dfe867e56aab1685a0f371665273291a2af Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 11:46:21 +0100 Subject: prio-queue: fix type of `insertion_ctr` In 62e745ced2 (prio-queue: use size_t rather than int for size, 2024-12-20), we have converted `struct prio_queue` to use `size_t` to track the number of entries in the queue as well as the allocated size of the underlying array. There is one more counter though, namely the insertion counter, that is still using an `unsigned` instead of a `size_t`. This is unlikely to ever be a problem, but it makes one wonder why some indices use `size_t` while others use `unsigned`. Furthermore, the mentioned commit stated the intent to also adapt these variables, but seemingly forgot to do so. Fix the issue by converting those counters to use `size_t`, as well. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- prio-queue.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/prio-queue.h b/prio-queue.h index 36f370625f..38d032636d 100644 --- a/prio-queue.h +++ b/prio-queue.h @@ -22,13 +22,13 @@ typedef int (*prio_queue_compare_fn)(const void *one, const void *two, void *cb_data); struct prio_queue_entry { - unsigned ctr; + size_t ctr; void *data; }; struct prio_queue { prio_queue_compare_fn compare; - unsigned insertion_ctr; + size_t insertion_ctr; void *cb_data; size_t alloc, nr; struct prio_queue_entry *array; -- cgit v1.2.3 From 95c09e4d07492fa9e4ad951a268b4ea6bae69038 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 11:46:22 +0100 Subject: commit-reach: fix index used to loop through unsigned integer In 62e745ced2 (prio-queue: use size_t rather than int for size, 2024-12-20), we refactored `struct prio_queue` to track the number of contained entries via a `size_t`. While the refactoring adapted one of the users of that variable, it forgot to also adapt "commit-reach.c" accordingly. This was missed because that file has -Wsign-conversion disabled. Fix the issue by using a `size_t` to iterate through entries. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- commit-reach.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/commit-reach.c b/commit-reach.c index e3edd11995..e658726170 100644 --- a/commit-reach.c +++ b/commit-reach.c @@ -42,8 +42,7 @@ static int compare_commits_by_gen(const void *_a, const void *_b) static int queue_has_nonstale(struct prio_queue *queue) { - int i; - for (i = 0; i < queue->nr; i++) { + for (size_t i = 0; i < queue->nr; i++) { struct commit *commit = queue->array[i].data; if (!(commit->object.flags & STALE)) return 1; -- cgit v1.2.3 From 04aeeeaab1f02213703c4e1997b2c2f1ca0f8f96 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 11:46:23 +0100 Subject: commit-reach: fix type of `min_commit_date` The `can_all_from_reach_with_flag()` function accepts a parameter that allows callers to cut off traversal at a specified commit date. This parameter is of type `time_t`, which is a signed type, while we end up comparing it to a commit's `date` field, which is of the unsigned type `timestamp_t`. Fix the parameter to be of type `timestamp_t`. There is only a single caller in "upload-pack.c" that sets this parameter, and that caller knows to pass in a `timestamp_t` already. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- commit-reach.c | 4 ++-- commit-reach.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/commit-reach.c b/commit-reach.c index e658726170..9f8b2457bc 100644 --- a/commit-reach.c +++ b/commit-reach.c @@ -780,7 +780,7 @@ int commit_contains(struct ref_filter *filter, struct commit *commit, int can_all_from_reach_with_flag(struct object_array *from, unsigned int with_flag, unsigned int assign_flag, - time_t min_commit_date, + timestamp_t min_commit_date, timestamp_t min_generation) { struct commit **list = NULL; @@ -883,9 +883,9 @@ int can_all_from_reach(struct commit_list *from, struct commit_list *to, int cutoff_by_min_date) { struct object_array from_objs = OBJECT_ARRAY_INIT; - time_t min_commit_date = cutoff_by_min_date ? from->item->date : 0; struct commit_list *from_iter = from, *to_iter = to; int result; + timestamp_t min_commit_date = cutoff_by_min_date ? from->item->date : 0; timestamp_t min_generation = GENERATION_NUMBER_INFINITY; while (from_iter) { diff --git a/commit-reach.h b/commit-reach.h index 9a745b7e17..d5f3347376 100644 --- a/commit-reach.h +++ b/commit-reach.h @@ -81,7 +81,7 @@ int commit_contains(struct ref_filter *filter, struct commit *commit, int can_all_from_reach_with_flag(struct object_array *from, unsigned int with_flag, unsigned int assign_flag, - time_t min_commit_date, + timestamp_t min_commit_date, timestamp_t min_generation); int can_all_from_reach(struct commit_list *from, struct commit_list *to, int commit_date_cutoff); -- cgit v1.2.3 From 45843d8f4eb2bbfc73cc361ba9d612d088dc8a4f Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 11:46:24 +0100 Subject: commit-reach: use `size_t` to track indices in `remove_redundant()` The function `remove_redundant()` gets as input an array of commits as well as the size of that array and then drops redundant commits from that array. It then returns either `-1` in case an error occurred, or the new number of items in the array. The function receives and returns these sizes with a signed integer, which causes several warnings with -Wsign-compare. Fix this issue by consistently using `size_t` to track array indices and splitting up the returned value into a returned error code and a separate out pointer for the new computed size. Note that `get_merge_bases_many()` and related functions still track array sizes as a signed integer. This will be fixed in a subsequent commit. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- commit-reach.c | 53 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/commit-reach.c b/commit-reach.c index 9f8b2457bc..d7f6f1be75 100644 --- a/commit-reach.c +++ b/commit-reach.c @@ -212,12 +212,13 @@ int get_octopus_merge_bases(struct commit_list *in, struct commit_list **result) } static int remove_redundant_no_gen(struct repository *r, - struct commit **array, int cnt) + struct commit **array, + size_t cnt, size_t *dedup_cnt) { struct commit **work; unsigned char *redundant; - int *filled_index; - int i, j, filled; + size_t *filled_index; + size_t i, j, filled; CALLOC_ARRAY(work, cnt); redundant = xcalloc(cnt, 1); @@ -267,20 +268,22 @@ static int remove_redundant_no_gen(struct repository *r, for (i = filled = 0; i < cnt; i++) if (!redundant[i]) array[filled++] = work[i]; + *dedup_cnt = filled; free(work); free(redundant); free(filled_index); - return filled; + return 0; } static int remove_redundant_with_gen(struct repository *r, - struct commit **array, int cnt) + struct commit **array, size_t cnt, + size_t *dedup_cnt) { - int i, count_non_stale = 0, count_still_independent = cnt; + size_t i, count_non_stale = 0, count_still_independent = cnt; timestamp_t min_generation = GENERATION_NUMBER_INFINITY; struct commit **walk_start, **sorted; size_t walk_start_nr = 0, walk_start_alloc = cnt; - int min_gen_pos = 0; + size_t min_gen_pos = 0; /* * Sort the input by generation number, ascending. This allows @@ -326,12 +329,12 @@ static int remove_redundant_with_gen(struct repository *r, * terminate early. Otherwise, we will do the same amount of work * as before. */ - for (i = walk_start_nr - 1; i >= 0 && count_still_independent > 1; i--) { + for (i = walk_start_nr; i && count_still_independent > 1; i--) { /* push the STALE bits up to min generation */ struct commit_list *stack = NULL; - commit_list_insert(walk_start[i], &stack); - walk_start[i]->object.flags |= STALE; + commit_list_insert(walk_start[i - 1], &stack); + walk_start[i - 1]->object.flags |= STALE; while (stack) { struct commit_list *parents; @@ -388,10 +391,12 @@ static int remove_redundant_with_gen(struct repository *r, clear_commit_marks_many(walk_start_nr, walk_start, STALE); free(walk_start); - return count_non_stale; + *dedup_cnt = count_non_stale; + return 0; } -static int remove_redundant(struct repository *r, struct commit **array, int cnt) +static int remove_redundant(struct repository *r, struct commit **array, + size_t cnt, size_t *dedup_cnt) { /* * Some commit in the array may be an ancestor of @@ -401,19 +406,17 @@ static int remove_redundant(struct repository *r, struct commit **array, int cnt * that number. */ if (generation_numbers_enabled(r)) { - int i; - /* * If we have a single commit with finite generation * number, then the _with_gen algorithm is preferred. */ - for (i = 0; i < cnt; i++) { + for (size_t i = 0; i < cnt; i++) { if (commit_graph_generation(array[i]) < GENERATION_NUMBER_INFINITY) - return remove_redundant_with_gen(r, array, cnt); + return remove_redundant_with_gen(r, array, cnt, dedup_cnt); } } - return remove_redundant_no_gen(r, array, cnt); + return remove_redundant_no_gen(r, array, cnt, dedup_cnt); } static int get_merge_bases_many_0(struct repository *r, @@ -425,7 +428,8 @@ static int get_merge_bases_many_0(struct repository *r, { struct commit_list *list; struct commit **rslt; - int cnt, i; + size_t cnt, i; + int ret; if (merge_bases_many(r, one, n, twos, result) < 0) return -1; @@ -452,8 +456,8 @@ static int get_merge_bases_many_0(struct repository *r, clear_commit_marks(one, all_flags); clear_commit_marks_many(n, twos, all_flags); - cnt = remove_redundant(r, rslt, cnt); - if (cnt < 0) { + ret = remove_redundant(r, rslt, cnt, &cnt); + if (ret < 0) { free(rslt); return -1; } @@ -582,7 +586,8 @@ struct commit_list *reduce_heads(struct commit_list *heads) struct commit_list *p; struct commit_list *result = NULL, **tail = &result; struct commit **array; - int num_head, i; + size_t num_head, i; + int ret; if (!heads) return NULL; @@ -603,11 +608,13 @@ struct commit_list *reduce_heads(struct commit_list *heads) p->item->object.flags &= ~STALE; } } - num_head = remove_redundant(the_repository, array, num_head); - if (num_head < 0) { + + ret = remove_redundant(the_repository, array, num_head, &num_head); + if (ret < 0) { free(array); return NULL; } + for (i = 0; i < num_head; i++) tail = &commit_list_insert(array[i], tail)->next; free(array); -- cgit v1.2.3 From 85ee0680e2d5d667919e06394ca7622f09652310 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 11:46:25 +0100 Subject: commit-reach: use `size_t` to track indices in `get_reachable_subset()` Similar as with the preceding commit, adapt `get_reachable_subset()` so that it tracks array indices via `size_t` instead of using signed integers to fix a couple of -Wsign-compare warnings. Adapt callers accordingly. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- bisect.c | 9 +++++---- commit-reach.c | 8 ++++---- commit-reach.h | 4 ++-- commit.c | 4 ++-- commit.h | 2 +- ref-filter.c | 2 +- remote.c | 4 ++-- 7 files changed, 17 insertions(+), 16 deletions(-) diff --git a/bisect.c b/bisect.c index 1a9069c9ad..7a1afc46e5 100644 --- a/bisect.c +++ b/bisect.c @@ -780,10 +780,10 @@ static struct commit *get_commit_reference(struct repository *r, } static struct commit **get_bad_and_good_commits(struct repository *r, - int *rev_nr) + size_t *rev_nr) { struct commit **rev; - int i, n = 0; + size_t i, n = 0; ALLOC_ARRAY(rev, 1 + good_revs.nr); rev[n++] = get_commit_reference(r, current_bad_oid); @@ -887,7 +887,7 @@ static enum bisect_error check_merge_bases(int rev_nr, struct commit **rev, int return res; } -static int check_ancestors(struct repository *r, int rev_nr, +static int check_ancestors(struct repository *r, size_t rev_nr, struct commit **rev, const char *prefix) { struct strvec rev_argv = STRVEC_INIT; @@ -922,7 +922,8 @@ static enum bisect_error check_good_are_ancestors_of_bad(struct repository *r, { char *filename; struct stat st; - int fd, rev_nr; + int fd; + size_t rev_nr; enum bisect_error res = BISECT_OK; struct commit **rev; diff --git a/commit-reach.c b/commit-reach.c index d7f6f1be75..bab40f5575 100644 --- a/commit-reach.c +++ b/commit-reach.c @@ -791,8 +791,8 @@ int can_all_from_reach_with_flag(struct object_array *from, timestamp_t min_generation) { struct commit **list = NULL; - int i; - int nr_commits; + size_t i; + size_t nr_commits; int result = 1; ALLOC_ARRAY(list, from->nr); @@ -944,8 +944,8 @@ int can_all_from_reach(struct commit_list *from, struct commit_list *to, return result; } -struct commit_list *get_reachable_subset(struct commit **from, int nr_from, - struct commit **to, int nr_to, +struct commit_list *get_reachable_subset(struct commit **from, size_t nr_from, + struct commit **to, size_t nr_to, unsigned int reachable_flag) { struct commit **item; diff --git a/commit-reach.h b/commit-reach.h index d5f3347376..fa5408054a 100644 --- a/commit-reach.h +++ b/commit-reach.h @@ -95,8 +95,8 @@ int can_all_from_reach(struct commit_list *from, struct commit_list *to, * This method uses the PARENT1 and PARENT2 flags during its operation, * so be sure these flags are not set before calling the method. */ -struct commit_list *get_reachable_subset(struct commit **from, int nr_from, - struct commit **to, int nr_to, +struct commit_list *get_reachable_subset(struct commit **from, size_t nr_from, + struct commit **to, size_t nr_to, unsigned int reachable_flag); struct ahead_behind_count { diff --git a/commit.c b/commit.c index a127fe60c5..540660359d 100644 --- a/commit.c +++ b/commit.c @@ -778,11 +778,11 @@ static void clear_commit_marks_1(struct commit_list **plist, } } -void clear_commit_marks_many(int nr, struct commit **commit, unsigned int mark) +void clear_commit_marks_many(size_t nr, struct commit **commit, unsigned int mark) { struct commit_list *list = NULL; - while (nr--) { + for (size_t i = 0; i < nr; i++) { clear_commit_marks_1(&list, *commit, mark); commit++; } diff --git a/commit.h b/commit.h index 943e3d74b2..70c870dae4 100644 --- a/commit.h +++ b/commit.h @@ -210,7 +210,7 @@ struct commit *pop_most_recent_commit(struct commit_list **list, struct commit *pop_commit(struct commit_list **stack); void clear_commit_marks(struct commit *commit, unsigned int mark); -void clear_commit_marks_many(int nr, struct commit **commit, unsigned int mark); +void clear_commit_marks_many(size_t nr, struct commit **commit, unsigned int mark); enum rev_sort_order { diff --git a/ref-filter.c b/ref-filter.c index 23054694c2..bf5534605e 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -3041,7 +3041,7 @@ static void reach_filter(struct ref_array *array, struct commit_list **check_reachable, int include_reached) { - int i, old_nr; + size_t i, old_nr; struct commit **to_clear; if (!*check_reachable) diff --git a/remote.c b/remote.c index 18e5ccf391..0f6fba8562 100644 --- a/remote.c +++ b/remote.c @@ -1535,7 +1535,7 @@ static struct ref **tail_ref(struct ref **head) struct tips { struct commit **tip; - int nr, alloc; + size_t nr, alloc; }; static void add_to_tips(struct tips *tips, const struct object_id *oid) @@ -1602,7 +1602,7 @@ static void add_missing_tags(struct ref *src, struct ref **dst, struct ref ***ds const int reachable_flag = 1; struct commit_list *found_commits; struct commit **src_commits; - int nr_src_commits = 0, alloc_src_commits = 16; + size_t nr_src_commits = 0, alloc_src_commits = 16; ALLOC_ARRAY(src_commits, alloc_src_commits); for_each_string_list_item(item, &src_tag) { -- cgit v1.2.3 From 0905ed201a87bc97dc4d47c0cb8fd65316f33269 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 11:46:26 +0100 Subject: builtin/log: use `size_t` to track indices Similar as with the preceding commit, adapt "builtin/log.c" so that it tracks array indices via `size_t` instead of using signed integers. This fixes a couple of -Wsign-compare warnings and prepares the code for a similar refactoring of `repo_get_merge_bases_many()` in a subsequent commit. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/log.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/builtin/log.c b/builtin/log.c index 75e1b34123..805b2355d9 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -1746,11 +1746,12 @@ struct base_tree_info { static struct commit *get_base_commit(const struct format_config *cfg, struct commit **list, - int total) + size_t total) { struct commit *base = NULL; struct commit **rev; - int i = 0, rev_nr = 0, auto_select, die_on_failure, ret; + int auto_select, die_on_failure, ret; + size_t i = 0, rev_nr = 0; switch (cfg->auto_base) { case AUTO_BASE_NEVER: @@ -1885,13 +1886,12 @@ define_commit_slab(commit_base, int); static void prepare_bases(struct base_tree_info *bases, struct commit *base, struct commit **list, - int total) + size_t total) { struct commit *commit; struct rev_info revs; struct diff_options diffopt; struct commit_base commit_base; - int i; if (!base) return; @@ -1906,7 +1906,7 @@ static void prepare_bases(struct base_tree_info *bases, repo_init_revisions(the_repository, &revs, NULL); revs.max_parents = 1; revs.topo_order = 1; - for (i = 0; i < total; i++) { + for (size_t i = 0; i < total; i++) { list[i]->object.flags &= ~UNINTERESTING; add_pending_object(&revs, &list[i]->object, "rev_list"); *commit_base_at(&commit_base, list[i]) = 1; @@ -2007,7 +2007,7 @@ int cmd_format_patch(int argc, struct rev_info rev; char *to_free = NULL; struct setup_revision_opt s_r_opt; - int nr = 0, total, i; + size_t nr = 0, total, i; int use_stdout = 0; int start_number = -1; int just_numbers = 0; @@ -2500,11 +2500,14 @@ int cmd_format_patch(int argc, if (show_progress) progress = start_delayed_progress(_("Generating patches"), total); - while (0 <= --nr) { + for (i = 0; i < nr; i++) { + size_t idx = nr - i - 1; int shown; - display_progress(progress, total - nr); - commit = list[nr]; - rev.nr = total - nr + (start_number - 1); + + display_progress(progress, total - idx); + commit = list[idx]; + rev.nr = total - idx + (start_number - 1); + /* Make the second and subsequent mails replies to the first */ if (cfg.thread) { /* Have we already had a message ID? */ -- cgit v1.2.3 From 1ab5948141e62b52bcb812b04a901b3efaf1b578 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 11:46:27 +0100 Subject: builtin/log: fix remaining -Wsign-compare warnings Fix remaining -Wsign-compare warnings in "builtin/log.c" and mark the file as -Wsign-compare-clean. While most of the fixes are obvious, one fix requires us to use `cast_size_t_to_int()`, which will cause us to die in case the `size_t` cannot be represented as `int`. This should be fine though, as the data would typically be set either via a config key or via the command line, neither of which should ever exceed a couple of kilobytes of data. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/log.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/builtin/log.c b/builtin/log.c index 805b2355d9..a4f41aafca 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -6,7 +6,6 @@ */ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" #include "abspath.h" @@ -209,7 +208,6 @@ static void cmd_log_init_defaults(struct rev_info *rev, static void set_default_decoration_filter(struct decoration_filter *decoration_filter) { - int i; char *value = NULL; struct string_list *include = decoration_filter->include_ref_pattern; const struct string_list *config_exclude; @@ -243,7 +241,7 @@ static void set_default_decoration_filter(struct decoration_filter *decoration_f * No command-line or config options were given, so * populate with sensible defaults. */ - for (i = 0; i < ARRAY_SIZE(ref_namespace); i++) { + for (size_t i = 0; i < ARRAY_SIZE(ref_namespace); i++) { if (!ref_namespace[i].decoration) continue; @@ -717,14 +715,14 @@ static int show_tag_object(const struct object_id *oid, struct rev_info *rev) unsigned long size; enum object_type type; char *buf = repo_read_object_file(the_repository, oid, &type, &size); - int offset = 0; + unsigned long offset = 0; if (!buf) return error(_("could not read object %s"), oid_to_hex(oid)); assert(type == OBJ_TAG); while (offset < size && buf[offset] != '\n') { - int new_offset = offset + 1; + unsigned long new_offset = offset + 1; const char *ident; while (new_offset < size && buf[new_offset++] != '\n') ; /* do nothing */ @@ -1316,24 +1314,25 @@ static void print_signature(const char *signature, FILE *file) static char *find_branch_name(struct rev_info *rev) { - int i, positive = -1; struct object_id branch_oid; const struct object_id *tip_oid; const char *ref, *v; char *full_ref, *branch = NULL; + int interesting_found = 0; + size_t idx; - for (i = 0; i < rev->cmdline.nr; i++) { + for (size_t i = 0; i < rev->cmdline.nr; i++) { if (rev->cmdline.rev[i].flags & UNINTERESTING) continue; - if (positive < 0) - positive = i; - else + if (interesting_found) return NULL; + interesting_found = 1; + idx = i; } - if (positive < 0) + if (!interesting_found) return NULL; - ref = rev->cmdline.rev[positive].name; - tip_oid = &rev->cmdline.rev[positive].item->oid; + ref = rev->cmdline.rev[idx].name; + tip_oid = &rev->cmdline.rev[idx].item->oid; if (repo_dwim_ref(the_repository, ref, strlen(ref), &branch_oid, &full_ref, 0) && skip_prefix(full_ref, "refs/heads/", &v) && @@ -2183,7 +2182,7 @@ int cmd_format_patch(int argc, fmt_patch_suffix = cfg.fmt_patch_suffix; /* Make sure "0000-$sub.patch" gives non-negative length for $sub */ - if (cfg.log.fmt_patch_name_max <= strlen("0000-") + strlen(fmt_patch_suffix)) + if (cfg.log.fmt_patch_name_max <= cast_size_t_to_int(strlen("0000-") + strlen(fmt_patch_suffix))) cfg.log.fmt_patch_name_max = strlen("0000-") + strlen(fmt_patch_suffix); if (cover_from_description_arg) -- cgit v1.2.3 From 455ac07021d4feede4f5b7e39bf00dc186ce3c09 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 11:46:28 +0100 Subject: shallow: fix -Wsign-compare warnings Fix a couple of -Wsign-compare issues in "shallow.c" and mark the file as -Wsign-compare-clean. This change prepares the code for a refactoring of `repo_in_merge_bases_many()`, which will be adapted to accept the number of commits as `size_t` instead of `int`. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- shallow.c | 38 ++++++++++++++++++-------------------- shallow.h | 6 +++--- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/shallow.c b/shallow.c index 82a8da3d73..b8fcfbef0f 100644 --- a/shallow.c +++ b/shallow.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "hex.h" @@ -134,7 +133,8 @@ static void free_depth_in_slab(int **ptr) struct commit_list *get_shallow_commits(struct object_array *heads, int depth, int shallow_flag, int not_shallow_flag) { - int i = 0, cur_depth = 0; + size_t i = 0; + int cur_depth = 0; struct commit_list *result = NULL; struct object_array stack = OBJECT_ARRAY_INIT; struct commit *commit = NULL; @@ -335,16 +335,16 @@ static int write_shallow_commits_1(struct strbuf *out, int use_pack_protocol, const struct oid_array *extra, unsigned flags) { - struct write_shallow_data data; - int i; - data.out = out; - data.use_pack_protocol = use_pack_protocol; - data.count = 0; - data.flags = flags; + struct write_shallow_data data = { + .out = out, + .use_pack_protocol = use_pack_protocol, + .flags = flags, + }; + for_each_commit_graft(write_one_shallow, &data); if (!extra) return data.count; - for (i = 0; i < extra->nr; i++) { + for (size_t i = 0; i < extra->nr; i++) { strbuf_addstr(out, oid_to_hex(extra->oid + i)); strbuf_addch(out, '\n'); data.count++; @@ -466,7 +466,6 @@ struct trace_key trace_shallow = TRACE_KEY_INIT(SHALLOW); */ void prepare_shallow_info(struct shallow_info *info, struct oid_array *sa) { - int i; trace_printf_key(&trace_shallow, "shallow: prepare_shallow_info\n"); memset(info, 0, sizeof(*info)); info->shallow = sa; @@ -474,7 +473,7 @@ void prepare_shallow_info(struct shallow_info *info, struct oid_array *sa) return; ALLOC_ARRAY(info->ours, sa->nr); ALLOC_ARRAY(info->theirs, sa->nr); - for (i = 0; i < sa->nr; i++) { + for (size_t i = 0; i < sa->nr; i++) { if (repo_has_object_file(the_repository, sa->oid + i)) { struct commit_graft *graft; graft = lookup_commit_graft(the_repository, @@ -507,7 +506,7 @@ void clear_shallow_info(struct shallow_info *info) void remove_nonexistent_theirs_shallow(struct shallow_info *info) { struct object_id *oid = info->shallow->oid; - int i, dst; + size_t i, dst; trace_printf_key(&trace_shallow, "shallow: remove_nonexistent_theirs_shallow\n"); for (i = dst = 0; i < info->nr_theirs; i++) { if (i != dst) @@ -560,7 +559,7 @@ static void paint_down(struct paint_info *info, const struct object_id *oid, { unsigned int i, nr; struct commit_list *head = NULL; - int bitmap_nr = DIV_ROUND_UP(info->nr_bits, 32); + size_t bitmap_nr = DIV_ROUND_UP(info->nr_bits, 32); size_t bitmap_size = st_mult(sizeof(uint32_t), bitmap_nr); struct commit *c = lookup_commit_reference_gently(the_repository, oid, 1); @@ -660,7 +659,7 @@ void assign_shallow_commits_to_refs(struct shallow_info *info, struct object_id *oid = info->shallow->oid; struct oid_array *ref = info->ref; unsigned int i, nr; - int *shallow, nr_shallow = 0; + size_t *shallow, nr_shallow = 0; struct paint_info pi; trace_printf_key(&trace_shallow, "shallow: assign_shallow_commits_to_refs\n"); @@ -735,7 +734,7 @@ void assign_shallow_commits_to_refs(struct shallow_info *info, struct commit_array { struct commit **commits; - int nr, alloc; + size_t nr, alloc; }; static int add_ref(const char *refname UNUSED, @@ -753,12 +752,11 @@ static int add_ref(const char *refname UNUSED, return 0; } -static void update_refstatus(int *ref_status, int nr, uint32_t *bitmap) +static void update_refstatus(int *ref_status, size_t nr, uint32_t *bitmap) { - unsigned int i; if (!ref_status) return; - for (i = 0; i < nr; i++) + for (size_t i = 0; i < nr; i++) if (bitmap[i / 32] & (1U << (i % 32))) ref_status[i]++; } @@ -773,8 +771,8 @@ static void post_assign_shallow(struct shallow_info *info, struct object_id *oid = info->shallow->oid; struct commit *c; uint32_t **bitmap; - int dst, i, j; - int bitmap_nr = DIV_ROUND_UP(info->ref->nr, 32); + size_t dst, i, j; + size_t bitmap_nr = DIV_ROUND_UP(info->ref->nr, 32); struct commit_array ca; trace_printf_key(&trace_shallow, "shallow: post_assign_shallow\n"); diff --git a/shallow.h b/shallow.h index e9ca7e4bc8..9bfeade93e 100644 --- a/shallow.h +++ b/shallow.h @@ -59,8 +59,8 @@ void prune_shallow(unsigned options); */ struct shallow_info { struct oid_array *shallow; - int *ours, nr_ours; - int *theirs, nr_theirs; + size_t *ours, nr_ours; + size_t *theirs, nr_theirs; struct oid_array *ref; /* for receive-pack */ @@ -69,7 +69,7 @@ struct shallow_info { int *reachable; int *shallow_ref; struct commit **commits; - int nr_commits; + size_t nr_commits; }; void prepare_shallow_info(struct shallow_info *, struct oid_array *); -- cgit v1.2.3 From 5e7fe8a7b89a07d8c3ab298ac69bc33f6ba88b47 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 11:46:29 +0100 Subject: commit-reach: use `size_t` to track indices when computing merge bases The functions `repo_get_merge_bases_many()` and friends accepts an array of commits as well as a parameter that indicates how large that array is. This parameter is using a signed integer, which leads to a couple of warnings with -Wsign-compare. Refactor the code to use `size_t` to track indices instead and adapt callers accordingly. While most callers are trivial, there are two callers that require a bit more scrutiny: - builtin/merge-base.c:show_merge_base() subtracts `1` from the `rev_nr` before calling `repo_get_merge_bases_many_dirty()`, so if the variable was `0` it would wrap. This code is fine though because its only caller will execute that code only when `argc >= 2`, and it follows that `rev_nr >= 2`, as well. - bisect.ccheck_merge_bases() similarly subtracts `1` from `rev_nr`. Again, there is only a single caller that populates `rev_nr` with `good_revs.nr`. And because a bisection always requires at least one good revision it follws that `rev_nr >= 1`. Mark the file as -Wsign-compare-clean. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- bisect.c | 2 +- builtin/merge-base.c | 4 ++-- commit-reach.c | 7 +++---- commit-reach.h | 4 ++-- t/helper/test-reach.c | 6 +++--- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/bisect.c b/bisect.c index 7a1afc46e5..7a3c77c6d8 100644 --- a/bisect.c +++ b/bisect.c @@ -855,7 +855,7 @@ static void handle_skipped_merge_base(const struct object_id *mb) * for early success, this will be converted back to 0 in * check_good_are_ancestors_of_bad(). */ -static enum bisect_error check_merge_bases(int rev_nr, struct commit **rev, int no_checkout) +static enum bisect_error check_merge_bases(size_t rev_nr, struct commit **rev, int no_checkout) { enum bisect_error res = BISECT_OK; struct commit_list *result = NULL; diff --git a/builtin/merge-base.c b/builtin/merge-base.c index a20c93b11a..123c81515e 100644 --- a/builtin/merge-base.c +++ b/builtin/merge-base.c @@ -8,7 +8,7 @@ #include "parse-options.h" #include "commit-reach.h" -static int show_merge_base(struct commit **rev, int rev_nr, int show_all) +static int show_merge_base(struct commit **rev, size_t rev_nr, int show_all) { struct commit_list *result = NULL, *r; @@ -149,7 +149,7 @@ int cmd_merge_base(int argc, struct repository *repo UNUSED) { struct commit **rev; - int rev_nr = 0; + size_t rev_nr = 0; int show_all = 0; int cmdmode = 0; int ret; diff --git a/commit-reach.c b/commit-reach.c index bab40f5575..a339e41aa4 100644 --- a/commit-reach.c +++ b/commit-reach.c @@ -1,5 +1,4 @@ #define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" #include "commit.h" @@ -421,7 +420,7 @@ static int remove_redundant(struct repository *r, struct commit **array, static int get_merge_bases_many_0(struct repository *r, struct commit *one, - int n, + size_t n, struct commit **twos, int cleanup, struct commit_list **result) @@ -469,7 +468,7 @@ static int get_merge_bases_many_0(struct repository *r, int repo_get_merge_bases_many(struct repository *r, struct commit *one, - int n, + size_t n, struct commit **twos, struct commit_list **result) { @@ -478,7 +477,7 @@ int repo_get_merge_bases_many(struct repository *r, int repo_get_merge_bases_many_dirty(struct repository *r, struct commit *one, - int n, + size_t n, struct commit **twos, struct commit_list **result) { diff --git a/commit-reach.h b/commit-reach.h index fa5408054a..6012402dfc 100644 --- a/commit-reach.h +++ b/commit-reach.h @@ -14,12 +14,12 @@ int repo_get_merge_bases(struct repository *r, struct commit *rev2, struct commit_list **result); int repo_get_merge_bases_many(struct repository *r, - struct commit *one, int n, + struct commit *one, size_t n, struct commit **twos, struct commit_list **result); /* To be used only when object flags after this call no longer matter */ int repo_get_merge_bases_many_dirty(struct repository *r, - struct commit *one, int n, + struct commit *one, size_t n, struct commit **twos, struct commit_list **result); diff --git a/t/helper/test-reach.c b/t/helper/test-reach.c index 01cf77ae65..028ec00306 100644 --- a/t/helper/test-reach.c +++ b/t/helper/test-reach.c @@ -35,7 +35,7 @@ int cmd__reach(int ac, const char **av) struct commit_list *X, *Y; struct object_array X_obj = OBJECT_ARRAY_INIT; struct commit **X_array, **Y_array; - int X_nr, X_alloc, Y_nr, Y_alloc; + size_t X_nr, X_alloc, Y_nr, Y_alloc; struct strbuf buf = STRBUF_INIT; struct repository *r = the_repository; @@ -157,7 +157,7 @@ int cmd__reach(int ac, const char **av) clear_contains_cache(&cache); } else if (!strcmp(av[1], "get_reachable_subset")) { const int reachable_flag = 1; - int i, count = 0; + int count = 0; struct commit_list *current; struct commit_list *list = get_reachable_subset(X_array, X_nr, Y_array, Y_nr, @@ -169,7 +169,7 @@ int cmd__reach(int ac, const char **av) oid_to_hex(&list->item->object.oid)); count++; } - for (i = 0; i < Y_nr; i++) { + for (size_t i = 0; i < Y_nr; i++) { if (Y_array[i]->object.flags & reachable_flag) count--; } -- cgit v1.2.3 From cef3d4a89f8d21fae6669822cbb540927020d93b Mon Sep 17 00:00:00 2001 From: Meet Soni Date: Fri, 27 Dec 2024 16:23:45 +0530 Subject: t7611: replace test -f with test_path_is* helpers Replace `test -f` and `test ! -f` with `test_path_is_file` and `test_path_is_missing` for better debuggability. While `test -f` ensures that the file exists and is a regular file, `test_path_is_file` provides clearer error messages on failure. On the other hand, `test ! -f` checks either the absence of a regular file or the presence of any other filesystem object, but looking at them in the test individually, all of them should've said `test ! -e`, i.e. "there shouldn't be anything at given path on filesystem." Replace these cases with `test_path_is_missing` for better debuggability. Helped-by: karthik nayak Helped-by: Junio C Hamano Signed-off-by: Meet Soni Signed-off-by: Junio C Hamano --- t/t7611-merge-abort.sh | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/t/t7611-merge-abort.sh b/t/t7611-merge-abort.sh index d6975ca48d..1a251485e1 100755 --- a/t/t7611-merge-abort.sh +++ b/t/t7611-merge-abort.sh @@ -54,13 +54,13 @@ test_expect_success 'fails without MERGE_HEAD (unstarted merge)' ' ' test_expect_success 'fails without MERGE_HEAD (unstarted merge): .git/MERGE_HEAD sanity' ' - test ! -f .git/MERGE_HEAD && + test_path_is_missing .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" ' test_expect_success 'fails without MERGE_HEAD (completed merge)' ' git merge clean_branch && - test ! -f .git/MERGE_HEAD && + test_path_is_missing .git/MERGE_HEAD && # Merge successfully completed post_merge_head="$(git rev-parse HEAD)" && test_must_fail git merge --abort 2>output && @@ -68,7 +68,7 @@ test_expect_success 'fails without MERGE_HEAD (completed merge)' ' ' test_expect_success 'fails without MERGE_HEAD (completed merge): .git/MERGE_HEAD sanity' ' - test ! -f .git/MERGE_HEAD && + test_path_is_missing .git/MERGE_HEAD && test "$post_merge_head" = "$(git rev-parse HEAD)" ' @@ -79,10 +79,10 @@ test_expect_success 'Forget previous merge' ' test_expect_success 'Abort after --no-commit' ' # Redo merge, but stop before creating merge commit git merge --no-commit clean_branch && - test -f .git/MERGE_HEAD && + test_path_is_file .git/MERGE_HEAD && # Abort non-conflicting merge git merge --abort && - test ! -f .git/MERGE_HEAD && + test_path_is_missing .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && test -z "$(git diff)" && test -z "$(git diff --staged)" @@ -91,10 +91,10 @@ test_expect_success 'Abort after --no-commit' ' test_expect_success 'Abort after conflicts' ' # Create conflicting merge test_must_fail git merge conflict_branch && - test -f .git/MERGE_HEAD && + test_path_is_file .git/MERGE_HEAD && # Abort conflicting merge git merge --abort && - test ! -f .git/MERGE_HEAD && + test_path_is_missing .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && test -z "$(git diff)" && test -z "$(git diff --staged)" @@ -105,7 +105,7 @@ test_expect_success 'Clean merge with dirty index fails' ' git add foo && git diff --staged > expect && test_must_fail git merge clean_branch && - test ! -f .git/MERGE_HEAD && + test_path_is_missing .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && test -z "$(git diff)" && git diff --staged > actual && @@ -114,7 +114,7 @@ test_expect_success 'Clean merge with dirty index fails' ' test_expect_success 'Conflicting merge with dirty index fails' ' test_must_fail git merge conflict_branch && - test ! -f .git/MERGE_HEAD && + test_path_is_missing .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && test -z "$(git diff)" && git diff --staged > actual && @@ -129,10 +129,10 @@ test_expect_success 'Reset index (but preserve worktree changes)' ' test_expect_success 'Abort clean merge with non-conflicting dirty worktree' ' git merge --no-commit clean_branch && - test -f .git/MERGE_HEAD && + test_path_is_file .git/MERGE_HEAD && # Abort merge git merge --abort && - test ! -f .git/MERGE_HEAD && + test_path_is_missing .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && test -z "$(git diff --staged)" && git diff > actual && @@ -141,10 +141,10 @@ test_expect_success 'Abort clean merge with non-conflicting dirty worktree' ' test_expect_success 'Abort conflicting merge with non-conflicting dirty worktree' ' test_must_fail git merge conflict_branch && - test -f .git/MERGE_HEAD && + test_path_is_file .git/MERGE_HEAD && # Abort merge git merge --abort && - test ! -f .git/MERGE_HEAD && + test_path_is_missing .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && test -z "$(git diff --staged)" && git diff > actual && @@ -159,7 +159,7 @@ test_expect_success 'Fail clean merge with conflicting dirty worktree' ' echo xyzzy >> bar && git diff > expect && test_must_fail git merge --no-commit clean_branch && - test ! -f .git/MERGE_HEAD && + test_path_is_missing .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && test -z "$(git diff --staged)" && git diff > actual && @@ -168,7 +168,7 @@ test_expect_success 'Fail clean merge with conflicting dirty worktree' ' test_expect_success 'Fail conflicting merge with conflicting dirty worktree' ' test_must_fail git merge conflict_branch && - test ! -f .git/MERGE_HEAD && + test_path_is_missing .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && test -z "$(git diff --staged)" && git diff > actual && @@ -183,7 +183,7 @@ test_expect_success 'Fail clean merge with matching dirty worktree' ' echo bart > bar && git diff > expect && test_must_fail git merge --no-commit clean_branch && - test ! -f .git/MERGE_HEAD && + test_path_is_missing .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && test -z "$(git diff --staged)" && git diff > actual && @@ -194,7 +194,7 @@ test_expect_success 'Fail conflicting merge with matching dirty worktree' ' echo barf > bar && git diff > expect && test_must_fail git merge conflict_branch && - test ! -f .git/MERGE_HEAD && + test_path_is_missing .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && test -z "$(git diff --staged)" && git diff > actual && -- cgit v1.2.3 From cfa1f2ae96f4c6bcc0d3acdbd9a2734a8f33a351 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 13:10:17 +0100 Subject: GIT-BUILD-OPTIONS: sort variables alphabetically The variables declared and substituted in GIT-BUILD-OPTIONS are not ordered in any obvious way. Sort them alphabetically so that it becomes obvious where new variables should go. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- GIT-BUILD-OPTIONS.in | 70 ++++++++++++++++++------------------- Makefile | 70 ++++++++++++++++++------------------- contrib/buildsystems/CMakeLists.txt | 70 ++++++++++++++++++------------------- 3 files changed, 105 insertions(+), 105 deletions(-) diff --git a/GIT-BUILD-OPTIONS.in b/GIT-BUILD-OPTIONS.in index f651116102..162cc39190 100644 --- a/GIT-BUILD-OPTIONS.in +++ b/GIT-BUILD-OPTIONS.in @@ -1,47 +1,47 @@ -SHELL_PATH=@SHELL_PATH@ -TEST_SHELL_PATH=@TEST_SHELL_PATH@ -PERL_PATH=@PERL_PATH@ -PERL_LOCALEDIR=@PERL_LOCALEDIR@ -NO_PERL_CPAN_FALLBACKS=@NO_PERL_CPAN_FALLBACKS@ +BROKEN_PATH_FIX=@BROKEN_PATH_FIX@ DIFF=@DIFF@ -PYTHON_PATH=@PYTHON_PATH@ -TAR=@TAR@ +FSMONITOR_DAEMON_BACKEND=@FSMONITOR_DAEMON_BACKEND@ +FSMONITOR_OS_SETTINGS=@FSMONITOR_OS_SETTINGS@ +GITWEBDIR=@GITWEBDIR@ +GIT_INTEROP_MAKE_OPTS=@GIT_INTEROP_MAKE_OPTS@ +GIT_PERF_LARGE_REPO=@GIT_PERF_LARGE_REPO@ +GIT_PERF_MAKE_COMMAND=@GIT_PERF_MAKE_COMMAND@ +GIT_PERF_MAKE_OPTS=@GIT_PERF_MAKE_OPTS@ +GIT_PERF_REPEAT_COUNT=@GIT_PERF_REPEAT_COUNT@ +GIT_PERF_REPO=@GIT_PERF_REPO@ +GIT_TEST_CMP=@GIT_TEST_CMP@ +GIT_TEST_CMP_USE_COPIED_CONTEXT=@GIT_TEST_CMP_USE_COPIED_CONTEXT@ +GIT_TEST_GITPERLLIB=@GIT_TEST_GITPERLLIB@ +GIT_TEST_INDEX_VERSION=@GIT_TEST_INDEX_VERSION@ +GIT_TEST_MERGE_TOOLS_DIR=@GIT_TEST_MERGE_TOOLS_DIR@ +GIT_TEST_OPTS=@GIT_TEST_OPTS@ +GIT_TEST_PERL_FATAL_WARNINGS=@GIT_TEST_PERL_FATAL_WARNINGS@ +GIT_TEST_POPATH=@GIT_TEST_POPATH@ +GIT_TEST_TEMPLATE_DIR=@GIT_TEST_TEMPLATE_DIR@ +GIT_TEST_TEXTDOMAINDIR=@GIT_TEST_TEXTDOMAINDIR@ +GIT_TEST_UTF8_LOCALE=@GIT_TEST_UTF8_LOCALE@ +LOCALEDIR=@LOCALEDIR@ NO_CURL=@NO_CURL@ -NO_ICONV=@NO_ICONV@ NO_EXPAT=@NO_EXPAT@ -USE_LIBPCRE2=@USE_LIBPCRE2@ +NO_GETTEXT=@NO_GETTEXT@ +NO_ICONV=@NO_ICONV@ NO_PERL=@NO_PERL@ +NO_PERL_CPAN_FALLBACKS=@NO_PERL_CPAN_FALLBACKS@ NO_PTHREADS=@NO_PTHREADS@ NO_PYTHON=@NO_PYTHON@ NO_REGEX=@NO_REGEX@ NO_UNIX_SOCKETS=@NO_UNIX_SOCKETS@ PAGER_ENV=@PAGER_ENV@ -SANITIZE_LEAK=@SANITIZE_LEAK@ +PERL_LOCALEDIR=@PERL_LOCALEDIR@ +PERL_PATH=@PERL_PATH@ +PYTHON_PATH=@PYTHON_PATH@ +RUNTIME_PREFIX=@RUNTIME_PREFIX@ SANITIZE_ADDRESS=@SANITIZE_ADDRESS@ -X=@X@ -FSMONITOR_DAEMON_BACKEND=@FSMONITOR_DAEMON_BACKEND@ -FSMONITOR_OS_SETTINGS=@FSMONITOR_OS_SETTINGS@ +SANITIZE_LEAK=@SANITIZE_LEAK@ +SHELL_PATH=@SHELL_PATH@ +TAR=@TAR@ TEST_OUTPUT_DIRECTORY=@TEST_OUTPUT_DIRECTORY@ -GIT_TEST_OPTS=@GIT_TEST_OPTS@ -GIT_TEST_CMP=@GIT_TEST_CMP@ -GIT_TEST_CMP_USE_COPIED_CONTEXT=@GIT_TEST_CMP_USE_COPIED_CONTEXT@ -GIT_TEST_UTF8_LOCALE=@GIT_TEST_UTF8_LOCALE@ -NO_GETTEXT=@NO_GETTEXT@ -GIT_PERF_REPEAT_COUNT=@GIT_PERF_REPEAT_COUNT@ -GIT_PERF_REPO=@GIT_PERF_REPO@ -GIT_PERF_LARGE_REPO=@GIT_PERF_LARGE_REPO@ -GIT_PERF_MAKE_OPTS=@GIT_PERF_MAKE_OPTS@ -GIT_PERF_MAKE_COMMAND=@GIT_PERF_MAKE_COMMAND@ -GIT_INTEROP_MAKE_OPTS=@GIT_INTEROP_MAKE_OPTS@ -GIT_TEST_INDEX_VERSION=@GIT_TEST_INDEX_VERSION@ -GIT_TEST_PERL_FATAL_WARNINGS=@GIT_TEST_PERL_FATAL_WARNINGS@ -GIT_TEST_TEXTDOMAINDIR=@GIT_TEST_TEXTDOMAINDIR@ -GIT_TEST_POPATH=@GIT_TEST_POPATH@ -GIT_TEST_TEMPLATE_DIR=@GIT_TEST_TEMPLATE_DIR@ -GIT_TEST_GITPERLLIB=@GIT_TEST_GITPERLLIB@ -GIT_TEST_MERGE_TOOLS_DIR=@GIT_TEST_MERGE_TOOLS_DIR@ -RUNTIME_PREFIX=@RUNTIME_PREFIX@ -GITWEBDIR=@GITWEBDIR@ +TEST_SHELL_PATH=@TEST_SHELL_PATH@ USE_GETTEXT_SCHEME=@USE_GETTEXT_SCHEME@ -LOCALEDIR=@LOCALEDIR@ -BROKEN_PATH_FIX=@BROKEN_PATH_FIX@ +USE_LIBPCRE2=@USE_LIBPCRE2@ +X=@X@ diff --git a/Makefile b/Makefile index 3fa4bf0d06..f80e70702f 100644 --- a/Makefile +++ b/Makefile @@ -3145,53 +3145,53 @@ endif # and the first level quoting from the shell that runs "echo". GIT-BUILD-OPTIONS: FORCE @sed \ - -e "s|@SHELL_PATH@|\'$(SHELL_PATH_SQ)\'|" \ - -e "s|@TEST_SHELL_PATH@|\'$(TEST_SHELL_PATH_SQ)\'|" \ - -e "s|@PERL_PATH@|\'$(PERL_PATH_SQ)\'|" \ - -e "s|@PERL_LOCALEDIR@|\'$(perl_localedir_SQ)\'|" \ - -e "s|@NO_PERL_CPAN_FALLBACKS@|\'$(NO_PERL_CPAN_FALLBACKS_SQ)\'|" \ + -e "s!@BROKEN_PATH_FIX@!\'$(BROKEN_PATH_FIX)\'!" \ -e "s|@DIFF@|\'$(DIFF)\'|" \ - -e "s|@PYTHON_PATH@|\'$(PYTHON_PATH_SQ)\'|" \ - -e "s|@TAR@|\'$(TAR)\'|" \ + -e "s|@FSMONITOR_DAEMON_BACKEND@|\'$(FSMONITOR_DAEMON_BACKEND)\'|" \ + -e "s|@FSMONITOR_OS_SETTINGS@|\'$(FSMONITOR_OS_SETTINGS)\'|" \ + -e "s|@GITWEBDIR@|\'$(gitwebdir_SQ)\'|" \ + -e "s|@GIT_INTEROP_MAKE_OPTS@|\'$(GIT_INTEROP_MAKE_OPTS)\'|" \ + -e "s|@GIT_PERF_LARGE_REPO@|\'$(GIT_PERF_LARGE_REPO)\'|" \ + -e "s|@GIT_PERF_MAKE_COMMAND@|\'$(GIT_PERF_MAKE_COMMAND)\'|" \ + -e "s|@GIT_PERF_MAKE_OPTS@|\'$(GIT_PERF_MAKE_OPTS)\'|" \ + -e "s|@GIT_PERF_REPEAT_COUNT@|\'$(GIT_PERF_REPEAT_COUNT)\'|" \ + -e "s|@GIT_PERF_REPO@|\'$(GIT_PERF_REPO)\'|" \ + -e "s|@GIT_TEST_CMP@|\'$(GIT_TEST_CMP)\'|" \ + -e "s|@GIT_TEST_CMP_USE_COPIED_CONTEXT@|\'$(GIT_TEST_CMP_USE_COPIED_CONTEXT)\'|" \ + -e "s|@GIT_TEST_GITPERLLIB@|\'$(shell pwd)/perl/build/lib\'|" \ + -e "s|@GIT_TEST_INDEX_VERSION@|\'$(GIT_TEST_INDEX_VERSION)\'|" \ + -e "s|@GIT_TEST_MERGE_TOOLS_DIR@|\'$(shell pwd)/mergetools\'|" \ + -e "s|@GIT_TEST_OPTS@|\'$(GIT_TEST_OPTS)\'|" \ + -e "s|@GIT_TEST_PERL_FATAL_WARNINGS@|\'$(GIT_TEST_PERL_FATAL_WARNINGS)\'|" \ + -e "s|@GIT_TEST_POPATH@|\'$(shell pwd)/po\'|" \ + -e "s|@GIT_TEST_TEMPLATE_DIR@|\'$(shell pwd)/templates/blt\'|" \ + -e "s|@GIT_TEST_TEXTDOMAINDIR@|\'$(shell pwd)/po/build/locale\'|" \ + -e "s|@GIT_TEST_UTF8_LOCALE@|\'$(GIT_TEST_UTF8_LOCALE)\'|" \ + -e "s|@LOCALEDIR@|\'$(localedir_SQ)\'|" \ -e "s|@NO_CURL@|\'$(NO_CURL)\'|" \ - -e "s|@NO_ICONV@|\'$(NO_ICONV)\'|" \ -e "s|@NO_EXPAT@|\'$(NO_EXPAT)\'|" \ - -e "s|@USE_LIBPCRE2@|\'$(USE_LIBPCRE2)\'|" \ + -e "s|@NO_GETTEXT@|\'$(NO_GETTEXT)\'|" \ + -e "s|@NO_ICONV@|\'$(NO_ICONV)\'|" \ -e "s|@NO_PERL@|\'$(NO_PERL)\'|" \ + -e "s|@NO_PERL_CPAN_FALLBACKS@|\'$(NO_PERL_CPAN_FALLBACKS_SQ)\'|" \ -e "s|@NO_PTHREADS@|\'$(NO_PTHREADS)\'|" \ -e "s|@NO_PYTHON@|\'$(NO_PYTHON)\'|" \ -e "s|@NO_REGEX@|\'$(NO_REGEX)\'|" \ -e "s|@NO_UNIX_SOCKETS@|\'$(NO_UNIX_SOCKETS)\'|" \ -e "s|@PAGER_ENV@|\'$(PAGER_ENV)\'|" \ - -e "s|@SANITIZE_LEAK@|\'$(SANITIZE_LEAK)\'|" \ + -e "s|@PERL_LOCALEDIR@|\'$(perl_localedir_SQ)\'|" \ + -e "s|@PERL_PATH@|\'$(PERL_PATH_SQ)\'|" \ + -e "s|@PYTHON_PATH@|\'$(PYTHON_PATH_SQ)\'|" \ + -e "s|@RUNTIME_PREFIX@|\'$(RUNTIME_PREFIX_OPTION)\'|" \ -e "s|@SANITIZE_ADDRESS@|\'$(SANITIZE_ADDRESS)\'|" \ - -e "s|@X@|\'$(X)\'|" \ - -e "s|@FSMONITOR_DAEMON_BACKEND@|\'$(FSMONITOR_DAEMON_BACKEND)\'|" \ - -e "s|@FSMONITOR_OS_SETTINGS@|\'$(FSMONITOR_OS_SETTINGS)\'|" \ + -e "s|@SANITIZE_LEAK@|\'$(SANITIZE_LEAK)\'|" \ + -e "s|@SHELL_PATH@|\'$(SHELL_PATH_SQ)\'|" \ + -e "s|@TAR@|\'$(TAR)\'|" \ -e "s|@TEST_OUTPUT_DIRECTORY@|\'$(TEST_OUTPUT_DIRECTORY)\'|" \ - -e "s|@GIT_TEST_OPTS@|\'$(GIT_TEST_OPTS)\'|" \ - -e "s|@GIT_TEST_CMP@|\'$(GIT_TEST_CMP)\'|" \ - -e "s|@GIT_TEST_CMP_USE_COPIED_CONTEXT@|\'$(GIT_TEST_CMP_USE_COPIED_CONTEXT)\'|" \ - -e "s|@GIT_TEST_UTF8_LOCALE@|\'$(GIT_TEST_UTF8_LOCALE)\'|" \ - -e "s|@NO_GETTEXT@|\'$(NO_GETTEXT)\'|" \ - -e "s|@GIT_PERF_REPEAT_COUNT@|\'$(GIT_PERF_REPEAT_COUNT)\'|" \ - -e "s|@GIT_PERF_REPO@|\'$(GIT_PERF_REPO)\'|" \ - -e "s|@GIT_PERF_LARGE_REPO@|\'$(GIT_PERF_LARGE_REPO)\'|" \ - -e "s|@GIT_PERF_MAKE_OPTS@|\'$(GIT_PERF_MAKE_OPTS)\'|" \ - -e "s|@GIT_PERF_MAKE_COMMAND@|\'$(GIT_PERF_MAKE_COMMAND)\'|" \ - -e "s|@GIT_INTEROP_MAKE_OPTS@|\'$(GIT_INTEROP_MAKE_OPTS)\'|" \ - -e "s|@GIT_TEST_INDEX_VERSION@|\'$(GIT_TEST_INDEX_VERSION)\'|" \ - -e "s|@GIT_TEST_PERL_FATAL_WARNINGS@|\'$(GIT_TEST_PERL_FATAL_WARNINGS)\'|" \ - -e "s|@GIT_TEST_TEXTDOMAINDIR@|\'$(shell pwd)/po/build/locale\'|" \ - -e "s|@GIT_TEST_POPATH@|\'$(shell pwd)/po\'|" \ - -e "s|@GIT_TEST_TEMPLATE_DIR@|\'$(shell pwd)/templates/blt\'|" \ - -e "s|@GIT_TEST_GITPERLLIB@|\'$(shell pwd)/perl/build/lib\'|" \ - -e "s|@GIT_TEST_MERGE_TOOLS_DIR@|\'$(shell pwd)/mergetools\'|" \ - -e "s|@RUNTIME_PREFIX@|\'$(RUNTIME_PREFIX_OPTION)\'|" \ - -e "s|@GITWEBDIR@|\'$(gitwebdir_SQ)\'|" \ + -e "s|@TEST_SHELL_PATH@|\'$(TEST_SHELL_PATH_SQ)\'|" \ -e "s|@USE_GETTEXT_SCHEME@|\'$(USE_GETTEXT_SCHEME)\'|" \ - -e "s|@LOCALEDIR@|\'$(localedir_SQ)\'|" \ - -e "s!@BROKEN_PATH_FIX@!\'$(BROKEN_PATH_FIX)\'!" \ + -e "s|@USE_LIBPCRE2@|\'$(USE_LIBPCRE2)\'|" \ + -e "s|@X@|\'$(X)\'|" \ GIT-BUILD-OPTIONS.in >$@+ @if grep -q '^[A-Z][A-Z_]*=@.*@$$' $@+; then echo "Unsubstituted build options in $@" >&2 && exit 1; fi @if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 802445c1eb..f45407b060 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -1158,53 +1158,53 @@ if(NOT PYTHON_TESTS) endif() file(STRINGS ${CMAKE_SOURCE_DIR}/GIT-BUILD-OPTIONS.in git_build_options NEWLINE_CONSUME) -string(REPLACE "@SHELL_PATH@" "'${SHELL_PATH}'" git_build_options "${git_build_options}") -string(REPLACE "@TEST_SHELL_PATH@" "'${TEST_SHELL_PATH}'" git_build_options "${git_build_options}") -string(REPLACE "@PERL_PATH@" "'${PERL_PATH}'" git_build_options "${git_build_options}") -string(REPLACE "@PERL_LOCALEDIR@" "'${LOCALEDIR}'" git_build_options "${git_build_options}") -string(REPLACE "@NO_PERL_CPAN_FALLBACKS@" "" git_build_options "${git_build_options}") +string(REPLACE "@BROKEN_PATH_FIX@" "" git_build_options "${git_build_options}") string(REPLACE "@DIFF@" "'${DIFF}'" git_build_options "${git_build_options}") -string(REPLACE "@PYTHON_PATH@" "'${PYTHON_PATH}'" git_build_options "${git_build_options}") -string(REPLACE "@TAR@" "'${TAR}'" git_build_options "${git_build_options}") +string(REPLACE "@FSMONITOR_DAEMON_BACKEND@" "win32" git_build_options "${git_build_options}") +string(REPLACE "@FSMONITOR_OS_SETTINGS@" "win32" git_build_options "${git_build_options}") +string(REPLACE "@GITWEBDIR@" "'${GITWEBDIR}'" git_build_options "${git_build_options}") +string(REPLACE "@GIT_INTEROP_MAKE_OPTS@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_PERF_LARGE_REPO@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_PERF_MAKE_COMMAND@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_PERF_MAKE_OPTS@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_PERF_REPEAT_COUNT@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_PERF_REPO@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_CMP@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_CMP_USE_COPIED_CONTEXT@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_GITPERLLIB@" "'${CMAKE_BINARY_DIR}/perl/build/lib'" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_INDEX_VERSION@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_MERGE_TOOLS_DIR@" "'${CMAKE_BINARY_DIR}/mergetools'" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_OPTS@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_PERL_FATAL_WARNINGS@" "" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_POPATH@" "'${CMAKE_BINARY_DIR}/po'" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_TEMPLATE_DIR@" "'${CMAKE_BINARY_DIR}/templates/blt'" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_TEXTDOMAINDIR@" "'${CMAKE_BINARY_DIR}/po/build/locale'" git_build_options "${git_build_options}") +string(REPLACE "@GIT_TEST_UTF8_LOCALE@" "" git_build_options "${git_build_options}") +string(REPLACE "@LOCALEDIR@" "'${LOCALEDIR}'" git_build_options "${git_build_options}") string(REPLACE "@NO_CURL@" "${NO_CURL}" git_build_options "${git_build_options}") -string(REPLACE "@NO_ICONV@" "${NO_ICONV}" git_build_options "${git_build_options}") string(REPLACE "@NO_EXPAT@" "${NO_EXPAT}" git_build_options "${git_build_options}") -string(REPLACE "@USE_LIBPCRE2@" "" git_build_options "${git_build_options}") +string(REPLACE "@NO_GETTEXT@" "${NO_GETTEXT}" git_build_options "${git_build_options}") +string(REPLACE "@NO_ICONV@" "${NO_ICONV}" git_build_options "${git_build_options}") string(REPLACE "@NO_PERL@" "${NO_PERL}" git_build_options "${git_build_options}") +string(REPLACE "@NO_PERL_CPAN_FALLBACKS@" "" git_build_options "${git_build_options}") string(REPLACE "@NO_PTHREADS@" "${NO_PTHREADS}" git_build_options "${git_build_options}") string(REPLACE "@NO_PYTHON@" "${NO_PYTHON}" git_build_options "${git_build_options}") string(REPLACE "@NO_REGEX@" "" git_build_options "${git_build_options}") string(REPLACE "@NO_UNIX_SOCKETS@" "${NO_UNIX_SOCKETS}" git_build_options "${git_build_options}") string(REPLACE "@PAGER_ENV@" "'${PAGER_ENV}'" git_build_options "${git_build_options}") -string(REPLACE "@SANITIZE_LEAK@" "" git_build_options "${git_build_options}") +string(REPLACE "@PERL_LOCALEDIR@" "'${LOCALEDIR}'" git_build_options "${git_build_options}") +string(REPLACE "@PERL_PATH@" "'${PERL_PATH}'" git_build_options "${git_build_options}") +string(REPLACE "@PYTHON_PATH@" "'${PYTHON_PATH}'" git_build_options "${git_build_options}") +string(REPLACE "@RUNTIME_PREFIX@" "'${RUNTIME_PREFIX}'" git_build_options "${git_build_options}") string(REPLACE "@SANITIZE_ADDRESS@" "" git_build_options "${git_build_options}") -string(REPLACE "@X@" "${EXE_EXTENSION}" git_build_options "${git_build_options}") -string(REPLACE "@FSMONITOR_DAEMON_BACKEND@" "win32" git_build_options "${git_build_options}") -string(REPLACE "@FSMONITOR_OS_SETTINGS@" "win32" git_build_options "${git_build_options}") +string(REPLACE "@SANITIZE_LEAK@" "" git_build_options "${git_build_options}") +string(REPLACE "@SHELL_PATH@" "'${SHELL_PATH}'" git_build_options "${git_build_options}") +string(REPLACE "@TAR@" "'${TAR}'" git_build_options "${git_build_options}") string(REPLACE "@TEST_OUTPUT_DIRECTORY@" "" git_build_options "${git_build_options}") -string(REPLACE "@GIT_TEST_OPTS@" "" git_build_options "${git_build_options}") -string(REPLACE "@GIT_TEST_CMP@" "" git_build_options "${git_build_options}") -string(REPLACE "@GIT_TEST_CMP_USE_COPIED_CONTEXT@" "" git_build_options "${git_build_options}") -string(REPLACE "@GIT_TEST_UTF8_LOCALE@" "" git_build_options "${git_build_options}") -string(REPLACE "@NO_GETTEXT@" "${NO_GETTEXT}" git_build_options "${git_build_options}") -string(REPLACE "@GIT_PERF_REPEAT_COUNT@" "" git_build_options "${git_build_options}") -string(REPLACE "@GIT_PERF_REPO@" "" git_build_options "${git_build_options}") -string(REPLACE "@GIT_PERF_LARGE_REPO@" "" git_build_options "${git_build_options}") -string(REPLACE "@GIT_PERF_MAKE_OPTS@" "" git_build_options "${git_build_options}") -string(REPLACE "@GIT_PERF_MAKE_COMMAND@" "" git_build_options "${git_build_options}") -string(REPLACE "@GIT_INTEROP_MAKE_OPTS@" "" git_build_options "${git_build_options}") -string(REPLACE "@GIT_TEST_INDEX_VERSION@" "" git_build_options "${git_build_options}") -string(REPLACE "@GIT_TEST_PERL_FATAL_WARNINGS@" "" git_build_options "${git_build_options}") -string(REPLACE "@GIT_TEST_TEXTDOMAINDIR@" "'${CMAKE_BINARY_DIR}/po/build/locale'" git_build_options "${git_build_options}") -string(REPLACE "@GIT_TEST_POPATH@" "'${CMAKE_BINARY_DIR}/po'" git_build_options "${git_build_options}") -string(REPLACE "@GIT_TEST_TEMPLATE_DIR@" "'${CMAKE_BINARY_DIR}/templates/blt'" git_build_options "${git_build_options}") -string(REPLACE "@GIT_TEST_GITPERLLIB@" "'${CMAKE_BINARY_DIR}/perl/build/lib'" git_build_options "${git_build_options}") -string(REPLACE "@GIT_TEST_MERGE_TOOLS_DIR@" "'${CMAKE_BINARY_DIR}/mergetools'" git_build_options "${git_build_options}") -string(REPLACE "@RUNTIME_PREFIX@" "'${RUNTIME_PREFIX}'" git_build_options "${git_build_options}") -string(REPLACE "@GITWEBDIR@" "'${GITWEBDIR}'" git_build_options "${git_build_options}") +string(REPLACE "@TEST_SHELL_PATH@" "'${TEST_SHELL_PATH}'" git_build_options "${git_build_options}") string(REPLACE "@USE_GETTEXT_SCHEME@" "" git_build_options "${git_build_options}") -string(REPLACE "@LOCALEDIR@" "'${LOCALEDIR}'" git_build_options "${git_build_options}") -string(REPLACE "@BROKEN_PATH_FIX@" "" git_build_options "${git_build_options}") +string(REPLACE "@USE_LIBPCRE2@" "" git_build_options "${git_build_options}") +string(REPLACE "@X@" "${EXE_EXTENSION}" git_build_options "${git_build_options}") if(USE_VCPKG) string(APPEND git_build_options "PATH=\"$PATH:$TEST_DIRECTORY/../compat/vcbuild/vcpkg/installed/x64-windows/bin\"\n") endif() -- cgit v1.2.3 From cbcc2f79117ded0161b012dc5107f181b5d87b09 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 13:10:18 +0100 Subject: GIT-BUILD-OPTIONS: wire up NO_GITWEB option Building our "gitweb" interface is optional in our Makefile and in Meson and not wired up at all with CMake, but disabling it causes a couple of tests in the t950* range that pull in "t/lib-gitweb.sh". This is because the test library knows to execute gitweb-tests based on whether or not Perl is available, but we may have Perl available and still end up not building gitweb e.g. with `make test NO_GITWEB=YesPlease`. Fix this issue by wiring up a new "NO_GITWEB" build option so that we can skip these tests in case gitweb is not built. Note that this new build option requires us to move the configuration of GIT-BUILD-OPTIONS to a later point in our Meson build instructions. But as that file is only consumed by our tests at runtime this change does not cause any issues. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- GIT-BUILD-OPTIONS.in | 1 + Makefile | 1 + contrib/buildsystems/CMakeLists.txt | 1 + meson.build | 59 +++++++++++++++++++------------------ t/lib-gitweb.sh | 5 ++++ t/test-lib.sh | 1 + 6 files changed, 40 insertions(+), 28 deletions(-) diff --git a/GIT-BUILD-OPTIONS.in b/GIT-BUILD-OPTIONS.in index 162cc39190..edff75ae16 100644 --- a/GIT-BUILD-OPTIONS.in +++ b/GIT-BUILD-OPTIONS.in @@ -24,6 +24,7 @@ LOCALEDIR=@LOCALEDIR@ NO_CURL=@NO_CURL@ NO_EXPAT=@NO_EXPAT@ NO_GETTEXT=@NO_GETTEXT@ +NO_GITWEB=@NO_GITWEB@ NO_ICONV=@NO_ICONV@ NO_PERL=@NO_PERL@ NO_PERL_CPAN_FALLBACKS=@NO_PERL_CPAN_FALLBACKS@ diff --git a/Makefile b/Makefile index f80e70702f..97e8385b66 100644 --- a/Makefile +++ b/Makefile @@ -3171,6 +3171,7 @@ GIT-BUILD-OPTIONS: FORCE -e "s|@NO_CURL@|\'$(NO_CURL)\'|" \ -e "s|@NO_EXPAT@|\'$(NO_EXPAT)\'|" \ -e "s|@NO_GETTEXT@|\'$(NO_GETTEXT)\'|" \ + -e "s|@NO_GITWEB@|\'$(NO_GITWEB)\'|" \ -e "s|@NO_ICONV@|\'$(NO_ICONV)\'|" \ -e "s|@NO_PERL@|\'$(NO_PERL)\'|" \ -e "s|@NO_PERL_CPAN_FALLBACKS@|\'$(NO_PERL_CPAN_FALLBACKS_SQ)\'|" \ diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index f45407b060..10dc54fdcb 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -1184,6 +1184,7 @@ string(REPLACE "@LOCALEDIR@" "'${LOCALEDIR}'" git_build_options "${git_build_opt string(REPLACE "@NO_CURL@" "${NO_CURL}" git_build_options "${git_build_options}") string(REPLACE "@NO_EXPAT@" "${NO_EXPAT}" git_build_options "${git_build_options}") string(REPLACE "@NO_GETTEXT@" "${NO_GETTEXT}" git_build_options "${git_build_options}") +string(REPLACE "@NO_GITWEB@" "1" git_build_options "${git_build_options}") string(REPLACE "@NO_ICONV@" "${NO_ICONV}" git_build_options "${git_build_options}") string(REPLACE "@NO_PERL@" "${NO_PERL}" git_build_options "${git_build_options}") string(REPLACE "@NO_PERL_CPAN_FALLBACKS@" "" git_build_options "${git_build_options}") diff --git a/meson.build b/meson.build index a0654a3f24..3e57793862 100644 --- a/meson.build +++ b/meson.build @@ -1456,34 +1456,6 @@ else build_options_config.set('RUNTIME_PREFIX', 'false') endif -foreach key, value : { - 'DIFF': diff.full_path(), - 'GIT_TEST_CMP': diff.full_path() + ' -u', - 'GIT_TEST_GITPERLLIB': meson.project_build_root() / 'perl', - 'GIT_TEST_MERGE_TOOLS_DIR': meson.project_source_root() / 'mergetools', - 'GIT_TEST_POPATH': meson.project_source_root() / 'po', - 'GIT_TEST_TEMPLATE_DIR': meson.project_build_root() / 'templates', - 'GIT_TEST_TEXTDOMAINDIR': meson.project_build_root() / 'po', - 'PAGER_ENV': get_option('pager_environment'), - 'PERL_PATH': perl.found() ? perl.full_path() : '', - 'PYTHON_PATH': python.found () ? python.full_path() : '', - 'SHELL_PATH': shell.full_path(), - 'TAR': tar.full_path(), - 'TEST_OUTPUT_DIRECTORY': test_output_directory, - 'TEST_SHELL_PATH': shell.full_path(), -} - if value != '' and cygpath.found() - value = run_command(cygpath, value, check: true).stdout().strip() - endif - build_options_config.set_quoted(key, value) -endforeach - -configure_file( - input: 'GIT-BUILD-OPTIONS.in', - output: 'GIT-BUILD-OPTIONS', - configuration: build_options_config, -) - git_version_file = custom_target( command: [ shell, @@ -1893,6 +1865,9 @@ subdir('contrib') gitweb_option = get_option('gitweb').disable_auto_if(not perl.found()) if gitweb_option.enabled() subdir('gitweb') + build_options_config.set('NO_GITWEB', '') +else + build_options_config.set('NO_GITWEB', '1') endif subdir('templates') @@ -1909,6 +1884,34 @@ if get_option('docs') != [] subdir('Documentation') endif +foreach key, value : { + 'DIFF': diff.full_path(), + 'GIT_TEST_CMP': diff.full_path() + ' -u', + 'GIT_TEST_GITPERLLIB': meson.project_build_root() / 'perl', + 'GIT_TEST_MERGE_TOOLS_DIR': meson.project_source_root() / 'mergetools', + 'GIT_TEST_POPATH': meson.project_source_root() / 'po', + 'GIT_TEST_TEMPLATE_DIR': meson.project_build_root() / 'templates', + 'GIT_TEST_TEXTDOMAINDIR': meson.project_build_root() / 'po', + 'PAGER_ENV': get_option('pager_environment'), + 'PERL_PATH': perl.found() ? perl.full_path() : '', + 'PYTHON_PATH': python.found () ? python.full_path() : '', + 'SHELL_PATH': shell.full_path(), + 'TAR': tar.full_path(), + 'TEST_OUTPUT_DIRECTORY': test_output_directory, + 'TEST_SHELL_PATH': shell.full_path(), +} + if value != '' and cygpath.found() + value = run_command(cygpath, value, check: true).stdout().strip() + endif + build_options_config.set_quoted(key, value) +endforeach + +configure_file( + input: 'GIT-BUILD-OPTIONS.in', + output: 'GIT-BUILD-OPTIONS', + configuration: build_options_config, +) + summary({ 'curl': curl.found(), 'expat': expat.found(), diff --git a/t/lib-gitweb.sh b/t/lib-gitweb.sh index 7f9808ec20..a6e3dd11b3 100644 --- a/t/lib-gitweb.sh +++ b/t/lib-gitweb.sh @@ -105,6 +105,11 @@ if ! test_have_prereq PERL; then test_done fi +if ! test_have_prereq GITWEB; then + skip_all='skipping gitweb tests, gitweb not available' + test_done +fi + perl -MEncode -e '$e="";decode_utf8($e, Encode::FB_CROAK)' >/dev/null 2>&1 || { skip_all='skipping gitweb tests, perl version is too old' test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index 62dfcc4aaf..1a67adb207 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -1687,6 +1687,7 @@ esac ( COLUMNS=1 && test $COLUMNS = 1 ) && test_set_prereq COLUMNS_CAN_BE_1 test -z "$NO_CURL" && test_set_prereq LIBCURL +test -z "$NO_GITWEB" && test_set_prereq GITWEB test -z "$NO_ICONV" && test_set_prereq ICONV test -z "$NO_PERL" && test_set_prereq PERL test -z "$NO_PTHREADS" && test_set_prereq PTHREADS -- cgit v1.2.3 From d963ac98ec94fd2003722a794f0168a70ea1b815 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 13:10:19 +0100 Subject: meson: enable auto-discovered "gitweb" In 7d549fe317 (meson: skip gitweb build when Perl is disabled, 2024-12-20) we have started to conditionally enable "gitweb" based on whether or not Perl is enabled. By accident though that change causes us to not build gitweb in case its feature flag is set to "auto" even if autoconfiguration determines that it could be built. This is because we use "gitweb_option.enabled()", which only checks whether the feature has been explicitly enabled. Fix the issue by using `gitweb_option.allowed()` instead, which returns true in case it is either explicitly enabled or set to "auto". This also works for the case where the feature becomes auto-disabled due to Perl not being present because we use `disable_auto_if(not perl.found())`. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 3e57793862..0064eb64f5 100644 --- a/meson.build +++ b/meson.build @@ -1863,7 +1863,7 @@ subdir('contrib') # We make sure further up that Perl is required in case the gitweb option is # enabled. gitweb_option = get_option('gitweb').disable_auto_if(not perl.found()) -if gitweb_option.enabled() +if gitweb_option.allowed() subdir('gitweb') build_options_config.set('NO_GITWEB', '') else @@ -1916,7 +1916,7 @@ summary({ 'curl': curl.found(), 'expat': expat.found(), 'gettext': intl.found(), - 'gitweb': gitweb_option.enabled(), + 'gitweb': gitweb_option.allowed(), 'https': https_backend, 'iconv': iconv.found(), 'pcre2': pcre2.found(), -- cgit v1.2.3 From d838d821c9687a789673b2ac9dff707fdc599e1e Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 14:59:29 +0100 Subject: meson: wire up support for AsciiDoctor While our Makefile supports both Asciidoc and AsciiDoctor, our Meson build instructions only support the former. Wire up support for the latter, as well. Our Makefile always favors Asciidoc, but Meson will automatically figure out which of both to use based on whether they are installed or not. To keep compatibility with our Makefile it favors Asciidoc over Asciidoctor in case both are available. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/meson.build | 110 ++++++++++++++++++++++++++++++++++------------ meson_options.txt | 2 + 2 files changed, 84 insertions(+), 28 deletions(-) diff --git a/Documentation/meson.build b/Documentation/meson.build index fca3eab1f1..acd6d86ec7 100644 --- a/Documentation/meson.build +++ b/Documentation/meson.build @@ -204,29 +204,87 @@ manpages = { 'gitworkflows.txt' : 7, } -asciidoc = find_program('asciidoc') -git = find_program('git', required: false) -xmlto = find_program('xmlto') +docs_backend = get_option('docs_backend') +if docs_backend == 'auto' + if find_program('asciidoc', required: false).found() + docs_backend = 'asciidoc' + elif find_program('asciidoctor', required: false).found() + docs_backend = 'asciidoctor' + else + error('Neither asciidoc nor asciidoctor were found.') + endif +endif -asciidoc_conf = custom_target( - command: [ - shell, - meson.project_source_root() / 'GIT-VERSION-GEN', - meson.project_source_root(), - '@INPUT@', - '@OUTPUT@', - ], - input: meson.current_source_dir() / 'asciidoc.conf.in', - output: 'asciidoc.conf', - depends: [git_version_file], - env: version_gen_environment, -) +if docs_backend == 'asciidoc' + asciidoc = find_program('asciidoc', required: true) + asciidoc_html = 'xhtml11' + asciidoc_docbook = 'docbook' + xmlto_extra = [ ] -asciidoc_common_options = [ - asciidoc, - '--conf-file=' + asciidoc_conf.full_path(), - '--attribute=build_dir=' + meson.current_build_dir(), -] + asciidoc_conf = custom_target( + command: [ + shell, + meson.project_source_root() / 'GIT-VERSION-GEN', + meson.project_source_root(), + '@INPUT@', + '@OUTPUT@', + ], + input: meson.current_source_dir() / 'asciidoc.conf.in', + output: 'asciidoc.conf', + depends: [git_version_file], + env: version_gen_environment, + ) + + asciidoc_common_options = [ + asciidoc, + '--conf-file=' + asciidoc_conf.full_path(), + '--attribute=build_dir=' + meson.current_build_dir(), + ] + + documentation_deps = [ + asciidoc_conf, + ] +elif docs_backend == 'asciidoctor' + asciidoctor = find_program('asciidoctor', required: true) + asciidoc_html = 'xhtml5' + asciidoc_docbook = 'docbook5' + xmlto_extra = [ + '--skip-validation', + '-x', meson.current_source_dir() / 'manpage.xsl', + ] + + asciidoctor_extensions = custom_target( + command: [ + shell, + meson.project_source_root() / 'GIT-VERSION-GEN', + meson.project_source_root(), + '@INPUT@', + '@OUTPUT@', + ], + input: meson.current_source_dir() / 'asciidoctor-extensions.rb.in', + output: 'asciidoctor-extensions.rb', + depends: [git_version_file], + env: version_gen_environment, + ) + + asciidoc_common_options = [ + asciidoctor, + '--attribute', 'compat-mode', + '--attribute', 'tabsize=8', + '--attribute', 'litdd=--', + '--attribute', 'docinfo=shared', + '--attribute', 'build_dir=' + meson.current_build_dir(), + '--load-path', meson.current_build_dir(), + '--require', 'asciidoctor-extensions', + ] + + documentation_deps = [ + asciidoctor_extensions, + ] +endif + +git = find_program('git', required: false) +xmlto = find_program('xmlto') cmd_lists = [ 'cmds-ancillaryinterrogators.txt', @@ -243,10 +301,6 @@ cmd_lists = [ 'cmds-foreignscminterface.txt', ] -documentation_deps = [ - asciidoc_conf, -] - documentation_deps += custom_target( command: [ perl, @@ -278,7 +332,7 @@ foreach manpage, category : manpages if get_option('docs').contains('man') manpage_xml_target = custom_target( command: asciidoc_common_options + [ - '--backend=docbook', + '--backend=' + asciidoc_docbook, '--doctype=manpage', '--out-file=@OUTPUT@', meson.current_source_dir() / manpage, @@ -301,7 +355,7 @@ foreach manpage, category : manpages manpage_xml_target, '-o', meson.current_build_dir(), - ], + ] + xmlto_extra, output: manpage_path, install: true, install_dir: get_option('mandir') / 'man' + category.to_string(), @@ -311,7 +365,7 @@ foreach manpage, category : manpages if get_option('docs').contains('html') and category == 1 custom_target( command: asciidoc_common_options + [ - '--backend=xhtml11', + '--backend=' + asciidoc_html, '--doctype=manpage', '--out-file=@OUTPUT@', meson.current_source_dir() / manpage, diff --git a/meson_options.txt b/meson_options.txt index 4be7eab399..f50bb40cdf 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -85,6 +85,8 @@ option('docs', type: 'array', choices: ['man', 'html'], value: [], description: 'Which documenattion formats to build and install.') option('default_help_format', type: 'combo', choices: ['man', 'html'], value: 'man', description: 'Default format used when executing git-help(1).') +option('docs_backend', type: 'combo', choices: ['asciidoc', 'asciidoctor', 'auto'], value: 'auto', + description: 'Which backend to use to generate documentation.') # Testing. option('tests', type: 'boolean', value: true, -- cgit v1.2.3 From 2a8bd34c5576e02fed38d85dc5c90ffb9d4ecfb3 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 14:59:30 +0100 Subject: meson: properly wire up dependencies for our docs A couple of Meson documentation targets use `meson.current_source_dir()` to resolve inputs. This has the downside that it does not automagically make Meson track these inputs as a dependency. After all, string arguments really can be anything, even if they happen to match an actual filesystem path. Adapt these build targets to instead use inputs. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/meson.build | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/Documentation/meson.build b/Documentation/meson.build index acd6d86ec7..b3c8b6c563 100644 --- a/Documentation/meson.build +++ b/Documentation/meson.build @@ -229,7 +229,7 @@ if docs_backend == 'asciidoc' '@INPUT@', '@OUTPUT@', ], - input: meson.current_source_dir() / 'asciidoc.conf.in', + input: 'asciidoc.conf.in', output: 'asciidoc.conf', depends: [git_version_file], env: version_gen_environment, @@ -261,7 +261,7 @@ elif docs_backend == 'asciidoctor' '@INPUT@', '@OUTPUT@', ], - input: meson.current_source_dir() / 'asciidoctor-extensions.rb.in', + input: 'asciidoctor-extensions.rb.in', output: 'asciidoctor-extensions.rb', depends: [git_version_file], env: version_gen_environment, @@ -304,10 +304,11 @@ cmd_lists = [ documentation_deps += custom_target( command: [ perl, - meson.current_source_dir() / 'cmd-list.perl', + '@INPUT@', meson.project_source_root(), meson.current_build_dir(), ] + cmd_lists, + input: 'cmd-list.perl', output: cmd_lists ) @@ -315,7 +316,7 @@ foreach mode : [ 'diff', 'merge' ] documentation_deps += custom_target( command: [ shell, - meson.current_source_dir() / 'generate-mergetool-list.sh', + '@INPUT@', '..', 'diff', '@OUTPUT@' @@ -324,6 +325,7 @@ foreach mode : [ 'diff', 'merge' ] 'MERGE_TOOLS_DIR=' + meson.project_source_root() / 'mergetools', 'TOOL_MODE=' + mode, ], + input: 'generate-mergetool-list.sh', output: 'mergetools-' + mode + '.txt', ) endforeach @@ -335,9 +337,10 @@ foreach manpage, category : manpages '--backend=' + asciidoc_docbook, '--doctype=manpage', '--out-file=@OUTPUT@', - meson.current_source_dir() / manpage, + '@INPUT@', ], depends: documentation_deps, + input: manpage, output: fs.stem(manpage) + '.xml', ) @@ -345,10 +348,8 @@ foreach manpage, category : manpages manpage_target = custom_target( command: [ xmlto, - '-m', - meson.current_source_dir() / 'manpage-normal.xsl', - '-m', - meson.current_source_dir() / 'manpage-bold-literal.xsl', + '-m', '@INPUT0@', + '-m', '@INPUT1@', '--stringparam', 'man.base.url.for.relative.links=' + get_option('prefix') / get_option('mandir'), 'man', @@ -356,6 +357,10 @@ foreach manpage, category : manpages '-o', meson.current_build_dir(), ] + xmlto_extra, + input: [ + 'manpage-normal.xsl', + 'manpage-bold-literal.xsl', + ], output: manpage_path, install: true, install_dir: get_option('mandir') / 'man' + category.to_string(), @@ -368,9 +373,10 @@ foreach manpage, category : manpages '--backend=' + asciidoc_html, '--doctype=manpage', '--out-file=@OUTPUT@', - meson.current_source_dir() / manpage, + '@INPUT@', ], depends: documentation_deps, + input: manpage, output: fs.stem(manpage) + '.html', install: true, install_dir: get_option('datadir') / 'doc/git-doc', -- cgit v1.2.3 From b88540045c3d70dbf4138c8f32209fea32e40d90 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 14:59:31 +0100 Subject: meson: fix generation of merge tools Our buildsystems generate a list of diff and merge tools that ultimately end up in our documentation. And while Meson does wire up the logic, it tries to use the TOOL_MODE environment variable to set up the mode. This is wrong though: the mode is set via an argument that we have fixed to 'diff' mode by accident. Fix this such that merge tools are properly generated. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/meson.build | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Documentation/meson.build b/Documentation/meson.build index b3c8b6c563..c2512328ca 100644 --- a/Documentation/meson.build +++ b/Documentation/meson.build @@ -318,12 +318,11 @@ foreach mode : [ 'diff', 'merge' ] shell, '@INPUT@', '..', - 'diff', + mode, '@OUTPUT@' ], env: [ 'MERGE_TOOLS_DIR=' + meson.project_source_root() / 'mergetools', - 'TOOL_MODE=' + mode, ], input: 'generate-mergetool-list.sh', output: 'mergetools-' + mode + '.txt', -- cgit v1.2.3 From 0696ebe9ce533cf3c839c9eb2bd2331c8fa0f014 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 14:59:32 +0100 Subject: meson: generate HTML pages for all man page categories When generating HTML pages for our man pages we only generate them for category 1 in Meson, which are the pages corresponding to our built-in commands. I cannot tell why I added this filter though: our Makefile installs all man pages, so a Meson-based build misses out on many of them. Fix this by removing the filter. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/meson.build b/Documentation/meson.build index c2512328ca..48583e9a7f 100644 --- a/Documentation/meson.build +++ b/Documentation/meson.build @@ -366,7 +366,7 @@ foreach manpage, category : manpages ) endif - if get_option('docs').contains('html') and category == 1 + if get_option('docs').contains('html') custom_target( command: asciidoc_common_options + [ '--backend=' + asciidoc_html, -- cgit v1.2.3 From 851ecc4290cbdb57f36f10b77da9c1ae13c10469 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 14:59:33 +0100 Subject: Documentation: inline user-manual.conf When generating our user manual we set up a bit of extra configuration compared to our normal configuration. This is done by having an extra "user-manual.conf" file that Asciidoc seems to pull in automatically due to matching filenames with "user-manual.txt". This dependency is quite hidden though and thus easy to miss. Furthermore, it seems that Asciidoc does not know to pull it in for out-of-tree builds where we use relative paths. The setup in AsciiDoctor is somewhat different: instead of having two sets of configuration, we condition the use of manual-specific configs based on whether the document type is "book". And as we only build our user manual with that type this is sufficient. Use the same trick for our user manual by inlining the configuration into "asciidoc.conf.in" and making it conditional on whether or not "doctype-book" is defined. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/Makefile | 2 +- Documentation/asciidoc.conf.in | 10 ++++++++++ Documentation/user-manual.conf | 11 ----------- 3 files changed, 11 insertions(+), 12 deletions(-) delete mode 100644 Documentation/user-manual.conf diff --git a/Documentation/Makefile b/Documentation/Makefile index a89823e1d1..4f152077dd 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -362,7 +362,7 @@ manpage-cmd = $(QUIET_XMLTO)$(XMLTO) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $< %.xml : %.txt $(ASCIIDOC_DEPS) $(QUIET_ASCIIDOC)$(TXT_TO_XML) -d manpage -o $@ $< -user-manual.xml: user-manual.txt user-manual.conf $(ASCIIDOC_DEPS) +user-manual.xml: user-manual.txt $(ASCIIDOC_DEPS) $(QUIET_ASCIIDOC)$(TXT_TO_XML) -d book -o $@ $< technical/api-index.txt: technical/api-index-skel.txt \ diff --git a/Documentation/asciidoc.conf.in b/Documentation/asciidoc.conf.in index b89bccf230..f2aef6cb79 100644 --- a/Documentation/asciidoc.conf.in +++ b/Documentation/asciidoc.conf.in @@ -25,12 +25,22 @@ manmanual=Git Manual mansource=Git @GIT_VERSION@ revdate=@GIT_DATE@ +ifdef::doctype-book[] +[titles] + underlines="__","==","--","~~","^^" +endif::doctype-book[] + ifdef::backend-docbook[] [linkgit-inlinemacro] +ifndef::doctype-book[] {0%{target}} {0#} {0#{target}{0}} {0#} +endif::doctype-book[] +ifdef::doctype-book[] +{target}{0?({0})} +endif::doctype-book[] [literal-inlinemacro] {eval:re.sub(r'(<[-a-zA-Z0-9.]+>)', r'\1', re.sub(r'([\[\s|()>]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@,\/_^\$]+\.?)+)',r'\1\2', re.sub(r'(\.\.\.?)([^\]$.])', r'\1\2', macros.passthroughs[int(attrs['passtext'][1:-1])] if attrs['passtext'][1:-1].isnumeric() else attrs['passtext'][1:-1])))} diff --git a/Documentation/user-manual.conf b/Documentation/user-manual.conf deleted file mode 100644 index 0148f126dc..0000000000 --- a/Documentation/user-manual.conf +++ /dev/null @@ -1,11 +0,0 @@ -[titles] - underlines="__","==","--","~~","^^" - -[attributes] -caret=^ -startsb=[ -endsb=] -tilde=~ - -[linkgit-inlinemacro] -{target}{0?({0})} -- cgit v1.2.3 From ae0b33939d233fa340f1ebb768588dc46a128e4c Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 14:59:34 +0100 Subject: meson: generate user manual Our documentation contains a user manual that gives people a short introduction to Git. Our Makefile knows to generate the manual into three different formats: an HTML page, a PDF and an info page. The Meson build instructions don't yet generate any of these. While wiring up all these formats I hit a couple of road blocks with how we generate our info pages. Even though I eventually resolved these, it made me question whether anybody actually uses info pages in the first place. Checking through a couple of downstream consumers I couldn't find a single user of either the info pages nor of our PDF manual in Arch Linux, Debian, Fedora, Ubuntu, FreeBSD or OpenBSDFedora. So it's rather safe to assume that there aren't really any users out there, and thus the added complexity does not seem worth it. Wire up support for building the user manual in HTML format and conciously skip over the other two formats. This is basically a form of silent deprecation: if people out there use the other two formats they will eventually complain about them missing in Meson, which means we can wire them up at a later point. If they don't we can phase out these formats eventually. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/meson.build | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/Documentation/meson.build b/Documentation/meson.build index 48583e9a7f..404cb20d10 100644 --- a/Documentation/meson.build +++ b/Documentation/meson.build @@ -382,3 +382,35 @@ foreach manpage, category : manpages ) endif endforeach + +if get_option('docs').contains('html') + xsltproc = find_program('xsltproc') + + user_manual_xml = custom_target( + command: asciidoc_common_options + [ + '--backend=' + asciidoc_docbook, + '--doctype=book', + '--out-file=@OUTPUT@', + '@INPUT@', + ], + input: 'user-manual.txt', + output: 'user-manual.xml', + depends: documentation_deps, + ) + + custom_target( + command: [ + xsltproc, + '--xinclude', + '--stringparam', 'html.stylesheet', 'docbook-xsl.css', + '--param', 'generate.consistent.ids', '1', + '--output', '@OUTPUT@', + '@INPUT@', + user_manual_xml, + ], + input: 'docbook.xsl', + output: 'user-manual.html', + install: true, + install_dir: get_option('datadir') / 'doc/git-doc', + ) +endif -- cgit v1.2.3 From 88e08b92e9a55fa453d44b26061a6a67a7eefafc Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 14:59:35 +0100 Subject: Documentation: refactor "api-index.sh" for out-of-tree builds The "api-index.sh" script generates an index of API-related documentation. The script does not handle out-of-tree builds and thus cannot be used easily by Meson. Refactor it to be independent of locations by both accepting a source directory where the API docs live as well as a path to an output file. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/Makefile | 2 +- Documentation/technical/api-index.sh | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Documentation/Makefile b/Documentation/Makefile index 4f152077dd..b2d146c44f 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -367,7 +367,7 @@ user-manual.xml: user-manual.txt $(ASCIIDOC_DEPS) technical/api-index.txt: technical/api-index-skel.txt \ technical/api-index.sh $(patsubst %,%.txt,$(API_DOCS)) - $(QUIET_GEN)cd technical && '$(SHELL_PATH_SQ)' ./api-index.sh + $(QUIET_GEN)'$(SHELL_PATH_SQ)' technical/api-index.sh ./technical ./technical/api-index.txt technical/%.html: ASCIIDOC_EXTRA += -a git-relative-html-prefix=../ $(patsubst %,%.html,$(API_DOCS) technical/api-index $(TECH_DOCS)): %.html : %.txt \ diff --git a/Documentation/technical/api-index.sh b/Documentation/technical/api-index.sh index 9c3f4131b8..2964885574 100755 --- a/Documentation/technical/api-index.sh +++ b/Documentation/technical/api-index.sh @@ -1,6 +1,17 @@ #!/bin/sh +if test $# -ne 2 +then + echo >&2 "USAGE: $0 " + exit 1 +fi + +SOURCE_DIR="$1" +OUTPUT="$2" + ( + cd "$SOURCE_DIR" + c=//////////////////////////////////////////////////////////////// skel=api-index-skel.txt sed -e '/^\/\/ table of contents begin/q' "$skel" @@ -18,11 +29,11 @@ done echo "$c" sed -n -e '/^\/\/ table of contents end/,$p' "$skel" -) >api-index.txt+ +) >"$OUTPUT"+ -if test -f api-index.txt && cmp api-index.txt api-index.txt+ >/dev/null +if test -f "$OUTPUT" && cmp "$OUTPUT" "$OUTPUT"+ >/dev/null then - rm -f api-index.txt+ + rm -f "$OUTPUT"+ else - mv api-index.txt+ api-index.txt + mv "$OUTPUT"+ "$OUTPUT" fi -- cgit v1.2.3 From 8922506cb2c34527f8b2321b4f7a4b454a325a07 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 14:59:36 +0100 Subject: Documentation: refactor "howto-index.sh" for out-of-tree builds The "howto-index.sh" is used to generate an index of our how-to docs. It receives as input the paths to these documents, which would typically be relative to the "Documentation/" directory in Makefile-based builds. In an out-of-tree build though it will get relative that may be rooted somewhere else entirely. The file paths do end up in the generated index, and the expectation is that they should always start with "howto/". But for out-of-tree builds we would populate it with the paths relative to the build directory, which is wrong. Fix the issue by using `$(basename "$file")` to generate the path. While at it, move the script into "howto/" to align it with the location of the comparable "api-index.sh" script. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/Makefile | 4 +-- Documentation/howto-index.sh | 56 -------------------------------------- Documentation/howto/howto-index.sh | 56 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 58 deletions(-) delete mode 100755 Documentation/howto-index.sh create mode 100755 Documentation/howto/howto-index.sh diff --git a/Documentation/Makefile b/Documentation/Makefile index b2d146c44f..e284ec8b98 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -411,8 +411,8 @@ gitman.info: gitman.texi $(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml $(QUIET_DB2TEXI)$(DOCBOOK2X_TEXI) --to-stdout $*.xml >$@ -howto-index.txt: howto-index.sh $(HOWTO_TXT) - $(QUIET_GEN)'$(SHELL_PATH_SQ)' ./howto-index.sh $(sort $(HOWTO_TXT)) >$@ +howto-index.txt: howto/howto-index.sh $(HOWTO_TXT) + $(QUIET_GEN)'$(SHELL_PATH_SQ)' ./howto/howto-index.sh $(sort $(HOWTO_TXT)) >$@ $(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt $(ASCIIDOC_DEPS) $(QUIET_ASCIIDOC)$(TXT_TO_HTML) $*.txt diff --git a/Documentation/howto-index.sh b/Documentation/howto-index.sh deleted file mode 100755 index 167b363668..0000000000 --- a/Documentation/howto-index.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/sh - -cat <<\EOF -Git Howto Index -=============== - -Here is a collection of mailing list postings made by various -people describing how they use Git in their workflow. - -EOF - -for txt -do - title=$(expr "$txt" : '.*/\(.*\)\.txt$') - from=$(sed -ne ' - /^$/q - /^From:[ ]/{ - s/// - s/^[ ]*// - s/[ ]*$// - s/^/by / - p - } - ' "$txt") - - abstract=$(sed -ne ' - /^Abstract:[ ]/{ - s/^[^ ]*// - x - s/.*// - x - : again - /^[ ]/{ - s/^[ ]*// - H - n - b again - } - x - p - q - }' "$txt") - - if grep 'Content-type: text/asciidoc' >/dev/null $txt - then - file=$(expr "$txt" : '\(.*\)\.txt$').html - else - file="$txt" - fi - - echo "* link:$file[$title] $from -$abstract - -" - -done diff --git a/Documentation/howto/howto-index.sh b/Documentation/howto/howto-index.sh new file mode 100755 index 0000000000..eecd123a93 --- /dev/null +++ b/Documentation/howto/howto-index.sh @@ -0,0 +1,56 @@ +#!/bin/sh + +cat <<\EOF +Git Howto Index +=============== + +Here is a collection of mailing list postings made by various +people describing how they use Git in their workflow. + +EOF + +for txt +do + title=$(expr "$txt" : '.*/\(.*\)\.txt$') + from=$(sed -ne ' + /^$/q + /^From:[ ]/{ + s/// + s/^[ ]*// + s/[ ]*$// + s/^/by / + p + } + ' "$txt") + + abstract=$(sed -ne ' + /^Abstract:[ ]/{ + s/^[^ ]*// + x + s/.*// + x + : again + /^[ ]/{ + s/^[ ]*// + H + n + b again + } + x + p + q + }' "$txt") + + if grep 'Content-type: text/asciidoc' >/dev/null $txt + then + file=$(expr "$txt" : '\(.*\)\.txt$').html + else + file="$txt" + fi + + echo "* link:howto/$(basename "$file")[$title] $from +$abstract + +" + +done -- cgit v1.2.3 From bcf7edee09e8f9c1779fafa953832f63e9a23545 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 14:59:37 +0100 Subject: meson: generate articles While the Meson build system already knows to generate man pages and our user manual, it does not yet generate the random assortment of articles that we have. Plug this gap. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/howto/meson.build | 62 ++++++++++++++++++++++++++++++++++ Documentation/meson.build | 36 ++++++++++++++++++++ Documentation/technical/meson.build | 66 +++++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+) create mode 100644 Documentation/howto/meson.build create mode 100644 Documentation/technical/meson.build diff --git a/Documentation/howto/meson.build b/Documentation/howto/meson.build new file mode 100644 index 0000000000..c023c10416 --- /dev/null +++ b/Documentation/howto/meson.build @@ -0,0 +1,62 @@ +howto_sources = [ + 'coordinate-embargoed-releases.txt', + 'keep-canonical-history-correct.txt', + 'maintain-git.txt', + 'new-command.txt', + 'rebase-from-internal-branch.txt', + 'rebuild-from-update-hook.txt', + 'recover-corrupted-blob-object.txt', + 'recover-corrupted-object-harder.txt', + 'revert-a-faulty-merge.txt', + 'revert-branch-rebase.txt', + 'separating-topic-branches.txt', + 'setup-git-server-over-http.txt', + 'update-hook-example.txt', + 'use-git-daemon.txt', + 'using-merge-subtree.txt', + 'using-signed-tag-in-pull-request.txt', +] + +howto_index = custom_target( + command: [ + shell, + meson.current_source_dir() / 'howto-index.sh', + '@INPUT@', + ], + env: script_environment, + capture: true, + input: howto_sources, + output: 'howto-index.txt', +) + +custom_target( + command: asciidoc_html_options, + input: howto_index, + output: 'howto-index.html', + depends: documentation_deps, + install: true, + install_dir: get_option('datadir') / 'doc/git-doc', +) + +foreach howto : howto_sources + howto_stripped = custom_target( + command: [ + find_program('sed'), + '-e', + '1,/^$/d', + '@INPUT@', + ], + input: howto, + output: fs.stem(howto) + '.stripped', + capture: true, + ) + + custom_target( + command: asciidoc_html_options, + input: howto_stripped, + output: fs.stem(howto_stripped.full_path()) + '.html', + depends: documentation_deps, + install: true, + install_dir: get_option('datadir') / 'doc/git-doc/howto', + ) +endforeach diff --git a/Documentation/meson.build b/Documentation/meson.build index 404cb20d10..8c6ff0bce1 100644 --- a/Documentation/meson.build +++ b/Documentation/meson.build @@ -413,4 +413,40 @@ if get_option('docs').contains('html') install: true, install_dir: get_option('datadir') / 'doc/git-doc', ) + + articles = [ + 'DecisionMaking.txt', + 'MyFirstContribution.txt', + 'MyFirstObjectWalk.txt', + 'ReviewingGuidelines.txt', + 'SubmittingPatches', + 'ToolsForGit.txt', + 'git-bisect-lk2009.txt', + 'git-tools.txt', + ] + + foreach article : articles + custom_target( + command: asciidoc_common_options + [ + '--backend=' + asciidoc_html, + '--out-file=@OUTPUT@', + '@INPUT@', + ], + input: article, + output: fs.stem(article) + '.html', + depends: documentation_deps, + install: true, + install_dir: get_option('datadir') / 'doc/git-doc', + ) + endforeach + + asciidoc_html_options = asciidoc_common_options + [ + '--backend=' + asciidoc_html, + '--out-file=@OUTPUT@', + '--attribute', 'git-relative-html-prefix=../', + '@INPUT@', + ] + + subdir('howto') + subdir('technical') endif diff --git a/Documentation/technical/meson.build b/Documentation/technical/meson.build new file mode 100644 index 0000000000..21dfb8b5c9 --- /dev/null +++ b/Documentation/technical/meson.build @@ -0,0 +1,66 @@ +api_docs = [ + 'api-error-handling.txt', + 'api-merge.txt', + 'api-parse-options.txt', + 'api-simple-ipc.txt', + 'api-trace2.txt', +] + +articles = [ + 'bitmap-format.txt', + 'build-systems.txt', + 'bundle-uri.txt', + 'commit-graph.txt', + 'directory-rename-detection.txt', + 'hash-function-transition.txt', + 'long-running-process-protocol.txt', + 'multi-pack-index.txt', + 'packfile-uri.txt', + 'pack-heuristics.txt', + 'parallel-checkout.txt', + 'partial-clone.txt', + 'platform-support.txt', + 'racy-git.txt', + 'reftable.txt', + 'remembering-renames.txt', + 'repository-version.txt', + 'rerere.txt', + 'scalar.txt', + 'send-pack-pipeline.txt', + 'shallow.txt', + 'sparse-checkout.txt', + 'sparse-index.txt', + 'trivial-merge.txt', + 'unit-tests.txt', +] + +api_index = custom_target( + command: [ + shell, + meson.current_source_dir() / 'api-index.sh', + meson.current_source_dir(), + '@OUTPUT@', + ], + env: script_environment, + input: api_docs, + output: 'api-index.txt', +) + +custom_target( + command: asciidoc_html_options, + input: api_index, + output: 'api-index.html', + depends: documentation_deps, + install: true, + install_dir: get_option('datadir') / 'doc/git-doc/technical', +) + +foreach article : api_docs + articles + custom_target( + command: asciidoc_html_options, + input: article, + output: fs.stem(article) + '.html', + install: true, + install_dir: get_option('datadir') / 'doc/git-doc/technical', + ) +endforeach -- cgit v1.2.3 From 7a3136e5c713c4a5ed2af51ccb8abb5cfa3d98bf Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 14:59:38 +0100 Subject: meson: install static files for HTML documentation Now that we generate man pages, articles and user manual with Meson the only thing that is still missing in an installation of HTML documents is a couple of static files. Wire these up to finalize Meson's support for generating HTML documentation. Diffing an installation that uses our Makefile with an installation that uses Meson only surfaces a couple of discepancies now: - Meson doesn't install "everyday.html" and "git-remote-helpers.html". These files are marked as obsolete and don't contain any useful information anymore: they simply point to their modern equivalents. - Meson doesn't install "*.txt" files when asking for HTML docs. I'm not sure why our Makefiles do this in the first place, and it does seem like the resulting installation is fully functional even without those files. Other than that, both layout and file contents are the exact same. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/meson.build | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Documentation/meson.build b/Documentation/meson.build index 8c6ff0bce1..4d95111565 100644 --- a/Documentation/meson.build +++ b/Documentation/meson.build @@ -384,6 +384,27 @@ foreach manpage, category : manpages endforeach if get_option('docs').contains('html') + configure_file( + input: 'docinfo-html.in', + output: 'docinfo.html', + copy: true, + install: true, + install_dir: get_option('datadir') / 'doc/git-doc', + ) + + configure_file( + input: 'docbook-xsl.css', + output: 'docbook-xsl.css', + copy: true, + install: true, + install_dir: get_option('datadir') / 'doc/git-doc', + ) + + install_symlink('index.html', + install_dir: get_option('datadir') / 'doc/git-doc', + pointing_to: 'git.html', + ) + xsltproc = find_program('xsltproc') user_manual_xml = custom_target( -- cgit v1.2.3 From d8af27d309c3637d05bd6b4957b3667c04dc861e Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 14:59:39 +0100 Subject: t/Makefile: make "check-meson" work with Dash The "check-meson" target uses process substitution to check whether extracted contents from "meson.build" match expected contents. Process substitution is unportable though and thus the target will fail when using for example Dash. Fix this by writing data into a temporary directory. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- t/.gitignore | 1 + t/Makefile | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/t/.gitignore b/t/.gitignore index 91cf5772fe..3e6b0f2cc5 100644 --- a/t/.gitignore +++ b/t/.gitignore @@ -2,4 +2,5 @@ /test-results /.prove /chainlinttmp +/mesontmp /out/ diff --git a/t/Makefile b/t/Makefile index 290fb03ff0..daa5fcae86 100644 --- a/t/Makefile +++ b/t/Makefile @@ -103,6 +103,7 @@ clean-except-prove-cache: clean-chainlint clean: clean-except-prove-cache $(RM) -r '$(TEST_RESULTS_DIRECTORY_SQ)' + $(RM) -r mesontmp $(RM) .prove clean-chainlint: @@ -116,16 +117,17 @@ check-chainlint: check-meson: @# awk acts up when trying to match single quotes, so we use \047 instead. - @printf "%s\n" \ + @mkdir -p mesontmp && \ + printf "%s\n" \ "integration_tests t[0-9][0-9][0-9][0-9]-*.sh" \ "unit_test_programs unit-tests/t-*.c" \ "clar_test_suites unit-tests/u-*.c" | \ while read -r variable pattern; do \ - meson_tests=$$(awk "/^$$variable = \[\$$/ {flag=1 ; next } /^]$$/ { flag=0 } flag { gsub(/^ \047/, \"\"); gsub(/\047,\$$/, \"\"); print }" meson.build) && \ - actual_tests=$$(ls $$pattern) && \ - if test "$$meson_tests" != "$$actual_tests"; then \ + awk "/^$$variable = \[\$$/ {flag=1 ; next } /^]$$/ { flag=0 } flag { gsub(/^ \047/, \"\"); gsub(/\047,\$$/, \"\"); print }" meson.build >mesontmp/meson.txt && \ + ls $$pattern >mesontmp/actual.txt && \ + if ! cmp mesontmp/meson.txt mesontmp/actual.txt; then \ echo "Meson tests differ from actual tests:"; \ - diff -u <(echo "$$meson_tests") <(echo "$$actual_tests"); \ + diff -u mesontmp/meson.txt mesontmp/actual.txt; \ exit 1; \ fi; \ done -- cgit v1.2.3 From 5419445b4d19b0979b14f239fe2362210174f613 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 27 Dec 2024 14:59:40 +0100 Subject: Documentation: wire up sanity checks for Meson Wire up sanity checks for Meson to verify that no man pages are missing. This check is similar to the same check we already have for our tests. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- Documentation/.gitignore | 1 + Documentation/Makefile | 16 ++++++++++++++++ Documentation/meson.build | 31 +++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/Documentation/.gitignore b/Documentation/.gitignore index 649df89474..9f4bb3c4bf 100644 --- a/Documentation/.gitignore +++ b/Documentation/.gitignore @@ -12,6 +12,7 @@ cmds-*.txt mergetools-*.txt SubmittingPatches.txt tmp-doc-diff/ +tmp-meson-diff/ GIT-ASCIIDOCFLAGS /.build/ /GIT-EXCLUDED-PROGRAMS diff --git a/Documentation/Makefile b/Documentation/Makefile index e284ec8b98..aedfe99d1d 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -339,6 +339,7 @@ clean: $(RM) $(cmds_txt) $(mergetools_txt) *.made $(RM) GIT-ASCIIDOCFLAGS $(RM) asciidoc.conf asciidoctor-extensions.rb + $(RM) -rf tmp-meson-diff docinfo.html: docinfo-html.in $(QUIET_GEN)$(RM) $@ && cat $< >$@ @@ -494,6 +495,20 @@ lint-docs-fsck-msgids: $(LINT_DOCS_FSCK_MSGIDS) lint-docs-manpages: $(QUIET_GEN)./lint-manpages.sh +.PHONY: lint-docs-meson +lint-docs-meson: + @# awk acts up when trying to match single quotes, so we use \047 instead. + @mkdir -p tmp-meson-diff && \ + awk "/^manpages = {$$/ {flag=1 ; next } /^}$$/ { flag=0 } flag { gsub(/^ \047/, \"\"); gsub(/\047 : [157],\$$/, \"\"); print }" meson.build | \ + grep -v -e '#' -e '^$$' | \ + sort >tmp-meson-diff/meson.txt && \ + ls git*.txt scalar.txt | grep -v -e git-bisect-lk2009.txt -e git-tools.txt >tmp-meson-diff/actual.txt && \ + if ! cmp tmp-meson-diff/meson.txt tmp-meson-diff/actual.txt; then \ + echo "Meson man pages differ from actual man pages:"; \ + diff -u tmp-meson-diff/meson.txt tmp-meson-diff/actual.txt; \ + exit 1; \ + fi + ## Lint: list of targets above .PHONY: lint-docs lint-docs: lint-docs-fsck-msgids @@ -501,6 +516,7 @@ lint-docs: lint-docs-gitlink lint-docs: lint-docs-man-end-blurb lint-docs: lint-docs-man-section-order lint-docs: lint-docs-manpages +lint-docs: lint-docs-meson ifeq ($(wildcard po/Makefile),po/Makefile) doc-l10n install-l10n:: diff --git a/Documentation/meson.build b/Documentation/meson.build index 4d95111565..2a26fa8a5f 100644 --- a/Documentation/meson.build +++ b/Documentation/meson.build @@ -471,3 +471,34 @@ if get_option('docs').contains('html') subdir('howto') subdir('technical') endif + +# Sanity check that we are not missing any tests present in 't/'. This check +# only runs once at configure time and is thus best-effort, only. Furthermore, +# it only verifies man pages for the sake of simplicity. +configured_manpages = manpages.keys() + [ 'git-bisect-lk2009.txt', 'git-tools.txt' ] +actual_manpages = run_command(shell, '-c', 'ls git*.txt scalar.txt', + check: true, + env: script_environment, +).stdout().strip().split('\n') + +if configured_manpages != actual_manpages + missing_manpage = [ ] + foreach actual_manpage : actual_manpages + if actual_manpage not in configured_manpages + missing_manpage += actual_manpage + endif + endforeach + if missing_manpage.length() > 0 + error('Man page found, but not configured:\n\n - ' + '\n - '.join(missing_manpage)) + endif + + superfluous_manpage = [ ] + foreach configured_manpage : configured_manpages + if configured_manpage not in actual_manpages + superfluous_manpage += configured_manpage + endif + endforeach + if superfluous_manpage.length() > 0 + error('Man page configured, but not found:\n\n - ' + '\n - '.join(superfluous_manpage)) + endif +endif -- cgit v1.2.3 From 24027256aa9614a445563707a72af7ce5ff49b5b Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 27 Dec 2024 12:25:30 -0800 Subject: sign-compare: avoid comparing ptrdiff with an int/unsigned Instead, offset the base pointer with integer and compare it with the other pointer. Signed-off-by: Junio C Hamano --- shallow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shallow.c b/shallow.c index b8fcfbef0f..b54244ffa9 100644 --- a/shallow.c +++ b/shallow.c @@ -534,7 +534,7 @@ static uint32_t *paint_alloc(struct paint_info *info) unsigned nr = DIV_ROUND_UP(info->nr_bits, 32); unsigned size = nr * sizeof(uint32_t); void *p; - if (!info->pool_count || size > info->end - info->free) { + if (!info->pool_count || info->end < info->free + size) { if (size > POOL_SIZE) BUG("pool size too small for %d in paint_alloc()", size); -- cgit v1.2.3 From 40fdd46b7f90b40f58a2b9f4bba5735c29dc82a8 Mon Sep 17 00:00:00 2001 From: Alexander Shopov Date: Sat, 21 Dec 2024 18:30:14 +0100 Subject: l10n: bg.po: Updated Bulgarian translation (5804t) Signed-off-by: Alexander Shopov --- po/bg.po | 357 +++++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 270 insertions(+), 87 deletions(-) diff --git a/po/bg.po b/po/bg.po index 1f7222dd93..2fc6c2b60c 100644 --- a/po/bg.po +++ b/po/bg.po @@ -225,6 +225,14 @@ # mailmap файл за съответствията на имената и адресите на е-поща # unit test поединичен тест # test suite група тестове +# object database базата от данни за обектите +# expecting integer изисква се число +# timeout максимално изчакване +# init timeout максимално първоначално изчакване +# implies option включва опцията +# cache-tree кеша на обектите-дървета +# acquire lock придобивам ключалка +# detached отделѐн, несвързан # # ------------------------ # „$var“ - може да не сработва за shell има gettext и eval_gettext - проверка - намират се лесно по „$ @@ -251,10 +259,10 @@ # for i in `sort -u FILES`; do cnt=`grep $i FILES | wc -l`; echo $cnt $i ;done | sort -n msgid "" msgstr "" -"Project-Id-Version: git 2.45\n" +"Project-Id-Version: git 2.48\n" "Report-Msgid-Bugs-To: Git Mailing List \n" -"POT-Creation-Date: 2024-10-05 01:20+0000\n" -"PO-Revision-Date: 2024-10-05 13:20+0200\n" +"POT-Creation-Date: 2024-12-27 22:37+0100\n" +"PO-Revision-Date: 2024-12-27 22:40+0100\n" "Last-Translator: Alexander Shopov \n" "Language-Team: Bulgarian \n" "Language: bg\n" @@ -564,8 +572,8 @@ msgstr "" #, c-format msgid "Discard mode change from worktree [y,n,q,a,d%s,?]? " msgstr "" -"Премахване на промяната в права̀та за достъп от работното дърво [y,n,q,a," -"d%s,?]? " +"Премахване на промяната в права̀та за достъп от работното дърво " +"[y,n,q,a,d%s,?]? " #, c-format msgid "Discard deletion from worktree [y,n,q,a,d%s,?]? " @@ -605,8 +613,8 @@ msgstr "" #, c-format msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? " msgstr "" -"Премахване на промяната в права̀та за достъп от индекса и работното дърво [y," -"n,q,a,d%s,?]? " +"Премахване на промяната в права̀та за достъп от индекса и работното дърво " +"[y,n,q,a,d%s,?]? " #, c-format msgid "Discard deletion from index and worktree [y,n,q,a,d%s,?]? " @@ -641,8 +649,8 @@ msgstr "" #, c-format msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? " msgstr "" -"Прилагане на промяната в права̀та за достъп от индекса и работното дърво [y,n," -"q,a,d%s,?]? " +"Прилагане на промяната в права̀та за достъп от индекса и работното дърво " +"[y,n,q,a,d%s,?]? " #, c-format msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? " @@ -676,8 +684,8 @@ msgstr "" #, c-format msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? " msgstr "" -"Прилагане на промяната в права̀та за достъп към работното дърво [y,n,q,a," -"d%s,?]? " +"Прилагане на промяната в права̀та за достъп към работното дърво " +"[y,n,q,a,d%s,?]? " #, c-format msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? " @@ -893,12 +901,12 @@ msgstr "Променени са само двоични файлове." #, c-format msgid "" "\n" -"Disable this message with \"git config advice.%s false\"" +"Disable this message with \"git config set advice.%s false\"" msgstr "" "\n" "За да изключите това предупреждение, изпълнете:\n" "\n" -" git config advice.%s false" +" git config set advice.%s false" #, c-format msgid "%shint:%s%.*s%s\n" @@ -1016,8 +1024,8 @@ msgstr "" "\n" " git switch -\n" "\n" -"Може да спрете това съобщение със задаване на настройката „advice." -"detachedHead“\n" +"Може да спрете това съобщение със задаване на настройката " +"„advice.detachedHead“\n" "да е „false“ (лъжа̀).\n" #, c-format @@ -1247,7 +1255,7 @@ msgstr "двоичната кръпка не може да се приложи #, c-format msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)" msgstr "" -"двоичната кръпка за „%s“ води до неправилни резултати (очакваше се: „%s“, а " +"двоичната кръпка за „%s“ води до неправилни резултати (изисква се: „%s“, а " "бе получено: „%s“)" #, c-format @@ -2651,9 +2659,9 @@ msgid "" "git bisect start [--term-(new|bad)= --term-(old|good)=] [--no-" "checkout] [--first-parent] [ [...]] [--] [...]" msgstr "" -"git bisect start [--term-(new,bad)=УПРАВЛЯВАЩА_ДУМА --term-(old," -"good)=УПРАВЛЯВАЩА_ДУМА] [--no-checkout] [--first-parent] [ЛОШО [ДОБРО…]] " -"[--] [ПЪТ…]" +"git bisect start [--term-(new,bad)=УПРАВЛЯВАЩА_ДУМА --term-" +"(old,good)=УПРАВЛЯВАЩА_ДУМА] [--no-checkout] [--first-parent] [ЛОШО " +"[ДОБРО…]] [--] [ПЪТ…]" msgid "git bisect (good|bad) [...]" msgstr "git bisect (good|bad) [ВЕРСИЯ…]" @@ -2936,7 +2944,7 @@ msgstr "ОПЦИИте_ЗА_ВЕРСИЯТА са документирани в #, c-format msgid "expecting a color: %s" -msgstr "трябва да е цвят: %s" +msgstr "изисква се цвят: %s" msgid "must end with a color" msgstr "трябва да завършва с цвят" @@ -3349,8 +3357,8 @@ msgid "HEAD not found below refs/heads!" msgstr "В директорията „refs/heads“ липсва файл „HEAD“" msgid "" -"branch with --recurse-submodules can only be used if submodule." -"propagateBranches is enabled" +"branch with --recurse-submodules can only be used if " +"submodule.propagateBranches is enabled" msgstr "" "може да се ползва клон с опцията „--recurse-submodules“, само ако " "настройката „submodule.propagateBranches“ е зададена" @@ -3653,8 +3661,8 @@ msgstr "позволяване на опциите „-s“ и „-t“ да р msgid "use mail map file" msgstr "" -"използване на файл за съответствията на имената и адресите на е-поща („." -"mailmap“)" +"използване на файл за съответствията на имената и адресите на е-поща " +"(„.mailmap“)" msgid "Batch objects requested on stdin (or --batch-all-objects)" msgstr "" @@ -4206,7 +4214,7 @@ msgstr "" "„zdiff3“)" msgid "detach HEAD at named commit" -msgstr "отделяне на указателя „HEAD“ към указаното подаване" +msgstr "отделяне на указателя „HEAD“ при указаното подаване" msgid "force checkout (throw away local modifications)" msgstr "принудително изтегляне (вашите промѐни ще бъдат занулени)" @@ -4220,8 +4228,8 @@ msgstr "нов неродѐн клон" msgid "update ignored files (default)" msgstr "обновяване на игнорираните файлове (стандартно)" -msgid "do not check if another worktree is holding the given ref" -msgstr "без проверка дали друго работно дърво държи указателя" +msgid "do not check if another worktree is using this branch" +msgstr "без проверка дали друго работно дърво ползва този клон" msgid "checkout our version for unmerged files" msgstr "изтегляне на вашата версия на неслетите файлове" @@ -4525,10 +4533,10 @@ msgstr "плитко клониране до тази ДЪЛБОЧИНА" msgid "create a shallow clone since a specific time" msgstr "плитко клониране до момент във времето" -msgid "revision" -msgstr "ВЕРСИЯ" +msgid "ref" +msgstr "УКАЗ" -msgid "deepen history of shallow clone, excluding rev" +msgid "deepen history of shallow clone, excluding ref" msgstr "задълбочаване на историята на плитко хранилище до изключващ указател" msgid "clone only one branch, HEAD or --branch" @@ -5509,9 +5517,10 @@ msgstr "" msgid "" "git config unset [] [--all] [--value=] [--fixed-value] " -" " +"" msgstr "" -"git config unset [ОПЦИЯ_ЗА_ФАЙЛ] [--all] [--value=СТОЙНОСТ] [--fixed-value]" +"git config unset [ОПЦИЯ_ЗА_ФАЙЛ] [--all] [--value=СТОЙНОСТ] [--fixed-value] " +"ИМЕ" msgid "git config rename-section [] " msgstr "git config rename-section [ОПЦИЯ_ЗА_ФАЙЛ] СТАРО_ИМЕ НОВО_ИМЕ" @@ -5963,12 +5972,8 @@ msgid "traversed %lu commits\n" msgstr "обходени са %lu подавания\n" #, c-format -msgid "" -"more than %i tags found; listed %i most recent\n" -"gave up search at %s\n" -msgstr "" -"открити са над %i етикета, изведени са последните %i,\n" -"търсенето бе прекратено при „%s“.\n" +msgid "found %i tags; gave up search at %s\n" +msgstr "открити са %i етикета. Търсенето приключи при „%s“\n" #, c-format msgid "describe %s\n" @@ -6414,6 +6419,27 @@ msgstr "„%s“ е неправилен обект" msgid "the object %s does not exist" msgstr "обектът „%s“ не съществува" +#, c-format +msgid "" +"Run 'git remote set-head %s %s' to follow the change, or set\n" +"'remote.%s.followRemoteHEAD' configuration option to a different value\n" +"if you do not want to see this message. Specifically running\n" +"'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n" +"until the remote changes HEAD to something else." +msgstr "" +"Изпълнете\n" +"\n" +" git remote set-head %s %s\n" +"\n" +"за да следвате промяната или задайте друга стойност на настройката\n" +"„remote.%s.followRemoteHEAD, ако не искате тези съобщения.\n" +"Изпълнението на\n" +"\n" +" git config set remote.%s.followRemoteHEAD %s\n" +"\n" +"ще изключи предупреждението, докато отдалеченият указател HEAD не\n" +"започне да сочи нещо друго." + msgid "multiple branches detected, incompatible with --set-upstream" msgstr "" "засечени са множество клони, това е несъвместимо с опцията „--set-upstream“" @@ -6553,6 +6579,9 @@ msgstr "КАРТА_С_УКАЗАТЕЛИ" msgid "specify fetch refmap" msgstr "указване на КАРТАта_С_УКАЗАТЕЛИ за доставяне" +msgid "revision" +msgstr "ВЕРСИЯ" + msgid "report that we have only objects reachable from this object" msgstr "докладване, че всички обекти може са достижими при започване от този" @@ -6608,8 +6637,8 @@ msgid "protocol does not support --negotiate-only, exiting" msgstr "протоколът не поддържа опцията „--negotiate-only“, изход от програмата" msgid "" -"--filter can only be used with the remote configured in extensions." -"partialclone" +"--filter can only be used with the remote configured in " +"extensions.partialclone" msgstr "" "опцията „--filter“ може да се ползва само с отдалеченото хранилище указано в " "настройката „extensions.partialclone“" @@ -6859,7 +6888,7 @@ msgstr "„%s“ сочи към нещо необичайно (%s)" #, c-format msgid "%s: detached HEAD points at nothing" -msgstr "%s: несвързаният връх „HEAD“ не сочи към нищо" +msgstr "%s: отделеният връх „HEAD“ не сочи към нищо" #, c-format msgid "notice: %s points to an unborn branch (%s)" @@ -7169,8 +7198,8 @@ msgstr "неуспешно изпълнение на „git multi-pack-index rep msgid "" "skipping incremental-repack task because core.multiPackIndex is disabled" msgstr "" -"задачата „incremental-repack“ се прескача, защото настройката „core." -"multiPackIndex“ е изключена" +"задачата „incremental-repack“ се прескача, защото настройката " +"„core.multiPackIndex“ е изключена" #, c-format msgid "lock file '%s' exists, skipping maintenance" @@ -7291,8 +7320,25 @@ msgstr "липсват както таймери на systemd, така и cront msgid "%s scheduler is not available" msgstr "планиращият модул „%s“ липсва" -msgid "another process is scheduling background maintenance" -msgstr "друг процес задава поддръжката на заден фон" +#, c-format +msgid "" +"unable to create '%s.lock': %s.\n" +"\n" +"Another scheduled git-maintenance(1) process seems to be running in this\n" +"repository. Please make sure no other maintenance processes are running and\n" +"then try again. If it still fails, a git-maintenance(1) process may have\n" +"crashed in this repository earlier: remove the file manually to continue." +msgstr "" +"Файлът-ключалка „%s.lock“ не може да бъде създаден: %s\n" +"\n" +"Изглежда, че и друг процес на git-maintenance(1) е пуснат в това\n" +"хранилище. Уверете се, че всички подобни процеси са спрени и опитайте\n" +"отново. Ако това не помогне, вероятната причина е, че някой процес на\n" +"git-maintenance(1) в това хранилище е забил. За да продължите работа,\n" +"ще трябва ръчно да изтриете файла:" + +msgid "cannot acquire lock for scheduled background maintenance" +msgstr "не може да се придобие ключалката за поддръжката на заден фон" msgid "git maintenance start [--scheduler=]" msgstr "git maintenance start [--scheduler=ПЛАНИРАЩ_МОДУЛ]" @@ -7876,6 +7922,24 @@ msgid_plural "chain length = %d: %lu objects" msgstr[0] "дължината на веригата е %d: %lu обект" msgstr[1] "дължината на веригата е %d: %lu обекта" +msgid "could not start pack-objects to repack local links" +msgstr "" +"командата „pack-objects“ не може да се стартира за препакетирането на " +"локалните връзки" + +msgid "failed to feed local object to pack-objects" +msgstr "локалните обекти не може да се подадат на командата „pack-objects“" + +msgid "index-pack: Expecting full hex object ID lines only from pack-objects." +msgstr "" +"index-pack: от „pack-objects“ се изискват редове само с пълни шестнайсетични " +"указатели." + +msgid "could not finish pack-objects to repack local links" +msgstr "" +"командата „pack-objects“ не може да завърши за препакетирането на локалните " +"връзки" + msgid "Cannot come back to cwd" msgstr "Процесът не може да се върне към предишната работна директория" @@ -7887,6 +7951,9 @@ msgstr "неправилна стойност „%s“" msgid "unknown hash algorithm '%s'" msgstr "непознат алгоритъм за контролни суми „%s“" +msgid "--promisor cannot be used with a pack name" +msgstr "опцията „--promisor“ е несъвместима с име на пакет" + msgid "--stdin requires a git repository" msgstr "„--stdin“ изисква хранилище на git" @@ -9283,11 +9350,14 @@ msgstr "git notes [--ref УКАЗАТЕЛ_ЗА_БЕЛЕЖКА] [list [ОБЕКТ msgid "" "git notes [--ref ] add [-f] [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" msgstr "" +"git notes [--ref ] add [-f] [--allow-empty] [--[no-]separator|--" +"separator=] [--[no-]stripspace] [-m | -F | (-c " +"| -C) ] [] [-e]\n" "git notes [--ref УКАЗАТЕЛ_ЗА_БЕЛЕЖКА] add [-f] [--allow-empty] [--" "[no-]separator|--separator=] [--[no-]stripspace] [-m " -"СЪОБЩЕНИЕ|-F ФАЙЛ|(-c|-C) ОБЕКТ] [ОБЕКТ]" +"СЪОБЩЕНИЕ|-F ФАЙЛ|(-c|-C) ОБЕКТ] [ОБЕКТ] [-e]" msgid "git notes [--ref ] copy [-f] " msgstr "" @@ -9296,11 +9366,11 @@ msgstr "" msgid "" "git notes [--ref ] append [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" msgstr "" "git notes [--ref УКАЗАТЕЛ_ЗА_БЕЛЕЖКА] append [--allow-empty] [--" "[no-]separator|--separator=КРАЙ_НА_АБЗАЦ] [--[no-]stripspace] [-m СЪОБЩЕНИЕ " -"| -F ФАЙЛ|(-c|-C) ОБЕКТ] [ОБЕКТ]" +"| -F ФАЙЛ|(-c|-C) ОБЕКТ] [ОБЕКТ] [-e]" msgid "git notes [--ref ] edit [--allow-empty] []" msgstr "git notes [--ref УКАЗАТЕЛ_ЗА_БЕЛЕЖКА] edit [--allow-empty] [ОБЕКТ]" @@ -9422,6 +9492,9 @@ msgstr "ФАЙЛ със съдържанието на бележката" msgid "reuse and edit specified note object" msgstr "преизползване и редактиране на указания ОБЕКТ-бележка" +msgid "edit note message in editor" +msgstr "редактиране на съобщението в редактора" + msgid "reuse specified note object" msgstr "преизползване на указания ОБЕКТ-бележка" @@ -9660,7 +9733,7 @@ msgstr "неуспешно записване на индекси на база #, c-format msgid "wrote % objects while expecting %" -msgstr "бяха записани % обекти, а се очакваха %" +msgstr "бяха записани % обекти, а се изискват %" msgid "disabling bitmap writing, as some objects are not being packed" msgstr "" @@ -9940,6 +10013,9 @@ msgstr "как да се обработват липсващите обекти" msgid "do not pack objects in promisor packfiles" msgstr "без пакетиране на обекти в гарантиращи пакети" +msgid "implies --missing=allow-any" +msgstr "включва опцията „--missing=allow-any“" + msgid "respect islands during delta compression" msgstr "без промяна на групите при делта компресия" @@ -10315,7 +10391,7 @@ msgid "" " git push %s HEAD:\n" msgstr "" "В момента не сте на никой клон. За да изтласкате историята до състоянието,\n" -"сочено в момента от указателя „HEAD“, използвайте командата:\n" +"сочено в момента от (несвързания) указател „HEAD“, използвайте командата:\n" "\n" " git push %s HEAD:ИМЕ_НА_ОТДАЛЕЧЕНИЯ_КЛОН\n" @@ -11592,6 +11668,30 @@ msgid_plural " Local refs configured for 'git push'%s:" msgstr[0] " Локалният указател, настроен за „git push“%s:" msgstr[1] " Локалните указатели, настроени за „git push“%s:" +#, c-format +msgid "'%s/HEAD' is unchanged and points to '%s'\n" +msgstr "„%s/HEAD“ не е променен и сочи към „%s“\n" + +#, c-format +msgid "'%s/HEAD' has changed from '%s' and now points to '%s'\n" +msgstr "„%s/HEAD“ е променен от „%s“ и сега сочи към „%s“\n" + +#, c-format +msgid "'%s/HEAD' is now created and points to '%s'\n" +msgstr "„%s/HEAD“ е създаден и сочи към „%s“\n" + +#, c-format +msgid "'%s/HEAD' was detached at '%s' and now points to '%s'\n" +msgstr "„%s/HEAD“ е отделѐн при „%s“ и сочи към „%s“\n" + +#, c-format +msgid "" +"'%s/HEAD' used to point to '%s' (which is not a remote branch), but now " +"points to '%s'\n" +msgstr "" +"„%s/HEAD“ сочеше към „%s“ (което не е отдалечен клон), но сега сочи към " +"„%s“\n" + msgid "set refs/remotes//HEAD according to remote" msgstr "задаване на refs/remotes/ИМЕ/HEAD според отдалеченото хранилище" @@ -11614,7 +11714,7 @@ msgid "Not a valid ref: %s" msgstr "Неправилен указател: %s" #, c-format -msgid "Could not setup %s" +msgid "Could not set up %s" msgstr "„%s“ не може да се настрои" #, c-format @@ -12287,8 +12387,8 @@ msgstr "" " или: git rev-parse --sq-quote [АРГУМЕНТ…]\n" " или: git rev-parse [ОПЦИЯ…] [АРГУМЕНТ…]\n" "\n" -"За повече информация за първия вариант изпълнете „git rev-parse --parseopt -" -"h“" +"За повече информация за първия вариант изпълнете „git rev-parse --parseopt " +"-h“" msgid "--resolve-git-dir requires an argument" msgstr "опцията „--resolve-git-dir“ изисква аргумент" @@ -13119,7 +13219,7 @@ msgstr "добавяне на „# “ в началото на всеки ре #, c-format msgid "Expecting a full ref name, got %s" -msgstr "Очаква се пълно име на указател, а не „%s“" +msgstr "Изисква се пълно име на указател, а не „%s“" #, c-format msgid "could not get a repository handle for submodule '%s'" @@ -13546,7 +13646,8 @@ msgid "don't print cloning progress" msgstr "без извеждане на напредъка на клонирането" msgid "disallow cloning into non-empty directory, implies --init" -msgstr "предотвратяване на клониране в непразна история, включва „--init“" +msgstr "" +"предотвратяване на клониране в непразна история, включва опцията „--init“" msgid "" "git submodule [--quiet] update [--init [--filter=]] [--remote] " @@ -14403,6 +14504,9 @@ msgstr "задаване на режима на следене (виж git-branc msgid "try to match the new branch name with a remote-tracking branch" msgstr "опит за напасване на името на новия клон с това на следящ клон" +msgid "use relative paths for worktrees" +msgstr "използване на относителни пътища за работните дървета" + #, c-format msgid "options '%s', '%s', and '%s' cannot be used together" msgstr "опциите „%s“, „%s“ и „%s“ са несъвместими" @@ -14684,6 +14788,26 @@ msgstr "файлът „%s“ не може да бъде създаден" msgid "index-pack died" msgstr "командата „git index-pack“ не завърши успешно" +#, c-format +msgid "directory '%s' is present in index, but not sparse" +msgstr "директорията „%s“ е в индекса, но не е частична" + +msgid "corrupted cache-tree has entries not present in index" +msgstr "повреденият кеш на обектите-дървета съдържа записи извън индекса" + +#, c-format +msgid "%s with flags 0x%x should not be in cache-tree" +msgstr "„%s“ с флагове 0x%x не трябва да е в кеша на обектите-дървета" + +#, c-format +msgid "bad subtree '%.*s'" +msgstr "неправилно поддърво „%.*s“" + +#, c-format +msgid "cache-tree for path %.*s does not match. Expected %s got %s" +msgstr "" +"кешираният обект-дърво за пътя „%.*s“ не съвпада. Изисква се „%s“, а не „%s“" + msgid "terminating chunk id appears earlier than expected" msgstr "идентификаторът за краен откъс се явява по-рано от очакваното" @@ -15468,7 +15592,7 @@ msgstr "временният файл на гра̀фа с подаваният #, c-format msgid "cannot merge graphs with %, % commits" msgstr "" -"не може да се слеят графове с % и % подавания (съответно)" +"не може да се слеят гра̀фи с % и % подавания (съответно)" #, c-format msgid "cannot merge graph %s, too many commits: %" @@ -15490,8 +15614,8 @@ msgid "" "attempting to write a commit-graph, but 'commitGraph.changedPathsVersion' " "(%d) is not supported" msgstr "" -"опит за запис на гра̀фа с подаванията, но настройката „commitGraph." -"changedPathsVersion“ (%d) не се поддържа" +"опит за запис на гра̀фа с подаванията, но настройката " +"„commitGraph.changedPathsVersion“ (%d) не се поддържа" msgid "too many commits to write graph" msgstr "прекалено много подавания за записване на гра̀фа" @@ -15578,7 +15702,7 @@ msgid "" "to convert the grafts into replace refs.\n" "\n" "Turn this message off by running\n" -"\"git config advice.graftFileDeprecated false\"" +"\"git config set advice.graftFileDeprecated false\"" msgstr "" "Поддръжката на „/info/grafts“ е остаряла.\n" "В бъдеща версия на Git ще бъде премахната.\n" @@ -15590,7 +15714,7 @@ msgstr "" "\n" "За да изключите това съобщение, изпълнете:\n" "\n" -" git config advice.graftFileDeprecated false" +" git config set advice.graftFileDeprecated false" #, c-format msgid "commit %s exists in commit-graph but not in the object database" @@ -16445,6 +16569,24 @@ msgstr "адресът е без схема: %s" msgid "credential url cannot be parsed: %s" msgstr "адресът за идентификация не може да се анализира: „%s“" +#, c-format +msgid "invalid timeout '%s', expecting a non-negative integer" +msgstr "" +"неправилна стойност за „timeout“ (максимално изчакване) „%s“, изисква се " +"неотрицателно цяло число" + +#, c-format +msgid "invalid init-timeout '%s', expecting a non-negative integer" +msgstr "" +"неправилна стойност за „init-timeout“ (максимално първоначално изчакване): " +"„%s“, изисква се неотрицателно цяло число" + +#, c-format +msgid "invalid max-connections '%s', expecting an integer" +msgstr "" +"неправилна стойност за „max-connections“ (максималния брой връзки): „%s“, " +"изисква се цяло число" + msgid "in the future" msgstr "в бъдещето" @@ -17170,6 +17312,22 @@ msgstr "неправилен път към пространства от име msgid "too many args to run %s" msgstr "прекалено много аргументи за изпълнение „%s“" +#, c-format +msgid "" +"You are attempting to fetch %s, which is in the commit graph file but not in " +"the object database.\n" +"This is probably due to repo corruption.\n" +"If you are attempting to repair this repo corruption by refetching the " +"missing object, use 'git fetch --refetch' with the missing object." +msgstr "" +"Пробвате да доставите „%s“, което е в гра̀фа с подаванията, но не и в базата " +"от данни за обектите.\n" +"Най-вероятната причина е повредено хранилище.\n" +"За да поправите хранилището като изтеглите липсващия обект наново, " +"изпълнете:\n" +"\n" +" git fetch --refetch" + msgid "git fetch-pack: expected shallow list" msgstr "git fetch-pack: очаква се плитък списък" @@ -17770,11 +17928,12 @@ msgstr[1] "" #, c-format msgid "" "The '%s' hook was ignored because it's not set as executable.\n" -"You can disable this warning with `git config advice.ignoredHook false`." +"You can disable this warning with `git config set advice.ignoredHook false`." msgstr "" "Куката „%s“ се прескача, защото липсват права̀ за изпълнение.\n" "За да изключите това предупреждение, изпълнете:\n" -" git config advice.ignoredHook false" +"\n" +" git config set advice.ignoredHook false" msgid "not a git repository" msgstr "не е хранилище на Git" @@ -17791,15 +17950,9 @@ msgstr "" msgid "Delegation control is not supported with cURL < 7.22.0" msgstr "Управлението на делегирането не се поддържа от cURL < 7.22.0" -msgid "Public key pinning not supported with cURL < 7.39.0" -msgstr "Задаването на постоянен публичен ключ не се поддържа от cURL < 7.39.0" - msgid "Unknown value for http.proactiveauth" msgstr "Непозната стойност за „http.proactiveauth“" -msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0" -msgstr "„CURLSSLOPT_NO_REVOKE“ не се поддържа от cURL < 7.44.0" - #, c-format msgid "Unsupported SSL backend '%s'. Supported SSL backends:" msgstr "Неподдържана реализация на SSL „%s“. Поддържат се:" @@ -17991,6 +18144,10 @@ msgstr "цитирани знаци CRLF" msgid "unable to format message: %s" msgstr "съобщението не може да се форматира: %s" +#, c-format +msgid "invalid marker-size '%s', expecting an integer" +msgstr "неправилен размер на маркер: „%s“, изисква се цяло число" + #, c-format msgid "Failed to merge submodule %s (not checked out)" msgstr "Неуспешно сливане на подмодула „%s“ (не е изтеглен)" @@ -19147,7 +19304,7 @@ msgid "" "\n" "where \"$br\" is somehow empty and a 40-hex ref is created. Please\n" "examine these refs and maybe delete them. Turn this message off by\n" -"running \"git config advice.objectNameWarning false\"" +"running \"git config set advice.objectNameWarning false\"" msgstr "" "При нормална работа Git никога не създава указатели, които завършват\n" "с 40 шестнадесетични знака, защото стандартно те ще бъдат прескачани.\n" @@ -19159,7 +19316,7 @@ msgstr "" "се създава подобен указател. Прегледайте тези указатели и ги изтрийте.\n" "За да изключите това съобщение, изпълнете:\n" "\n" -" git config advice.objectNameWarning false" +" config set advice.objectNameWarning false" #, c-format msgid "log for '%.*s' only goes back to %s" @@ -19330,15 +19487,6 @@ msgstr "задължителният обратен индекс липсва в msgid "could not open pack %s" msgstr "пакетът „%s“ не може да се отвори" -msgid "could not determine MIDX preferred pack" -msgstr "" -"предпочитаният пакет за файла с индекса за множество пакети не може да се " -"определи" - -#, c-format -msgid "preferred pack (%s) is invalid" -msgstr "предпочитаният пакет „%s“ е неправилен" - msgid "corrupt bitmap lookup table: triplet position out of index" msgstr "" "повредена таблица със съответствия: местоположението на тройката е извън " @@ -20497,19 +20645,27 @@ msgstr "журналът с подаванията за указателя „%s msgid "log for %s is empty" msgstr "журналът с подаванията за указателя „%s“ е празен" -msgid "refusing to force and skip creation of reflog" -msgstr "" -"принудителна операция без създаване на журнал на указателите няма да се " -"приеме" - #, c-format -msgid "refusing to update ref with bad name '%s'" -msgstr "указател не може да се обнови с грешно име „%s“" +msgid "refusing to update reflog for pseudoref '%s'" +msgstr "журналът на указателите няма да се обнови с псевдо указателя „%s“" #, c-format msgid "refusing to update pseudoref '%s'" msgstr "псевдо указателят „%s“ няма да се обнови" +#, c-format +msgid "refusing to update reflog with bad name '%s'" +msgstr "журналът на указателите няма да се обнови с грешно име „%s“" + +#, c-format +msgid "refusing to update ref with bad name '%s'" +msgstr "указател не може да се обнови с грешно име „%s“" + +msgid "refusing to force and skip creation of reflog" +msgstr "" +"принудителна операция без създаване на журнал на указателите няма да се " +"приеме" + #, c-format msgid "update_ref failed for ref '%s': %s" msgstr "неуспешно обновяване на указателя (update_ref) „%s“: %s" @@ -20559,6 +20715,10 @@ msgstr "" "указателят „%s“ не може да се заключи: очакваше се файл с указател с цел " "„%s“, но вместо това е обикновен указател" +#, c-format +msgid "cannot read ref file '%s'" +msgstr "файлът с указател „%s“ не може да се прочете" + #, c-format msgid "cannot open directory %s" msgstr "директорията „%s“ не може да бъде отворена" @@ -20780,6 +20940,10 @@ msgstr "зададен е повече от един пакет за получ msgid "more than one uploadpack given, using the first" msgstr "зададен е повече от един пакет за изпращане, ще се ползва първият" +#, c-format +msgid "unrecognized followRemoteHEAD value '%s' ignored" +msgstr "непознатата стойност за „followRemoteHEAD“: „%s“, се прескача" + #, c-format msgid "unrecognized value transfer.credentialsInUrl: '%s'" msgstr "непозната стойност за „transfer.credentialsInUrl“: „%s“" @@ -22788,6 +22952,11 @@ msgstr "подаването „%s“ не е отбелязано като до msgid "too many commits marked reachable" msgstr "прекалено много подавания са отбелязани като достижими" +msgid "could not determine MIDX preferred pack" +msgstr "" +"предпочитаният пакет за файла с индекса за множество пакети не може да се " +"определи" + msgid "test-tool serve-v2 []" msgstr "test-tool serve-v2 [ОПЦИЯ…]" @@ -23444,6 +23613,9 @@ msgstr "„.git“ е повреден" msgid ".git file incorrect" msgstr "„.git“ е неправилен" +msgid ".git file absolute/relative path mismatch" +msgstr "несъвпадение на абсолютния/относителния път на „.git“" + msgid "not a valid path" msgstr "неправилен път" @@ -23459,6 +23631,9 @@ msgstr "не може да се открие хранилище: „.git“ е msgid "gitdir unreadable" msgstr "директорията „gitdir“ не може да се прочете" +msgid "gitdir absolute/relative path mismatch" +msgstr "„gitdir“ указва несъвпадение на абсолютния/относителния път" + msgid "gitdir incorrect" msgstr "неправилна директория „gitdir“" @@ -23495,6 +23670,14 @@ msgstr "„%s“ не може да се изчисти в „%s“" msgid "failed to set extensions.worktreeConfig setting" msgstr "неуспешно задаване на настройката „extensions.worktreeConfig“" +msgid "unable to upgrade repository format to support relative worktrees" +msgstr "" +"форматът на хранилището не може да се обнови за поддръжката на относителни " +"работни дървета" + +msgid "unable to set extensions.relativeWorktrees setting" +msgstr "неуспешно задаване на настройката „extensions.relativeWorktrees“" + #, c-format msgid "could not setenv '%s'" msgstr "променливата на средата „%s“ не може да се зададе чрез „setenv“" -- cgit v1.2.3 From ffbd89cbb7933081446e1dbde736d5dfce983383 Mon Sep 17 00:00:00 2001 From: Yi-Jyun Pan Date: Tue, 17 Dec 2024 20:52:43 +0800 Subject: l10n: zh_TW: Git 2.48 Signed-off-by: Yi-Jyun Pan --- po/zh_TW.po | 545 ++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 347 insertions(+), 198 deletions(-) diff --git a/po/zh_TW.po b/po/zh_TW.po index 5e6818f453..28afb3662f 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -30,8 +30,8 @@ msgid "" msgstr "" "Project-Id-Version: Git\n" "Report-Msgid-Bugs-To: Git Mailing List \n" -"POT-Creation-Date: 2024-10-05 01:20+0000\n" -"PO-Revision-Date: 2024-10-05 15:45+0800\n" +"POT-Creation-Date: 2024-12-17 20:14+0800\n" +"PO-Revision-Date: 2024-12-17 20:52+0800\n" "Last-Translator: Yi-Jyun Pan \n" "Language-Team: Chinese (Traditional) \n" @@ -764,10 +764,10 @@ msgstr "只有二進位檔案更動了。" #, c-format msgid "" "\n" -"Disable this message with \"git config advice.%s false\"" +"Disable this message with \"git config set advice.%s false\"" msgstr "" "\n" -"請使用「git config advice.%s false」停用此訊息" +"請使用「git config set advice.%s false」停用此訊息" #: advice.c #, c-format @@ -2620,7 +2620,7 @@ msgstr "" #: builtin/am.c builtin/reset.c #, c-format msgid "Could not parse object '%s'." -msgstr "無法解析「%s」物件。" +msgstr "無法解析物件「%s」。" #: builtin/am.c msgid "failed to clean index" @@ -2917,7 +2917,7 @@ msgstr "「%s」不是有效的提交" #, c-format msgid "" "could not check out original HEAD '%s'. Try 'git bisect reset '." -msgstr "不能簽出原始 HEAD「%s」。請嘗試「git bisect reset 」。" +msgstr "無法簽出原始 HEAD「%s」。請嘗試「git bisect reset 」。" #: builtin/bisect.c #, c-format @@ -3460,7 +3460,7 @@ msgstr "無法解析格式化字串" #: builtin/branch.c msgid "could not resolve HEAD" -msgstr "無法解析 HEAD 指標" +msgstr "無法解析 HEAD" #: builtin/branch.c #, c-format @@ -4718,8 +4718,8 @@ msgid "update ignored files (default)" msgstr "更新忽略的檔案(預設值)" #: builtin/checkout.c -msgid "do not check if another worktree is holding the given ref" -msgstr "不檢查其他工作區是否正在佔用指定的引用" +msgid "do not check if another worktree is using this branch" +msgstr "不檢查其他工作區是否正在使用這個提交" #: builtin/checkout.c msgid "checkout our version for unmerged files" @@ -4875,7 +4875,7 @@ msgstr "無法移除 %s" #: builtin/clean.c #, c-format msgid "could not lstat %s\n" -msgstr "不能對 %s 進行 lstat\n" +msgstr "無法對 %s 進行 lstat\n" #: builtin/clean.c msgid "Refusing to remove current working directory\n" @@ -5099,14 +5099,14 @@ msgstr "建立指定深度的淺層複製" msgid "create a shallow clone since a specific time" msgstr "建立從指定時間到現在的淺層複製" -#: builtin/clone.c builtin/fetch.c builtin/pull.c builtin/rebase.c -#: builtin/replay.c -msgid "revision" -msgstr "revision" +#: builtin/clone.c builtin/fetch.c builtin/pull.c +#| msgid "rev" +msgid "ref" +msgstr "ref" #: builtin/clone.c builtin/fetch.c builtin/pull.c -msgid "deepen history of shallow clone, excluding rev" -msgstr "取得更多淺層複製的過去歷史記錄,除了特定修訂版" +msgid "deepen history of shallow clone, excluding ref" +msgstr "取得更多淺層複製的過往歷史記錄,除了特定修訂版" #: builtin/clone.c builtin/submodule--helper.c msgid "clone only one branch, HEAD or --branch" @@ -5325,12 +5325,12 @@ msgstr "工作區 '%s' 已經存在。" #: builtin/clone.c builtin/difftool.c builtin/log.c builtin/worktree.c #, c-format msgid "could not create leading directories of '%s'" -msgstr "不能為 '%s' 建立先導目錄" +msgstr "無法為「%s」建立前導目錄" #: builtin/clone.c #, c-format msgid "could not create work tree dir '%s'" -msgstr "不能建立工作區目錄 '%s'" +msgstr "無法建立工作區目錄「%s」" #: builtin/clone.c #, c-format @@ -5789,12 +5789,12 @@ msgstr "(正從標準輸入中讀取日誌訊息)\n" #: builtin/commit.c msgid "could not read log from standard input" -msgstr "不能從標準輸入中讀取日誌訊息" +msgstr "無法從標準輸入中讀取記錄" #: builtin/commit.c #, c-format msgid "could not read log file '%s'" -msgstr "不能讀取日誌檔案 '%s'" +msgstr "無法讀取日誌檔案「%s」" #: builtin/commit.c #, c-format @@ -5803,11 +5803,11 @@ msgstr "「%s」和「%s:%s」選項不得同時使用" #: builtin/commit.c msgid "could not read SQUASH_MSG" -msgstr "不能讀取 SQUASH_MSG" +msgstr "無法讀取 SQUASH_MSG" #: builtin/commit.c msgid "could not read MERGE_MSG" -msgstr "不能讀取 MERGE_MSG" +msgstr "無法讀取 MERGE_MSG" #: builtin/commit.c bundle.c rerere.c sequencer.c #, c-format @@ -5816,7 +5816,7 @@ msgstr "無法開啟「%s」" #: builtin/commit.c msgid "could not write commit template" -msgstr "不能寫提交範本" +msgstr "無法寫入提交模板" #: builtin/commit.c #, c-format @@ -6192,7 +6192,7 @@ msgstr "允許空的提交說明" #: builtin/commit.c sequencer.c msgid "could not parse HEAD commit" -msgstr "不能解析 HEAD 提交" +msgstr "無法解析 HEAD 提交" #: builtin/commit.c #, c-format @@ -6201,12 +6201,12 @@ msgstr "損壞的 MERGE_HEAD 檔案(%s)" #: builtin/commit.c msgid "could not read MERGE_MODE" -msgstr "不能讀取 MERGE_MODE" +msgstr "無法讀取 MERGE_MODE" #: builtin/commit.c #, c-format msgid "could not read commit message: %s" -msgstr "不能讀取提交說明:%s" +msgstr "無法讀取提交說明:%s" #: builtin/commit.c #, c-format @@ -6253,12 +6253,15 @@ msgstr "" "value] <名稱> <值>" #: builtin/config.c +#| msgid "" +#| "git config unset [] [--all] [--value=] [--fixed-" +#| "value] " msgid "" "git config unset [] [--all] [--value=] [--fixed-value] " -" " +"" msgstr "" -"git config unset [<檔案選項>] [--all] [--value=<值>] [--fixed-value] <名稱> <" -"值>" +"git config unset [] [--all] [--value=] [--fixed-value] " +"" #: builtin/config.c msgid "git config rename-section [] " @@ -6804,12 +6807,8 @@ msgstr "已遍歷 %lu 個提交\n" #: builtin/describe.c #, c-format -msgid "" -"more than %i tags found; listed %i most recent\n" -"gave up search at %s\n" -msgstr "" -"發現多於 %i 個標籤,列出最近的 %i 個\n" -"在 %s 放棄搜尋\n" +msgid "found %i tags; gave up search at %s\n" +msgstr "找到 %i 個標籤;在 %s 放棄搜尋\n" #: builtin/describe.c #, c-format @@ -6997,7 +6996,7 @@ msgstr "工作區檔案被留了下來。" #: builtin/difftool.c sequencer.c #, c-format msgid "could not copy '%s' to '%s'" -msgstr "不能複製 '%s' 至 '%s'" +msgstr "無法將「%s」複製到「%s」" #: builtin/difftool.c #, c-format @@ -7397,12 +7396,12 @@ msgstr "正在取得 %s\n" #: builtin/fetch.c #, c-format msgid "could not fetch %s" -msgstr "不能取得 %s" +msgstr "無法取得 %s" #: builtin/fetch.c #, c-format msgid "could not fetch '%s' (exit code: %d)\n" -msgstr "無法取得 '%s'(離開碼:%d)\n" +msgstr "無法取得「%s」(離開碼:%d)\n" #: builtin/fetch.c msgid "" @@ -7527,6 +7526,10 @@ msgstr "引用映射" msgid "specify fetch refmap" msgstr "指定取得動作的引用映射" +#: builtin/fetch.c builtin/pull.c builtin/rebase.c builtin/replay.c +msgid "revision" +msgstr "revision" + #: builtin/fetch.c builtin/pull.c msgid "report that we have only objects reachable from this object" msgstr "報告我們只擁有從該物件開始可以取得的物件" @@ -7788,18 +7791,18 @@ msgstr "懸空 %s %s" #: builtin/fsck.c msgid "could not create lost-found" -msgstr "不能建立 lost-found" +msgstr "無法建立 lost-found" #: builtin/fsck.c builtin/gc.c builtin/rebase.c rebase-interactive.c rerere.c #: sequencer.c #, c-format msgid "could not write '%s'" -msgstr "不能寫入 '%s'" +msgstr "無法寫入「%s」" #: builtin/fsck.c #, c-format msgid "could not finish '%s'" -msgstr "不能完成 '%s'" +msgstr "無法完成「%s」" #: builtin/fsck.c #, c-format @@ -8069,7 +8072,7 @@ msgstr "無法啟動 fsmonitor 監聽執行緒" #: builtin/fsmonitor--daemon.c msgid "could not start fsmonitor health thread" -msgstr "無法啟動 fsmonitor 健康監聽執行緒" +msgstr "無法啟動 fsmonitor 健康檢查執行緒" #: builtin/fsmonitor--daemon.c msgid "could not initialize listener thread" @@ -8077,7 +8080,7 @@ msgstr "無法初始化監聽執行緒" #: builtin/fsmonitor--daemon.c msgid "could not initialize health thread" -msgstr "無法初始化健康監聽執行緒" +msgstr "無法初始化健康檢查執行緒" #: builtin/fsmonitor--daemon.c #, c-format @@ -8437,8 +8440,26 @@ msgid "%s scheduler is not available" msgstr "無法使用 %s 排程器" #: builtin/gc.c -msgid "another process is scheduling background maintenance" -msgstr "其他處理程序正在排定背景維護工作" +#, c-format +msgid "" +"unable to create '%s.lock': %s.\n" +"\n" +"Another scheduled git-maintenance(1) process seems to be running in this\n" +"repository. Please make sure no other maintenance processes are running and\n" +"then try again. If it still fails, a git-maintenance(1) process may have\n" +"crashed in this repository earlier: remove the file manually to continue." +msgstr "" +"無法建立「%s.lock」:%s。\n" +"\n" +"似乎有另一個排定的 git-maintenance(1) 程序正在此\n" +"版本庫中執行。請確保沒有其他維護程序正在執行,\n" +"然後再試一次。如果仍然失敗,可能是先前的\n" +"git-maintenance(1) 程序在這個版本庫中意外中斷:\n" +"請手動移除檔案以繼續。" + +#: builtin/gc.c +msgid "cannot acquire lock for scheduled background maintenance" +msgstr "無法取得用來進行排定背景維護的鎖" #: builtin/gc.c msgid "git maintenance start [--scheduler=]" @@ -8727,7 +8748,7 @@ msgstr "--open-files-in-pager 僅用於工作區" #: builtin/grep.c msgid "--[no-]exclude-standard cannot be used for tracked contents" -msgstr "--[no-]exclude-standard 不能用於已追蹤內容" +msgstr "--[no-]exclude-standard 無法用於已追蹤內容" #: builtin/grep.c msgid "both --cached and trees are given" @@ -9157,6 +9178,22 @@ msgid "chain length = %d: %lu object" msgid_plural "chain length = %d: %lu objects" msgstr[0] "鏈長 = %d: %lu 物件" +#: builtin/index-pack.c +msgid "could not start pack-objects to repack local links" +msgstr "無法啟動 pack-objects 來重新打包本機連結" + +#: builtin/index-pack.c +msgid "failed to feed local object to pack-objects" +msgstr "無法將本機物件喂給 pack-objects" + +#: builtin/index-pack.c +msgid "index-pack: Expecting full hex object ID lines only from pack-objects." +msgstr "index-pack:只預期接受來自 pack-objects 的完整十六進位物件 ID。" + +#: builtin/index-pack.c +msgid "could not finish pack-objects to repack local links" +msgstr "無法結束 pack-objects 來重新封包" + #: builtin/index-pack.c msgid "Cannot come back to cwd" msgstr "無法返回目前工作目錄" @@ -9171,6 +9208,10 @@ msgstr "錯誤選項 %s" msgid "unknown hash algorithm '%s'" msgstr "未知的「%s」雜湊算法" +#: builtin/index-pack.c +msgid "--promisor cannot be used with a pack name" +msgstr "--promisor 不能與封包名稱一起使用" + #: builtin/index-pack.c msgid "--stdin requires a git repository" msgstr "--stdin 需要一個 git 版本庫" @@ -9256,7 +9297,7 @@ msgstr "" #: builtin/interpret-trailers.c wrapper.c #, c-format msgid "could not stat %s" -msgstr "不能對 %s 呼叫 stat" +msgstr "無法 stat %s" #: builtin/interpret-trailers.c #, c-format @@ -9270,21 +9311,21 @@ msgstr "檔案 %s 使用者不可寫" #: builtin/interpret-trailers.c msgid "could not open temporary file" -msgstr "不能開啟暫存檔" +msgstr "無法開啟暫存檔" #: builtin/interpret-trailers.c #, c-format msgid "could not read input file '%s'" -msgstr "不能讀取輸入檔案 '%s'" +msgstr "無法讀取輸入檔案「%s」" #: builtin/interpret-trailers.c builtin/mktag.c imap-send.c msgid "could not read from stdin" -msgstr "不能自標準輸入讀取" +msgstr "無法從標準輸入讀取" #: builtin/interpret-trailers.c #, c-format msgid "could not rename temporary file to %s" -msgstr "不能重新命名暫存檔為 %s" +msgstr "無法將暫存檔重新命名為 %s" #: builtin/interpret-trailers.c msgid "edit files in place" @@ -9407,7 +9448,7 @@ msgstr "git show %s: 損壞的檔案" #: builtin/log.c #, c-format msgid "could not read object %s" -msgstr "不能讀取物件 %s" +msgstr "無法讀取物件 %s" #: builtin/log.c #, c-format @@ -9474,7 +9515,7 @@ msgstr "無法將 '%s' 解析為一個有效引用" #: builtin/log.c msgid "could not find exact merge base" -msgstr "不能找到準確的合併基礎" +msgstr "找不到準確的合併基礎" #: builtin/log.c msgid "" @@ -9727,7 +9768,7 @@ msgstr "--remerge-diff 無意義" #: builtin/log.c builtin/submodule--helper.c rerere.c submodule.c #, c-format msgid "could not create directory '%s'" -msgstr "不能建立目錄 '%s'" +msgstr "無法建立「%s」目錄" #: builtin/log.c msgid "--interdiff requires --cover-letter or single patch" @@ -9776,7 +9817,7 @@ msgstr "git cherry [-v] [<上游> [<頭> [<限制>]]]" #, c-format msgid "" "Could not find a tracked remote branch, please specify manually.\n" -msgstr "不能找到追蹤的遠端分支,請手動指定 <上游>。\n" +msgstr "無法找到追蹤的遠端分支,請手動指定 <上游>。\n" #: builtin/ls-files.c builtin/ls-tree.c #, c-format @@ -9900,7 +9941,7 @@ msgid "" "--format cannot be used with -s, -o, -k, -t, --resolve-undo, --deduplicate, " "--eol" msgstr "" -"--format 不能和 -s、-o、-k、-t、--resolve-undo、--deduplicate、--eol 一起使用" +"--format 無法和 -s、-o、-k、-t、--resolve-undo、--deduplicate、--eol 一起使用" #: builtin/ls-remote.c msgid "" @@ -10162,7 +10203,7 @@ msgstr "未知選項 %s" #: builtin/merge-recursive.c #, c-format msgid "could not parse object '%s'" -msgstr "不能解析物件 '%s'" +msgstr "無法解析物件「%s」" #: builtin/merge-recursive.c #, c-format @@ -10177,7 +10218,7 @@ msgstr "不能處理兩個頭合併之外的任何動作。" #: builtin/merge-recursive.c #, c-format msgid "could not resolve ref '%s'" -msgstr "無法解析引用 '%s'" +msgstr "無法解析引用「%s」" #: builtin/merge-recursive.c #, c-format @@ -10280,7 +10321,7 @@ msgstr "選項 `%s' 需要一個值" #: builtin/merge.c #, c-format msgid "Could not find merge strategy '%s'.\n" -msgstr "不能找到合併策略 '%s'。\n" +msgstr "找不到合併策略「%s」。\n" #: builtin/merge.c #, c-format @@ -10368,7 +10409,7 @@ msgstr "繞過 pre-merge-commit 和 commit-msg 掛鉤" #: builtin/merge.c msgid "could not run stash." -msgstr "不能執行貯存。" +msgstr "無法執行貯存。" #: builtin/merge.c msgid "stash failed" @@ -10428,7 +10469,7 @@ msgstr "不能寫 %s" #: builtin/merge.c #, c-format msgid "Could not read from '%s'" -msgstr "不能從 '%s' 讀取" +msgstr "無法從「%s」進行讀取" #: builtin/merge.c #, c-format @@ -10495,7 +10536,7 @@ msgstr "環境 '%2$s' 中存在壞的取值 '%1$s'" #: builtin/merge.c editor.c read-cache.c wrapper.c #, c-format msgid "could not close '%s'" -msgstr "不能關閉 '%s'" +msgstr "無法關閉「%s」" #: builtin/merge.c #, c-format @@ -10882,28 +10923,36 @@ msgid "git notes [--ref ] [list []]" msgstr "git notes [--ref <註解引用>] [list [<物件>]]" #: builtin/notes.c +#| msgid "" +#| "git notes [--ref ] add [-f] [--allow-empty] [--" +#| "[no-]separator|--separator=] [--[no-]stripspace] [-m " +#| " | -F | (-c | -C) ] []" msgid "" "git notes [--ref ] add [-f] [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" msgstr "" "git notes [--ref ] add [-f] [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" #: builtin/notes.c msgid "git notes [--ref ] copy [-f] " msgstr "git notes [--ref <註解引用>] copy [-f] <來源物件> <目標物件>" #: builtin/notes.c +#| msgid "" +#| "git notes [--ref ] append [--allow-empty] [--[no-]separator|--" +#| "separator=] [--[no-]stripspace] [-m | -F | " +#| "(-c | -C) ] []" msgid "" "git notes [--ref ] append [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" msgstr "" "git notes [--ref ] append [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" #: builtin/notes.c msgid "git notes [--ref ] edit [--allow-empty] []" @@ -10984,7 +11033,7 @@ msgstr "為下面的物件寫/編輯說明:" #: builtin/notes.c msgid "could not read 'show' output" -msgstr "不能讀取 'show' 的輸出" +msgstr "無法讀取「show」的輸出" #: builtin/notes.c #, c-format @@ -11007,7 +11056,7 @@ msgstr "註解內容被留在 %s 中" #: builtin/notes.c builtin/tag.c #, c-format msgid "could not open or read '%s'" -msgstr "不能開啟或讀取 '%s'" +msgstr "無法開啟或讀取「%s」" #: builtin/notes.c #, c-format @@ -11054,6 +11103,10 @@ msgstr "註解內容到一個檔案中" msgid "reuse and edit specified note object" msgstr "重用和編輯指定的註解物件" +#: builtin/notes.c +msgid "edit note message in editor" +msgstr "在編輯器中編輯備註訊息" + #: builtin/notes.c msgid "reuse specified note object" msgstr "重用指定的註解物件" @@ -11352,7 +11405,7 @@ msgstr "%s 的 delta 基準位移越界" #: builtin/pack-objects.c msgid "Counting objects" -msgstr "物件計數中" +msgstr "正在計算物件數量" #: builtin/pack-objects.c pack-bitmap.c #, c-format @@ -11667,6 +11720,10 @@ msgstr "處理遺失的物件" msgid "do not pack objects in promisor packfiles" msgstr "不要打包 promisor packfile 中的物件" +#: builtin/pack-objects.c +msgid "implies --missing=allow-any" +msgstr "隱含 --missing=allow-any" + #: builtin/pack-objects.c msgid "respect islands during delta compression" msgstr "在差異壓縮時尊重資料島" @@ -11696,7 +11753,7 @@ msgstr "錯誤的打包壓縮級別 %d" #: builtin/pack-objects.c msgid "--max-pack-size cannot be used to build a pack for transfer" -msgstr "不能使用 --max-pack-size 來組建傳輸用的包檔案" +msgstr "不能使用 --max-pack-size 來建構傳輸用的包檔案" #: builtin/pack-objects.c msgid "minimum pack size limit is 1 MiB" @@ -12330,7 +12387,7 @@ msgstr "" #: builtin/push.c msgid "--all can't be combined with refspecs" -msgstr "--all 不能和引用規格同時使用" +msgstr "--all 無法和引用規格同時使用" #: builtin/push.c msgid "--mirror can't be combined with refspecs" @@ -12492,12 +12549,12 @@ msgstr "" #: builtin/rebase.c sequencer.c #, c-format msgid "could not read '%s'." -msgstr "不能讀取 '%s'。" +msgstr "無法讀取「%s」。" #: builtin/rebase.c #, c-format msgid "could not create temporary %s" -msgstr "無法建立暫時的 %s" +msgstr "無法建立暫存用的 %s" #: builtin/rebase.c msgid "could not mark as interactive" @@ -12505,7 +12562,7 @@ msgstr "無法標記為互動式" #: builtin/rebase.c msgid "could not generate todo list" -msgstr "無法生成待辦列表" +msgstr "無法產生待辦列表" #: builtin/rebase.c msgid "a base commit must be provided with --upstream or --onto" @@ -12534,7 +12591,7 @@ msgstr "忽略無效的 allow_rerere_autoupdate:'%s'" #: builtin/rebase.c builtin/rm.c sequencer.c #, c-format msgid "could not remove '%s'" -msgstr "無法刪除 '%s'" +msgstr "無法刪除「%s」" #: builtin/rebase.c #, c-format @@ -12879,7 +12936,7 @@ msgstr "無效的上游 '%s'" #: builtin/rebase.c msgid "Could not create new root commit" -msgstr "不能建立新的根提交" +msgstr "無法建立新的根提交" #: builtin/rebase.c #, c-format @@ -13235,7 +13292,7 @@ msgstr "更新 %s 中" #: builtin/remote.c #, c-format msgid "Could not fetch %s" -msgstr "不能取得 %s" +msgstr "無法取得 %s" #: builtin/remote.c msgid "" @@ -13290,7 +13347,7 @@ msgstr "遠端 %s 已經存在。" #: builtin/remote.c #, c-format msgid "Could not setup master '%s'" -msgstr "無法設定 master '%s'" +msgstr "無法配置 master「%s」" #: builtin/remote.c trailer.c #, c-format @@ -13305,7 +13362,7 @@ msgstr "branch.%s.rebase=%s 未處理。假設成 'true'" #: builtin/remote.c #, c-format msgid "Could not get fetch map for refspec %s" -msgstr "無法得到引用規格 %s 的取得列表" +msgstr "無法取得引用規格 %s 的 fetch 映射" #: builtin/remote.c msgid "(matching)" @@ -13318,12 +13375,12 @@ msgstr "(刪除)" #: builtin/remote.c #, c-format msgid "could not set '%s'" -msgstr "無法設定 '%s'" +msgstr "無法設定「%s」" #: builtin/remote.c config.c #, c-format msgid "could not unset '%s'" -msgstr "不能取消設定 '%s'" +msgstr "無法取消設定「%s」" #: builtin/remote.c #, c-format @@ -13344,7 +13401,7 @@ msgstr "沒有此遠端版本庫:'%s'" #: builtin/remote.c #, c-format msgid "Could not rename config section '%s' to '%s'" -msgstr "不能重新命名設定小節 '%s' 到 '%s'" +msgstr "無法將組態的「%s」區段重新命名為「%s」" #: builtin/remote.c #, c-format @@ -13383,7 +13440,7 @@ msgstr[0] "注意:refs/remotes/ 層級之外的一個分支未被移除。要 #: builtin/remote.c #, c-format msgid "Could not remove config section '%s'" -msgstr "不能移除設定小節 '%s'" +msgstr "無法移除組態的「%s」區段" #: builtin/remote.c #, c-format @@ -13583,7 +13640,7 @@ msgstr "不是一個有效引用:%s" #: builtin/remote.c #, c-format msgid "Could not setup %s" -msgstr "不能設定 %s" +msgstr "無法配置 %s" # 譯者:請維持前導空格 #: builtin/remote.c @@ -13702,7 +13759,7 @@ msgstr "repack:期望來自 pack-objects 的完整十六進位物件 ID。" #: builtin/repack.c msgid "could not finish pack-objects to repack promisor objects" -msgstr "無法完成 pack-objects 來重新打包 promisor 物件" +msgstr "無法結束 pack-objects 來重新打包 promisor 物件" #: builtin/repack.c #, c-format @@ -13722,7 +13779,7 @@ msgstr "%s 包太大,以致不能縮合" #: builtin/repack.c #, c-format msgid "could not open tempfile %s for writing" -msgstr "無法開啟 '%s' 暫存檔進行寫入" +msgstr "無法開啟暫存檔 %s 進行寫入" #: builtin/repack.c msgid "could not close refs snapshot tempfile" @@ -13986,7 +14043,7 @@ msgstr "新物件和舊物件相同:'%s'" #: builtin/replace.c #, c-format msgid "could not parse %s as a commit" -msgstr "無法將 %s 解析為一個提交" +msgstr "無法將 %s 解析為提交" #: builtin/replace.c #, c-format @@ -14017,7 +14074,7 @@ msgstr "在取代的提交中簽名將被移除!" #: builtin/replace.c #, c-format msgid "could not write replacement commit for: '%s'" -msgstr "不能為 '%s' 寫取代提交" +msgstr "無法寫入下列項目的替代提交:「%s」" #: builtin/replace.c #, c-format @@ -14035,7 +14092,7 @@ msgid "" "could not convert the following graft(s):\n" "%s" msgstr "" -"不能轉換下列移植:\n" +"無法轉換下列移植:\n" "%s" #: builtin/replace.c @@ -14072,7 +14129,7 @@ msgstr "使用此格式" #: builtin/replace.c msgid "--format cannot be used when not listing" -msgstr "不列出時不能使用 --format" +msgstr "非列出操作不能使用 --format" #: builtin/replace.c msgid "-f only makes sense when writing a replacement" @@ -14338,11 +14395,11 @@ msgstr "" #: builtin/reset.c #, c-format msgid "Could not reset index file to revision '%s'." -msgstr "不能重設索引檔案至版本 '%s'。" +msgstr "無法將索引檔案重設到修訂版「%s」。" #: builtin/reset.c msgid "Could not write new index file." -msgstr "不能寫入新的索引檔案。" +msgstr "無法寫入新的索引檔案。" #: builtin/rev-list.c #, c-format @@ -15231,7 +15288,7 @@ msgstr "無法在合併過程套用貯存" #: builtin/stash.c #, c-format msgid "could not generate diff %s^!." -msgstr "無法生成差異 %s^!." +msgstr "無法產生差異 %s^!." #: builtin/stash.c msgid "conflicts in index. Try without --index." @@ -15239,7 +15296,7 @@ msgstr "索引中有衝突。請試試看不用 --index。" #: builtin/stash.c msgid "could not save index tree" -msgstr "不能儲存索引樹" +msgstr "無法儲存索引樹" #: builtin/stash.c #, c-format @@ -15415,14 +15472,14 @@ msgstr "期望一個完整的引用名稱,卻得到 %s" #: builtin/submodule--helper.c #, c-format msgid "could not get a repository handle for submodule '%s'" -msgstr "無法獲得子模組 '%s' 的版本庫句柄" +msgstr "無法取得子模組「%s」的版本庫控制代碼" #: builtin/submodule--helper.c #, c-format msgid "" "could not look up configuration '%s'. Assuming this repository is its own " "authoritative upstream." -msgstr "無法找到設定 '%s'。假定這個版本庫是其自身的官方上游。" +msgstr "找不到「%s」組態設定。假定這個版本庫是其自身的官方上游。" #: builtin/submodule--helper.c #, c-format @@ -15501,7 +15558,7 @@ msgstr "在 .gitmodules 中沒有發現路徑 '%s' 的子模組映射" #: builtin/submodule--helper.c #, c-format msgid "could not resolve HEAD ref inside the submodule '%s'" -msgstr "無法解析子模組 '%s' 的 HEAD 引用" +msgstr "無法解析子模組「%s」的 HEAD 引用" #: builtin/submodule--helper.c #, c-format @@ -15540,7 +15597,7 @@ msgstr "%s" #: builtin/submodule--helper.c #, c-format msgid "couldn't hash object from '%s'" -msgstr "無法雜湊來自 '%s' 的物件" +msgstr "無法雜湊來自「%s」的物件" #: builtin/submodule--helper.c #, c-format @@ -15569,7 +15626,7 @@ msgstr "git submodule summary [] [] [--] []" #: builtin/submodule--helper.c msgid "could not fetch a revision for HEAD" -msgstr "無法取得 HEAD 的版本" +msgstr "無法取得 HEAD 的修訂版" #: builtin/submodule--helper.c #, c-format @@ -15617,12 +15674,12 @@ msgstr "已清除目錄 '%s'\n" #: builtin/submodule--helper.c #, c-format msgid "Could not remove submodule work tree '%s'\n" -msgstr "無法移除子模組工作區 '%s'\n" +msgstr "無法移除子模組工作區「%s」\n" #: builtin/submodule--helper.c #, c-format msgid "could not create empty submodule directory %s" -msgstr "不能建立空的子模組目錄 %s" +msgstr "無法建立空的子模組目錄 %s" #: builtin/submodule--helper.c #, c-format @@ -15662,7 +15719,7 @@ msgstr "" #: builtin/submodule--helper.c #, c-format msgid "could not get a repository handle for gitdir '%s'" -msgstr "無法取得 gitdir「%s」的版本庫控點" +msgstr "無法取得 gitdir「%s」的版本庫控制代碼" #: builtin/submodule--helper.c #, c-format @@ -15697,7 +15754,7 @@ msgstr "無法複製 '%s' 到子模組路徑 '%s'" #: builtin/submodule--helper.c #, c-format msgid "could not get submodule directory for '%s'" -msgstr "無法得到 '%s' 的子模組目錄" +msgstr "無法取得「%s」的子模組目錄" #: builtin/submodule--helper.c msgid "alternative anchor for relative paths" @@ -16826,7 +16883,7 @@ msgstr "無法取消「%2$s」中「%1$s」的設定" #: builtin/worktree.c #, c-format msgid "could not create directory of '%s'" -msgstr "不能建立目錄 '%s'" +msgstr "無法建立「%s」的目錄" #: builtin/worktree.c msgid "initializing" @@ -16917,6 +16974,10 @@ msgstr "設定追蹤模式(參見 git-branch(1))" msgid "try to match the new branch name with a remote-tracking branch" msgstr "嘗試為新分支名符合一個遠端追蹤分支" +#: builtin/worktree.c +msgid "use relative paths for worktrees" +msgstr "對工作區使用相對路徑" + #: builtin/worktree.c diff.c parse-options.c #, c-format msgid "options '%s', '%s', and '%s' cannot be used together" @@ -16987,7 +17048,7 @@ msgstr "'%s' 是一個主工作區" #: builtin/worktree.c #, c-format msgid "could not figure out destination name from '%s'" -msgstr "無法從 '%s' 算出目的地名稱" +msgstr "無法從「%s」得出目的地名稱" #: builtin/worktree.c #, c-format @@ -17251,6 +17312,30 @@ msgstr "無法建立「%s」" msgid "index-pack died" msgstr "index-pack 終止" +#: cache-tree.c +#, c-format +msgid "directory '%s' is present in index, but not sparse" +msgstr "「%s」目錄已經在索引裡面,但不在稀疏簽出當中。" + +#: cache-tree.c unpack-trees.c +msgid "corrupted cache-tree has entries not present in index" +msgstr "損壞的快取樹有不在索引中的項目" + +#: cache-tree.c +#, c-format +msgid "%s with flags 0x%x should not be in cache-tree" +msgstr "有 0x%2$x 標記的 %1$s 不應該在快取樹當中" + +#: cache-tree.c +#, c-format +msgid "bad subtree '%.*s'" +msgstr "「%.*s」子樹損壞" + +#: cache-tree.c +#, c-format +msgid "cache-tree for path %.*s does not match. Expected %s got %s" +msgstr "%.*s 路徑的快取樹不符。預期是 %s,卻得到 %s" + #: chunk-format.c msgid "terminating chunk id appears earlier than expected" msgstr "終止區塊 ID 比預期還早出現" @@ -18339,7 +18424,7 @@ msgstr "正在驗證提交圖中的提交" #: commit-reach.c sequencer.c #, c-format msgid "could not parse commit %s" -msgstr "不能解析提交 %s" +msgstr "無法解析提交 %s" #: commit.c #, c-format @@ -18355,7 +18440,7 @@ msgid "" "to convert the grafts into replace refs.\n" "\n" "Turn this message off by running\n" -"\"git config advice.graftFileDeprecated false\"" +"\"git config set advice.graftFileDeprecated false\"" msgstr "" "對 /info/grafts 的支援已棄用,並將在\n" "未來的 Git 版本中被移除。\n" @@ -18363,8 +18448,8 @@ msgstr "" "請使用「git replace --convert-graft-file」將\n" "grafts 轉換為取代引用。\n" "\n" -"設定「git config advice.graftFileDeprecated false」\n" -"可以將本訊息關閉" +"設定「git config set advice.graftFileDeprecated false」\n" +"可以關閉此訊息" #: commit.c #, c-format @@ -18672,7 +18757,7 @@ msgstr "" #: config.c #, c-format msgid "could not expand include path '%s'" -msgstr "無法展開包含路徑 '%s'" +msgstr "無法展開包含路徑「%s」" #: config.c msgid "relative config includes must come from files" @@ -18971,7 +19056,7 @@ msgstr "不允許多列備註:「%s」" #: config.c #, c-format msgid "could not lock config file %s" -msgstr "不能鎖定設定檔案 %s" +msgstr "無法鎖定組態檔案 %s" #: config.c #, c-format @@ -19001,12 +19086,12 @@ msgstr "對 %s 呼叫 chmod 失敗" #: config.c #, c-format msgid "could not write config file %s" -msgstr "不能寫入設定檔案 %s" +msgstr "無法寫入組態檔案 %s" #: config.c #, c-format msgid "could not set '%s' to '%s'" -msgstr "不能設定 '%s' 為 '%s'" +msgstr "無法將「%s」設為「%s」" #: config.c #, c-format @@ -19205,7 +19290,7 @@ msgstr "無法 fork" #: connected.c msgid "Could not run 'git rev-list'" -msgstr "不能執行 'git rev-list'" +msgstr "無法執行「git rev-list」" #: connected.c msgid "failed write to rev-list" @@ -19362,6 +19447,21 @@ msgstr "URL 沒有 Scheme:%s" msgid "credential url cannot be parsed: %s" msgstr "無法解析憑證 URL:%s" +#: daemon.c +#, c-format +msgid "invalid timeout '%s', expecting a non-negative integer" +msgstr "無效的 timeout「%s」,預期為非負整數" + +#: daemon.c +#, c-format +msgid "invalid init-timeout '%s', expecting a non-negative integer" +msgstr "無效的 init-timeout「%s」,應為非負整數" + +#: daemon.c +#, c-format +msgid "invalid max-connections '%s', expecting an integer" +msgstr "無效的 max-connections「%s」,應為整數" + #: date.c msgid "in the future" msgstr "在將來" @@ -19458,7 +19558,7 @@ msgstr "無法封存不存在的路徑「%s」" #: diagnose.c dir.c #, c-format msgid "could not open directory '%s'" -msgstr "不能開啟目錄 '%s'" +msgstr "無法開啟目錄「%s」" #: diagnose.c #, c-format @@ -20178,12 +20278,12 @@ msgstr "版本庫 %s 中的索引檔案損壞" #: dir.c #, c-format msgid "could not create directories for %s" -msgstr "不能為 %s 建立目錄" +msgstr "無法建立 %s 的目錄" #: dir.c #, c-format msgid "could not migrate git directory from '%s' to '%s'" -msgstr "不能從 '%s' 遷移 git 目錄到 '%s'" +msgstr "無法從「%s」遷移 git 目錄到「%s」" #: editor.c #, c-format @@ -20193,12 +20293,12 @@ msgstr "提示:等待您的編輯器關閉檔案...%c" #: editor.c sequencer.c wrapper.c #, c-format msgid "could not write to '%s'" -msgstr "不能寫入 '%s'" +msgstr "無法寫入「%s」" #: editor.c #, c-format msgid "could not edit '%s'" -msgstr "無法編輯 '%s'" +msgstr "無法編輯「%s」" #: entry.c msgid "Filtering content" @@ -20207,7 +20307,7 @@ msgstr "過濾內容" #: entry.c #, c-format msgid "could not stat file '%s'" -msgstr "不能對檔案 '%s' 呼叫 stat" +msgstr "無法 stat 檔案「%s」" #: environment.c #, c-format @@ -20219,6 +20319,23 @@ msgstr "錯誤的 git 名字空間路徑 \"%s\"" msgid "too many args to run %s" msgstr "執行 %s 的參數太多" +#: fetch-pack.c +#, c-format +msgid "" +"You are attempting to fetch %s, which is in the commit graph file but not in " +"the object database.\n" +"This is probably due to repo corruption.\n" +"If you are attempting to repair this repo corruption by refetching the " +"missing object, use 'git fetch --refetch' with the missing object." +msgstr "" +"你正在嘗試取得 %s。這個物件在提交圖檔案中,\n" +"但不在物件資料庫中。\n" +"\n" +"這可能是由於儲存庫損壞所致。\n" +"\n" +"如果你想透過重新擷取遺失的物件來修復儲存庫損壞,\n" +"請使用「git fetch --refetch」並指定遺失的物件。" + #: fetch-pack.c msgid "git fetch-pack: expected shallow list" msgstr "git fetch-pack:應為 shallow 列表" @@ -20647,7 +20764,7 @@ msgstr "執行指令 '%s' 失敗:%s\n" #: gpg-interface.c msgid "could not create temporary file" -msgstr "不能建立暫存檔" +msgstr "無法建立暫存檔" #: gpg-interface.c #, c-format @@ -20925,10 +21042,10 @@ msgstr[0] "" #, c-format msgid "" "The '%s' hook was ignored because it's not set as executable.\n" -"You can disable this warning with `git config advice.ignoredHook false`." +"You can disable this warning with `git config set advice.ignoredHook false`." msgstr "" -"因為沒有將掛鉤 '%s' 設定為可執行,掛鉤被忽略。您可以透過\n" -"設定 `git config advice.ignoredHook false` 來關閉這條警告。" +"因為沒有將掛鉤「%s」設定為可執行,因此忽略這個掛鉤。\n" +"您可以透過設定「git config set advice.ignoredHook false」來關閉這則警告。" #: http-fetch.c msgid "not a git repository" @@ -20948,18 +21065,10 @@ msgstr "http.postBuffer 為負值,預設為 %d" msgid "Delegation control is not supported with cURL < 7.22.0" msgstr "不支援委託控制,因為 cURL < 7.22.0" -#: http.c -msgid "Public key pinning not supported with cURL < 7.39.0" -msgstr "不支援公鑰檔案鎖定,因為 cURL < 7.39.0" - #: http.c msgid "Unknown value for http.proactiveauth" msgstr "http.proactiveauth 的值未知" -#: http.c -msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0" -msgstr "不支援 CURLSSLOPT_NO_REVOKE,因為 cURL < 7.44.0" - #: http.c #, c-format msgid "Unsupported SSL backend '%s'. Supported SSL backends:" @@ -20968,12 +21077,12 @@ msgstr "不支援的 SSL 後端 '%s'。支援的 SSL 後端:" #: http.c #, c-format msgid "Could not set SSL backend to '%s': cURL was built without SSL backends" -msgstr "無法將 SSL 後端設定為 '%s':組建 cURL 時未加入 SSL 後端" +msgstr "無法將 SSL 後端設定為「%s」:組建 cURL 時未加入 SSL 後端" #: http.c #, c-format msgid "Could not set SSL backend to '%s': already set" -msgstr "無法將 SSL 後端設定為 '%s':已經設定" +msgstr "無法將 SSL 後端設定為「%s」:已經設定" #: http.c msgid "refusing to read cookies from http.cookiefile '-'" @@ -21089,7 +21198,7 @@ msgstr "不能混用多種過濾規格" #: list-objects-filter-options.c msgid "unable to upgrade repository format to support partial clone" -msgstr "無法升級版本庫格式,以致不支援部分複製" +msgstr "無法升級版本庫格式,以支援部分複製" #: list-objects-filter-options.h msgid "args" @@ -21180,6 +21289,11 @@ msgstr "偵測到由可列印字元 (quoted) 所組成的 CRLF" msgid "unable to format message: %s" msgstr "無法格式化訊息:%s" +#: merge-ll.c +#, c-format +msgid "invalid marker-size '%s', expecting an integer" +msgstr "無效的 marker-size「%s」,應為整數" + #: merge-ort.c merge-recursive.c #, c-format msgid "Failed to merge submodule %s (not checked out)" @@ -21751,7 +21865,7 @@ msgstr "合併未返回提交" #: merge-recursive.c #, c-format msgid "Could not parse object '%s'" -msgstr "不能解析物件 '%s'" +msgstr "無法解析物件「%s」" #: merge.c msgid "failed to read the cache" @@ -21871,7 +21985,7 @@ msgstr "無法將一個增量多封裝索引的套件設為過期" #: midx-write.c msgid "Counting referenced objects" -msgstr "正在計算引用物件" +msgstr "正在計算引用物件數量" #: midx-write.c msgid "Finding and deleting unreferenced packfiles" @@ -21883,11 +21997,11 @@ msgstr "無法重新封裝增量的多封裝索引" #: midx-write.c msgid "could not start pack-objects" -msgstr "不能開始 pack-objects" +msgstr "無法啟動 pack-objects" #: midx-write.c msgid "could not finish pack-objects" -msgstr "不能結束 pack-objects" +msgstr "無法結束 pack-objects" #: midx.c msgid "multi-pack-index OID fanout is of the wrong size" @@ -22489,17 +22603,17 @@ msgid "" "\n" "where \"$br\" is somehow empty and a 40-hex ref is created. Please\n" "examine these refs and maybe delete them. Turn this message off by\n" -"running \"git config advice.objectNameWarning false\"" +"running \"git config set advice.objectNameWarning false\"" msgstr "" -"Git 通常不會建立以 40 個十六進位字元結尾的引用,\n" -"因為當您只提供 40 個十六進位字元時,其將被忽略。\n" -"這些引用可能被意外建立。例如:\n" +"Git 通常不會建立以 40 個十六進位字元結尾的參照,\n" +"因為在指定 40 個十六進位字元時會被忽略。\n" +"這些參照可能是意外建立的。例如,\n" "\n" " git switch -c $br $(git rev-parse ...)\n" "\n" -"當「$br」因為某些原因空白時,會建立出 40 位十六進位的引用。\n" -"請檢查這些引用,並視需要刪除。執行\n" -"「git config advice.objectNameWarning false」命令以關閉本訊息通知" +"其中「$br」不知何故為空白,導致建立了一個 40 個\n" +"十六進位字元的參照。請檢查這些參照,必要時刪除它們。\n" +"若要關閉此訊息,請執行「git config set advice.objectNameWarning false」" #: object-name.c #, c-format @@ -22774,7 +22888,7 @@ msgstr "偽合併索引超出範圍(% >= %)" #: pack-bitmap.c #, c-format msgid "could not find '%s' in pack '%s' at offset %" -msgstr "在「%2$s」封包,位移 %3$ 的地方找不到「%1$s」" +msgstr "無法在「%2$s」封包,位移 %3$ 的地方找到「%1$s」" #: pack-bitmap.c #, c-format @@ -23071,7 +23185,7 @@ msgstr "解析 %s 失敗" #: path.c #, c-format msgid "Could not make %s writable by group" -msgstr "不能設定 %s 為組可寫" +msgstr "無法設定 %s 為群組可寫" #: pathspec.c msgid "Escape character '\\' not allowed as last character in attr value" @@ -23325,16 +23439,16 @@ msgstr "無法讀取提交 %s 的延伸偽合併表" #: range-diff.c msgid "could not start `log`" -msgstr "不能啟動 `log`" +msgstr "無法啟動「log」" #: range-diff.c msgid "could not read `log` output" -msgstr "不能讀取 `log` 的輸出" +msgstr "無法讀取「log」的輸出" #: range-diff.c sequencer.c #, c-format msgid "could not parse commit '%s'" -msgstr "不能解析提交 '%s'" +msgstr "無法解析提交「%s」" #: range-diff.c #, c-format @@ -23346,7 +23460,7 @@ msgstr "無法解析第一行「log」輸出:開頭不是「commit」:「%s #: range-diff.c #, c-format msgid "could not parse git header '%.*s'" -msgstr "無法解析 git 頭 '%.*s'" +msgstr "無法解析 git 標頭「%.*s」" #: range-diff.c msgid "failed to generate diff" @@ -23355,7 +23469,7 @@ msgstr "生成 diff 失敗" #: range-diff.c #, c-format msgid "could not parse log for '%s'" -msgstr "不能解析 '%s' 的日誌" +msgstr "無法解析「%s」的日誌" #: reachable.c #, c-format @@ -23509,7 +23623,7 @@ msgstr "無法加入 load_index_extensions 執行緒:%s" #: read-cache.c #, c-format msgid "could not freshen shared index '%s'" -msgstr "無法重新整理共享索引 '%s'" +msgstr "無法更新共享索引「%s」" #: read-cache.c #, c-format @@ -23669,7 +23783,7 @@ msgstr "" #: rebase-interactive.c #, c-format msgid "could not write '%s'." -msgstr "不能寫入 '%s'。" +msgstr "無法寫入「%s」。" #: rebase-interactive.c #, c-format @@ -23879,7 +23993,7 @@ msgstr "本命令拒絕 atom %%(%.*s)" #: ref-filter.c #, c-format msgid "--format=%.*s cannot be used with --python, --shell, --tcl" -msgstr "--format=%.*s 不能和 --python、--shell、--tcl 一起使用" +msgstr "--format=%.*s 無法和 --python、--shell、--tcl 一起使用" #: ref-filter.c msgid "failed to run 'describe'" @@ -24109,6 +24223,11 @@ msgid "" "cannot lock ref '%s': expected symref with target '%s': but is a regular ref" msgstr "無法鎖定引用「%s」:預期是指向「%s」的符號引用,但這個是一般引用" +#: refs/files-backend.c +#, c-format +msgid "cannot read ref file '%s'" +msgstr "無法寫入參照檔案「%s」" + #: refs/files-backend.c #, c-format msgid "cannot open directory %s" @@ -24657,7 +24776,7 @@ msgstr "寫入 '%s' (%s) 時發生錯誤" #: rerere.c #, c-format msgid "could not parse conflict hunks in '%s'" -msgstr "不能解析 '%s' 中的衝突區塊" +msgstr "無法解析「%s」中的衝突區塊" #: rerere.c #, c-format @@ -24724,7 +24843,7 @@ msgstr "如果可能,重用衝突解決更新索引" #: reset.c msgid "could not determine HEAD revision" -msgstr "不能確定 HEAD 版本" +msgstr "無法確定 HEAD 修訂版" #: reset.c sequencer.c #, c-format @@ -25110,7 +25229,7 @@ msgstr "無效的提交說明清理模式 '%s'" #: sequencer.c #, c-format msgid "could not delete '%s'" -msgstr "無法刪除 '%s'" +msgstr "無法刪除「%s」" #: sequencer.c msgid "revert" @@ -25185,12 +25304,12 @@ msgstr "" #: sequencer.c #, c-format msgid "could not lock '%s'" -msgstr "不能鎖定 '%s'" +msgstr "無法鎖定「%s」" #: sequencer.c #, c-format msgid "could not write eol to '%s'" -msgstr "不能將換行符號寫入 '%s'" +msgstr "無法將換行符號寫入「%s」" #: sequencer.c #, c-format @@ -25220,7 +25339,7 @@ msgstr "不能更新快取樹" #: sequencer.c msgid "could not resolve HEAD commit" -msgstr "不能解析 HEAD 提交" +msgstr "無法解析 HEAD 提交" #: sequencer.c #, c-format @@ -25347,7 +25466,7 @@ msgstr "無法找到新建立的提交" #: sequencer.c msgid "could not parse newly created commit" -msgstr "不能解析新建立的提交" +msgstr "無法解析新建立的提交" #: sequencer.c msgid "unable to resolve HEAD after creating commit" @@ -25364,7 +25483,7 @@ msgstr " (根提交)" #: sequencer.c msgid "could not parse HEAD" -msgstr "不能解析 HEAD" +msgstr "無法解析 HEAD" #: sequencer.c #, c-format @@ -25392,12 +25511,12 @@ msgstr "作者資訊損壞:缺少日期資訊" #: sequencer.c #, c-format msgid "could not update %s" -msgstr "不能更新 %s" +msgstr "無法更新 %s" #: sequencer.c #, c-format msgid "could not parse parent commit %s" -msgstr "不能解析父提交 %s" +msgstr "無法解析父提交 %s" #: sequencer.c #, c-format @@ -25438,16 +25557,16 @@ msgstr "需要一個 HEAD 來修復" #: sequencer.c msgid "could not read HEAD" -msgstr "不能讀取 HEAD" +msgstr "無法讀取 HEAD" #: sequencer.c msgid "could not read HEAD's commit message" -msgstr "不能讀取 HEAD 的提交說明" +msgstr "無法讀取 HEAD 的提交說明" #: sequencer.c #, c-format msgid "could not read commit message of %s" -msgstr "不能讀取 %s 的提交說明" +msgstr "無法讀取 %s 的提交說明" #: sequencer.c msgid "your index file is unmerged." @@ -25482,12 +25601,12 @@ msgstr "%s:不能解析父提交 %s" #: sequencer.c #, c-format msgid "could not revert %s... %s" -msgstr "不能還原 %s... %s" +msgstr "無法還原 %s... %s" #: sequencer.c #, c-format msgid "could not apply %s... %s" -msgstr "不能套用 %s... %s" +msgstr "無法套用 %s... %s" #: sequencer.c #, c-format @@ -25580,7 +25699,7 @@ msgstr "缺少 %s 的參數" #: sequencer.c #, c-format msgid "could not parse '%s'" -msgstr "無法解析 '%s'" +msgstr "無法解析「%s」" #: sequencer.c #, c-format @@ -25655,7 +25774,7 @@ msgstr "嘗試 \"git cherry-pick (--continue | %s--abort | --quit)\"" #: sequencer.c #, c-format msgid "could not create sequencer directory '%s'" -msgstr "不能建立序列目錄 '%s'" +msgstr "無法建立序列目錄「%s」" #: sequencer.c msgid "no cherry-pick or revert in progress" @@ -25742,12 +25861,12 @@ msgstr "" #: sequencer.c #, c-format msgid "Could not apply %s... %.*s" -msgstr "不能套用 %s... %.*s" +msgstr "無法套用 %s... %.*s" #: sequencer.c #, c-format msgid "Could not merge %.*s" -msgstr "不能合併 %.*s" +msgstr "無法合併 %.*s" #: sequencer.c #, c-format @@ -25799,7 +25918,7 @@ msgstr "非法的標籤名稱:'%.*s'" #: sequencer.c #, c-format msgid "could not resolve '%s'" -msgstr "無法解析 '%s'" +msgstr "無法解析「%s」" #: sequencer.c msgid "writing fake root commit" @@ -25830,12 +25949,12 @@ msgstr "章魚合並不能在一個新的根提交上執行" #: sequencer.c #, c-format msgid "could not get commit message of '%s'" -msgstr "不能取得 '%s' 的提交說明" +msgstr "無法取得「%s」的提交說明" #: sequencer.c #, c-format msgid "could not even attempt to merge '%.*s'" -msgstr "甚至不能嘗試合併 '%.*s'" +msgstr "甚至無法嘗試合併「%.*s」" #: sequencer.c msgid "merge: Unable to write new index file" @@ -25877,7 +25996,7 @@ msgstr "意外的 stash 回應:'%s'" #: sequencer.c #, c-format msgid "Could not create directory for '%s'" -msgstr "不能為 '%s' 建立目錄" +msgstr "無法建立「%s」的目錄" #: sequencer.c #, c-format @@ -25923,7 +26042,7 @@ msgstr "autostash 引用是符號引用" #: sequencer.c msgid "could not detach HEAD" -msgstr "不能分離開頭指標" +msgstr "無法分離開頭指標" #: sequencer.c #, c-format @@ -25950,7 +26069,7 @@ msgstr "" "無法執行待辦指令\n" "\n" " %.*s\n" -"已被重新安排,在繼續之前編輯指令,請先編輯待辦列表:\n" +"已經重新安排。若要在繼續之前編輯指令,請先編輯待辦列表:\n" "\n" " git rebase --edit-todo\n" " git rebase --continue\n" @@ -25972,16 +26091,16 @@ msgstr "未知指令 %d" #: sequencer.c msgid "could not read orig-head" -msgstr "不能讀取 orig-head" +msgstr "無法讀取 orig-head" #: sequencer.c msgid "could not read 'onto'" -msgstr "不能讀取 'onto'" +msgstr "無法讀取「onto」" #: sequencer.c #, c-format msgid "could not update HEAD to %s" -msgstr "不能更新 HEAD 為 %s" +msgstr "無法將 HEAD 更新到 %s" #: sequencer.c #, c-format @@ -26018,15 +26137,15 @@ msgstr "" #: sequencer.c #, c-format msgid "could not write file: '%s'" -msgstr "不能寫入檔案:'%s'" +msgstr "無法寫入檔案:「%s」" #: sequencer.c msgid "could not remove CHERRY_PICK_HEAD" -msgstr "不能刪除 CHERRY_PICK_HEAD" +msgstr "無法刪除 CHERRY_PICK_HEAD" #: sequencer.c msgid "could not commit staged changes." -msgstr "不能提交暫存的修改。" +msgstr "無法提交暫存的修改。" #: sequencer.c #, c-format @@ -26446,7 +26565,7 @@ msgstr "忽略可能被解析為命令列選項的 '%s':%s" #: submodule-config.c #, c-format msgid "Could not update .gitmodules entry %s" -msgstr "不能更新 .gitmodules 條目 %s" +msgstr "無法更新 .gitmodules 條目 %s" #: submodule.c msgid "Cannot change unmerged .gitmodules, resolve merge conflicts first" @@ -26498,7 +26617,7 @@ msgstr "子模組條目 '%s'(%s)是一個 %s,不是一個提交" msgid "" "Could not run 'git rev-list --not --remotes -n 1' command in " "submodule %s" -msgstr "無法在 %s 子模組執行 'git rev-list <提交> --not --remotes -n 1' 命令" +msgstr "無法在 %s 子模組執行「git rev-list <提交> --not --remotes -n 1」命令" #: submodule.c #, c-format @@ -26552,7 +26671,7 @@ msgstr "無法將 '%s' 識別為一個 git 版本庫" #: submodule.c #, c-format msgid "Could not run 'git status --porcelain=2' in submodule %s" -msgstr "無法在 %s 子模組執行 'git status --porcelain=2'" +msgstr "無法在 %s 子模組執行「git status --porcelain=2」" #: submodule.c #, c-format @@ -26562,17 +26681,17 @@ msgstr "%s 子模組執行 'git status --porcelain=2' 失敗" #: submodule.c #, c-format msgid "could not start 'git status' in submodule '%s'" -msgstr "無法在子模組 '%s' 中啟動 'git status'" +msgstr "無法在子模組「%s」中啟動「git status」" #: submodule.c #, c-format msgid "could not run 'git status' in submodule '%s'" -msgstr "無法在子模組 '%s' 中執行 'git status'" +msgstr "無法在子模組「%s」中執行「git status」" #: submodule.c #, c-format msgid "Could not unset core.worktree setting in submodule '%s'" -msgstr "無法在子模組 '%s' 中取消 core.worktree 的設定" +msgstr "無法在子模組「%s」中取消 core.worktree 的設定" #: submodule.c #, c-format @@ -26617,7 +26736,7 @@ msgstr "不支援對有多個工作區的子模組 '%s' 執行 relocate_gitdir" #: submodule.c #, c-format msgid "could not lookup name for submodule '%s'" -msgstr "不能查詢子模組 '%s' 的名稱" +msgstr "無法查詢子模組「%s」的名稱" #: submodule.c #, c-format @@ -26833,7 +26952,7 @@ msgstr "%s 也鎖定了 %s" #: transport-helper.c msgid "couldn't run fast-import" -msgstr "不能執行 fast-import" +msgstr "無法執行 fast-import" #: transport-helper.c msgid "error while running fast-import" @@ -27014,7 +27133,7 @@ msgstr "伺服器不支援「等待完成」(wait-for-done) 功能" #: transport.c msgid "could not parse transport.color.* config" -msgstr "不能解析 transport.color.* 設定" +msgstr "無法解析 transport.color.* 組態" #: transport.c msgid "support for protocol v2 not implemented yet" @@ -27452,6 +27571,10 @@ msgstr ".git 檔案損毀" msgid ".git file incorrect" msgstr ".git 檔案不正確" +#: worktree.c +msgid ".git file absolute/relative path mismatch" +msgstr ".git 檔案的絕對或相對路徑不一致" + #: worktree.c msgid "not a valid path" msgstr "非有效路徑" @@ -27472,6 +27595,10 @@ msgstr "無法定位版本庫;.git 檔案損壞" msgid "gitdir unreadable" msgstr "無法讀取 gitdir" +#: worktree.c +msgid "gitdir absolute/relative path mismatch" +msgstr "gitdir 的絕對或相對路徑不一致" + #: worktree.c msgid "gitdir incorrect" msgstr "不正確的 gitdir" @@ -27516,10 +27643,18 @@ msgstr "無法取消在「%2$s」設定的 %1$s" msgid "failed to set extensions.worktreeConfig setting" msgstr "無法設定 extensions.worktreeConfig 設定" +#: worktree.c +msgid "unable to upgrade repository format to support relative worktrees" +msgstr "無法升級版本庫格式,以支援相對路徑工作區" + +#: worktree.c +msgid "unable to set extensions.relativeWorktrees setting" +msgstr "無法設定 extensions.relativeWorktrees 設定" + #: wrapper.c #, c-format msgid "could not setenv '%s'" -msgstr "無法 setenv '%s'" +msgstr "無法 setenv「%s」" #: wrapper.c #, c-format @@ -27529,7 +27664,7 @@ msgstr "不能建立 '%s'" #: wrapper.c #, c-format msgid "could not open '%s' for reading and writing" -msgstr "無法開啟 '%s' 進行讀寫" +msgstr "無法開啟「%s」進行讀寫" #: wrapper.c #, c-format @@ -28582,6 +28717,20 @@ msgstr "略過 %s 含備份後綴 '%s'。\n" msgid "Do you really want to send %s? [y|N]: " msgstr "您真的要傳送 %s?[y|N]: " +#, c-format +#~ msgid "" +#~ "more than %i tags found; listed %i most recent\n" +#~ "gave up search at %s\n" +#~ msgstr "" +#~ "發現多於 %i 個標籤,列出最近的 %i 個\n" +#~ "在 %s 放棄搜尋\n" + +#~ msgid "Public key pinning not supported with cURL < 7.39.0" +#~ msgstr "不支援公鑰檔案鎖定,因為 cURL < 7.39.0" + +#~ msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0" +#~ msgstr "不支援 CURLSSLOPT_NO_REVOKE,因為 cURL < 7.44.0" + #~ msgid "revision walk setup failed\n" #~ msgstr "修訂版遍歷設定失敗\n" -- cgit v1.2.3 From 2c3ca00b48fb06f1b59ee6fa4401346e42806cb2 Mon Sep 17 00:00:00 2001 From: Yi-Jyun Pan Date: Sat, 28 Dec 2024 13:23:19 +0800 Subject: l10n: zh_TW: Git 2.48 round 2 Co-authored-by: Lumynous Signed-off-by: Yi-Jyun Pan --- po/zh_TW.po | 152 +++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 98 insertions(+), 54 deletions(-) diff --git a/po/zh_TW.po b/po/zh_TW.po index 28afb3662f..a61f544304 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -30,8 +30,8 @@ msgid "" msgstr "" "Project-Id-Version: Git\n" "Report-Msgid-Bugs-To: Git Mailing List \n" -"POT-Creation-Date: 2024-12-17 20:14+0800\n" -"PO-Revision-Date: 2024-12-17 20:52+0800\n" +"POT-Creation-Date: 2024-12-28 13:16+0800\n" +"PO-Revision-Date: 2024-12-28 13:23+0800\n" "Last-Translator: Yi-Jyun Pan \n" "Language-Team: Chinese (Traditional) \n" @@ -941,12 +941,12 @@ msgstr "引數過多" #: apply.c #, c-format msgid "unrecognized whitespace option '%s'" -msgstr "空白字元選項「%s」無法識別" +msgstr "空白字元選項「%s」不認識" #: apply.c #, c-format msgid "unrecognized whitespace ignore option '%s'" -msgstr "空白字元忽略選項「%s」無法識別" +msgstr "空白字元忽略選項「%s」不認識" #: apply.c archive.c builtin/add.c builtin/branch.c builtin/checkout-index.c #: builtin/checkout.c builtin/clean.c builtin/clone.c builtin/commit.c @@ -1081,7 +1081,7 @@ msgstr "二進位修補檔在第 %d 列損壞:%.*s" #: apply.c #, c-format msgid "unrecognized binary patch at line %d" -msgstr "第 %d 列的二進位修補檔無法識別" +msgstr "第 %d 列的二進位修補檔不認識" #: apply.c #, c-format @@ -3021,7 +3021,7 @@ msgstr "「 」不是有效術語" #: builtin/bisect.c #, c-format msgid "unrecognized option: '%s'" -msgstr "無法識別選項:「%s」" +msgstr "不認識選項:「%s」" #: builtin/bisect.c #, c-format @@ -4689,7 +4689,7 @@ msgstr "未知的衝突輸出風格「%s」" msgid "perform a 3-way merge with the new branch" msgstr "和新分支進行三方合併" -#: builtin/checkout.c builtin/log.c parse-options.h +#: builtin/checkout.c builtin/log.c builtin/range-diff.c parse-options.h msgid "style" msgstr "style" @@ -4719,7 +4719,7 @@ msgstr "更新忽略的檔案(預設值)" #: builtin/checkout.c msgid "do not check if another worktree is using this branch" -msgstr "不檢查其他工作區是否正在使用這個提交" +msgstr "不檢查其他工作區是否正在使用此分支" #: builtin/checkout.c msgid "checkout our version for unmerged files" @@ -5100,7 +5100,6 @@ msgid "create a shallow clone since a specific time" msgstr "建立從指定時間到現在的淺層複製" #: builtin/clone.c builtin/fetch.c builtin/pull.c -#| msgid "rev" msgid "ref" msgstr "ref" @@ -5495,7 +5494,7 @@ msgstr "無法開啟提交圖鏈「%s」" #: builtin/commit-graph.c #, c-format msgid "unrecognized --split argument, %s" -msgstr "無法識別的 --split 參數,%s" +msgstr "不認識的 --split 參數,%s" #: builtin/commit-graph.c #, c-format @@ -6253,9 +6252,6 @@ msgstr "" "value] <名稱> <值>" #: builtin/config.c -#| msgid "" -#| "git config unset [] [--all] [--value=] [--fixed-" -#| "value] " msgid "" "git config unset [] [--all] [--value=] [--fixed-value] " "" @@ -6393,7 +6389,7 @@ msgstr "除了顯示組態值,額外顯示其鍵名" #: builtin/config.c #, c-format msgid "unrecognized --type argument, %s" -msgstr "無法識別的 --type 參數,%s" +msgstr "不認識的 --type 參數,%s" #: builtin/config.c msgid "only one type at a time" @@ -7356,6 +7352,21 @@ msgstr "%s 不是一個有效的物件" msgid "the object %s does not exist" msgstr "%s 物件不存在" +#: builtin/fetch.c +#, c-format +msgid "" +"Run 'git remote set-head %s %s' to follow the change, or set\n" +"'remote.%s.followRemoteHEAD' configuration option to a different value\n" +"if you do not want to see this message. Specifically running\n" +"'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n" +"until the remote changes HEAD to something else." +msgstr "" +"執行「git remote set-head %s %s」以追蹤這個變更,或者\n" +"如果您不想看到這則訊息,請將「remote.%s.followRemoteHEAD」\n" +"組態選項設定成不同的值。更具體些來說,執行\n" +"「git config set remote.%s.followRemoteHEAD %s」會停用這個警告,\n" +"直到遠端將 HEAD 變更為其他內容。" + #: builtin/fetch.c msgid "multiple branches detected, incompatible with --set-upstream" msgstr "檢測到多分支,和 --set-upstream 不相容" @@ -8254,7 +8265,7 @@ msgstr "不允許 --no-schedule" #: builtin/gc.c #, c-format msgid "unrecognized --schedule argument '%s'" -msgstr "無法識別的 --schedule 引數 '%s'" +msgstr "不認識的 --schedule 引數 '%s'" #: builtin/gc.c msgid "failed to write commit-graph" @@ -8428,7 +8439,7 @@ msgstr "無法執行 systemctl" #: builtin/gc.c #, c-format msgid "unrecognized --scheduler argument '%s'" -msgstr "無法識別的 --scheduler 引數 '%s'" +msgstr "不認識的 --scheduler 引數 '%s'" #: builtin/gc.c msgid "neither systemd timers nor crontab are available" @@ -8846,7 +8857,7 @@ msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [|]" #: builtin/help.c #, c-format msgid "unrecognized help format '%s'" -msgstr "無法識別的協助格式 '%s'" +msgstr "不認識的協助格式 '%s'" #: builtin/help.c msgid "Failed to start emacsclient." @@ -9429,7 +9440,7 @@ msgstr "追蹤 <開始>,<結束> 範圍中橫列或 <檔案> 中> :<函數名稱 #: builtin/log.c builtin/replay.c builtin/shortlog.c bundle.c #, c-format msgid "unrecognized argument: %s" -msgstr "無法識別的引數:%s" +msgstr "不認識的引數:%s" #: builtin/log.c msgid "-L: cannot be used with pathspec" @@ -10923,10 +10934,6 @@ msgid "git notes [--ref ] [list []]" msgstr "git notes [--ref <註解引用>] [list [<物件>]]" #: builtin/notes.c -#| msgid "" -#| "git notes [--ref ] add [-f] [--allow-empty] [--" -#| "[no-]separator|--separator=] [--[no-]stripspace] [-m " -#| " | -F | (-c | -C) ] []" msgid "" "git notes [--ref ] add [-f] [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " @@ -10941,10 +10948,6 @@ msgid "git notes [--ref ] copy [-f] " msgstr "git notes [--ref <註解引用>] copy [-f] <來源物件> <目標物件>" #: builtin/notes.c -#| msgid "" -#| "git notes [--ref ] append [--allow-empty] [--[no-]separator|--" -#| "separator=] [--[no-]stripspace] [-m | -F | " -#| "(-c | -C) ] []" msgid "" "git notes [--ref ] append [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " @@ -12634,7 +12637,7 @@ msgstr "--empty=ask 已棄用。請改用「--empty=stop」。" msgid "" "unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and " "\"stop\"." -msgstr "無法識別空類型「%s」;有效的數值有「drop」、「keep」跟「stop」。" +msgstr "不認識空類型「%s」;有效的數值有「drop」、「keep」跟「stop」。" #: builtin/rebase.c msgid "" @@ -13611,6 +13614,33 @@ msgid " Local ref configured for 'git push'%s:" msgid_plural " Local refs configured for 'git push'%s:" msgstr[0] " 為 'git push' 設定的本機引用%s:" +#: builtin/remote.c +#, c-format +msgid "'%s/HEAD' is unchanged and points to '%s'\n" +msgstr "「%s/HEAD」沒有變更,指向「%s」\n" + +#: builtin/remote.c +#, c-format +msgid "'%s/HEAD' has changed from '%s' and now points to '%s'\n" +msgstr "「%s/HEAD」已經從「%s」變更,現在指向「%s」\n" + +#: builtin/remote.c +#, c-format +msgid "'%s/HEAD' is now created and points to '%s'\n" +msgstr "「%s/HEAD」現在已經建立並指向「%s」\n" + +#: builtin/remote.c +#, c-format +msgid "'%s/HEAD' was detached at '%s' and now points to '%s'\n" +msgstr "「%s/HEAD」已經在「%s」處分離,現在指向「%s」\n" + +#: builtin/remote.c +#, c-format +msgid "" +"'%s/HEAD' used to point to '%s' (which is not a remote branch), but now " +"points to '%s'\n" +msgstr "「%s/HEAD」原本指向「%s」(不是遠端分支),但現在指向「%s」\n" + #: builtin/remote.c msgid "set refs/remotes//HEAD according to remote" msgstr "根據遠端設定 refs/remotes/<名稱>/HEAD" @@ -13639,7 +13669,7 @@ msgstr "不是一個有效引用:%s" #: builtin/remote.c #, c-format -msgid "Could not setup %s" +msgid "Could not set up %s" msgstr "無法配置 %s" # 譯者:請維持前導空格 @@ -17178,7 +17208,7 @@ msgstr "無法儲存最大的建立權杖" #: bundle-uri.c #, c-format msgid "unrecognized bundle mode from URI '%s'" -msgstr "無法識別從 URI「%s」取回的套件包模式" +msgstr "不認識從 URI「%s」取回的套件包模式" #: bundle-uri.c #, c-format @@ -17219,7 +17249,7 @@ msgstr "bundle-uri: 列有空鍵或空值" #: bundle.c #, c-format msgid "unrecognized bundle hash algorithm: %s" -msgstr "無法識別的套件包雜湊演算法:%s" +msgstr "不認識的套件包雜湊演算法:%s" #: bundle.c #, c-format @@ -17234,7 +17264,7 @@ msgstr "「%s」不像是一個 v2 或 v3 版本的套件包檔案" #: bundle.c #, c-format msgid "unrecognized header: %s%s (%d)" -msgstr "無法識別的標頭:%s%s (%d)" +msgstr "不認識的標頭:%s%s (%d)" #: bundle.c msgid "Repository lacks these prerequisite commits:" @@ -20233,12 +20263,12 @@ msgstr "路徑規格 '%s' 未符合任何 git 已知檔案" #: dir.c #, c-format msgid "unrecognized pattern: '%s'" -msgstr "無法識別樣式:「%s」" +msgstr "不認識樣式:「%s」" #: dir.c #, c-format msgid "unrecognized negative pattern: '%s'" -msgstr "無法識別反向模式:「%s」" +msgstr "不認識反向模式:「%s」" #: dir.c #, c-format @@ -22807,15 +22837,6 @@ msgstr "多包位圖缺少需要的反向索引" msgid "could not open pack %s" msgstr "無法開啟封包 %s" -#: pack-bitmap.c t/helper/test-read-midx.c -msgid "could not determine MIDX preferred pack" -msgstr "無法確定 MIDX 偏好的封裝" - -#: pack-bitmap.c -#, c-format -msgid "preferred pack (%s) is invalid" -msgstr "偏好的封包 (%s) 無效" - #: pack-bitmap.c msgid "corrupt bitmap lookup table: triplet position out of index" msgstr "位圖查詢表損壞:三元組位置超出索引" @@ -23681,7 +23702,7 @@ msgstr "" #, c-format msgid "" "unrecognized setting %s for option rebase.missingCommitsCheck. Ignoring." -msgstr "選項 rebase.missingCommitsCheck 的值 %s 無法識別。已忽略。" +msgstr "選項 rebase.missingCommitsCheck 的值 %s 不認識。已忽略。" #: rebase-interactive.c msgid "" @@ -23842,7 +23863,7 @@ msgstr "%%(%.*s) 不取引數" #: ref-filter.c #, c-format msgid "unrecognized %%(%.*s) argument: %s" -msgstr "無法識別的 %%(%.*s) 引數:%s" +msgstr "不認識的 %%(%.*s) 引數:%s" #: ref-filter.c #, c-format @@ -23852,7 +23873,7 @@ msgstr "期望的格式:%%(color:<顏色>)" #: ref-filter.c #, c-format msgid "unrecognized color: %%(color:%s)" -msgstr "無法識別的顏色:%%(color:%s)" +msgstr "不認識的顏色:%%(color:%s)" #: ref-filter.c #, c-format @@ -23912,17 +23933,17 @@ msgstr "期望的格式:%%(align:<寬度>,<位置>)" #: ref-filter.c #, c-format msgid "unrecognized position:%s" -msgstr "無法識別的位置:%s" +msgstr "不認識的位置:%s" #: ref-filter.c #, c-format msgid "unrecognized width:%s" -msgstr "無法識別的寬度:%s" +msgstr "不認識的寬度:%s" #: ref-filter.c #, c-format msgid "unrecognized %%(%s) argument: %s" -msgstr "無法識別的 %%(%s) 參數:%s" +msgstr "不認識的 %%(%s) 參數:%s" #: ref-filter.c #, c-format @@ -24151,8 +24172,19 @@ msgid "log for %s is empty" msgstr "%s 的日誌為空" #: refs.c -msgid "refusing to force and skip creation of reflog" -msgstr "拒絕強制並略過建立引用日誌" +#, c-format +msgid "refusing to update reflog for pseudoref '%s'" +msgstr "拒絕更新偽引用「%s」 的 reflog" + +#: refs.c +#, c-format +msgid "refusing to update pseudoref '%s'" +msgstr "拒絕更新偽引用「%s」" + +#: refs.c +#, c-format +msgid "refusing to update reflog with bad name '%s'" +msgstr "拒絕更新有錯誤名稱「%s」的 reflog" #: refs.c #, c-format @@ -24160,9 +24192,8 @@ msgid "refusing to update ref with bad name '%s'" msgstr "拒絕更新有錯誤名稱 '%s' 的引用" #: refs.c -#, c-format -msgid "refusing to update pseudoref '%s'" -msgstr "拒絕更新偽引用「%s」" +msgid "refusing to force and skip creation of reflog" +msgstr "拒絕強制並略過建立引用日誌" #: refs.c #, c-format @@ -24484,10 +24515,15 @@ msgstr "提供了一個以上的 receivepack,使用第一個" msgid "more than one uploadpack given, using the first" msgstr "提供了一個以上的 uploadpack,使用第一個" +#: remote.c +#, c-format +msgid "unrecognized followRemoteHEAD value '%s' ignored" +msgstr "已經忽略不認識的「%s」數值" + #: remote.c #, c-format msgid "unrecognized value transfer.credentialsInUrl: '%s'" -msgstr "數值 transfer.credentialsInUrl 無法識別:「%s」" +msgstr "數值 transfer.credentialsInUrl 不認識:「%s」" #: remote.c #, c-format @@ -26797,6 +26833,10 @@ msgstr "提交 %s 沒有標記為可以取得" msgid "too many commits marked reachable" msgstr "太多提交標記為可以取得" +#: t/helper/test-read-midx.c +msgid "could not determine MIDX preferred pack" +msgstr "無法確定 MIDX 偏好的封裝" + #: t/helper/test-serve-v2.c msgid "test-tool serve-v2 []" msgstr "test-tool serve-v2 [<選項>]" @@ -28717,6 +28757,10 @@ msgstr "略過 %s 含備份後綴 '%s'。\n" msgid "Do you really want to send %s? [y|N]: " msgstr "您真的要傳送 %s?[y|N]: " +#, c-format +#~ msgid "preferred pack (%s) is invalid" +#~ msgstr "偏好的封包 (%s) 無效" + #, c-format #~ msgid "" #~ "more than %i tags found; listed %i most recent\n" -- cgit v1.2.3 From 8db127d43f5b0eff254a851f9c966b7b85d91992 Mon Sep 17 00:00:00 2001 From: René Scharfe Date: Sat, 28 Dec 2024 10:47:05 +0100 Subject: reftable: avoid leaks on realloc error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When realloc(3) fails, it returns NULL and keeps the original allocation intact. REFTABLE_ALLOC_GROW overwrites both the original pointer and the allocation count variable in that case, simultaneously leaking the original allocation and misrepresenting the number of storable items. parse_names() and reftable_buf_add() avoid leaking by restoring the original pointer value on failure, but all other callers seem to be OK with losing the old allocation. Add a new variant of the macro, REFTABLE_ALLOC_GROW_OR_NULL, which plugs the leak and zeros the allocation counter. Use it for those callers. Signed-off-by: René Scharfe Signed-off-by: Junio C Hamano --- reftable/basics.h | 10 ++++++++++ reftable/block.c | 10 ++++++---- reftable/pq.c | 2 +- reftable/record.c | 12 ++++++------ reftable/stack.c | 8 +++++--- reftable/writer.c | 5 +++-- t/unit-tests/t-reftable-basics.c | 30 ++++++++++++++++++++++++++++++ 7 files changed, 61 insertions(+), 16 deletions(-) diff --git a/reftable/basics.h b/reftable/basics.h index 36beda2c25..259f4c274c 100644 --- a/reftable/basics.h +++ b/reftable/basics.h @@ -129,6 +129,16 @@ char *reftable_strdup(const char *str); REFTABLE_REALLOC_ARRAY(x, alloc); \ } \ } while (0) + +#define REFTABLE_ALLOC_GROW_OR_NULL(x, nr, alloc) do { \ + void *reftable_alloc_grow_or_null_orig_ptr = (x); \ + REFTABLE_ALLOC_GROW((x), (nr), (alloc)); \ + if (!(x)) { \ + reftable_free(reftable_alloc_grow_or_null_orig_ptr); \ + alloc = 0; \ + } \ +} while (0) + #define REFTABLE_FREE_AND_NULL(p) do { reftable_free(p); (p) = NULL; } while (0) #ifndef REFTABLE_ALLOW_BANNED_ALLOCATORS diff --git a/reftable/block.c b/reftable/block.c index 0198078485..9858bbc7c5 100644 --- a/reftable/block.c +++ b/reftable/block.c @@ -53,7 +53,8 @@ static int block_writer_register_restart(struct block_writer *w, int n, if (2 + 3 * rlen + n > w->block_size - w->next) return -1; if (is_restart) { - REFTABLE_ALLOC_GROW(w->restarts, w->restart_len + 1, w->restart_cap); + REFTABLE_ALLOC_GROW_OR_NULL(w->restarts, w->restart_len + 1, + w->restart_cap); if (!w->restarts) return REFTABLE_OUT_OF_MEMORY_ERROR; w->restarts[w->restart_len++] = w->next; @@ -176,7 +177,8 @@ int block_writer_finish(struct block_writer *w) * is guaranteed to return `Z_STREAM_END`. */ compressed_len = deflateBound(w->zstream, src_len); - REFTABLE_ALLOC_GROW(w->compressed, compressed_len, w->compressed_cap); + REFTABLE_ALLOC_GROW_OR_NULL(w->compressed, compressed_len, + w->compressed_cap); if (!w->compressed) { ret = REFTABLE_OUT_OF_MEMORY_ERROR; return ret; @@ -235,8 +237,8 @@ int block_reader_init(struct block_reader *br, struct reftable_block *block, uLong src_len = block->len - block_header_skip; /* Log blocks specify the *uncompressed* size in their header. */ - REFTABLE_ALLOC_GROW(br->uncompressed_data, sz, - br->uncompressed_cap); + REFTABLE_ALLOC_GROW_OR_NULL(br->uncompressed_data, sz, + br->uncompressed_cap); if (!br->uncompressed_data) { err = REFTABLE_OUT_OF_MEMORY_ERROR; goto done; diff --git a/reftable/pq.c b/reftable/pq.c index 6ee1164dd3..5591e875e1 100644 --- a/reftable/pq.c +++ b/reftable/pq.c @@ -49,7 +49,7 @@ int merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry { size_t i = 0; - REFTABLE_ALLOC_GROW(pq->heap, pq->len + 1, pq->cap); + REFTABLE_ALLOC_GROW_OR_NULL(pq->heap, pq->len + 1, pq->cap); if (!pq->heap) return REFTABLE_OUT_OF_MEMORY_ERROR; pq->heap[pq->len++] = *e; diff --git a/reftable/record.c b/reftable/record.c index fb5652ed57..04429d23fe 100644 --- a/reftable/record.c +++ b/reftable/record.c @@ -246,8 +246,8 @@ static int reftable_ref_record_copy_from(void *rec, const void *src_rec, if (src->refname) { size_t refname_len = strlen(src->refname); - REFTABLE_ALLOC_GROW(ref->refname, refname_len + 1, - ref->refname_cap); + REFTABLE_ALLOC_GROW_OR_NULL(ref->refname, refname_len + 1, + ref->refname_cap); if (!ref->refname) { err = REFTABLE_OUT_OF_MEMORY_ERROR; goto out; @@ -385,7 +385,7 @@ static int reftable_ref_record_decode(void *rec, struct reftable_buf key, SWAP(r->refname, refname); SWAP(r->refname_cap, refname_cap); - REFTABLE_ALLOC_GROW(r->refname, key.len + 1, r->refname_cap); + REFTABLE_ALLOC_GROW_OR_NULL(r->refname, key.len + 1, r->refname_cap); if (!r->refname) { err = REFTABLE_OUT_OF_MEMORY_ERROR; goto done; @@ -839,7 +839,7 @@ static int reftable_log_record_decode(void *rec, struct reftable_buf key, if (key.len <= 9 || key.buf[key.len - 9] != 0) return REFTABLE_FORMAT_ERROR; - REFTABLE_ALLOC_GROW(r->refname, key.len - 8, r->refname_cap); + REFTABLE_ALLOC_GROW_OR_NULL(r->refname, key.len - 8, r->refname_cap); if (!r->refname) { err = REFTABLE_OUT_OF_MEMORY_ERROR; goto done; @@ -947,8 +947,8 @@ static int reftable_log_record_decode(void *rec, struct reftable_buf key, } string_view_consume(&in, n); - REFTABLE_ALLOC_GROW(r->value.update.message, scratch->len + 1, - r->value.update.message_cap); + REFTABLE_ALLOC_GROW_OR_NULL(r->value.update.message, scratch->len + 1, + r->value.update.message_cap); if (!r->value.update.message) { err = REFTABLE_OUT_OF_MEMORY_ERROR; goto done; diff --git a/reftable/stack.c b/reftable/stack.c index 634f0c5425..531660a49f 100644 --- a/reftable/stack.c +++ b/reftable/stack.c @@ -317,7 +317,9 @@ static int reftable_stack_reload_once(struct reftable_stack *st, * thus need to keep them alive here, which we * do by bumping their refcount. */ - REFTABLE_ALLOC_GROW(reused, reused_len + 1, reused_alloc); + REFTABLE_ALLOC_GROW_OR_NULL(reused, + reused_len + 1, + reused_alloc); if (!reused) { err = REFTABLE_OUT_OF_MEMORY_ERROR; goto done; @@ -949,8 +951,8 @@ int reftable_addition_add(struct reftable_addition *add, if (err < 0) goto done; - REFTABLE_ALLOC_GROW(add->new_tables, add->new_tables_len + 1, - add->new_tables_cap); + REFTABLE_ALLOC_GROW_OR_NULL(add->new_tables, add->new_tables_len + 1, + add->new_tables_cap); if (!add->new_tables) { err = REFTABLE_OUT_OF_MEMORY_ERROR; goto done; diff --git a/reftable/writer.c b/reftable/writer.c index 624e90fb53..740c98038e 100644 --- a/reftable/writer.c +++ b/reftable/writer.c @@ -254,7 +254,8 @@ static int writer_index_hash(struct reftable_writer *w, struct reftable_buf *has if (key->offset_len > 0 && key->offsets[key->offset_len - 1] == off) return 0; - REFTABLE_ALLOC_GROW(key->offsets, key->offset_len + 1, key->offset_cap); + REFTABLE_ALLOC_GROW_OR_NULL(key->offsets, key->offset_len + 1, + key->offset_cap); if (!key->offsets) return REFTABLE_OUT_OF_MEMORY_ERROR; key->offsets[key->offset_len++] = off; @@ -820,7 +821,7 @@ static int writer_flush_nonempty_block(struct reftable_writer *w) * Note that this also applies when flushing index blocks, in which * case we will end up with a multi-level index. */ - REFTABLE_ALLOC_GROW(w->index, w->index_len + 1, w->index_cap); + REFTABLE_ALLOC_GROW_OR_NULL(w->index, w->index_len + 1, w->index_cap); if (!w->index) return REFTABLE_OUT_OF_MEMORY_ERROR; diff --git a/t/unit-tests/t-reftable-basics.c b/t/unit-tests/t-reftable-basics.c index 65d50df091..5bf79c9976 100644 --- a/t/unit-tests/t-reftable-basics.c +++ b/t/unit-tests/t-reftable-basics.c @@ -20,6 +20,11 @@ static int integer_needle_lesseq(size_t i, void *_args) return args->needle <= args->haystack[i]; } +static void *realloc_stub(void *p UNUSED, size_t size UNUSED) +{ + return NULL; +} + int cmd_main(int argc UNUSED, const char *argv[] UNUSED) { if_test ("binary search with binsearch works") { @@ -141,5 +146,30 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED) check_int(in, ==, out); } + if_test ("REFTABLE_ALLOC_GROW_OR_NULL works") { + int *arr = NULL; + size_t alloc = 0, old_alloc; + + REFTABLE_ALLOC_GROW_OR_NULL(arr, 1, alloc); + check(arr != NULL); + check_uint(alloc, >=, 1); + arr[0] = 42; + + old_alloc = alloc; + REFTABLE_ALLOC_GROW_OR_NULL(arr, old_alloc + 1, alloc); + check(arr != NULL); + check_uint(alloc, >, old_alloc); + arr[alloc - 1] = 42; + + old_alloc = alloc; + reftable_set_alloc(malloc, realloc_stub, free); + REFTABLE_ALLOC_GROW_OR_NULL(arr, old_alloc + 1, alloc); + check(arr == NULL); + check_uint(alloc, ==, 0); + reftable_set_alloc(malloc, realloc, free); + + reftable_free(arr); + } + return test_done(); } -- cgit v1.2.3 From 2cca185e85171c462166839cfd6ee57c09573160 Mon Sep 17 00:00:00 2001 From: René Scharfe Date: Sat, 28 Dec 2024 10:48:00 +0100 Subject: reftable: fix allocation count on realloc error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When realloc(3) fails, it returns NULL and keeps the original allocation intact. REFTABLE_ALLOC_GROW overwrites both the original pointer and the allocation count variable in that case, simultaneously leaking the original allocation and misrepresenting the number of storable items. parse_names() avoids the leak by keeping the original pointer if reallocation fails, but still increase the allocation count in such a case as if it succeeded. That's OK, because the error handling code just frees everything and doesn't look at names_cap anymore. reftable_buf_add() does the same, but here it is a problem as it leaves the reftable_buf in a broken state, with ->alloc being roughly twice as big as the actually allocated memory, allowing out-of-bounds writes in subsequent calls. Reimplement REFTABLE_ALLOC_GROW to avoid leaks, keep allocation counts in sync and still signal failures to callers while avoiding code duplication in callers. Make it an expression that evaluates to 0 if no reallocation is needed or it succeeded and 1 on failure while keeping the original pointer and allocation counter values. Adjust REFTABLE_ALLOC_GROW_OR_NULL to the new calling convention for REFTABLE_ALLOC_GROW, but keep its support for non-size_t alloc variables for now. Signed-off-by: René Scharfe Signed-off-by: Junio C Hamano --- reftable/basics.c | 11 +++-------- reftable/basics.h | 39 ++++++++++++++++++++++++++------------- t/unit-tests/t-reftable-basics.c | 26 ++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 21 deletions(-) diff --git a/reftable/basics.c b/reftable/basics.c index 70b1091d14..cd6b39dbe9 100644 --- a/reftable/basics.c +++ b/reftable/basics.c @@ -124,11 +124,8 @@ int reftable_buf_add(struct reftable_buf *buf, const void *data, size_t len) size_t newlen = buf->len + len; if (newlen + 1 > buf->alloc) { - char *reallocated = buf->buf; - REFTABLE_ALLOC_GROW(reallocated, newlen + 1, buf->alloc); - if (!reallocated) + if (REFTABLE_ALLOC_GROW(buf->buf, newlen + 1, buf->alloc)) return REFTABLE_OUT_OF_MEMORY_ERROR; - buf->buf = reallocated; } memcpy(buf->buf + buf->len, data, len); @@ -233,11 +230,9 @@ char **parse_names(char *buf, int size) next = end; } if (p < next) { - char **names_grown = names; - REFTABLE_ALLOC_GROW(names_grown, names_len + 1, names_cap); - if (!names_grown) + if (REFTABLE_ALLOC_GROW(names, names_len + 1, + names_cap)) goto err; - names = names_grown; names[names_len] = reftable_strdup(p); if (!names[names_len++]) diff --git a/reftable/basics.h b/reftable/basics.h index 259f4c274c..4bf71b0954 100644 --- a/reftable/basics.h +++ b/reftable/basics.h @@ -120,22 +120,35 @@ char *reftable_strdup(const char *str); #define REFTABLE_ALLOC_ARRAY(x, alloc) (x) = reftable_malloc(st_mult(sizeof(*(x)), (alloc))) #define REFTABLE_CALLOC_ARRAY(x, alloc) (x) = reftable_calloc((alloc), sizeof(*(x))) #define REFTABLE_REALLOC_ARRAY(x, alloc) (x) = reftable_realloc((x), st_mult(sizeof(*(x)), (alloc))) -#define REFTABLE_ALLOC_GROW(x, nr, alloc) \ - do { \ - if ((nr) > alloc) { \ - alloc = 2 * (alloc) + 1; \ - if (alloc < (nr)) \ - alloc = (nr); \ - REFTABLE_REALLOC_ARRAY(x, alloc); \ - } \ - } while (0) + +static inline void *reftable_alloc_grow(void *p, size_t nelem, size_t elsize, + size_t *allocp) +{ + void *new_p; + size_t alloc = *allocp * 2 + 1; + if (alloc < nelem) + alloc = nelem; + new_p = reftable_realloc(p, st_mult(elsize, alloc)); + if (!new_p) + return p; + *allocp = alloc; + return new_p; +} + +#define REFTABLE_ALLOC_GROW(x, nr, alloc) ( \ + (nr) > (alloc) && ( \ + (x) = reftable_alloc_grow((x), (nr), sizeof(*(x)), &(alloc)), \ + (nr) > (alloc) \ + ) \ +) #define REFTABLE_ALLOC_GROW_OR_NULL(x, nr, alloc) do { \ - void *reftable_alloc_grow_or_null_orig_ptr = (x); \ - REFTABLE_ALLOC_GROW((x), (nr), (alloc)); \ - if (!(x)) { \ - reftable_free(reftable_alloc_grow_or_null_orig_ptr); \ + size_t reftable_alloc_grow_or_null_alloc = alloc; \ + if (REFTABLE_ALLOC_GROW((x), (nr), reftable_alloc_grow_or_null_alloc)) { \ + REFTABLE_FREE_AND_NULL(x); \ alloc = 0; \ + } else { \ + alloc = reftable_alloc_grow_or_null_alloc; \ } \ } while (0) diff --git a/t/unit-tests/t-reftable-basics.c b/t/unit-tests/t-reftable-basics.c index 5bf79c9976..990dc1a244 100644 --- a/t/unit-tests/t-reftable-basics.c +++ b/t/unit-tests/t-reftable-basics.c @@ -146,6 +146,32 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED) check_int(in, ==, out); } + if_test ("REFTABLE_ALLOC_GROW works") { + int *arr = NULL, *old_arr; + size_t alloc = 0, old_alloc; + + check(!REFTABLE_ALLOC_GROW(arr, 1, alloc)); + check(arr != NULL); + check_uint(alloc, >=, 1); + arr[0] = 42; + + old_alloc = alloc; + old_arr = arr; + reftable_set_alloc(malloc, realloc_stub, free); + check(REFTABLE_ALLOC_GROW(arr, old_alloc + 1, alloc)); + check(arr == old_arr); + check_uint(alloc, ==, old_alloc); + + old_alloc = alloc; + reftable_set_alloc(malloc, realloc, free); + check(!REFTABLE_ALLOC_GROW(arr, old_alloc + 1, alloc)); + check(arr != NULL); + check_uint(alloc, >, old_alloc); + arr[alloc - 1] = 42; + + reftable_free(arr); + } + if_test ("REFTABLE_ALLOC_GROW_OR_NULL works") { int *arr = NULL; size_t alloc = 0, old_alloc; -- cgit v1.2.3 From e4981ed1e72d3f25da901b9415d2c4805bed0dbc Mon Sep 17 00:00:00 2001 From: René Scharfe Date: Sat, 28 Dec 2024 10:48:50 +0100 Subject: reftable: handle realloc error in parse_names() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check the final reallocation for adding the terminating NULL and handle it just like those in the loop. Simply use REFTABLE_ALLOC_GROW instead of keeping the REFTABLE_REALLOC_ARRAY call and adding code to preserve the original pointer value around it. Signed-off-by: René Scharfe Signed-off-by: Junio C Hamano --- reftable/basics.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/reftable/basics.c b/reftable/basics.c index cd6b39dbe9..fe2b83ff83 100644 --- a/reftable/basics.c +++ b/reftable/basics.c @@ -241,7 +241,8 @@ char **parse_names(char *buf, int size) p = next + 1; } - REFTABLE_REALLOC_ARRAY(names, names_len + 1); + if (REFTABLE_ALLOC_GROW(names, names_len + 1, names_cap)) + goto err; names[names_len] = NULL; return names; -- cgit v1.2.3 From 1e781209284eb5952e153339f45bf0c1555e78bb Mon Sep 17 00:00:00 2001 From: René Scharfe Date: Sat, 28 Dec 2024 10:49:38 +0100 Subject: t-reftable-merged: handle realloc errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check reallocation errors in unit tests, like everywhere else. Signed-off-by: René Scharfe Signed-off-by: Junio C Hamano --- t/unit-tests/t-reftable-merged.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/unit-tests/t-reftable-merged.c b/t/unit-tests/t-reftable-merged.c index a12bd0e1a3..60836f80d6 100644 --- a/t/unit-tests/t-reftable-merged.c +++ b/t/unit-tests/t-reftable-merged.c @@ -178,7 +178,7 @@ static void t_merged_refs(void) if (err > 0) break; - REFTABLE_ALLOC_GROW(out, len + 1, cap); + check(!REFTABLE_ALLOC_GROW(out, len + 1, cap)); out[len++] = ref; } reftable_iterator_destroy(&it); @@ -459,7 +459,7 @@ static void t_merged_logs(void) if (err > 0) break; - REFTABLE_ALLOC_GROW(out, len + 1, cap); + check(!REFTABLE_ALLOC_GROW(out, len + 1, cap)); out[len++] = log; } reftable_iterator_destroy(&it); -- cgit v1.2.3 From 31f5549c285ec793a67a9d072db38fec087c7e32 Mon Sep 17 00:00:00 2001 From: Jean-Noël Avila Date: Fri, 20 Dec 2024 18:37:48 +0100 Subject: l10n: fr: v2.48.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-Noël Avila --- po/fr.po | 331 ++++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 243 insertions(+), 88 deletions(-) diff --git a/po/fr.po b/po/fr.po index b113e3870b..64a75aecf5 100644 --- a/po/fr.po +++ b/po/fr.po @@ -87,8 +87,8 @@ msgid "" msgstr "" "Project-Id-Version: git\n" "Report-Msgid-Bugs-To: Git Mailing List \n" -"POT-Creation-Date: 2024-10-02 16:57+0000\n" -"PO-Revision-Date: 2024-10-04 23:03+0200\n" +"POT-Creation-Date: 2024-12-23 18:57+0000\n" +"PO-Revision-Date: 2024-12-29 18:26+0100\n" "Last-Translator: Cédric Malard \n" "Language-Team: Jean-Noël Avila \n" "Language: fr\n" @@ -468,14 +468,14 @@ msgstr "" #, c-format msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? " msgstr "" -"Appliquer le changement de mode dans l'index et l'arbre de travail [y,n,q,a," -"d%s,?] ? " +"Appliquer le changement de mode dans l'index et l'arbre de travail " +"[y,n,q,a,d%s,?] ? " #, c-format msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? " msgstr "" -"Appliquer la suppression dans l'index et l'arbre de travail [y,n,q,a," -"d%s,?] ? " +"Appliquer la suppression dans l'index et l'arbre de travail " +"[y,n,q,a,d%s,?] ? " #, c-format msgid "Apply addition to index and worktree [y,n,q,a,d%s,?]? " @@ -717,10 +717,10 @@ msgstr "Seuls des fichiers binaires ont changé." #, c-format msgid "" "\n" -"Disable this message with \"git config advice.%s false\"" +"Disable this message with \"git config set advice.%s false\"" msgstr "" "\n" -"Désactivez ce message avec \"git config advice.%s false\"" +"Désactivez ce message avec \"git config set advice.%s false\"" #, c-format msgid "%shint:%s%.*s%s\n" @@ -844,8 +844,8 @@ msgstr "" "\n" " git switch -\n" "\n" -"Désactivez ce conseil en renseignant la variable de configuration advice." -"detachedHead à false\n" +"Désactivez ce conseil en renseignant la variable de configuration " +"advice.detachedHead à false\n" "\n" #, c-format @@ -919,14 +919,14 @@ msgstr "" #, c-format msgid "git apply: bad git-diff - inconsistent new filename on line %d" msgstr "" -"git apply : mauvais format de git-diff - nouveau nom de fichier incohérent " -"à la ligne %d" +"git apply : mauvais format de git-diff - nouveau nom de fichier incohérent à " +"la ligne %d" #, c-format msgid "git apply: bad git-diff - inconsistent old filename on line %d" msgstr "" -"git apply : mauvais format de git-diff - ancien nom de fichier incohérent " -"à la ligne %d" +"git apply : mauvais format de git-diff - ancien nom de fichier incohérent à " +"la ligne %d" #, c-format msgid "git apply: bad git-diff - expected /dev/null on line %d" @@ -1039,8 +1039,8 @@ msgstr "données de rustine binaire manquantes pour '%s'" #, c-format msgid "cannot reverse-apply a binary patch without the reverse hunk to '%s'" msgstr "" -"impossible d'appliquer l'inverse d'une rustine binaire à '%s' sans la section " -"inverse" +"impossible d'appliquer l'inverse d'une rustine binaire à '%s' sans la " +"section inverse" #, c-format msgid "cannot apply binary patch to '%s' without full index line" @@ -1052,7 +1052,8 @@ msgstr "" msgid "" "the patch applies to '%s' (%s), which does not match the current contents." msgstr "" -"la rustine s'applique à '%s' (%s), ce qui ne correspond pas au contenu actuel." +"la rustine s'applique à '%s' (%s), ce qui ne correspond pas au contenu " +"actuel." #, c-format msgid "the patch applies to an empty '%s' but it is not empty" @@ -1473,8 +1474,9 @@ msgstr "nom d'objet invalide : %s" msgid "not a tree object: %s" msgstr "objet arbre invalide : %s" -msgid "unable to checkout working tree" -msgstr "impossible d'extraire la copie de travail" +#, c-format +msgid "failed to unpack tree object %s" +msgstr "échec du dépaquetage de l'objet arbre %s" #, c-format msgid "File not found: %s" @@ -3137,11 +3139,11 @@ msgid "HEAD not found below refs/heads!" msgstr "HEAD non trouvée sous refs/heads !" msgid "" -"branch with --recurse-submodules can only be used if submodule." -"propagateBranches is enabled" +"branch with --recurse-submodules can only be used if " +"submodule.propagateBranches is enabled" msgstr "" -"brancher avec --recurse-submodules ne peut être utilisé que si submodule." -"propagateBranches est activé" +"brancher avec --recurse-submodules ne peut être utilisé que si " +"submodule.propagateBranches est activé" msgid "--recurse-submodules can only be used to create branches" msgstr "--recurse-submodules ne peut être utilisé que pour créer des branches" @@ -3592,10 +3594,6 @@ msgstr "git check-mailmap [] ..." msgid "also read contacts from stdin" msgstr "lire aussi les contacts depuis l'entrée standard" -#, c-format -msgid "unable to parse contact: %s" -msgstr "impossible d'analyser le contact : %s" - msgid "read additional mailmap entries from file" msgstr "lire des entrées supplémentaires de mailmap depuis un fichier" @@ -4007,9 +4005,8 @@ msgstr "nouvelle branche non née" msgid "update ignored files (default)" msgstr "mettre à jour les fichiers ignorés (par défaut)" -msgid "do not check if another worktree is holding the given ref" -msgstr "" -"ne pas vérifier si une autre copie de travail contient le référence fournie" +msgid "do not check if another worktree is using this branch" +msgstr "ne pas vérifier si une autre copie-de-travail utilise cette branche" msgid "checkout our version for unmerged files" msgstr "extraire notre version pour les fichiers non fusionnés" @@ -4312,12 +4309,11 @@ msgstr "créer un clone superficiel de cette profondeur" msgid "create a shallow clone since a specific time" msgstr "créer un clone superficiel depuis une date spécifique" -msgid "revision" -msgstr "révision" +msgid "ref" +msgstr "ref" -msgid "deepen history of shallow clone, excluding rev" -msgstr "" -"approfondir l'historique d'un clone superficiel en excluant une révision" +msgid "deepen history of shallow clone, excluding ref" +msgstr "approfondit l'historique d'un clone superficiel en excluant une ref" msgid "clone only one branch, HEAD or --branch" msgstr "cloner seulement une branche, HEAD ou --branch" @@ -4451,6 +4447,9 @@ msgstr "" "la HEAD distante réfère à une référence non existante, impossible de " "l'extraire" +msgid "unable to checkout working tree" +msgstr "impossible d'extraire la copie de travail" + msgid "unable to write parameters to config file" msgstr "impossible d'écrire les paramètres dans le fichier de configuration" @@ -5270,10 +5269,10 @@ msgstr "" msgid "" "git config unset [] [--all] [--value=] [--fixed-value] " -" " +"" msgstr "" "git config unset [] [--all] [--value=] [--fixed-" -"value] " +"value] " msgid "git config rename-section [] " msgstr "" @@ -5719,13 +5718,8 @@ msgid "traversed %lu commits\n" msgstr "%lu commits parcourus\n" #, c-format -msgid "" -"more than %i tags found; listed %i most recent\n" -"gave up search at %s\n" -msgstr "" -"plus de %i étiquettes ont été trouvées; seules les %i plus récentes sont " -"affichées\n" -"abandon de la recherche à %s\n" +msgid "found %i tags; gave up search at %s\n" +msgstr "%i étiquettes trouvées ; recherche abandonnée à %s\n" #, c-format msgid "describe %s\n" @@ -6169,6 +6163,20 @@ msgstr "%s n'est pas un objet valide" msgid "the object %s does not exist" msgstr "l'objet %s n'existe pas" +#, c-format +msgid "" +"Run 'git remote set-head %s %s' to follow the change, or set\n" +"'remote.%s.followRemoteHEAD' configuration option to a different value\n" +"if you do not want to see this message. Specifically running\n" +"'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n" +"until the remote changes HEAD to something else." +msgstr "" +"Lancez 'git remote set-head %s %s' pour suivre la modification, ou\n" +"réglez l'option de configuration 'remote.%s.followRemoteHEAD' à une\n" +"valeur différente si vous ne souhaitez pas voir ce message. Lancer\n" +"spécifiquement 'git config set remote.%s.followRemoteHEAD %s'\n" +"va désactiver l'alerte jusqu'à ce que le distant change HEAD." + msgid "multiple branches detected, incompatible with --set-upstream" msgstr "branches multiples détectées, imcompatible avec --set-upstream" @@ -6309,6 +6317,9 @@ msgstr "correspondance de référence" msgid "specify fetch refmap" msgstr "spécifier une correspondance de référence pour la récupération" +msgid "revision" +msgstr "révision" + msgid "report that we have only objects reachable from this object" msgstr "rapporte que nous n'avons que des objets joignables depuis cet objet" @@ -6366,8 +6377,8 @@ msgid "protocol does not support --negotiate-only, exiting" msgstr "Le protocole ne prend pas en charge --negotiate-only, abandon" msgid "" -"--filter can only be used with the remote configured in extensions." -"partialclone" +"--filter can only be used with the remote configured in " +"extensions.partialclone" msgstr "" "--filter ne peut être utilisé qu'avec le dépôt distant configuré dans " "extensions.partialclone" @@ -7042,9 +7053,27 @@ msgstr "ni les minuteurs systemd ni crontab ne sont disponibles" msgid "%s scheduler is not available" msgstr "le planificateur %s n'est pas disponible" -msgid "another process is scheduling background maintenance" +#, c-format +msgid "" +"unable to create '%s.lock': %s.\n" +"\n" +"Another scheduled git-maintenance(1) process seems to be running in this\n" +"repository. Please make sure no other maintenance processes are running and\n" +"then try again. If it still fails, a git-maintenance(1) process may have\n" +"crashed in this repository earlier: remove the file manually to continue." +msgstr "" +"impossible de créer '%s.lock' : %s.\n" +"\n" +"Il semble qu'un processus git-maintenance(1) programmé est déjà lancé dans\n" +"ce dépôt. Veuillez vous assurer qu'aucun processus de maintenance n'est " +"lancé\n" +"et réessayez. Si l'échec persiste, un processus git-maintenance(1) peut " +"avoir\n" +"planté dans ce dépôt : supprimez le fichier manuellement pour poursuivre." + +msgid "cannot acquire lock for scheduled background maintenance" msgstr "" -"un autre processus est en train de programmer une maintenance en tâche de " +"impossible d'acquérir le verrou pour une maintenance programmée en tâche de " "fond" msgid "git maintenance start [--scheduler=]" @@ -7625,6 +7654,22 @@ msgid_plural "chain length = %d: %lu objects" msgstr[0] "longueur chaînée = %d : %lu objet" msgstr[1] "longueur chaînée = %d : %lu objets" +msgid "could not start pack-objects to repack local links" +msgstr "" +"impossible de démarrer pack-objects pour ré-empaqueter les liens locaux" + +msgid "failed to feed local object to pack-objects" +msgstr "échéc de la fourniture les objets locaux à pack-objects" + +msgid "index-pack: Expecting full hex object ID lines only from pack-objects." +msgstr "" +"index-pack : attente de lignes d'Id d'objets en hexa complet seulement " +"depuis les objects de paquet." + +msgid "could not finish pack-objects to repack local links" +msgstr "" +"impossible de terminer pack-objects pour ré-empaqueter les objets locaux" + msgid "Cannot come back to cwd" msgstr "Impossible de revenir au répertoire de travail courant" @@ -7636,6 +7681,9 @@ msgstr "mauvais %s" msgid "unknown hash algorithm '%s'" msgstr "algorithme d'empreinte inconnu '%s'" +msgid "--promisor cannot be used with a pack name" +msgstr "--promisor ne peut pas être utilisé avec un nom de paquet" + msgid "--stdin requires a git repository" msgstr "--stdin requiert un dépôt git" @@ -9022,11 +9070,11 @@ msgstr "git notes [--ref ] [list []]" msgid "" "git notes [--ref ] add [-f] [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" msgstr "" "git notes [--ref ] add [-f] [--allow-empty] [--" "[no-]separator|--separator=] [--[no-]stripspace] [-m " -" | -F | (-c | -C) ] []" +" | -F | (-c | -C) ] [] [-e]" msgid "git notes [--ref ] copy [-f] " msgstr "" @@ -9035,11 +9083,11 @@ msgstr "" msgid "" "git notes [--ref ] append [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" msgstr "" "git notes [--ref ] append [--allow-empty] [--" "[no-]separator|--separator=] [--[no-]stripspace]-m " -" | -F | (-c | -C) ] []" +" | -F | (-c | -C) ] [] [-e]" msgid "git notes [--ref ] edit [--allow-empty] []" msgstr "git notes [--ref ] edit [--allow-empty] []" @@ -9158,6 +9206,9 @@ msgstr "contenu de la note dans un fichier" msgid "reuse and edit specified note object" msgstr "réutiliser et éditer l'objet de note spécifié" +msgid "edit note message in editor" +msgstr "éditer le message de node dans un éditeur" + msgid "reuse specified note object" msgstr "réutiliser l'objet de note spécifié" @@ -9667,6 +9718,9 @@ msgstr "gestion des objets manquants" msgid "do not pack objects in promisor packfiles" msgstr "ne pas empaqueter les objets dans les fichiers paquets prometteurs" +msgid "implies --missing=allow-any" +msgstr "implique --missing=allow-any" + msgid "respect islands during delta compression" msgstr "respecter les îlots pendant la compression des deltas" @@ -10079,8 +10133,8 @@ msgstr "" msgid "" "You didn't specify any refspecs to push, and push.default is \"nothing\"." msgstr "" -"Vous n'avez pas spécifié de spécifications de référence à pousser, et push." -"default est \"nothing\"." +"Vous n'avez pas spécifié de spécifications de référence à pousser, et " +"push.default est \"nothing\"." #, c-format msgid "" @@ -11302,6 +11356,30 @@ msgid_plural " Local refs configured for 'git push'%s:" msgstr[0] " Référence locale configurée pour 'git push'%s :" msgstr[1] " Références locales configurées pour 'git push'%s :" +#, c-format +msgid "'%s/HEAD' is unchanged and points to '%s'\n" +msgstr "'%s/HEAD' est inchangé et pointe sur '%s'\n" + +#, c-format +msgid "'%s/HEAD' has changed from '%s' and now points to '%s'\n" +msgstr "'%s/HEAD' a changé depuis '%s' et pointe à présent sur '%s'\n" + +#, c-format +msgid "'%s/HEAD' is now created and points to '%s'\n" +msgstr "'%s/HEAD' a été créé et pointe sur '%s'\n" + +#, c-format +msgid "'%s/HEAD' was detached at '%s' and now points to '%s'\n" +msgstr "'%s/HEAD' est détaché de '%s' et pointe à présent sur '%s'\n" + +#, c-format +msgid "" +"'%s/HEAD' used to point to '%s' (which is not a remote branch), but now " +"points to '%s'\n" +msgstr "" +"'%s/HEAD' pointait sur '%s' (qui n'est pas une branche distante), mais " +"pointe à présent sur '%s'\n" + msgid "set refs/remotes//HEAD according to remote" msgstr "définir refs/remotes//HEAD selon la distante" @@ -11325,7 +11403,7 @@ msgid "Not a valid ref: %s" msgstr "Référence non valide : %s" #, c-format -msgid "Could not setup %s" +msgid "Could not set up %s" msgstr "Impossible de paramétrer %s" #, c-format @@ -14112,6 +14190,9 @@ msgstr "régler le mode de suivi (voir git-branch(1))" msgid "try to match the new branch name with a remote-tracking branch" msgstr "essayer de nommer la nouvelle branche comme la branche amont" +msgid "use relative paths for worktrees" +msgstr "utiliser des chemins relatifs pour les arbres-de-travail" + #, c-format msgid "options '%s', '%s', and '%s' cannot be used together" msgstr "les options '%s', '%s' et '%s' ne peuvent pas être utilisées ensemble" @@ -14394,6 +14475,26 @@ msgstr "impossible de créer '%s'" msgid "index-pack died" msgstr "l'index de groupe a disparu" +#, c-format +msgid "directory '%s' is present in index, but not sparse" +msgstr "Le répertoire '%s' est présent dans l'index et pourtant pas clairsemé" + +msgid "corrupted cache-tree has entries not present in index" +msgstr "l'arbre de cache corrompu a des entrées non présentes dans l'index" + +#, c-format +msgid "%s with flags 0x%x should not be in cache-tree" +msgstr "%s avec les drapeaux 0x%x ne devrait pas être dans l'arbre de cache" + +#, c-format +msgid "bad subtree '%.*s'" +msgstr "mauvais sous-arbre '%.*s'" + +#, c-format +msgid "cache-tree for path %.*s does not match. Expected %s got %s" +msgstr "" +"l'arbre de cache pour le chemin %.*s ne correspond pas. %s attendu, %s obtenu" + msgid "terminating chunk id appears earlier than expected" msgstr "l'identifiant de terminaison de tronçon apparaît plus tôt qu'attendu" @@ -15217,8 +15318,8 @@ msgid "" "attempting to write a commit-graph, but 'commitGraph.changedPathsVersion' " "(%d) is not supported" msgstr "" -"essai d'écriture de graphe de commits, mais 'commitGraph." -"changedPathsVersion' (%d) n'est pas pris en charge" +"essai d'écriture de graphe de commits, mais " +"'commitGraph.changedPathsVersion' (%d) n'est pas pris en charge" msgid "too many commits to write graph" msgstr "trop de commits pour écrire un graphe" @@ -15307,13 +15408,13 @@ msgid "" "to convert the grafts into replace refs.\n" "\n" "Turn this message off by running\n" -"\"git config advice.graftFileDeprecated false\"" +"\"git config set advice.graftFileDeprecated false\"" msgstr "" "Le support de /info/grafts est déconseillé\n" "et sera supprimé dans une version future de Git.\n" "\n" "Veuillez utiliser \"git replace --convert-graft-file\"\n" -"pour convertir les grafts en référence de remplacement.\n" +"pour convertir les grafts en références de remplacement.\n" "\n" "Supprimez ce message en lançant\n" "\"git config advice.graftFileDeprecated false\"" @@ -16154,6 +16255,18 @@ msgstr "l'url n'a pas de schéma : %s" msgid "credential url cannot be parsed: %s" msgstr "impossible d'analyser l'url d'identification : %s" +#, c-format +msgid "invalid timeout '%s', expecting a non-negative integer" +msgstr "délai d'attente invalide '%s', entier positif ou nul attendu" + +#, c-format +msgid "invalid init-timeout '%s', expecting a non-negative integer" +msgstr "délai d'attente d'init invalide '%s', entier positif ou nul attendu" + +#, c-format +msgid "invalid max-connections '%s', expecting an integer" +msgstr "max-connections invalide '%s', entier attendu" + msgid "in the future" msgstr "dans le futur" @@ -16226,8 +16339,8 @@ msgstr "impossible de charger la regex île pour '%s' : %s" #, c-format msgid "island regex from config has too many capture groups (max=%d)" msgstr "" -"l'expression régulière depuis la configuration a trop de groupes de " -"capture (max=%d)" +"l'expression régulière depuis la configuration a trop de groupes de capture " +"(max=%d)" #, c-format msgid "Marked %d islands, done.\n" @@ -16750,8 +16863,7 @@ msgstr "" "ou -G" msgid "treat in -S as extended POSIX regular expression" -msgstr "" -"traiter dans -S comme une expression régulière POSIX étendue" +msgstr "traiter dans -S comme une expression régulière POSIX étendue" msgid "control the order in which files appear in the output" msgstr "contrôler l'ordre dans lequel les fichiers apparaissent dans la sortie" @@ -16895,6 +17007,20 @@ msgstr "espaces de nom de Git \"%s\"" msgid "too many args to run %s" msgstr "trop d'arguments pour lancer %s" +#, c-format +msgid "" +"You are attempting to fetch %s, which is in the commit graph file but not in " +"the object database.\n" +"This is probably due to repo corruption.\n" +"If you are attempting to repair this repo corruption by refetching the " +"missing object, use 'git fetch --refetch' with the missing object." +msgstr "" +"Vous tentez de récupérer %s, qui est dans le graphe de commit mais pas dans " +"la base de données des objets.\n" +"C'est probablement du à une corruption de dépôt.\n" +"Si vous essayez de réparer cette corruption de dépôt en re-récupérer l'objet " +"manquant, utilisez 'git fetch --refetch' sur les objets manquants." + msgid "git fetch-pack: expected shallow list" msgstr "git fetch-pack : liste superficielle attendue" @@ -17484,11 +17610,11 @@ msgstr[1] "" #, c-format msgid "" "The '%s' hook was ignored because it's not set as executable.\n" -"You can disable this warning with `git config advice.ignoredHook false`." +"You can disable this warning with `git config set advice.ignoredHook false`." msgstr "" "Le crochet '%s' a été ignoré parce qu'il n'est pas marqué comme exécutable.\n" -"Vous pouvez désactiver cet avertissement avec `git config advice.ignoredHook " -"false`." +"Vous pouvez désactiver cet avertissement avec `git config set " +"advice.ignoredHook false`." msgid "not a git repository" msgstr "pas un dépôt git" @@ -17505,15 +17631,9 @@ msgstr "" msgid "Delegation control is not supported with cURL < 7.22.0" msgstr "La délégation de commande n'est pas supporté avec cuRL < 7.22.0" -msgid "Public key pinning not supported with cURL < 7.39.0" -msgstr "L'épinglage de clé publique n'est pas supporté avec cuRL < 7.39.0" - msgid "Unknown value for http.proactiveauth" msgstr "valeur inconnue pour http.proactiveauth" -msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0" -msgstr "CURLSSLOPT_NO_REVOKE n'est pas supporté avec cuRL < 7.44.0" - #, c-format msgid "Unsupported SSL backend '%s'. Supported SSL backends:" msgstr "Dorsale SSL '%s' non supportée. Dorsales SSL supportées :" @@ -17702,6 +17822,10 @@ msgstr "CRLF citées détectées" msgid "unable to format message: %s" msgstr "impossible de formater le message : %s" +#, c-format +msgid "invalid marker-size '%s', expecting an integer" +msgstr "taille de marqueur invalide '%s', entier attendu" + #, c-format msgid "Failed to merge submodule %s (not checked out)" msgstr "Échec de la fusion du sous-module %s (non extrait)" @@ -18824,7 +18948,7 @@ msgid "" "\n" "where \"$br\" is somehow empty and a 40-hex ref is created. Please\n" "examine these refs and maybe delete them. Turn this message off by\n" -"running \"git config advice.objectNameWarning false\"" +"running \"git config set advice.objectNameWarning false\"" msgstr "" "Git ne crée normalement jamais de référence qui se termine par 40\n" "caractères hexa car elle serait ignorée si vous spécifiez juste\n" @@ -18836,7 +18960,7 @@ msgstr "" "est créée.\n" "Veuillez examiner ces références et peut-être les supprimer. Désactivez ce " "message\n" -"en lançant \"git config advice.objectNameWarning false\"" +"en lançant \"git config set advice.objectNameWarning false\"" #, c-format msgid "log for '%.*s' only goes back to %s" @@ -19001,13 +19125,6 @@ msgstr "l'index inverse requis manque dans l'index multi-paquet" msgid "could not open pack %s" msgstr "impossible d'ouvrir le paquet '%s'" -msgid "could not determine MIDX preferred pack" -msgstr "impossible de déterminer le paquet préféré de MIDX" - -#, c-format -msgid "preferred pack (%s) is invalid" -msgstr "le paquet préféré (%s) est invalide" - msgid "corrupt bitmap lookup table: triplet position out of index" msgstr "" "table de recherche en bitmap corrompue : position de triplet hors d'index" @@ -20143,17 +20260,25 @@ msgstr "le journal pour la réf %s s'arrête de manière inattendue sur %s" msgid "log for %s is empty" msgstr "le journal pour la réf %s est vide" -msgid "refusing to force and skip creation of reflog" -msgstr "refus de forcer et sauter la création du reflog" - #, c-format -msgid "refusing to update ref with bad name '%s'" -msgstr "refus de mettre à jour une réf avec un nom cassé '%s'" +msgid "refusing to update reflog for pseudoref '%s'" +msgstr "refus de mettre à jour le réflog pour la pseudo-réf '%s'" #, c-format msgid "refusing to update pseudoref '%s'" msgstr "refus de mettre à jour la pseudo-réf '%s'" +#, c-format +msgid "refusing to update reflog with bad name '%s'" +msgstr "refus de mettre à jour le réflog avec un nom cassé '%s'" + +#, c-format +msgid "refusing to update ref with bad name '%s'" +msgstr "refus de mettre à jour une réf avec un nom cassé '%s'" + +msgid "refusing to force and skip creation of reflog" +msgstr "refus de forcer et sauter la création du reflog" + #, c-format msgid "update_ref failed for ref '%s': %s" msgstr "échec de update_ref pour la réf '%s' : %s" @@ -20204,6 +20329,10 @@ msgstr "" "impossible de vérrouiller '%s' : symref attendu avec la cible '%s', mais réf " "normale trouvée" +#, c-format +msgid "cannot read ref file '%s'" +msgstr "impossible de lire le fichier de référence '%s'" + #, c-format msgid "cannot open directory %s" msgstr "impossible d'ouvrir le répertoire %s" @@ -20336,8 +20465,8 @@ msgstr "le serveur distant a envoyé un paquet de fin de réponse inattendu" msgid "unable to rewind rpc post data - try increasing http.postBuffer" msgstr "" -"impossible de rembobiner le données post rpc - essayer d'augmenter http." -"postBuffer" +"impossible de rembobiner le données post rpc - essayer d'augmenter " +"http.postBuffer" #, c-format msgid "remote-curl: bad line length character: %.4s" @@ -20420,6 +20549,10 @@ msgstr "plus d'un receivepack fournis, utilisation du premier" msgid "more than one uploadpack given, using the first" msgstr "plus d'un uploadpack fournis, utilisation du premier" +#, c-format +msgid "unrecognized followRemoteHEAD value '%s' ignored" +msgstr "valeur '%s' de followRemoteHEAD non reconnue et ignorée " + #, c-format msgid "unrecognized value transfer.credentialsInUrl: '%s'" msgstr "valeur non reconnue transfer.credentialsInUrl : '%s'" @@ -22379,6 +22512,9 @@ msgstr "le commit %s n'est pas marqué joignable" msgid "too many commits marked reachable" msgstr "trop de commits marqués joignables" +msgid "could not determine MIDX preferred pack" +msgstr "impossible de déterminer le paquet préféré de MIDX" + msgid "test-tool serve-v2 []" msgstr "test-tool serve-v2 []" @@ -23049,6 +23185,10 @@ msgstr "fichier .git cassé" msgid ".git file incorrect" msgstr "fichier .git incorrect" +msgid ".git file absolute/relative path mismatch" +msgstr "" +"non-correspondance entre les chemin absolu entre relatif du fichier .git" + msgid "not a valid path" msgstr "pas un chemin valide" @@ -23065,6 +23205,9 @@ msgstr "impossible de localiser le dépôt ; fichier .git cassé" msgid "gitdir unreadable" msgstr "gitdir non lisible" +msgid "gitdir absolute/relative path mismatch" +msgstr "non-correspondance de chemin absolu/relatif de gitdir" + msgid "gitdir incorrect" msgstr "gitdir incorrect" @@ -23100,6 +23243,14 @@ msgstr "impossible de désinitialiser %s dans '%s'" msgid "failed to set extensions.worktreeConfig setting" msgstr "échec de paramétrage extensions.worktreeConfig" +msgid "unable to upgrade repository format to support relative worktrees" +msgstr "" +"impossible de mettre à jour le format de dépôt pour prendre en charge les " +"arbres-de-travail relatifs" + +msgid "unable to set extensions.relativeWorktrees setting" +msgstr "échec de modification du paramètre extensions.relativeWorktrees" + #, c-format msgid "could not setenv '%s'" msgstr "impossible de configurer l'environnement '%s'" @@ -23975,3 +24126,7 @@ msgstr "%s sauté avec un suffix de sauvegarde '%s'.\n" #, perl-format msgid "Do you really want to send %s? [y|N]: " msgstr "Souhaitez-vous réellement envoyer %s ?[y|N] : " + +#, c-format +#~ msgid "preferred pack (%s) is invalid" +#~ msgstr "le paquet préféré (%s) est invalide" -- cgit v1.2.3 From 956b486cacff05ebbe580eb9d89a1c508c4fa3a3 Mon Sep 17 00:00:00 2001 From: Peter Krefting Date: Mon, 30 Dec 2024 12:04:46 +0100 Subject: l10n: sv.po: Update Swedish translation Signed-off-by: Peter Krefting --- po/sv.po | 275 ++++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 212 insertions(+), 63 deletions(-) diff --git a/po/sv.po b/po/sv.po index 973dd940ac..e36f035bf4 100644 --- a/po/sv.po +++ b/po/sv.po @@ -5,10 +5,10 @@ # msgid "" msgstr "" -"Project-Id-Version: git 2.47.0\n" +"Project-Id-Version: git 2.48.0\n" "Report-Msgid-Bugs-To: Git Mailing List \n" -"POT-Creation-Date: 2024-09-19 02:06+0000\n" -"PO-Revision-Date: 2024-09-28 15:45+0100\n" +"POT-Creation-Date: 2024-12-30 11:57+0100\n" +"PO-Revision-Date: 2024-12-30 12:03+0100\n" "Last-Translator: Peter Krefting \n" "Language-Team: Svenska \n" "Language: sv\n" @@ -624,10 +624,10 @@ msgstr "Endast binära filer ändrade." #, c-format msgid "" "\n" -"Disable this message with \"git config advice.%s false\"" +"Disable this message with \"git config set advice.%s false\"" msgstr "" "\n" -"Slå av meddelandet med ”git config advice.%s false”" +"Slå av meddelandet med ”git config set advice.%s false”" #, c-format msgid "%shint:%s%.*s%s\n" @@ -1357,6 +1357,10 @@ msgstr "objektnamnet är inte giltigt: %s" msgid "not a tree object: %s" msgstr "inte ett trädobjekt: %s" +#, c-format +msgid "failed to unpack tree object %s" +msgstr "misslyckades packa upp trädobjektet %s" + #, c-format msgid "File not found: %s" msgstr "Hittar inte filen: %s" @@ -3825,9 +3829,8 @@ msgstr "ny ofödd gren" msgid "update ignored files (default)" msgstr "uppdatera ignorerade filer (standard)" -msgid "do not check if another worktree is holding the given ref" -msgstr "" -"kontrollera inte om en annan arbetskatalog håller den angivna referensen" +msgid "do not check if another worktree is using this branch" +msgstr "kontrollera inte om en annan arbetskatalog använder grenen" msgid "checkout our version for unmerged files" msgstr "checka ut vår version för ej sammanslagna filer" @@ -4125,11 +4128,11 @@ msgstr "skapa en grund klon på detta djup" msgid "create a shallow clone since a specific time" msgstr "skapa en grund klon från en angiven tidpunkt" -msgid "revision" -msgstr "revision" +msgid "ref" +msgstr "ref" -msgid "deepen history of shallow clone, excluding rev" -msgstr "fördjupa historik för grund klon, exkludera revisionen" +msgid "deepen history of shallow clone, excluding ref" +msgstr "fördjupa historik för grund klon, exkludera ref" msgid "clone only one branch, HEAD or --branch" msgstr "klona endast en gren, HEAD eller --branch" @@ -5054,10 +5057,10 @@ msgstr "" msgid "" "git config unset [] [--all] [--value=] [--fixed-value] " -" " +"" msgstr "" "git config unset [] [--all] [--value=] [--fixed-value] " -" " +"" msgid "git config rename-section [] " msgstr "git config rename-section [] " @@ -5490,12 +5493,8 @@ msgid "traversed %lu commits\n" msgstr "traverserade %lu incheckningar\n" #, c-format -msgid "" -"more than %i tags found; listed %i most recent\n" -"gave up search at %s\n" -msgstr "" -"mer än %i taggar hittades; listar de %i senaste\n" -"gav upp sökningen vid %s\n" +msgid "found %i tags; gave up search at %s\n" +msgstr "hittade %i taggar; gav upp sökning vid %s\n" #, c-format msgid "describe %s\n" @@ -5927,6 +5926,20 @@ msgstr "%s är inte ett giltigt objekt" msgid "the object %s does not exist" msgstr "objektet %s finns inte" +#, c-format +msgid "" +"Run 'git remote set-head %s %s' to follow the change, or set\n" +"'remote.%s.followRemoteHEAD' configuration option to a different value\n" +"if you do not want to see this message. Specifically running\n" +"'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n" +"until the remote changes HEAD to something else." +msgstr "" +"Kör ”git remote set-head %s %s” för att följa ändringen, eller sätt\n" +"konfigurationsflaggan ”remote %s.followRemoteHEAD” till ett annat värde\n" +"om du inte vill se det här meddelandet. Du kan specifikt inaktivera\n" +"varningen till fjärren ändrar HEAD till något annat genom att köra\n" +"”git config set remote %s.followRemoteHEAD %s”." + msgid "multiple branches detected, incompatible with --set-upstream" msgstr "flera grenar upptäcktes, inkompatibelt med --set-upstream" @@ -6064,6 +6077,9 @@ msgstr "referenskarta" msgid "specify fetch refmap" msgstr "ange referenskarta för ”fetch”" +msgid "revision" +msgstr "revision" + msgid "report that we have only objects reachable from this object" msgstr "rapportera att vi bara har objekt nåbara från detta objektet" @@ -6789,8 +6805,25 @@ msgstr "varken systemd-timer eller crontab är tillgänglig" msgid "%s scheduler is not available" msgstr "%s-schemaläggare är inte tillgänglig" -msgid "another process is scheduling background maintenance" -msgstr "en annan process schemalägger bakgrundsunderhåll" +#, c-format +msgid "" +"unable to create '%s.lock': %s.\n" +"\n" +"Another scheduled git-maintenance(1) process seems to be running in this\n" +"repository. Please make sure no other maintenance processes are running and\n" +"then try again. If it still fails, a git-maintenance(1) process may have\n" +"crashed in this repository earlier: remove the file manually to continue." +msgstr "" +"Kunde inte skapa ”%s.lock”: %s.\n" +"\n" +"Det verkar som en annan schemalagd git-maintenance(1)-process kör i det\n" +"här arkivet. Se till att inga andra underhållsprocesser körs och försök\n" +"sedan igen. Om det fortfarande misslyckas kanske en git-maintenance(1)-\n" +"process har kraschat i det här arkivet tidigare: ta bort filen manuellt\n" +"för att fortsätta." + +msgid "cannot acquire lock for scheduled background maintenance" +msgstr "kan inte erhålla låset för schemalagt bakgrundsunderhåll" msgid "git maintenance start [--scheduler=]" msgstr "git maintenance start [--scheduler=]" @@ -7320,7 +7353,7 @@ msgstr "paketfilnamnet ”%s” slutar inte med ”.%s”" #, c-format msgid "cannot write %s file '%s'" -msgstr "kan inte ta skriva %s-fil ”%s”" +msgstr "kan inte skriva %s-fil ”%s”" #, c-format msgid "cannot close written %s file '%s'" @@ -7357,6 +7390,19 @@ msgid_plural "chain length = %d: %lu objects" msgstr[0] "kedjelängd = %d: %lu objekt" msgstr[1] "kedjelängd = %d: %lu objekt" +msgid "could not start pack-objects to repack local links" +msgstr "kunde inte starta pack-objects för att packa om lokala länkar" + +msgid "failed to feed local object to pack-objects" +msgstr "misslyckades sända lokala objekt till pack-objects" + +msgid "index-pack: Expecting full hex object ID lines only from pack-objects." +msgstr "" +"index-pack: Förväntar kompletta hex-objekt-ID-rader endast från pack-objects." + +msgid "could not finish pack-objects to repack local links" +msgstr "kunde inte avsluta pack-objects för att packa om lokala länkar" + msgid "Cannot come back to cwd" msgstr "Kan inte gå tillbaka till arbetskatalogen (cwd)" @@ -7368,6 +7414,9 @@ msgstr "felaktig %s" msgid "unknown hash algorithm '%s'" msgstr "okänd hashningsalgoritm ”%s”" +msgid "--promisor cannot be used with a pack name" +msgstr "--promisor kan inte användas med ett paketnamn" + msgid "--stdin requires a git repository" msgstr "--stdin kräver ett git-arkiv" @@ -8708,11 +8757,11 @@ msgstr "git notes [--ref ] [list []]" msgid "" "git notes [--ref ] add [-f] [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" msgstr "" "git notes [--ref ] add [-f] [--allow-empty] [--" "[no-]separator|--separator=] [--[no-]stripspace] [-m " -"| -F | (-c | -C) ] []" +"| -F | (-c | -C) ] [] [-e]" msgid "git notes [--ref ] copy [-f] " msgstr "" @@ -8721,11 +8770,11 @@ msgstr "" msgid "" "git notes [--ref ] append [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" msgstr "" "git notes [--ref ] append [--allow-empty] [--" "[no-]separator|--separator=] [--[no-]stripspace] [-m " -"| -F | (-c | -C) ] []" +"| -F | (-c | -C) ] [] [-e]" msgid "git notes [--ref ] edit [--allow-empty] []" msgstr "git notes [--ref ] edit [--allow-empty] []" @@ -8844,6 +8893,9 @@ msgstr "anteckningsinnehåll i en fil" msgid "reuse and edit specified note object" msgstr "återanvänd och redigera angivet anteckningsobjekt" +msgid "edit note message in editor" +msgstr "redigera anteckning i textredigeringsprogram" + msgid "reuse specified note object" msgstr "återanvänd angivet anteckningsobjekt" @@ -9336,6 +9388,9 @@ msgstr "hantering av saknade objekt" msgid "do not pack objects in promisor packfiles" msgstr "packa inte objekt i kontraktspackfiler" +msgid "implies --missing=allow-any" +msgstr "implicerar --missing=allow-any" + msgid "respect islands during delta compression" msgstr "respektera öar under deltakomprimering" @@ -10919,6 +10974,30 @@ msgid_plural " Local refs configured for 'git push'%s:" msgstr[0] " Lokal referens konfigurerad för ”git push”%s:" msgstr[1] " Lokala referenser konfigurerade för ”git push”%s:" +#, c-format +msgid "'%s/HEAD' is unchanged and points to '%s'\n" +msgstr "”%s/HEAD” är oförändrad och pekar på ”%s”\n" + +#, c-format +msgid "'%s/HEAD' has changed from '%s' and now points to '%s'\n" +msgstr "”%s/HEAD” har ändrats från ”%s” och pekar nu på ”%s”\n" + +#, c-format +msgid "'%s/HEAD' is now created and points to '%s'\n" +msgstr "”%s/HEAD” har nu skapats och pekar på ”%s”\n" + +#, c-format +msgid "'%s/HEAD' was detached at '%s' and now points to '%s'\n" +msgstr "”%s/HEAD” kopplades från vid ”%s” och pekar nu på ”%s”\n" + +#, c-format +msgid "" +"'%s/HEAD' used to point to '%s' (which is not a remote branch), but now " +"points to '%s'\n" +msgstr "" +"”%s/HEAD” pekade tidigare på ”%s” (som inte är en fjärrgren), men pekar nu " +"på ”%s”\n" + msgid "set refs/remotes//HEAD according to remote" msgstr "sätt refs/remotes//HEAD enligt fjärren" @@ -10940,7 +11019,7 @@ msgid "Not a valid ref: %s" msgstr "Inte en giltig referens: %s" #, c-format -msgid "Could not setup %s" +msgid "Could not set up %s" msgstr "Kunde inte ställa in %s" #, c-format @@ -13641,6 +13720,9 @@ msgstr "ställ in spårningsläge (se git-branch(1))" msgid "try to match the new branch name with a remote-tracking branch" msgstr "försök träffa namn på ny gren mot en fjärrspårande gren" +msgid "use relative paths for worktrees" +msgstr "använd relativa sökvägar för arbetskataloger" + #, c-format msgid "options '%s', '%s', and '%s' cannot be used together" msgstr "flaggorna ”%s”, ”%s” och ”%s” kan inte användas samtidigt" @@ -13912,6 +13994,26 @@ msgstr "kan inte skapa ”%s”" msgid "index-pack died" msgstr "index-pack dog" +#, c-format +msgid "directory '%s' is present in index, but not sparse" +msgstr "katalogen ”%s” finns i indexet, men inte glest" + +msgid "corrupted cache-tree has entries not present in index" +msgstr "trasigt cacheträd innehåller poster som inte finns i indexet" + +#, c-format +msgid "%s with flags 0x%x should not be in cache-tree" +msgstr "%s med flaggorna 0x%x borde inte finnas i cacheträdet" + +#, c-format +msgid "bad subtree '%.*s'" +msgstr "felaktigt underträd ”%.*s”" + +#, c-format +msgid "cache-tree for path %.*s does not match. Expected %s got %s" +msgstr "" +"cacheträd för sökvägen %.*s stämmer inte överens. Förväntade %s fick %s" + msgid "terminating chunk id appears earlier than expected" msgstr "avslutande stycke-id förekommer tidigare än förväntat" @@ -14777,7 +14879,7 @@ msgid "" "to convert the grafts into replace refs.\n" "\n" "Turn this message off by running\n" -"\"git config advice.graftFileDeprecated false\"" +"\"git config set advice.graftFileDeprecated false\"" msgstr "" "Stöd för /info/grafts avråds från och\n" "kommer tas bort i en framtida version av Git.\n" @@ -14786,7 +14888,7 @@ msgstr "" "för att omvandla grafts till ersättningsreferenser.\n" "\n" "Slå av detta meddelande genom att skriva\n" -"”git config advice.graftFileDeprecated false”" +"”git config set advice.graftFileDeprecated false”" #, c-format msgid "commit %s exists in commit-graph but not in the object database" @@ -15597,6 +15699,19 @@ msgstr "url saknar protokoll: %s" msgid "credential url cannot be parsed: %s" msgstr "kan inte tolka url för inloggingsuppgifter: %s" +#, c-format +msgid "invalid timeout '%s', expecting a non-negative integer" +msgstr "felaktig tidsgräns ”%s”, förväntade ett icke-negativt heltal" + +#, c-format +msgid "invalid init-timeout '%s', expecting a non-negative integer" +msgstr "" +"felaktig värde för init-timeout ”%s”, förväntade ett icke-negativt heltal" + +#, c-format +msgid "invalid max-connections '%s', expecting an integer" +msgstr "felaktigt värde för max-connections ”%s”, förväntade ett heltal" + msgid "in the future" msgstr "i framtiden" @@ -16296,6 +16411,20 @@ msgstr "felaktig git-namnrymdssökväg ”%s”" msgid "too many args to run %s" msgstr "för många flaggor för att köra %s" +#, c-format +msgid "" +"You are attempting to fetch %s, which is in the commit graph file but not in " +"the object database.\n" +"This is probably due to repo corruption.\n" +"If you are attempting to repair this repo corruption by refetching the " +"missing object, use 'git fetch --refetch' with the missing object." +msgstr "" +"Du försöker hämta %s som är i incheckningsgrafen men inte i " +"objektdatabasen.\n" +"Det händer antagligen på grund av att arkivet är trasigt.\n" +"Om du försöker reparera det trasiga arkivet genom att hämta om det saknade " +"objektet, använd ”git fetch --refetch” med det saknade objektet." + msgid "git fetch-pack: expected shallow list" msgstr "git fetch-pack: förväntade grund lista" @@ -16880,10 +17009,10 @@ msgstr[1] "" #, c-format msgid "" "The '%s' hook was ignored because it's not set as executable.\n" -"You can disable this warning with `git config advice.ignoredHook false`." +"You can disable this warning with `git config set advice.ignoredHook false`." msgstr "" "Kroken ”%s” ignorerades eftersom den inte är markerad som körbar.\n" -"Du kan inaktivera varningen med ”git config advice.ignoredHook false”." +"Du kan inaktivera varningen med ”git config set advice.ignoredHook false”." msgid "not a git repository" msgstr "inte ett git-arkiv" @@ -16900,15 +17029,9 @@ msgstr "http.postBuffer har negativt värde; använder förvalet %d" msgid "Delegation control is not supported with cURL < 7.22.0" msgstr "Delegerad styrning stöds inte av cURL < 7.22.0" -msgid "Public key pinning not supported with cURL < 7.39.0" -msgstr "Fastnålning av öppen nyckel stöds inte av cURL < 7.39.0" - msgid "Unknown value for http.proactiveauth" msgstr "Okänt värde för http.proactiveauth" -msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0" -msgstr "CURLSSLOPT_NO_REVOKE stöds inte av cURL < 7.44.0" - #, c-format msgid "Unsupported SSL backend '%s'. Supported SSL backends:" msgstr "SSL-bakändan ”%s” stöds inte. Dessa SSL-bakändor stöds:" @@ -17091,6 +17214,10 @@ msgstr "citerad CRLF upptäcktes" msgid "unable to format message: %s" msgstr "kan inte formatera meddelandet: %s" +#, c-format +msgid "invalid marker-size '%s', expecting an integer" +msgstr "felaktigt värde för marker-size ”%s”, förväntade ett heltal" + #, c-format msgid "Failed to merge submodule %s (not checked out)" msgstr "Misslyckades slå ihop undermodulen %s (ej utcheckad)" @@ -17995,6 +18122,14 @@ msgstr "packat objekt %s (lagrat i %s) är trasigt" msgid "missing mapping of %s to %s" msgstr "saknar koppling av %s till %s" +#, c-format +msgid "unable to open %s" +msgstr "kan inte öppna %s" + +#, c-format +msgid "files '%s' and '%s' differ in contents" +msgstr "filerna ”%s” och ”%s” har olika innehåll" + #, c-format msgid "unable to write file %s" msgstr "kan inte skriva filen %s" @@ -18080,10 +18215,6 @@ msgstr "%s: filtypen stöds ej" msgid "%s is not a valid '%s' object" msgstr "%s är inte ett giltigt ”%s”-objekt" -#, c-format -msgid "unable to open %s" -msgstr "kan inte öppna %s" - #, c-format msgid "hash mismatch for %s (expected %s)" msgstr "hash stämmer inte för %s (förväntade %s)" @@ -18185,7 +18316,7 @@ msgid "" "\n" "where \"$br\" is somehow empty and a 40-hex ref is created. Please\n" "examine these refs and maybe delete them. Turn this message off by\n" -"running \"git config advice.objectNameWarning false\"" +"running \"git config set advice.objectNameWarning false\"" msgstr "" "Git skapar normalt aldrig referenser som slutar med 40 hexadecimala\n" "tecken, då detta ignoreras när du anger 40-hex enbart. Dessa\n" @@ -18195,7 +18326,7 @@ msgstr "" "\n" "där ”$br” på något sätt blivit tomt och en 40-hex-referens skapats.\n" "Undersök referenserna och ta kanske bort dem. Stäng av meddelandet\n" -"genom att köra ”git config advice.objectNameWarning false”" +"genom att köra ”git config set advice.objectNameWarning false”" #, c-format msgid "log for '%.*s' only goes back to %s" @@ -18354,13 +18485,6 @@ msgstr "flerpaketsbitkarta saknar nödvändigt omvänt index" msgid "could not open pack %s" msgstr "kunde inte öppna paketfilen %s" -msgid "could not determine MIDX preferred pack" -msgstr "kunde inte bestämma det föredragna MIDX-paketet" - -#, c-format -msgid "preferred pack (%s) is invalid" -msgstr "föredragen paketfil (%s) är ogiltig" - msgid "corrupt bitmap lookup table: triplet position out of index" msgstr "trasig bitkarteuppslagstabell: trippelposition utanför indexet" @@ -19475,17 +19599,25 @@ msgstr "loggen för referensen %s slutade oväntat på %s" msgid "log for %s is empty" msgstr "loggen för %s är tom" -msgid "refusing to force and skip creation of reflog" -msgstr "vägrar att tvinga och hoppa över skapande av reflogg" - #, c-format -msgid "refusing to update ref with bad name '%s'" -msgstr "vägrar uppdatera referens med trasigt namn ”%s”" +msgid "refusing to update reflog for pseudoref '%s'" +msgstr "vägrar uppdatera referenslogg för pseudoreferensen ”%s”" #, c-format msgid "refusing to update pseudoref '%s'" msgstr "vägrar uppdatera pseudoreferensen ”%s”" +#, c-format +msgid "refusing to update reflog with bad name '%s'" +msgstr "vägrar uppdatera referenslogg med trasigt namn ”%s”" + +#, c-format +msgid "refusing to update ref with bad name '%s'" +msgstr "vägrar uppdatera referens med trasigt namn ”%s”" + +msgid "refusing to force and skip creation of reflog" +msgstr "vägrar att tvinga och hoppa över skapande av reflogg" + #, c-format msgid "update_ref failed for ref '%s': %s" msgstr "update_ref misslyckades för referensen ”%s”: %s" @@ -19535,6 +19667,10 @@ msgstr "" "kan inte läsa referensen ”%s”: förväntade symbolisk referens med målet ”%s”: " "men är en vanlig referens" +#, c-format +msgid "cannot read ref file '%s'" +msgstr "kan inte läsa ref-fil ”%s”" + #, c-format msgid "cannot open directory %s" msgstr "kunde inte öppna katalogen %s" @@ -19740,6 +19876,10 @@ msgstr "mer än en receivepack angavs, använder den första" msgid "more than one uploadpack given, using the first" msgstr "mer än en uploadpack angavs, använder den första" +#, c-format +msgid "unrecognized followRemoteHEAD value '%s' ignored" +msgstr "okänt värde ”%s” för followRemoteHEAD ignorerades" + #, c-format msgid "unrecognized value transfer.credentialsInUrl: '%s'" msgstr "okänt värde transfer.credentialsInUrl: ”%s”" @@ -21665,6 +21805,9 @@ msgstr "incheckning %s är inte märkt nåbar" msgid "too many commits marked reachable" msgstr "för många incheckningar markerade nåbara" +msgid "could not determine MIDX preferred pack" +msgstr "kunde inte bestämma det föredragna MIDX-paketet" + msgid "test-tool serve-v2 []" msgstr "test-tool serve-v2 []" @@ -22319,6 +22462,9 @@ msgstr ".git-filen är trasig" msgid ".git file incorrect" msgstr ".git-filen är felaktig" +msgid ".git file absolute/relative path mismatch" +msgstr "absolut/relativ sökväg för .git-fil stämmer inte överens" + msgid "not a valid path" msgstr "inte en giltig sökväg" @@ -22334,6 +22480,9 @@ msgstr "kan inte hitta arkivet; ”.git”-filen är trasig" msgid "gitdir unreadable" msgstr "gitdir är oläsbar" +msgid "gitdir absolute/relative path mismatch" +msgstr "absolut/relativ sökväg för git-katalog stämmer inte överens" + msgid "gitdir incorrect" msgstr "gitdir är felaktig" @@ -22368,6 +22517,13 @@ msgstr "kan inte slå av %s i ”%s”" msgid "failed to set extensions.worktreeConfig setting" msgstr "misslyckades ändra inställningen extensions.worktreeConfig" +msgid "unable to upgrade repository format to support relative worktrees" +msgstr "" +"kunde inte uppgradera arkivformat till att stöda relativa arbetskataloger" + +msgid "unable to set extensions.relativeWorktrees setting" +msgstr "misslyckades ändra inställningen extensions.relativeWorktrees" + #, c-format msgid "could not setenv '%s'" msgstr "kunde inte lagra miljövariabeln ”%s”" @@ -23217,10 +23373,3 @@ msgstr "" #, perl-format msgid "Do you really want to send %s? [y|N]: " msgstr "Vill du verkligen sända %s? [y=ja, n=nej]: " - -#~ msgid "revision walk setup failed\n" -#~ msgstr "misslyckades starta revisionstraversering\n" - -#, c-format -#~ msgid "unable to parse contact: %s" -#~ msgstr "kan inte tolka kontakt: %s" -- cgit v1.2.3 From d601aee6056a0afc6df7f77e15cdc155ff402dee Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 29 Dec 2024 23:24:01 -0500 Subject: test-lib: use individual lsan dir for --stress runs When storing output in test-results/, we usually give each numbered run in a --stress set its own output file. But we don't do that for storing LSan logs, so something like: ./t0003-attributes.sh --stress will have many scripts simultaneously creating, writing to, and deleting the test-results/t0003-attributes.leak directory. This can cause logs from one run to be attributed to another, spurious failures when creation and deletion race, and so on. This has always been broken, but nobody noticed because it's rare to do a --stress run with LSan (since the point is for the code to run quickly many times in order to hit races). But if you're trying to find a race in the leak sanitizing code, it makes sense to use these together. We can fix it by using $TEST_RESULTS_BASE, which already incorporates the stress job suffix. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/test-lib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/test-lib.sh b/t/test-lib.sh index 1a67adb207..96f2dfb69d 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -331,7 +331,7 @@ TEST_RESULTS_BASE="$TEST_RESULTS_DIR/$TEST_NAME$TEST_STRESS_JOB_SFX" TEST_RESULTS_SAN_FILE_PFX=trace TEST_RESULTS_SAN_DIR_SFX=leak TEST_RESULTS_SAN_FILE= -TEST_RESULTS_SAN_DIR="$TEST_RESULTS_DIR/$TEST_NAME.$TEST_RESULTS_SAN_DIR_SFX" +TEST_RESULTS_SAN_DIR="$TEST_RESULTS_BASE.$TEST_RESULTS_SAN_DIR_SFX" TRASH_DIRECTORY="trash directory.$TEST_NAME$TEST_STRESS_JOB_SFX" test -n "$root" && TRASH_DIRECTORY="$root/$TRASH_DIRECTORY" case "$TRASH_DIRECTORY" in -- cgit v1.2.3 From ca9d60f2460c296b32b3da97eb953bbc4d292197 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 29 Dec 2024 23:26:10 -0500 Subject: Revert "index-pack: spawn threads atomically" This reverts commit 993d38a0669a8056d496797516e743e26b6b8b54. That commit was trying to solve a race between LSan setting up the threads stack and another thread calling exit(), by making sure that all pthread_create() calls have finished before doing any work that might trigger the exit(). But that isn't sufficient. The setup code actually runs in the individual threads themselves, not in the spawning thread's call to pthread_create(). So while it may have improved the race a bit, you can still trigger it pretty quickly with: make SANITIZE=leak cd t ./t5309-pack-delta-cycles.sh --stress Let's back out that failed attempt so we can try again. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin/index-pack.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/builtin/index-pack.c b/builtin/index-pack.c index d773809c4c..0b62b2589f 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -1336,7 +1336,6 @@ static void resolve_deltas(struct pack_idx_option *opts) base_cache_limit = opts->delta_base_cache_limit * nr_threads; if (nr_threads > 1 || getenv("GIT_FORCE_THREADS")) { init_thread(); - work_lock(); for (i = 0; i < nr_threads; i++) { int ret = pthread_create(&thread_data[i].thread, NULL, threaded_second_pass, thread_data + i); @@ -1344,7 +1343,6 @@ static void resolve_deltas(struct pack_idx_option *opts) die(_("unable to create thread: %s"), strerror(ret)); } - work_unlock(); for (i = 0; i < nr_threads; i++) pthread_join(thread_data[i].thread, NULL); cleanup_thread(); -- cgit v1.2.3 From 7d0037b59ae0d22a2718c28d8e70e3ef3f3f991e Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 29 Dec 2024 23:28:30 -0500 Subject: thread-utils: introduce optional barrier type One thread primitive we don't yet support is a barrier: it waits for all threads to reach a synchronization point before letting any of them continue. This would be useful for avoiding the LSan race we see in index-pack (and other places) by having all threads complete their initialization before any of them start to do real work. POSIX introduced a pthread_barrier_t in 2004, which does what we want. But if we want to rely on it: 1. Our Windows pthread emulation would need a new set of wrapper functions. There's a Synchronization Barrier primitive there, which was introduced in Windows 8 (which is old enough for us to depend on). 2. macOS (and possibly other systems) has pthreads but not pthread_barrier_t. So there we'd have to implement our own barrier based on the mutex and cond primitives. Those are do-able, but since we only care about avoiding races in our LSan builds, there's an easier way: make it a noop on systems without a native pthread barrier. This patch introduces a "maybe_thread_barrier" API. The clunky name (rather than just using pthread_barrier directly) should hopefully clue people in that on some systems it will do nothing. It's wired to a Makefile knob which has to be triggered manually, and we enable it for the linux-leaks CI jobs (since we know we'll have it there). There are some other possible options: - we could turn it on all the time for Linux systems based on uname. But we really only care about it for LSan builds, and there is no need to add extra code to regular builds. - we could turn it on only for LSan builds. But that would break builds on non-Linux platforms (like macOS) that otherwise should support sanitizers. - we could trigger only on the combination of Linux and LSan together. This isn't too hard to do, but the uname check isn't completely accurate. It is really about what your libc supports, and non-glibc systems might not have it (though at least musl seems to). So we'd risk breaking builds on those systems, which would need to add a new knob. Though the upside would be that running local "make SANITIZE=leak test" would be protected automatically. And of course none of this protects LSan runs from races on systems without pthread barriers. It's probably OK in practice to protect only our CI jobs, though. The race is rare-ish and most leak-checking happens through CI. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- Makefile | 7 +++++++ ci/lib.sh | 1 + thread-utils.h | 17 +++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/Makefile b/Makefile index 97e8385b66..2c6dad8a75 100644 --- a/Makefile +++ b/Makefile @@ -141,6 +141,10 @@ include shared.mak # # Define NO_PTHREADS if you do not have or do not want to use Pthreads. # +# Define THREAD_BARRIER_PTHREAD if your system has pthread_barrier_t. Barrier +# support is optional and is only helpful when building with SANITIZE=leak, as +# it is used to eliminate some races in the leak-checker. +# # Define NO_PREAD if you have a problem with pread() system call (e.g. # cygwin1.dll before v1.5.22). # @@ -2079,6 +2083,9 @@ ifdef NO_PTHREADS else BASIC_CFLAGS += $(PTHREAD_CFLAGS) EXTLIBS += $(PTHREAD_LIBS) + ifdef THREAD_BARRIER_PTHREAD + BASIC_CFLAGS += -DTHREAD_BARRIER_PTHREAD + endif endif ifdef HAVE_PATHS_H diff --git a/ci/lib.sh b/ci/lib.sh index 8885ee3c3f..6a1267fbcb 100755 --- a/ci/lib.sh +++ b/ci/lib.sh @@ -385,6 +385,7 @@ linux-musl) ;; linux-leaks|linux-reftable-leaks) export SANITIZE=leak + export THREAD_BARRIER_PTHREAD=1 ;; linux-asan-ubsan) export SANITIZE=address,undefined diff --git a/thread-utils.h b/thread-utils.h index 4961487ed9..3df5be9916 100644 --- a/thread-utils.h +++ b/thread-utils.h @@ -53,5 +53,22 @@ int dummy_pthread_init(void *); int online_cpus(void); int init_recursive_mutex(pthread_mutex_t*); +#ifdef THREAD_BARRIER_PTHREAD +#define maybe_thread_barrier_t pthread_barrier_t +#define maybe_thread_barrier_init pthread_barrier_init +#define maybe_thread_barrier_wait pthread_barrier_wait +#define maybe_thread_barrier_destroy pthread_barrier_destroy +#else +#define maybe_thread_barrier_t int +static inline int maybe_thread_barrier_init(maybe_thread_barrier_t *b UNUSED, + void *attr UNUSED, + unsigned nr UNUSED) +{ + errno = ENOSYS; + return -1; +} +#define maybe_thread_barrier_wait(barrier) +#define maybe_thread_barrier_destroy(barrier) +#endif #endif /* THREAD_COMPAT_H */ -- cgit v1.2.3 From 526c0a851b14d1bbec4b8d31a23d93ca0eb82637 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 29 Dec 2024 23:29:38 -0500 Subject: index-pack: work around LSan threading race with barrier We sometimes get false positives from our linux-leaks CI job because of a race in LSan itself. The problem is that one thread is still initializing its stack in LSan's code (and allocating memory to do so) while anothe thread calls die(), taking down the whole process and triggering a leak check. The problem is described in more detail in 993d38a066 (index-pack: spawn threads atomically, 2024-01-05), which tried to fix it by pausing worker threads until all calls to pthread_create() had completed. But that's not enough to fix the problem, because the LSan setup code runs in the threads themselves. So even though pthread_create() has returned, we have no idea if all threads actually finished their setup before letting any of them do real work. We can fix that by using a barrier inside the threads themselves, waiting for all of them to hit the start of their main function before any of them proceed. You can test for the race by running: make SANITIZE=leak THREAD_BARRIER_PTHREAD=YesOnLinux cd t ./t5309-pack-delta-cycles.sh --stress which fails quickly before this patch, and should run indefinitely without it. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin/index-pack.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 0b62b2589f..27b120f26c 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -185,6 +185,8 @@ static pthread_mutex_t deepest_delta_mutex; static pthread_key_t key; +static maybe_thread_barrier_t start_barrier; + static inline void lock_mutex(pthread_mutex_t *mutex) { if (threads_active) @@ -209,6 +211,7 @@ static void init_thread(void) if (show_stat) pthread_mutex_init(&deepest_delta_mutex, NULL); pthread_key_create(&key, NULL); + maybe_thread_barrier_init(&start_barrier, NULL, nr_threads); CALLOC_ARRAY(thread_data, nr_threads); for (i = 0; i < nr_threads; i++) { thread_data[i].pack_fd = xopen(curr_pack, O_RDONLY); @@ -231,6 +234,7 @@ static void cleanup_thread(void) for (i = 0; i < nr_threads; i++) close(thread_data[i].pack_fd); pthread_key_delete(key); + maybe_thread_barrier_destroy(&start_barrier); free(thread_data); } @@ -1100,6 +1104,8 @@ static int compare_ref_delta_entry(const void *a, const void *b) static void *threaded_second_pass(void *data) { + if (threads_active) + maybe_thread_barrier_wait(&start_barrier); if (data) set_thread_data(data); for (;;) { -- cgit v1.2.3 From 7a8d9efc26f194eb20114d1f639ec9fa48d70bff Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 29 Dec 2024 23:30:26 -0500 Subject: grep: work around LSan threading race with barrier There's a race with LSan when spawning threads and one of the threads calls die(). We worked around one such problem with index-pack in the previous commit, but it exists in git-grep, too. You can see it with: make SANITIZE=leak THREAD_BARRIER_PTHREAD=YesOnLinux cd t ./t0003-attributes.sh --stress which fails pretty quickly with: ==git==4096424==ERROR: LeakSanitizer: detected memory leaks Direct leak of 32 byte(s) in 1 object(s) allocated from: #0 0x7f906de14556 in realloc ../../../../src/libsanitizer/lsan/lsan_interceptors.cpp:98 #1 0x7f906dc9d2c1 in __pthread_getattr_np nptl/pthread_getattr_np.c:180 #2 0x7f906de2500d in __sanitizer::GetThreadStackTopAndBottom(bool, unsigned long*, unsigned long*) ../../../../src/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp:150 #3 0x7f906de25187 in __sanitizer::GetThreadStackAndTls(bool, unsigned long*, unsigned long*, unsigned long*, unsigned long*) ../../../../src/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp:614 #4 0x7f906de17d18 in __lsan::ThreadStart(unsigned int, unsigned long long, __sanitizer::ThreadType) ../../../../src/libsanitizer/lsan/lsan_posix.cpp:53 #5 0x7f906de143a9 in ThreadStartFunc ../../../../src/libsanitizer/lsan/lsan_interceptors.cpp:431 #6 0x7f906dc9bf51 in start_thread nptl/pthread_create.c:447 #7 0x7f906dd1a677 in __clone3 ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78 As with the previous commit, we can fix this by inserting a barrier that makes sure all threads have finished their setup before continuing. But there's one twist in this case: the thread which calls die() is not one of the worker threads, but the main thread itself! So we need the main thread to wait in the barrier, too, until all threads have gotten to it. And thus we initialize the barrier for num_threads+1, to account for all of the worker threads plus the main one. If we then test as above, t0003 should run indefinitely. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin/grep.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/builtin/grep.c b/builtin/grep.c index d00ee76f24..61b2c27490 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -101,6 +101,9 @@ static pthread_cond_t cond_write; /* Signalled when we are finished with everything. */ static pthread_cond_t cond_result; +/* Synchronize the start of all threads */ +static maybe_thread_barrier_t start_barrier; + static int skip_first_line; static void add_work(struct grep_opt *opt, struct grep_source *gs) @@ -198,6 +201,8 @@ static void *run(void *arg) int hit = 0; struct grep_opt *opt = arg; + maybe_thread_barrier_wait(&start_barrier); + while (1) { struct work_item *w = get_work(); if (!w) @@ -229,6 +234,7 @@ static void start_threads(struct grep_opt *opt) pthread_cond_init(&cond_add, NULL); pthread_cond_init(&cond_write, NULL); pthread_cond_init(&cond_result, NULL); + maybe_thread_barrier_init(&start_barrier, NULL, num_threads + 1); grep_use_locks = 1; enable_obj_read_lock(); @@ -248,6 +254,7 @@ static void start_threads(struct grep_opt *opt) die(_("grep: failed to create thread: %s"), strerror(err)); } + maybe_thread_barrier_wait(&start_barrier); } static int wait_all(void) @@ -284,6 +291,7 @@ static int wait_all(void) pthread_cond_destroy(&cond_add); pthread_cond_destroy(&cond_write); pthread_cond_destroy(&cond_result); + maybe_thread_barrier_destroy(&start_barrier); grep_use_locks = 0; disable_obj_read_lock(); -- cgit v1.2.3 From 0ad3d656521aa16a6496aa855bbde97160a2b2bc Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 30 Dec 2024 11:32:23 +0100 Subject: object-file: fix race in object collision check One of the tests in t5616 asserts that git-fetch(1) with `--refetch` triggers repository maintenance with the correct set of arguments. This test is flaky and causes us to fail sometimes: ++ git -c protocol.version=0 -c gc.autoPackLimit=0 -c maintenance.incremental-repack.auto=1234 -C pc1 fetch --refetch origin error: unable to open .git/objects/pack/pack-029d08823bd8a8eab510ad6ac75c823cfd3ed31e.pack: No such file or directory fatal: unable to rename temporary file to '.git/objects/pack/pack-029d08823bd8a8eab510ad6ac75c823cfd3ed31e.pack' fatal: could not finish pack-objects to repack local links fatal: index-pack failed error: last command exited with $?=128 The error message is quite confusing as it talks about trying to rename a temporary packfile. A first hunch would thus be that this packfile gets written by git-fetch(1), but removed by git-maintenance(1) while it hasn't yet been finalized, which shouldn't ever happen. And indeed, when looking closer one notices that the file that is supposedly of temporary nature does not have the typical `tmp_pack_` prefix. As it turns out, the "unable to rename temporary file" fatal error is a red herring and the real error is "unable to open". That error is raised by `check_collision()`, which is called by `finalize_object_file()` when moving the new packfile into place. Because t5616 re-fetches objects, we end up with the exact same pack as we already have in the repository. So when the concurrent git-maintenance(1) process rewrites the preexisting pack and unlinks it exactly at the point in time where git-fetch(1) wants to check the old and new packfiles for equality we will see ENOENT and thus `check_collision()` returns an error, which gets bubbled up by `finalize_object_file()` and is then handled by `rename_tmp_packfile()`. That function does not know about the exact root cause of the error and instead just claims that the rename has failed. This race is thus caused by b1b8dfde69 (finalize_object_file(): implement collision check, 2024-09-26), where we have newly introduced the collision check. By definition, two files cannot collide with each other when one of them has been removed. We can thus trivially fix the issue by ignoring ENOENT when opening either of the files we're about to check for collision. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- object-file.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/object-file.c b/object-file.c index b1a3463852..0293b93bbc 100644 --- a/object-file.c +++ b/object-file.c @@ -1982,13 +1982,15 @@ static int check_collision(const char *filename_a, const char *filename_b) fd_a = open(filename_a, O_RDONLY); if (fd_a < 0) { - ret = error_errno(_("unable to open %s"), filename_a); + if (errno != ENOENT) + ret = error_errno(_("unable to open %s"), filename_a); goto out; } fd_b = open(filename_b, O_RDONLY); if (fd_b < 0) { - ret = error_errno(_("unable to open %s"), filename_b); + if (errno != ENOENT) + ret = error_errno(_("unable to open %s"), filename_b); goto out; } -- cgit v1.2.3 From 9218c0bfe1baef0a67688b8a0189121d7d834926 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 30 Dec 2024 15:24:01 +0100 Subject: bulk-checkin: fix segfault with unsafe SHA1 backend In 1b9e9be8b4 (csum-file.c: use unsafe SHA-1 implementation when available, 2024-09-26) we have converted our `struct hashfile` to use the unsafe SHA1 backend, which results in a significant speedup. One needs to be careful with how to use that structure now though because callers need to consistently use either the safe or unsafe variants of SHA1, as otherwise one can easily trigger corruption. As it turns out, we have one inconsistent usage in our tree because we directly initialize `struct hashfile_checkpoint::ctx` with the safe variant of SHA1, but end up writing to that context with the unsafe ones. This went unnoticed so far because our CI systems do not exercise different hash functions for these two backends, and consequently safe and unsafe variants are equivalent. But when using SHA1DC as safe and OpenSSL as unsafe backend this leads to a crash an t1050: ++ git -c core.compression=0 add large1 AddressSanitizer:DEADLYSIGNAL ================================================================= ==1367==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000040 (pc 0x7ffff7a01a99 bp 0x507000000db0 sp 0x7fffffff5690 T0) ==1367==The signal is caused by a READ memory access. ==1367==Hint: address points to the zero page. #0 0x7ffff7a01a99 in EVP_MD_CTX_copy_ex (/nix/store/h1ydpxkw9qhjdxjpic1pdc2nirggyy6f-openssl-3.3.2/lib/libcrypto.so.3+0x201a99) (BuildId: 41746a580d39075fc85e8c8065b6c07fb34e97d4) #1 0x555555ddde56 in openssl_SHA1_Clone ../sha1/openssl.h:40:2 #2 0x555555dce2fc in git_hash_sha1_clone_unsafe ../object-file.c:123:2 #3 0x555555c2d5f8 in hashfile_checkpoint ../csum-file.c:211:2 #4 0x555555b9905d in deflate_blob_to_pack ../bulk-checkin.c:286:4 #5 0x555555b98ae9 in index_blob_bulk_checkin ../bulk-checkin.c:362:15 #6 0x555555ddab62 in index_blob_stream ../object-file.c:2756:9 #7 0x555555dda420 in index_fd ../object-file.c:2778:9 #8 0x555555ddad76 in index_path ../object-file.c:2796:7 #9 0x555555e947f3 in add_to_index ../read-cache.c:771:7 #10 0x555555e954a4 in add_file_to_index ../read-cache.c:804:9 #11 0x5555558b5c39 in add_files ../builtin/add.c:355:7 #12 0x5555558b412e in cmd_add ../builtin/add.c:578:18 #13 0x555555b1f493 in run_builtin ../git.c:480:11 #14 0x555555b1bfef in handle_builtin ../git.c:740:9 #15 0x555555b1e6f4 in run_argv ../git.c:807:4 #16 0x555555b1b87a in cmd_main ../git.c:947:19 #17 0x5555561649e6 in main ../common-main.c:64:11 #18 0x7ffff742a1fb in __libc_start_call_main (/nix/store/65h17wjrrlsj2rj540igylrx7fqcd6vq-glibc-2.40-36/lib/libc.so.6+0x2a1fb) (BuildId: bf320110569c8ec2425e9a0c5e4eb7e97f1fb6e4) #19 0x7ffff742a2b8 in __libc_start_main@GLIBC_2.2.5 (/nix/store/65h17wjrrlsj2rj540igylrx7fqcd6vq-glibc-2.40-36/lib/libc.so.6+0x2a2b8) (BuildId: bf320110569c8ec2425e9a0c5e4eb7e97f1fb6e4) #20 0x555555772c84 in _start (git+0x21ec84) ==1367==Register values: rax = 0x0000511000001080 rbx = 0x0000000000000000 rcx = 0x000000000000000c rdx = 0x0000000000000000 rdi = 0x0000000000000000 rsi = 0x0000507000000db0 rbp = 0x0000507000000db0 rsp = 0x00007fffffff5690 r8 = 0x0000000000000000 r9 = 0x0000000000000000 r10 = 0x0000000000000000 r11 = 0x00007ffff7a01a30 r12 = 0x0000000000000000 r13 = 0x00007fffffff6b38 r14 = 0x00007ffff7ffd000 r15 = 0x00005555563b9910 AddressSanitizer can not provide additional info. SUMMARY: AddressSanitizer: SEGV (/nix/store/h1ydpxkw9qhjdxjpic1pdc2nirggyy6f-openssl-3.3.2/lib/libcrypto.so.3+0x201a99) (BuildId: 41746a580d39075fc85e8c8065b6c07fb34e97d4) in EVP_MD_CTX_copy_ex ==1367==ABORTING ./test-lib.sh: line 1023: 1367 Aborted git $config add large1 error: last command exited with $?=134 not ok 4 - add with -c core.compression=0 Fix the issue by using the unsafe variant instead. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- bulk-checkin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bulk-checkin.c b/bulk-checkin.c index 2753d5bbe4..c1080b488f 100644 --- a/bulk-checkin.c +++ b/bulk-checkin.c @@ -271,7 +271,7 @@ static int deflate_blob_to_pack(struct bulk_checkin_packfile *state, OBJ_BLOB, size); the_hash_algo->init_fn(&ctx); the_hash_algo->update_fn(&ctx, obuf, header_len); - the_hash_algo->init_fn(&checkpoint.ctx); + the_hash_algo->unsafe_init_fn(&checkpoint.ctx); /* Note: idx is non-NULL when we are writing */ if ((flags & HASH_WRITE_OBJECT) != 0) -- cgit v1.2.3 From 106140a99fbdb7acf19723473621e0ccaa03c158 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 30 Dec 2024 15:24:02 +0100 Subject: builtin/fast-import: fix segfault with unsafe SHA1 backend Same as with the preceding commit, git-fast-import(1) is using the safe variant to initialize a hashfile checkpoint. This leads to a segfault when passing the checkpoint into the hashfile subsystem because it would use the unsafe variants instead: ++ git --git-dir=R/.git fast-import --big-file-threshold=1 AddressSanitizer:DEADLYSIGNAL ================================================================= ==577126==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000040 (pc 0x7ffff7a01a99 bp 0x5070000009c0 sp 0x7fffffff5b30 T0) ==577126==The signal is caused by a READ memory access. ==577126==Hint: address points to the zero page. #0 0x7ffff7a01a99 in EVP_MD_CTX_copy_ex (/nix/store/h1ydpxkw9qhjdxjpic1pdc2nirggyy6f-openssl-3.3.2/lib/libcrypto.so.3+0x201a99) (BuildId: 41746a580d39075fc85e8c8065b6c07fb34e97d4) #1 0x555555ddde56 in openssl_SHA1_Clone ../sha1/openssl.h:40:2 #2 0x555555dce2fc in git_hash_sha1_clone_unsafe ../object-file.c:123:2 #3 0x555555c2d5f8 in hashfile_checkpoint ../csum-file.c:211:2 #4 0x5555559647d1 in stream_blob ../builtin/fast-import.c:1110:2 #5 0x55555596247b in parse_and_store_blob ../builtin/fast-import.c:2031:3 #6 0x555555967f91 in file_change_m ../builtin/fast-import.c:2408:5 #7 0x55555595d8a2 in parse_new_commit ../builtin/fast-import.c:2768:4 #8 0x55555595bb7a in cmd_fast_import ../builtin/fast-import.c:3614:4 #9 0x555555b1f493 in run_builtin ../git.c:480:11 #10 0x555555b1bfef in handle_builtin ../git.c:740:9 #11 0x555555b1e6f4 in run_argv ../git.c:807:4 #12 0x555555b1b87a in cmd_main ../git.c:947:19 #13 0x5555561649e6 in main ../common-main.c:64:11 #14 0x7ffff742a1fb in __libc_start_call_main (/nix/store/65h17wjrrlsj2rj540igylrx7fqcd6vq-glibc-2.40-36/lib/libc.so.6+0x2a1fb) (BuildId: bf320110569c8ec2425e9a0c5e4eb7e97f1fb6e4) #15 0x7ffff742a2b8 in __libc_start_main@GLIBC_2.2.5 (/nix/store/65h17wjrrlsj2rj540igylrx7fqcd6vq-glibc-2.40-36/lib/libc.so.6+0x2a2b8) (BuildId: bf320110569c8ec2425e9a0c5e4eb7e97f1fb6e4) #16 0x555555772c84 in _start (git+0x21ec84) ==577126==Register values: rax = 0x0000511000000cc0 rbx = 0x0000000000000000 rcx = 0x000000000000000c rdx = 0x0000000000000000 rdi = 0x0000000000000000 rsi = 0x00005070000009c0 rbp = 0x00005070000009c0 rsp = 0x00007fffffff5b30 r8 = 0x0000000000000000 r9 = 0x0000000000000000 r10 = 0x0000000000000000 r11 = 0x00007ffff7a01a30 r12 = 0x0000000000000000 r13 = 0x00007fffffff6b60 r14 = 0x00007ffff7ffd000 r15 = 0x00005555563b9910 AddressSanitizer can not provide additional info. SUMMARY: AddressSanitizer: SEGV (/nix/store/h1ydpxkw9qhjdxjpic1pdc2nirggyy6f-openssl-3.3.2/lib/libcrypto.so.3+0x201a99) (BuildId: 41746a580d39075fc85e8c8065b6c07fb34e97d4) in EVP_MD_CTX_copy_ex ==577126==ABORTING ./test-lib.sh: line 1039: 577126 Aborted git --git-dir=R/.git fast-import --big-file-threshold=1 < input error: last command exited with $?=134 not ok 167 - R: blob bigger than threshold The segfault is only exposed in case the unsafe and safe backends are different from one another. Fix the issue by initializing the context with the unsafe SHA1 variant. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/fast-import.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/fast-import.c b/builtin/fast-import.c index 1e7ab67f6e..48f8d015a0 100644 --- a/builtin/fast-import.c +++ b/builtin/fast-import.c @@ -1102,7 +1102,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark) || (pack_size + PACK_SIZE_THRESHOLD + len) < pack_size) cycle_packfile(); - the_hash_algo->init_fn(&checkpoint.ctx); + the_hash_algo->unsafe_init_fn(&checkpoint.ctx); hashfile_checkpoint(pack_file, &checkpoint); offset = checkpoint.offset; -- cgit v1.2.3 From 599a63409bed67d61c359d316da5a10bcddc954b Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 30 Dec 2024 15:24:03 +0100 Subject: ci: exercise unsafe OpenSSL backend In the preceding commit we have fixed a segfault when using an unsafe SHA1 backend that is different from the safe one. This segfault only went by unnoticed because we never set up an unsafe backend in our CI systems. Fix this ommission by setting `OPENSSL_SHA1_UNSAFE` in our TEST-vars job. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- ci/run-build-and-tests.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh index 2e28d02b20..e90b338001 100755 --- a/ci/run-build-and-tests.sh +++ b/ci/run-build-and-tests.sh @@ -17,6 +17,7 @@ linux-gcc) export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main ;; linux-TEST-vars) + export OPENSSL_SHA1_UNSAFE=YesPlease export GIT_TEST_SPLIT_INDEX=yes export GIT_TEST_MERGE_ALGORITHM=recursive export GIT_TEST_FULL_IN_PACK_ARRAY=true -- cgit v1.2.3 From 8214e27d275915079ddf7c294c379515e34e8efb Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 30 Dec 2024 15:24:04 +0100 Subject: meson: consistenlty spell 'CommonCrypto' The 'CommonCrypto' backend can be specified as HTTPS and SHA1 backends, but the value that one needs to use is inconsistent across those two build options. Unify it to 'CommonCrypto'. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- meson.build | 2 +- meson_options.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 0064eb64f5..9da58dafe0 100644 --- a/meson.build +++ b/meson.build @@ -1367,7 +1367,7 @@ if sha1_backend == 'sha1dc' 'sha1dc/sha1.c', 'sha1dc/ubc_check.c', ] -elif sha1_backend == 'common-crypto' +elif sha1_backend == 'CommonCrypto' libgit_c_args += '-DCOMMON_DIGEST_FOR_OPENSSL' libgit_c_args += '-DSHA1_APPLE' # Apple CommonCrypto requires chunking diff --git a/meson_options.txt b/meson_options.txt index 4be7eab399..a7f308d217 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -49,7 +49,7 @@ option('regex', type: 'feature', value: 'auto', # Backends. option('https_backend', type: 'combo', value: 'auto', choices: ['auto', 'openssl', 'CommonCrypto', 'none'], description: 'The HTTPS backend to use when connecting to remotes.') -option('sha1_backend', type: 'combo', choices: ['openssl', 'block', 'sha1dc', 'common-crypto'], value: 'sha1dc', +option('sha1_backend', type: 'combo', choices: ['openssl', 'block', 'sha1dc', 'CommonCrypto'], value: 'sha1dc', description: 'The backend used for hashing objects with the SHA1 object format') option('sha256_backend', type: 'combo', choices: ['openssl', 'nettle', 'gcrypt', 'block'], value: 'block', description: 'The backend used for hashing objects with the SHA256 object format') -- cgit v1.2.3 From 31eb6d7cf09c3fa668c1839d8c5759ab7cdf280c Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 30 Dec 2024 15:24:05 +0100 Subject: meson: deduplicate access to SHA1/SHA256 backend options We've got a couple of repeated calls to `get_option()` for the SHA1 and SHA256 backend options. While not an issue, it makes the code needlessly verbose. Fix this by consistently using a local variable. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- meson.build | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 9da58dafe0..6fa4d900ee 100644 --- a/meson.build +++ b/meson.build @@ -1326,6 +1326,8 @@ if not meson.is_cross_build() and fs.exists('/dev/tty') endif https_backend = get_option('https_backend') +sha1_backend = get_option('sha1_backend') +sha256_backend = get_option('sha256_backend') security_framework = dependency('Security', required: https_backend == 'CommonCrypto') core_foundation_framework = dependency('CoreFoundation', required: security_framework.found()) @@ -1333,7 +1335,7 @@ if https_backend == 'auto' and security_framework.found() https_backend = 'CommonCrypto' endif -openssl_required = https_backend == 'openssl' or get_option('sha1_backend') == 'openssl' or get_option('sha256_backend') == 'openssl' +openssl_required = https_backend == 'openssl' or sha1_backend == 'openssl' or sha256_backend == 'openssl' openssl = dependency('openssl', required: openssl_required, default_options: ['default_library=static']) if https_backend == 'auto' and openssl.found() https_backend = 'openssl' @@ -1354,7 +1356,6 @@ if https_backend != 'openssl' libgit_c_args += '-DNO_OPENSSL' endif -sha1_backend = get_option('sha1_backend') if sha1_backend == 'sha1dc' libgit_c_args += '-DSHA1_DC' libgit_c_args += '-DSHA1DC_NO_STANDARD_INCLUDES=1' @@ -1382,7 +1383,6 @@ else error('Unhandled SHA1 backend ' + sha1_backend) endif -sha256_backend = get_option('sha256_backend') if sha256_backend == 'openssl' libgit_c_args += '-DSHA256_OPENSSL' libgit_dependencies += openssl -- cgit v1.2.3 From d6787d975147a74f1560fffc09dcb2a1f92460bb Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 30 Dec 2024 15:24:06 +0100 Subject: meson: require SecurityFramework when it's used as SHA1 backend The Security framework is required when we use CommonCrypto either as HTTPS or SHA1 backend, but we only require it in case it is set up as HTTPS backend. Fix this. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 6fa4d900ee..bc75ad954a 100644 --- a/meson.build +++ b/meson.build @@ -1329,7 +1329,7 @@ https_backend = get_option('https_backend') sha1_backend = get_option('sha1_backend') sha256_backend = get_option('sha256_backend') -security_framework = dependency('Security', required: https_backend == 'CommonCrypto') +security_framework = dependency('Security', required: https_backend == 'CommonCrypto' or sha1_backend == 'CommonCrypto') core_foundation_framework = dependency('CoreFoundation', required: security_framework.found()) if https_backend == 'auto' and security_framework.found() https_backend = 'CommonCrypto' -- cgit v1.2.3 From 6d8aa2aec81abf4935c72745790bc5f9bf7541b9 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 30 Dec 2024 15:24:07 +0100 Subject: meson: simplify conditions for HTTPS and SHA1 dependencies The conditions used to figure out whteher the Security framework or OpenSSL library is required are a bit convoluted because they can be pulled in via the HTTPS, SHA1 or SHA256 backends. Refactor them to be easier to read. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index bc75ad954a..46f807899b 100644 --- a/meson.build +++ b/meson.build @@ -1329,13 +1329,13 @@ https_backend = get_option('https_backend') sha1_backend = get_option('sha1_backend') sha256_backend = get_option('sha256_backend') -security_framework = dependency('Security', required: https_backend == 'CommonCrypto' or sha1_backend == 'CommonCrypto') +security_framework = dependency('Security', required: 'CommonCrypto' in [https_backend, sha1_backend]) core_foundation_framework = dependency('CoreFoundation', required: security_framework.found()) if https_backend == 'auto' and security_framework.found() https_backend = 'CommonCrypto' endif -openssl_required = https_backend == 'openssl' or sha1_backend == 'openssl' or sha256_backend == 'openssl' +openssl_required = 'openssl' in [https_backend, sha1_backend, sha256_backend] openssl = dependency('openssl', required: openssl_required, default_options: ['default_library=static']) if https_backend == 'auto' and openssl.found() https_backend = 'openssl' -- cgit v1.2.3 From 12068bd4de03c7769f50cd8321f792477692d0ea Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 30 Dec 2024 15:24:08 +0100 Subject: meson: add missing dots for build options Most of our Meson build options end with a trailing dot, but those for our SHA1 and SHA256 backends don't. Add it. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- meson_options.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson_options.txt b/meson_options.txt index a7f308d217..d8d283982b 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -50,9 +50,9 @@ option('regex', type: 'feature', value: 'auto', option('https_backend', type: 'combo', value: 'auto', choices: ['auto', 'openssl', 'CommonCrypto', 'none'], description: 'The HTTPS backend to use when connecting to remotes.') option('sha1_backend', type: 'combo', choices: ['openssl', 'block', 'sha1dc', 'CommonCrypto'], value: 'sha1dc', - description: 'The backend used for hashing objects with the SHA1 object format') + description: 'The backend used for hashing objects with the SHA1 object format.') option('sha256_backend', type: 'combo', choices: ['openssl', 'nettle', 'gcrypt', 'block'], value: 'block', - description: 'The backend used for hashing objects with the SHA256 object format') + description: 'The backend used for hashing objects with the SHA256 object format.') # Build tweaks. option('macos_use_homebrew_gettext', type: 'boolean', value: true, -- cgit v1.2.3 From d2c0b6a86cb0f1a73d9ad5fcffda45497cd7ad42 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 30 Dec 2024 15:24:09 +0100 Subject: meson: wire up unsafe SHA1 backend In 06c92dafb8 (Makefile: allow specifying a SHA-1 for non-cryptographic uses, 2024-09-26), we have introduced a cryptographically-insecure backend for SHA1 that can optionally be used in some contexts where the processed data is not security relevant. This effort was in-flight with the effort to introduce Meson, so we don't have an equivalent here. Wire up a new build option that lets users pick an unsafe SHA1 backend. Note that for simplicity's sake we have to drop the error condition around an unhandled SHA1 backend. This should be fine though given that Meson verifies the value for combo-options for us. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- meson.build | 40 ++++++++++++++++++++++++++++++---------- meson_options.txt | 2 ++ 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/meson.build b/meson.build index 46f807899b..dc82c23cb4 100644 --- a/meson.build +++ b/meson.build @@ -1327,15 +1327,16 @@ endif https_backend = get_option('https_backend') sha1_backend = get_option('sha1_backend') +sha1_unsafe_backend = get_option('sha1_unsafe_backend') sha256_backend = get_option('sha256_backend') -security_framework = dependency('Security', required: 'CommonCrypto' in [https_backend, sha1_backend]) +security_framework = dependency('Security', required: 'CommonCrypto' in [https_backend, sha1_backend, sha1_unsafe_backend]) core_foundation_framework = dependency('CoreFoundation', required: security_framework.found()) if https_backend == 'auto' and security_framework.found() https_backend = 'CommonCrypto' endif -openssl_required = 'openssl' in [https_backend, sha1_backend, sha256_backend] +openssl_required = 'openssl' in [https_backend, sha1_backend, sha1_unsafe_backend, sha256_backend] openssl = dependency('openssl', required: openssl_required, default_options: ['default_library=static']) if https_backend == 'auto' and openssl.found() https_backend = 'openssl' @@ -1368,19 +1369,38 @@ if sha1_backend == 'sha1dc' 'sha1dc/sha1.c', 'sha1dc/ubc_check.c', ] -elif sha1_backend == 'CommonCrypto' +endif +if sha1_backend == 'CommonCrypto' or sha1_unsafe_backend == 'CommonCrypto' + if sha1_backend == 'CommonCrypto' + libgit_c_args += '-DSHA1_APPLE' + endif + if sha1_unsafe_backend == 'CommonCrypto' + libgit_c_args += '-DSHA1_APPLE_UNSAFE' + endif + libgit_c_args += '-DCOMMON_DIGEST_FOR_OPENSSL' - libgit_c_args += '-DSHA1_APPLE' # Apple CommonCrypto requires chunking libgit_c_args += '-DSHA1_MAX_BLOCK_SIZE=1024L*1024L*1024L' -elif sha1_backend == 'openssl' - libgit_c_args += '-DSHA1_OPENSSL' +endif +if sha1_backend == 'openssl' or sha1_unsafe_backend == 'openssl' + if sha1_backend == 'openssl' + libgit_c_args += '-DSHA1_OPENSSL' + endif + if sha1_unsafe_backend == 'openssl' + libgit_c_args += '-DSHA1_OPENSSL_UNSAFE' + endif + libgit_dependencies += openssl -elif sha1_backend == 'block' - libgit_c_args += '-DSHA1_BLK' +endif +if sha1_backend == 'block' or sha1_unsafe_backend == 'block' + if sha1_backend == 'block' + libgit_c_args += '-DSHA1_BLK' + endif + if sha1_unsafe_backend == 'block' + libgit_c_args += '-DSHA1_BLK_UNSAFE' + endif + libgit_sources += 'block-sha1/sha1.c' -else - error('Unhandled SHA1 backend ' + sha1_backend) endif if sha256_backend == 'openssl' diff --git a/meson_options.txt b/meson_options.txt index d8d283982b..8282b1dea8 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -51,6 +51,8 @@ option('https_backend', type: 'combo', value: 'auto', choices: ['auto', 'openssl description: 'The HTTPS backend to use when connecting to remotes.') option('sha1_backend', type: 'combo', choices: ['openssl', 'block', 'sha1dc', 'CommonCrypto'], value: 'sha1dc', description: 'The backend used for hashing objects with the SHA1 object format.') +option('sha1_unsafe_backend', type: 'combo', choices: ['openssl', 'block', 'CommonCrypto', 'none'], value: 'none', + description: 'The backend used for hashing data with the SHA1 object format in case no cryptographic security is needed.') option('sha256_backend', type: 'combo', choices: ['openssl', 'nettle', 'gcrypt', 'block'], value: 'block', description: 'The backend used for hashing objects with the SHA256 object format.') -- cgit v1.2.3 From 6a0ee54f9a3ebf667e86f7110c36b2240df96166 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 30 Dec 2024 15:24:10 +0100 Subject: meson: provide a summary of configured backends There are a couple of backends from which the user can choose for HTTPS, SHA1, its unsafe variant as well as SHA256. Provide a summary of the configured values to make these more discoverable. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- meson.build | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/meson.build b/meson.build index dc82c23cb4..7361eb2eaa 100644 --- a/meson.build +++ b/meson.build @@ -1943,3 +1943,10 @@ summary({ 'perl': perl_features_enabled, 'python': python.found(), }, section: 'Auto-detected features') + +summary({ + 'https': https_backend, + 'sha1': sha1_backend, + 'sha1_unsafe': sha1_unsafe_backend, + 'sha256': sha256_backend, +}, section: 'Backends') -- cgit v1.2.3 From 5b34dd08d0ffc967b92abe187cc890d52ade5ac7 Mon Sep 17 00:00:00 2001 From: Alexander Shopov Date: Sat, 28 Dec 2024 12:42:18 +0100 Subject: parse-options: localize mark-up of placeholder text in the short help i18n: expose substitution hint chars in functions and macros to translators For example (based on builtin/commit.c and shortened): the "--author" option takes a name. In source this can be represented as: OPT_STRING(0, "author", &force_author, N_("author"), N_("override author")), When the command is run with "-h" (short help) option (git commit -h), the above definition is displayed as: --[no-]author override author Git does not use translated option names so the first part of the above, "--[no-]author", is given as-is (it is based on the 2nd argument of OPT_STRING). However the string "author" in the pair of "<>", and the explanation "override author for commit" may be translated into user's language. The user's language may use a convention to mark a replaceable part of the command line (called a "placeholder string") differently from enclosing it inside a pair of "<>", but the implementation in parse-options.c hardcodes "<%s>". Allow translators to specify the presentation of a placeholder string for their languages by overriding the "<%s>". In case the translator's writing system is sufficiently different than Latin the "<>" characters can be substituted by an empty string thus effectively skipping them in the output. For example languages with uppercase versions of characters can use that to deliniate replaceability. Alternatively a translator can decide to use characters that are visually close to "<>" but are not interpreted by the shell. Signed-off-by: Alexander Shopov Signed-off-by: Junio C Hamano --- parse-options.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/parse-options.c b/parse-options.c index 33bfba0ed4..3ff6a5d1fa 100644 --- a/parse-options.c +++ b/parse-options.c @@ -1076,11 +1076,48 @@ static int usage_argh(const struct option *opts, FILE *outfile) !opts->argh || !!strpbrk(opts->argh, "()<>[]|"); if (opts->flags & PARSE_OPT_OPTARG) if (opts->long_name) - s = literal ? "[=%s]" : "[=<%s>]"; + /* + * TRANSLATORS: The "<%s>" part of this string + * stands for an optional value given to a command + * line option in the long form, and "<>" is there + * as a convention to signal that it is a + * placeholder (i.e. the user should substitute it + * with the real value). If your language uses a + * different convention, you can change "<%s>" part + * to match yours, e.g. it might use "|%s|" instead, + * or if the alphabet is different enough it may use + * "%s" without any placeholder signal. Most + * translations leave this message as is. + */ + s = literal ? "[=%s]" : _("[=<%s>]"); else - s = literal ? "[%s]" : "[<%s>]"; + /* + * TRANSLATORS: The "<%s>" part of this string + * stands for an optional value given to a command + * line option in the short form, and "<>" is there + * as a convention to signal that it is a + * placeholder (i.e. the user should substitute it + * with the real value). If your language uses a + * different convention, you can change "<%s>" part + * to match yours, e.g. it might use "|%s|" instead, + * or if the alphabet is different enough it may use + * "%s" without any placeholder signal. Most + * translations leave this message as is. + */ + s = literal ? "[%s]" : _("[<%s>]"); else - s = literal ? " %s" : " <%s>"; + /* + * TRANSLATORS: The "<%s>" part of this string stands for a + * value given to a command line option, and "<>" is there + * as a convention to signal that it is a placeholder + * (i.e. the user should substitute it with the real value). + * If your language uses a different convention, you can + * change "<%s>" part to match yours, e.g. it might use + * "|%s|" instead, or if the alphabet is different enough it + * may use "%s" without any placeholder signal. Most + * translations leave this message as is. + */ + s = literal ? " %s" : _(" <%s>"); return utf8_fprintf(outfile, s, opts->argh ? _(opts->argh) : _("...")); } -- cgit v1.2.3 From bc2c65770dca70c1d4e151fad971bc7c7235a702 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 30 Dec 2024 06:58:28 -0800 Subject: Git 2.48-rc1 Signed-off-by: Junio C Hamano --- Documentation/RelNotes/2.48.0.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/RelNotes/2.48.0.txt b/Documentation/RelNotes/2.48.0.txt index 33c11e742f..f9fc8c1086 100644 --- a/Documentation/RelNotes/2.48.0.txt +++ b/Documentation/RelNotes/2.48.0.txt @@ -161,6 +161,9 @@ Performance, Internal Implementation, Development Support etc. * "git refs migrate" learned to also migrate the reflog data across backends. + * The developer documentation has been updated to give the latest + info on gitk and git-gui maintainer. + Fixes since v2.47 ----------------- -- cgit v1.2.3 From 1a18bf3a5b251557a7b10a496f9036f00790086a Mon Sep 17 00:00:00 2001 From: Emir SARI Date: Wed, 18 Dec 2024 19:10:42 +0300 Subject: l10n: tr: Update Turkish translations for 2.48 Signed-off-by: Emir SARI --- po/tr.po | 293 ++++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 225 insertions(+), 68 deletions(-) diff --git a/po/tr.po b/po/tr.po index 7aede5cd5f..1bc43453aa 100644 --- a/po/tr.po +++ b/po/tr.po @@ -2,7 +2,7 @@ # Git Türkçe çevirileri # Copyright (C) 2020-2024 Emir SARI # This file is distributed under the same license as the Git package. -# Emir SARI , 2020-2024 +# Emir SARI , 2020-2025 # # ######################################################### # # Git Türkçe kavramlar dizini / Git Turkish Glossary # @@ -96,8 +96,8 @@ msgid "" msgstr "" "Project-Id-Version: Git Turkish Localization Project\n" "Report-Msgid-Bugs-To: Git Mailing List \n" -"POT-Creation-Date: 2024-10-03 06:52+0300\n" -"PO-Revision-Date: 2024-10-03 07:00+0300\n" +"POT-Creation-Date: 2024-12-23 18:57+0000\n" +"PO-Revision-Date: 2025-01-01 15:00+0300\n" "Last-Translator: Emir SARI \n" "Language-Team: Turkish (https://github.com/bitigchi/git-po/)\n" "Language: tr\n" @@ -714,10 +714,10 @@ msgstr "Yalnızca ikili dosyalar değiştirildi." #, c-format msgid "" "\n" -"Disable this message with \"git config advice.%s false\"" +"Disable this message with \"git config set advice.%s false\"" msgstr "" "\n" -"Bu iletiyi \"git config advice.%s false\" ile devre dışı bırakın" +"Bu iletiyi \"git config set advice.%s false\" ile devre dışı bırakın" #, c-format msgid "%shint:%s%.*s%s\n" @@ -1441,8 +1441,9 @@ msgstr "geçerli bir nesne adı değil: %s" msgid "not a tree object: %s" msgstr "bir ağaç nesnesi değil: %s" -msgid "unable to checkout working tree" -msgstr "çalışma ağacı çıkış yapılamıyor" +#, c-format +msgid "failed to unpack tree object %s" +msgstr "%s ağaç nesnesi açılamadı" #, c-format msgid "File not found: %s" @@ -3072,8 +3073,8 @@ msgid "HEAD not found below refs/heads!" msgstr "HEAD, refs/heads altında bulunamadı!" msgid "" -"branch with --recurse-submodules can only be used if submodule." -"propagateBranches is enabled" +"branch with --recurse-submodules can only be used if " +"submodule.propagateBranches is enabled" msgstr "" "--recurse-submodules ile dallanma, yalnızca submodule.propagateBranches " "etkinleştirilmişse kullanılabilir" @@ -3921,9 +3922,8 @@ msgstr "yeni henüz doğmamış dal" msgid "update ignored files (default)" msgstr "yok sayılan dosyaları güncelle (öntanımlı)" -msgid "do not check if another worktree is holding the given ref" -msgstr "" -"verilen başvuruyu başka bir çalışma ağacının tutup tutmadığını denetleme" +msgid "do not check if another worktree is using this branch" +msgstr "bu dalı başka bir çalışma ağacının kullanıp kullanmadığını denetleme" msgid "checkout our version for unmerged files" msgstr "birleştirilmeyen dosyalar için bizdeki sürümü çıkış yap" @@ -4224,11 +4224,11 @@ msgstr "verilen derinlikte sığ bir depo oluştur" msgid "create a shallow clone since a specific time" msgstr "verilen zamandan sonrasını içeren bir sığ depo oluştur" -msgid "revision" -msgstr "revizyon" +msgid "ref" +msgstr "başvuru" -msgid "deepen history of shallow clone, excluding rev" -msgstr "revizyonu hariç tutarak sığ klonun geçmişini derinleştir" +msgid "deepen history of shallow clone, excluding ref" +msgstr "başvuru hariç tutarak sığ klonun geçmişini derinleştir" msgid "clone only one branch, HEAD or --branch" msgstr "yalnızca bir dal klonla, HEAD veya --branch" @@ -4355,6 +4355,9 @@ msgstr "sparse-checkout ilklendirilemedi" msgid "remote HEAD refers to nonexistent ref, unable to checkout" msgstr "uzak konum HEAD'i, var olmayan başvuruya başvuruyor; çıkış yapılamıyor" +msgid "unable to checkout working tree" +msgstr "çalışma ağacı çıkış yapılamıyor" + msgid "unable to write parameters to config file" msgstr "parametreler yapılandırma dosyasına yazılamıyor" @@ -5163,10 +5166,10 @@ msgstr "" msgid "" "git config unset [] [--all] [--value=] [--fixed-value] " -" " +"" msgstr "" "git config unset [] [--all] [--value=] [--fixed-" -"value] " +"value] " msgid "git config rename-section [] " msgstr "git config rename-section [] " @@ -5601,12 +5604,8 @@ msgid "traversed %lu commits\n" msgstr "%lu işleme katedildi\n" #, c-format -msgid "" -"more than %i tags found; listed %i most recent\n" -"gave up search at %s\n" -msgstr "" -"%i etiketten fazla etiket bulundu; en son %i listelendi\n" -"şu konumda arama bırakıldı: %s\n" +msgid "found %i tags; gave up search at %s\n" +msgstr "%i etiket bulundu; arama şurada bitirildi: %s\n" #, c-format msgid "describe %s\n" @@ -6040,6 +6039,21 @@ msgstr "%s geçerli bir nesne değil" msgid "the object %s does not exist" msgstr "%s diye bir nesne yok" +#, c-format +msgid "" +"Run 'git remote set-head %s %s' to follow the change, or set\n" +"'remote.%s.followRemoteHEAD' configuration option to a different value\n" +"if you do not want to see this message. Specifically running\n" +"'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n" +"until the remote changes HEAD to something else." +msgstr "" +"Değişikliği izlemek için 'git remote set-head %s %s' yapın veya\n" +"'remote.%s.followRemoteHEAD' yapılandırma seçeneğini başka bir\n" +"değere ayarlayın (bu iletiyi görmek istemiyorsanız). Özellikle\n" +"'git config set remote.%s.followRemoteHEAD %s' komutunu çalıştırmak\n" +"uyarıyı HEAD'e veya başka bir şeye uzaktan değişiklik olana dek\n" +"devre dışı bırakır." + msgid "multiple branches detected, incompatible with --set-upstream" msgstr "birden çok dal algılandı, --set-upstream ile uyumsuz" @@ -6178,6 +6192,9 @@ msgstr "ilgili başvuru" msgid "specify fetch refmap" msgstr "getirme ile ilgili başvuruları belirt" +msgid "revision" +msgstr "revizyon" + msgid "report that we have only objects reachable from this object" msgstr "yalnızca bu nesneden ulaşılabilir nesnelerimiz olduğunu bildir" @@ -6232,8 +6249,8 @@ msgid "protocol does not support --negotiate-only, exiting" msgstr "protokol, --negotiate-only desteklemediğinden çıkılıyor" msgid "" -"--filter can only be used with the remote configured in extensions." -"partialclone" +"--filter can only be used with the remote configured in " +"extensions.partialclone" msgstr "" "--filter, yalnızca extensions.partialclone içinde yapılandırılmış uzak konum " "ile kullanılabilir" @@ -6898,8 +6915,27 @@ msgstr "ne systemd zamanlayıcıları ne de crontab kullanılabiliyor" msgid "%s scheduler is not available" msgstr "%s planlayıcısı kullanılamıyor" -msgid "another process is scheduling background maintenance" -msgstr "başka bir işlem arka plan bakımı zamanını planlıyor" +#, c-format +msgid "" +"unable to create '%s.lock': %s.\n" +"\n" +"Another scheduled git-maintenance(1) process seems to be running in this\n" +"repository. Please make sure no other maintenance processes are running and\n" +"then try again. If it still fails, a git-maintenance(1) process may have\n" +"crashed in this repository earlier: remove the file manually to continue." +msgstr "" +"'%s.lock' oluşturulamıyor: %s.\n" +"\n" +"Bu depoda başka bir planlı git-maintenance(1) süreci çalışıyor gibi\n" +"görünüyor. Lütfen başka bir bakım sürecinin çalışmıyor olduğundan emin\n" +"olun ve yeniden deneyin. Eğer hâlâ başarısız oluyorsa bir git-" +"maintenance(1)\n" +"süreci bu depo içinde daha önceden çakılmış olabilir: Sürdürmek için " +"dosyayı\n" +"elle kaldırın." + +msgid "cannot acquire lock for scheduled background maintenance" +msgstr "planlı arka plan bakımı için kilit alınamıyor" msgid "git maintenance start [--scheduler=]" msgstr "git maintenance start [--scheduler=]" @@ -7472,8 +7508,22 @@ msgid_plural "chain length = %d: %lu objects" msgstr[0] "zincir uzunluğu = %d: %lu nesne" msgstr[1] "zincir uzunluğu = %d: %lu nesne" +msgid "could not start pack-objects to repack local links" +msgstr "yerel bağlantıları yeniden paketleme için pack-objects başlatılamadı" + +msgid "failed to feed local object to pack-objects" +msgstr "yerel nesne pack-objects'e beslenemedi" + +msgid "index-pack: Expecting full hex object ID lines only from pack-objects." +msgstr "" +"index-pack: Onaltılı tam nesne kimliği satırları yalnızca pack-objects'ten " +"bekleniyor." + +msgid "could not finish pack-objects to repack local links" +msgstr "yerel bağlantıları yeniden paketleme için pack-objects bitirilemedi" + msgid "Cannot come back to cwd" -msgstr "Şu anki çalışma dizinine geri gelinemiyor" +msgstr "Geçerli çalışma dizinine geri gelinemiyor" #, c-format msgid "bad %s" @@ -7483,6 +7533,9 @@ msgstr "hatalı %s" msgid "unknown hash algorithm '%s'" msgstr "bilinmeyen sağlama algoritması '%s'" +msgid "--promisor cannot be used with a pack name" +msgstr "--promisor bir paket adıyla kullanılamaz" + msgid "--stdin requires a git repository" msgstr "--stdin bir git dizini gerektirir" @@ -8826,11 +8879,11 @@ msgstr "git notes [--ref ] [list []]" msgid "" "git notes [--ref ] add [-f] [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" msgstr "" -"git notes [--ref ] add [-f] [--allow-empty] [--[no-]separator|--" -"separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"git notes [--ref ] add [-f] [--allow-empty] [--[no-]separator|--" +"separator=] [--[no-]stripspace] [-m | -F | (-c " +"| -C) ] [] [-e]" msgid "git notes [--ref ] copy [-f] " msgstr "git notes [--ref ] copy [-f] " @@ -8838,11 +8891,11 @@ msgstr "git notes [--ref ] copy [-f] " msgid "" "git notes [--ref ] append [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" msgstr "" -"git notes [--ref ] append [--allow-empty] [--[no-]separator|--" -"separator=] [--[no-]stripspace] [-m | -F | (-" -"c | -C) ] []" +"git notes [--ref ] append [--allow-empty] [--[no-]separator|--" +"separator=] [--[no-]stripspace] [-m | -F | (-c " +"| -C) ] [] [-e]" msgid "git notes [--ref ] edit [--allow-empty] []" msgstr "git notes [--ref ] edit [--allow-empty] []" @@ -8960,6 +9013,9 @@ msgstr "not içeriği bir dosyada" msgid "reuse and edit specified note object" msgstr "belirtilen not nesnesini düzenle ve yeniden kullan" +msgid "edit note message in editor" +msgstr "not iletisini düzenleyicide aç" + msgid "reuse specified note object" msgstr "belirtilen not nesnesini yeniden kullan" @@ -9456,6 +9512,9 @@ msgstr "eksik nesneler için işlem" msgid "do not pack objects in promisor packfiles" msgstr "nesneleri vaatçi paket dosyalarıyla paketleme" +msgid "implies --missing=allow-any" +msgstr "--missing=allow-any ima eder" + msgid "respect islands during delta compression" msgstr "delta sıkıştırması sırasında adalara uy" @@ -11057,6 +11116,31 @@ msgid_plural " Local refs configured for 'git push'%s:" msgstr[0] " 'git push'%s için yapılandırılan yerel başvuru:" msgstr[1] " 'git push'%s için yapılandırılan yerel başvurular:" +#, c-format +msgid "'%s/HEAD' is unchanged and points to '%s'\n" +msgstr "'%s/HEAD' değiştirilmedi ve '%s' konumuna işaret ediyor\n" + +#, c-format +msgid "'%s/HEAD' has changed from '%s' and now points to '%s'\n" +msgstr "'%s/HEAD', '%s' konumundan '%s' konumuna değiştirildi\n" + +#, c-format +msgid "'%s/HEAD' is now created and points to '%s'\n" +msgstr "'%s/HEAD' şimdi oluşturuldu ve '%s' konumuna işaret ediyor\n" + +#, c-format +msgid "'%s/HEAD' was detached at '%s' and now points to '%s'\n" +msgstr "" +"'%s/HEAD', '%s' konumunda ayrıldı ve artık '%s' konumuna işaret ediyor\n" + +#, c-format +msgid "" +"'%s/HEAD' used to point to '%s' (which is not a remote branch), but now " +"points to '%s'\n" +msgstr "" +"'%s/HEAD', uzak dal olmayan '%s' konumuna işaret ediyordu; ancak şimdi '%s' " +"konumuna işaret ediyor\n" + msgid "set refs/remotes//HEAD according to remote" msgstr "refs/remotes//HEAD'i uzak konuma göre ayarla" @@ -11078,7 +11162,7 @@ msgid "Not a valid ref: %s" msgstr "Geçerli bir başvuru değil: %s" #, c-format -msgid "Could not setup %s" +msgid "Could not set up %s" msgstr "%s ayarlanamadı" #, c-format @@ -13779,6 +13863,9 @@ msgstr "izleme kipini ayarla (bkz: git-branch(1))" msgid "try to match the new branch name with a remote-tracking branch" msgstr "yeni dalın adını bir uzak izleme dalıyla eşleştirmeyi dene" +msgid "use relative paths for worktrees" +msgstr "çalışma ağaçları için göreceli yollar kullan" + #, c-format msgid "options '%s', '%s', and '%s' cannot be used together" msgstr "'%s', '%s' ve '%s' seçenekleri birlikte kullanılamaz" @@ -14050,6 +14137,25 @@ msgstr "'%s' oluşturulamıyor" msgid "index-pack died" msgstr "index-pack sonlandı" +#, c-format +msgid "directory '%s' is present in index, but not sparse" +msgstr "'%s' dizini indekste var; ancak aralıklı değil" + +msgid "corrupted cache-tree has entries not present in index" +msgstr "hasarlı cache-tree'de indekste olmayan girdiler var" + +#, c-format +msgid "%s with flags 0x%x should not be in cache-tree" +msgstr "%s, 0x%x bayraklı olarak cache-tree'de olmamalı" + +#, c-format +msgid "bad subtree '%.*s'" +msgstr "hatalı alt ağaç '%.*s'" + +#, c-format +msgid "cache-tree for path %.*s does not match. Expected %s got %s" +msgstr "%.*s yolu için olan cache-tree eşleşmiyor. %s bekleniyordu, %s alındı" + msgid "terminating chunk id appears earlier than expected" msgstr "iri parça numarası sonlandırması beklenenden önce ortaya çıkıyor" @@ -14829,8 +14935,8 @@ msgid "" "attempting to write a commit-graph, but 'commitGraph.changedPathsVersion' " "(%d) is not supported" msgstr "" -"bir commit-graph yazılmaya çalışılıyor; ancak 'commitGraph." -"changedPathsVersion' (%d) desteklenmiyor" +"bir commit-graph yazılmaya çalışılıyor; ancak " +"'commitGraph.changedPathsVersion' (%d) desteklenmiyor" msgid "too many commits to write graph" msgstr "grafik yazımı için pek fazla işleme" @@ -14909,7 +15015,7 @@ msgid "" "to convert the grafts into replace refs.\n" "\n" "Turn this message off by running\n" -"\"git config advice.graftFileDeprecated false\"" +"\"git config set advice.graftFileDeprecated false\"" msgstr "" "/info/grafts desteği artık kullanılmamalı\n" "ve ileriki bir Git sürümünde kaldırılacak.\n" @@ -14917,7 +15023,7 @@ msgstr "" "Aşıları değiştirme başvurularına dönüştürmek için\n" "lütfen \"git replace --convert-graft-file\" kullanın.\n" "\n" -"\"git config advice.graftFileDeprecated false\"\n" +"\"git config set advice.graftFileDeprecated false\"\n" "kullanarak bu iletiyi kapatabilirsiniz" #, c-format @@ -15176,8 +15282,8 @@ msgid "" "remote URLs cannot be configured in file directly or indirectly included by " "includeIf.hasconfig:remote.*.url" msgstr "" -"uzak URL'ler dosya içinde doğrudan veya başka türlü includeIf.hasconfig:" -"remote.*.url kullanarak yapılandırılamaz" +"uzak URL'ler dosya içinde doğrudan veya başka türlü " +"includeIf.hasconfig:remote.*.url kullanarak yapılandırılamaz" #, c-format msgid "invalid config format: %s" @@ -15733,6 +15839,19 @@ msgstr "url'nin şeması yok: %s" msgid "credential url cannot be parsed: %s" msgstr "yetki url'si ayrıştırılamıyor: %s" +#, c-format +msgid "invalid timeout '%s', expecting a non-negative integer" +msgstr "geçersiz zaman aşımı '%s', negatif olmayan bir tamsayı bekleniyor" + +#, c-format +msgid "invalid init-timeout '%s', expecting a non-negative integer" +msgstr "" +"geçersiz ilklendirme zaman aşımı '%s', negatif olmayan bir tamsayı bekleniyor" + +#, c-format +msgid "invalid max-connections '%s', expecting an integer" +msgstr "geçersiz en çok bağlantı '%s', bir tamsayı bekleniyor" + msgid "in the future" msgstr "gelecekte" @@ -16439,6 +16558,20 @@ msgstr "hatalı git ad alanı yolu \"%s\"" msgid "too many args to run %s" msgstr "%s çalıştırmak için pek fazla argüman" +#, c-format +msgid "" +"You are attempting to fetch %s, which is in the commit graph file but not in " +"the object database.\n" +"This is probably due to repo corruption.\n" +"If you are attempting to repair this repo corruption by refetching the " +"missing object, use 'git fetch --refetch' with the missing object." +msgstr "" +"İşleme grafiğinde bulunan; ancak nesne veritabanında bulunmayan %s ögesini " +"getirmeyi deniyorsunuz.\n" +"Bu, büyük olasılıkla depo hasarından dolayı oluyor.\n" +"Bu depo hasarını eksik nesneyi yeniden getirerek onarmayı düşünüyorsanız " +"eksik nesneyle birlikte 'git fetch --refetch' kullanmayı deneyin." + msgid "git fetch-pack: expected shallow list" msgstr "git fetch-pack: sığ bir liste bekleniyordu" @@ -17024,10 +17157,10 @@ msgstr[1] "" #, c-format msgid "" "The '%s' hook was ignored because it's not set as executable.\n" -"You can disable this warning with `git config advice.ignoredHook false`." +"You can disable this warning with `git config set advice.ignoredHook false`." msgstr "" "'%s' kancası yok sayıldı; çünkü bir yürütülebilir olarak ayarlanmamış.\n" -"Bu uyarıyı 'git config advice.ignoredHook false' ile kapatabilirsiniz." +"Bu uyarıyı 'git config set advice.ignoredHook false' ile kapatabilirsiniz." msgid "not a git repository" msgstr "bir git deposu değil" @@ -17043,15 +17176,9 @@ msgstr "http.postBuffer için negatif değer; %d olarak varsayılıyor" msgid "Delegation control is not supported with cURL < 7.22.0" msgstr "Delegasyon denetimi cURL < 7.22.0 tarafından desteklenmiyor" -msgid "Public key pinning not supported with cURL < 7.39.0" -msgstr "Ortak anahtar iğnelemesi cURL < 7.39.0 tarafından desteklenmiyor" - msgid "Unknown value for http.proactiveauth" msgstr "http.proactiveauth için bilinmeyen değer" -msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0" -msgstr "CURLSSLOPT_NO_REVOKE cURL < 7.44.0 tarafından desteklenmiyor" - #, c-format msgid "Unsupported SSL backend '%s'. Supported SSL backends:" msgstr "Desteklenmeyen SSL arka ucu '%s'. Desteklenen SSL arka uçları:" @@ -17237,6 +17364,10 @@ msgstr "alıntılanmış CRLF algılandı" msgid "unable to format message: %s" msgstr "ileti biçimlendirilemiyor: %s" +#, c-format +msgid "invalid marker-size '%s', expecting an integer" +msgstr "geçersiz imleyici boyutu '%s', bir tamsayı bekleniyor" + #, c-format msgid "Failed to merge submodule %s (not checked out)" msgstr "%s altmodülü birleştirilemedi (çıkış yapılmadı)" @@ -18339,7 +18470,7 @@ msgid "" "\n" "where \"$br\" is somehow empty and a 40-hex ref is created. Please\n" "examine these refs and maybe delete them. Turn this message off by\n" -"running \"git config advice.objectNameWarning false\"" +"running \"git config set advice.objectNameWarning false\"" msgstr "" "Git normalde hiçbir zaman 40 onaltılı karakterlerle biten bir başvuru\n" "oluşturmaz; çünkü 40 onaltılı bir başvuru, onu belirlediğiniz zaman yok\n" @@ -18350,7 +18481,7 @@ msgstr "" "komutunda \"$br\" bir şekilde boş kalmış ve 40 onaltılı bir başvuru\n" "oluşturulmuş. Lütfen bu başvuruları inceleyin ve gerekirse silin. Bu " "iletiyi\n" -"kapatmak için \"git config advice.objectNameWarning\" yapın" +"kapatmak için \"git config set advice.objectNameWarning\" yapın" #, c-format msgid "log for '%.*s' only goes back to %s" @@ -18511,13 +18642,6 @@ msgstr "çoklu paket biteşlemi gereken ters indeksi içermiyor" msgid "could not open pack %s" msgstr "%s paketi açılamadı" -msgid "could not determine MIDX preferred pack" -msgstr "MIDX yeğlenen paketi algılanamadı" - -#, c-format -msgid "preferred pack (%s) is invalid" -msgstr "yeğlenen paket (%s) geçersiz" - msgid "corrupt bitmap lookup table: triplet position out of index" msgstr "hasarlı biteşlem arama tablosu: üçlü konum indeks dışında" @@ -19343,8 +19467,8 @@ msgid "" msgstr "" "Bu iletiden kaçınmak için, bir işlemeyi kaldırırken açıkça \"drop\" " "kullanın.\n" -"Uyarıların düzeyini değiştirmek için 'git config rebase." -"missingCommitsCheck'\n" +"Uyarıların düzeyini değiştirmek için 'git config " +"rebase.missingCommitsCheck'\n" "kullanın. Kullanılabilir davranışlar: ignore, warn, error.\n" "\n" @@ -19626,17 +19750,26 @@ msgstr "" msgid "log for %s is empty" msgstr "%s için olan günlük boş" -msgid "refusing to force and skip creation of reflog" -msgstr "başvuru günlüğünün oluşturulma/atlanma zorlanması reddediliyor" - #, c-format -msgid "refusing to update ref with bad name '%s'" -msgstr "hatalı ada iye '%s' başvurusunu güncelleme reddediliyor" +msgid "refusing to update reflog for pseudoref '%s'" +msgstr "" +"'%s' yalancı başvurusu için olan başvuru günlüğünü güncelleme reddediliyor" #, c-format msgid "refusing to update pseudoref '%s'" msgstr "'%s' yalancı başvurusunun güncellenmesi reddediliyor" +#, c-format +msgid "refusing to update reflog with bad name '%s'" +msgstr "hatalı adlı '%s' başvuru günlüğünü güncelleme reddediliyor" + +#, c-format +msgid "refusing to update ref with bad name '%s'" +msgstr "hatalı ada iye '%s' başvurusunu güncelleme reddediliyor" + +msgid "refusing to force and skip creation of reflog" +msgstr "başvuru günlüğünün oluşturulma/atlanma zorlanması reddediliyor" + #, c-format msgid "update_ref failed for ref '%s': %s" msgstr "'%s' başvurusu için update_ref başarısız oldu: %s" @@ -19686,6 +19819,10 @@ msgstr "" "'%s' başvurusu kilitlenemiyor: '%s' hedefiyle bir sembolik başvuru " "bekleniyordu; ancak bu normal bir başvuru" +#, c-format +msgid "cannot read ref file '%s'" +msgstr "başvuru dosyası '%s' yazılamıyor" + #, c-format msgid "cannot open directory %s" msgstr "%s dizini açılamıyor" @@ -19893,6 +20030,10 @@ msgstr "birden fazla receivepack verildi, birincisi kullanılıyor" msgid "more than one uploadpack given, using the first" msgstr "birden fazla uploadpack verildi, birincisi kullanılıyor" +#, c-format +msgid "unrecognized followRemoteHEAD value '%s' ignored" +msgstr "tanımlanamayan followRemoteHEAD değeri '%s' yok sayıldı" + #, c-format msgid "unrecognized value transfer.credentialsInUrl: '%s'" msgstr "tanımlanamayan değer transfer.credentialsInUrl: '%s'" @@ -21814,6 +21955,9 @@ msgstr "%s işlemesi ulaşılabilir olarak imlenmedi" msgid "too many commits marked reachable" msgstr "pek fazla işleme ulaşılabilir olarak imlenmiş" +msgid "could not determine MIDX preferred pack" +msgstr "MIDX yeğlenen paketi algılanamadı" + msgid "test-tool serve-v2 []" msgstr "test-tool serve-v2 []" @@ -22462,6 +22606,9 @@ msgstr ".git dosyası bozuk" msgid ".git file incorrect" msgstr ".git dosyası doğru değil" +msgid ".git file absolute/relative path mismatch" +msgstr ".git dosyası mutlak/göreceli yolu uyumsuzluğu" + msgid "not a valid path" msgstr "geçerli bir yol değil" @@ -22477,6 +22624,9 @@ msgstr "depo konumu bulunamıyor: .git dosyası bozuk" msgid "gitdir unreadable" msgstr "okunamayan gitdir" +msgid "gitdir absolute/relative path mismatch" +msgstr "gitdir mutlak/göreceli yolu uyumsuzluğu" + msgid "gitdir incorrect" msgstr "doğru olmayan gitdir" @@ -22511,6 +22661,13 @@ msgstr "%s, '%s' içinde ayarı kaldırılamıyor" msgid "failed to set extensions.worktreeConfig setting" msgstr "extensions.worktreeConfig yapılandırması ayarlanamadı" +msgid "unable to upgrade repository format to support relative worktrees" +msgstr "" +"depo biçimi göreceli çalışma ağaçlarını desteklemesi için yükseltilemiyor" + +msgid "unable to set extensions.relativeWorktrees setting" +msgstr "extensions.relativeWorktrees yapılandırması ayarlanamadı" + #, c-format msgid "could not setenv '%s'" msgstr "setenv '%s' yapılamadı" -- cgit v1.2.3 From d062ccf4c3af1e5153ed5064d4d05b05e0fdd4d5 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 1 Jan 2025 09:20:53 -0800 Subject: A bit more post Git 2.48-rc1 Signed-off-by: Junio C Hamano --- Documentation/RelNotes/2.48.0.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/RelNotes/2.48.0.txt b/Documentation/RelNotes/2.48.0.txt index f9fc8c1086..d62c62dc17 100644 --- a/Documentation/RelNotes/2.48.0.txt +++ b/Documentation/RelNotes/2.48.0.txt @@ -165,6 +165,10 @@ Performance, Internal Implementation, Development Support etc. info on gitk and git-gui maintainer. + * CI jobs that run threaded programs under LSan has been giving false + positives from time to time, which has been worked around. + + Fixes since v2.47 ----------------- @@ -310,6 +314,12 @@ Fixes since v2.47 to avoid race condition even when multiple packs are involved. (merge 62b3ec8a3f tb/bitmap-fix-pack-reuse later to maint). + * An earlier "csum-file checksum does not have to be computed with + sha1dc" topic had a few code paths that had initialized an + implementation of a hash function to be used by an unmatching hash + by mistake, which have been corrected. + (merge 599a63409b ps/weak-sha1-for-tail-sum-fix later to maint). + * Other code cleanup, docfix, build fix, etc. (merge 77af53f56f aa/t7300-modernize later to maint). (merge dcd590a39d bf/t-readme-mention-reftable later to maint). -- cgit v1.2.3 From fc89d14c639faec779956b4e3cd873c07bd4327b Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 1 Jan 2025 14:13:01 -0800 Subject: Revert barrier-based LSan threading race workaround The extra "barrier" approach was too much code whose sole purpose was to work around a race that is not even ours (i.e. in LSan's teardown code). In preparation for queuing a solution taking a much-less-invasive approach, let's revert them. --- Makefile | 7 ------- builtin/grep.c | 8 -------- builtin/index-pack.c | 6 ------ ci/lib.sh | 1 - thread-utils.h | 17 ----------------- 5 files changed, 39 deletions(-) diff --git a/Makefile b/Makefile index 2c6dad8a75..97e8385b66 100644 --- a/Makefile +++ b/Makefile @@ -141,10 +141,6 @@ include shared.mak # # Define NO_PTHREADS if you do not have or do not want to use Pthreads. # -# Define THREAD_BARRIER_PTHREAD if your system has pthread_barrier_t. Barrier -# support is optional and is only helpful when building with SANITIZE=leak, as -# it is used to eliminate some races in the leak-checker. -# # Define NO_PREAD if you have a problem with pread() system call (e.g. # cygwin1.dll before v1.5.22). # @@ -2083,9 +2079,6 @@ ifdef NO_PTHREADS else BASIC_CFLAGS += $(PTHREAD_CFLAGS) EXTLIBS += $(PTHREAD_LIBS) - ifdef THREAD_BARRIER_PTHREAD - BASIC_CFLAGS += -DTHREAD_BARRIER_PTHREAD - endif endif ifdef HAVE_PATHS_H diff --git a/builtin/grep.c b/builtin/grep.c index 61b2c27490..d00ee76f24 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -101,9 +101,6 @@ static pthread_cond_t cond_write; /* Signalled when we are finished with everything. */ static pthread_cond_t cond_result; -/* Synchronize the start of all threads */ -static maybe_thread_barrier_t start_barrier; - static int skip_first_line; static void add_work(struct grep_opt *opt, struct grep_source *gs) @@ -201,8 +198,6 @@ static void *run(void *arg) int hit = 0; struct grep_opt *opt = arg; - maybe_thread_barrier_wait(&start_barrier); - while (1) { struct work_item *w = get_work(); if (!w) @@ -234,7 +229,6 @@ static void start_threads(struct grep_opt *opt) pthread_cond_init(&cond_add, NULL); pthread_cond_init(&cond_write, NULL); pthread_cond_init(&cond_result, NULL); - maybe_thread_barrier_init(&start_barrier, NULL, num_threads + 1); grep_use_locks = 1; enable_obj_read_lock(); @@ -254,7 +248,6 @@ static void start_threads(struct grep_opt *opt) die(_("grep: failed to create thread: %s"), strerror(err)); } - maybe_thread_barrier_wait(&start_barrier); } static int wait_all(void) @@ -291,7 +284,6 @@ static int wait_all(void) pthread_cond_destroy(&cond_add); pthread_cond_destroy(&cond_write); pthread_cond_destroy(&cond_result); - maybe_thread_barrier_destroy(&start_barrier); grep_use_locks = 0; disable_obj_read_lock(); diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 27b120f26c..0b62b2589f 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -185,8 +185,6 @@ static pthread_mutex_t deepest_delta_mutex; static pthread_key_t key; -static maybe_thread_barrier_t start_barrier; - static inline void lock_mutex(pthread_mutex_t *mutex) { if (threads_active) @@ -211,7 +209,6 @@ static void init_thread(void) if (show_stat) pthread_mutex_init(&deepest_delta_mutex, NULL); pthread_key_create(&key, NULL); - maybe_thread_barrier_init(&start_barrier, NULL, nr_threads); CALLOC_ARRAY(thread_data, nr_threads); for (i = 0; i < nr_threads; i++) { thread_data[i].pack_fd = xopen(curr_pack, O_RDONLY); @@ -234,7 +231,6 @@ static void cleanup_thread(void) for (i = 0; i < nr_threads; i++) close(thread_data[i].pack_fd); pthread_key_delete(key); - maybe_thread_barrier_destroy(&start_barrier); free(thread_data); } @@ -1104,8 +1100,6 @@ static int compare_ref_delta_entry(const void *a, const void *b) static void *threaded_second_pass(void *data) { - if (threads_active) - maybe_thread_barrier_wait(&start_barrier); if (data) set_thread_data(data); for (;;) { diff --git a/ci/lib.sh b/ci/lib.sh index 6a1267fbcb..8885ee3c3f 100755 --- a/ci/lib.sh +++ b/ci/lib.sh @@ -385,7 +385,6 @@ linux-musl) ;; linux-leaks|linux-reftable-leaks) export SANITIZE=leak - export THREAD_BARRIER_PTHREAD=1 ;; linux-asan-ubsan) export SANITIZE=address,undefined diff --git a/thread-utils.h b/thread-utils.h index 3df5be9916..4961487ed9 100644 --- a/thread-utils.h +++ b/thread-utils.h @@ -53,22 +53,5 @@ int dummy_pthread_init(void *); int online_cpus(void); int init_recursive_mutex(pthread_mutex_t*); -#ifdef THREAD_BARRIER_PTHREAD -#define maybe_thread_barrier_t pthread_barrier_t -#define maybe_thread_barrier_init pthread_barrier_init -#define maybe_thread_barrier_wait pthread_barrier_wait -#define maybe_thread_barrier_destroy pthread_barrier_destroy -#else -#define maybe_thread_barrier_t int -static inline int maybe_thread_barrier_init(maybe_thread_barrier_t *b UNUSED, - void *attr UNUSED, - unsigned nr UNUSED) -{ - errno = ENOSYS; - return -1; -} -#define maybe_thread_barrier_wait(barrier) -#define maybe_thread_barrier_destroy(barrier) -#endif #endif /* THREAD_COMPAT_H */ -- cgit v1.2.3 From 5fa0c4dd296d3731bbbd1977d7bf9c50d8c4b7c1 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 1 Jan 2025 15:14:44 -0500 Subject: test-lib: rely on logs to detect leaks When we run with sanitizers, we set abort_on_error=1 so that the tests themselves can detect problems directly (when the buggy program exits with SIGABRT). This has one blind spot, though: we don't always check the exit codes for all programs (e.g., helpers like upload-pack invoked behind the scenes). For ASan and UBSan this is mostly fine; they exit as soon as they see an error, so the unexpected abort of the program causes the test to fail anyway. But for LSan, the program runs to completion, since we can only check for leaks at the end. And in that case we could miss leak reports. And thus we started checking LSan logs in faececa53f (test-lib: have the "check" mode for SANITIZE=leak consider leak logs, 2022-07-28). Originally the logs were optional, but logs are generated (and checked) always as of 8c1d6691bc (test-lib: GIT_TEST_SANITIZE_LEAK_LOG enabled by default, 2024-07-11). And we even check them for each test snippet, as of cf1464331b (test-lib: check for leak logs after every test, 2024-09-24). So now aborting on error is superfluous for LSan! We can get everything we need by checking the logs. And checking the logs is actually preferable, since it gives us more control over silencing false positives (something we do not yet do, but will soon). So let's tell LSan to just exit normally, even if it finds leaks. We can do so with exitcode=0, which also suppresses the abort_on_error flag. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/test-lib.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 96f2dfb69d..dd2ba6e6cc 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -80,6 +80,7 @@ prepend_var ASAN_OPTIONS : detect_leaks=0 export ASAN_OPTIONS prepend_var LSAN_OPTIONS : $GIT_SAN_OPTIONS +prepend_var LSAN_OPTIONS : exitcode=0 prepend_var LSAN_OPTIONS : fast_unwind_on_malloc=0 export LSAN_OPTIONS -- cgit v1.2.3 From 373a4326961c504ad6365fc1e4a9082e387499c7 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 1 Jan 2025 15:17:21 -0500 Subject: test-lib: simplify leak-log checking We have a function to count the number of leaks found (actually, it is the number of processes which produced a log file). Once upon a time we cared about seeing if this number increased between runs. But we simplified that away in 95c679ad86 (test-lib: stop showing old leak logs, 2024-09-24), and now we only care if it returns any results or not. In preparation for refactoring it further, let's drop the counting function entirely, and roll it into the "is it empty" check. The outcome should be the same, but we'll be free to return a boolean "did we find anything" without worrying about somebody adding a new call to the counting function. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/test-lib.sh | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/t/test-lib.sh b/t/test-lib.sh index dd2ba6e6cc..23eb26bfbe 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -340,17 +340,6 @@ case "$TRASH_DIRECTORY" in *) TRASH_DIRECTORY="$TEST_OUTPUT_DIRECTORY/$TRASH_DIRECTORY" ;; esac -# Utility functions using $TEST_RESULTS_* variables -nr_san_dir_leaks_ () { - # stderr piped to /dev/null because the directory may have - # been "rmdir"'d already. - find "$TEST_RESULTS_SAN_DIR" \ - -type f \ - -name "$TEST_RESULTS_SAN_FILE_PFX.*" 2>/dev/null | - xargs grep -lv "Unable to get registers from thread" | - wc -l -} - # If --stress was passed, run this test repeatedly in several parallel loops. if test "$GIT_TEST_STRESS_STARTED" = "done" then @@ -1181,8 +1170,14 @@ test_atexit_handler () { } check_test_results_san_file_empty_ () { - test -z "$TEST_RESULTS_SAN_FILE" || - test "$(nr_san_dir_leaks_)" = 0 + test -z "$TEST_RESULTS_SAN_FILE" && return 0 + + # stderr piped to /dev/null because the directory may have + # been "rmdir"'d already. + ! find "$TEST_RESULTS_SAN_DIR" \ + -type f \ + -name "$TEST_RESULTS_SAN_FILE_PFX.*" 2>/dev/null | + xargs grep -qv "Unable to get registers from thread" } check_test_results_san_file_ () { -- cgit v1.2.3 From 6fb8cb3d685382089a2e34ba35a30e898d63ab26 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 1 Jan 2025 15:18:28 -0500 Subject: test-lib: check leak logs for presence of DEDUP_TOKEN When we check the leak logs, our original strategy was to check for any non-empty log file produced by LSan. We later amended that to ignore noisy lines in 370ef7e40d (test-lib: ignore uninteresting LSan output, 2023-08-28). This makes it hard to ignore noise which is more than a single line; we'd have to actually parse the file to determine the meaning of each line. But there's an easy line-oriented solution. Because we always pass the dedup_token_length option, the output will contain a DEDUP_TOKEN line for each leak that has been found. So if we invert our strategy to stop ignoring useless lines and only look for useful ones, we can just count the number of DEDUP_TOKEN lines. If it's non-zero, then we found at least one leak (it would even give us a count of unique leaks, but we really only care if it is non-zero). This should yield the same outcome, but will help us build more false positive detection on top. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/test-lib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/test-lib.sh b/t/test-lib.sh index 23eb26bfbe..c9487d0805 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -1177,7 +1177,7 @@ check_test_results_san_file_empty_ () { ! find "$TEST_RESULTS_SAN_DIR" \ -type f \ -name "$TEST_RESULTS_SAN_FILE_PFX.*" 2>/dev/null | - xargs grep -qv "Unable to get registers from thread" + xargs grep -q ^DEDUP_TOKEN } check_test_results_san_file_ () { -- cgit v1.2.3 From b119a687d411864433aed92017c144d311b53a4c Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 1 Jan 2025 15:21:24 -0500 Subject: test-lib: ignore leaks in the sanitizer's thread code Our CI jobs sometimes see false positive leaks like this: ================================================================= ==3904583==ERROR: LeakSanitizer: detected memory leaks Direct leak of 32 byte(s) in 1 object(s) allocated from: #0 0x7fa790d01986 in __interceptor_realloc ../../../../src/libsanitizer/lsan/lsan_interceptors.cpp:98 #1 0x7fa790add769 in __pthread_getattr_np nptl/pthread_getattr_np.c:180 #2 0x7fa790d117c5 in __sanitizer::GetThreadStackTopAndBottom(bool, unsigned long*, unsigned long*) ../../../../src/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp:150 #3 0x7fa790d11957 in __sanitizer::GetThreadStackAndTls(bool, unsigned long*, unsigned long*, unsigned long*, unsigned long*) ../../../../src/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp:598 #4 0x7fa790d03fe8 in __lsan::ThreadStart(unsigned int, unsigned long long, __sanitizer::ThreadType) ../../../../src/libsanitizer/lsan/lsan_posix.cpp:51 #5 0x7fa790d013fd in __lsan_thread_start_func ../../../../src/libsanitizer/lsan/lsan_interceptors.cpp:440 #6 0x7fa790adc3eb in start_thread nptl/pthread_create.c:444 #7 0x7fa790b5ca5b in clone3 ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81 This is not a leak in our code, but appears to be a race between one thread calling exit() while another one is in LSan's stack setup code. You can reproduce it easily by running t0003 or t5309 with --stress (these trigger it because of the threading in git-grep and index-pack respectively). This may be a bug in LSan, but regardless of whether it is eventually fixed, it is useful to work around it so that we stop seeing these false positives. We can recognize it by the mention of the sanitizer functions in the DEDUP_TOKEN line. With this patch, the scripts mentioned above should run with --stress indefinitely. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/test-lib.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/t/test-lib.sh b/t/test-lib.sh index c9487d0805..d1f62adbf8 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -1177,7 +1177,8 @@ check_test_results_san_file_empty_ () { ! find "$TEST_RESULTS_SAN_DIR" \ -type f \ -name "$TEST_RESULTS_SAN_FILE_PFX.*" 2>/dev/null | - xargs grep -q ^DEDUP_TOKEN + xargs grep ^DEDUP_TOKEN | + grep -qv sanitizer::GetThreadStackTopAndBottom } check_test_results_san_file_ () { -- cgit v1.2.3 From 38d7016891e37a789d389eddc7cd3dc9b76370b4 Mon Sep 17 00:00:00 2001 From: Martin Ågren Date: Fri, 3 Jan 2025 12:33:30 +0100 Subject: git.txt: fix heading line of tildes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The two-line heading added in 8525e92886 (Document HOME environment variable, 2024-12-09) uses too many tilde characters, so the heading isn't detected as such. Both AsciiDoc and Asciidoctor end up misrendering this in different ways. Use the correct number of tilde characters to fix this. Signed-off-by: Martin Ågren Signed-off-by: Junio C Hamano --- Documentation/git.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/git.txt b/Documentation/git.txt index 47509c9e1a..e9f55620e8 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -478,7 +478,7 @@ their values the same way as Boolean valued configuration variables, e.g. Here are the variables: System -~~~~~~~~~~~~~~~~~~ +~~~~~~ `HOME`:: Specifies the path to the user's home directory. On Windows, if unset, Git will set a process environment variable equal to: -- cgit v1.2.3 From b67a603f6360051f174a00f8d10dc088dc7093be Mon Sep 17 00:00:00 2001 From: Martin Ågren Date: Fri, 3 Jan 2025 12:33:31 +0100 Subject: gitcli.txt: typeset pathnames as monospace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 1bc1e94091 (doc: option value may be separate for valid reasons, 2024-11-25) added a paragraph discussing tilde-expansion of, e.g., ~/directory/file. The tilde character has a special meaning to asciidoc tools. In this particular case, AsciiDoc matches up the two tildes in "e.g. ~/directory/file or ~u/d/f" and sets the text between them using subscript. In the manpage, where subscripting is not possible, this renders as "e.g. /directory/file oru/d/f". These paths are literal values, which our coding guidelines want typeset as verbatim using backticks. Do that. One effect of this is indeed that the asciidoc tools stop interpreting tilde and other special characters. Signed-off-by: Martin Ågren Signed-off-by: Junio C Hamano --- Documentation/gitcli.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt index bd62cbd043..fcd86d2eee 100644 --- a/Documentation/gitcli.txt +++ b/Documentation/gitcli.txt @@ -91,7 +91,7 @@ scripting Git: written in the 'stuck' form. * Despite the above suggestion, when Arg is a path relative to the - home directory of a user, e.g. ~/directory/file or ~u/d/f, you + home directory of a user, e.g. `~/directory/file` or `~u/d/f`, you may want to use the separate form, e.g. `git foo --file ~/mine`, not `git foo --file=~/mine`. The shell will expand `~/` in the former to your home directory, but most shells keep the tilde in -- cgit v1.2.3 From b1dbc87686db1da0d9ee8ece2e6faa78354f2970 Mon Sep 17 00:00:00 2001 From: Ralf Thielow Date: Fri, 20 Dec 2024 17:45:01 +0100 Subject: l10n: Update German translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Matthias Rüster Signed-off-by: Ralf Thielow --- po/de.po | 304 +++++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 230 insertions(+), 74 deletions(-) diff --git a/po/de.po b/po/de.po index 06055e7611..addd5919bd 100644 --- a/po/de.po +++ b/po/de.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: Git\n" "Report-Msgid-Bugs-To: Git Mailing List \n" -"POT-Creation-Date: 2024-10-05 16:17+0200\n" -"PO-Revision-Date: 2024-10-05 16:18+0200\n" +"POT-Creation-Date: 2024-12-20 17:44+0100\n" +"PO-Revision-Date: 2024-12-27 16:43+0100\n" "Last-Translator: Ralf Thielow \n" "Language-Team: German\n" "Language: de\n" @@ -366,11 +366,11 @@ msgstr "" #, c-format msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? " msgstr "" -"Modusänderung vom Index und Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? " +"Modusänderung im Index und Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? " #, c-format msgid "Discard deletion from index and worktree [y,n,q,a,d%s,?]? " -msgstr "Löschung vom Index und Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? " +msgstr "Löschung im Index und Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? " #, c-format msgid "Discard addition from index and worktree [y,n,q,a,d%s,?]? " @@ -379,7 +379,7 @@ msgstr "Ergänzung im Index und Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? " #, c-format msgid "Discard this hunk from index and worktree [y,n,q,a,d%s,?]? " msgstr "" -"Diesen Patch-Block vom Index und Arbeitsverzeichnis verwerfen [y,n,q,a," +"Diesen Patch-Block im Index und Arbeitsverzeichnis verwerfen [y,n,q,a," "d%s,?]? " msgid "" @@ -650,10 +650,10 @@ msgstr "Nur Binärdateien geändert." #, c-format msgid "" "\n" -"Disable this message with \"git config advice.%s false\"" +"Disable this message with \"git config set advice.%s false\"" msgstr "" "\n" -"Deaktivieren Sie diese Nachricht mit \"git config advice.%s false\"" +"Deaktivieren Sie diese Meldung mit \"git config set advice.%s false\"" #, c-format msgid "%shint:%s%.*s%s\n" @@ -3962,10 +3962,9 @@ msgstr "neuer ungeborener Branch" msgid "update ignored files (default)" msgstr "ignorierte Dateien aktualisieren (Standard)" -msgid "do not check if another worktree is holding the given ref" +msgid "do not check if another worktree is using this branch" msgstr "" -"Prüfung, ob die Referenz bereits in einem anderen Arbeitsverzeichnis " -"ausgecheckt wurde, deaktivieren" +"nicht prüfen, ob ein anderes Arbeitsverzeichnis diesen Branch verwendet" msgid "checkout our version for unmerged files" msgstr "unsere Variante für nicht zusammengeführte Dateien auschecken" @@ -4272,13 +4271,11 @@ msgstr "" "Zeit\n" "erstellen" -msgid "revision" -msgstr "Commit" +msgid "ref" +msgstr "Referenz" -msgid "deepen history of shallow clone, excluding rev" -msgstr "" -"die Historie eines Klons mit unvollständiger Historie (shallow) mittels\n" -"Ausschluss eines Commits vertiefen" +msgid "deepen history of shallow clone, excluding ref" +msgstr "Historie eines flachen Klons vertiefen, Referenz exkludiert" msgid "clone only one branch, HEAD or --branch" msgstr "nur einen Branch klonen, HEAD oder --branch" @@ -5232,8 +5229,7 @@ msgid "" "regexp] [--value=] [--fixed-value] [--default=] " msgstr "" "git config get [] [] [--includes] [--all] [--" -"regexp] [--value=] [--fixed-value] [--default=] " -"" +"regexp] [--value=] [--fixed-value] [--default=] " msgid "" "git config set [] [--type=] [--all] [--value=] [--" @@ -5244,10 +5240,10 @@ msgstr "" msgid "" "git config unset [] [--all] [--value=] [--fixed-value] " -" " +"" msgstr "" "git config unset [] [--all] [--value=] [--fixed-value] " -" " +"" msgid "git config rename-section [] " msgstr "git config rename-section [] " @@ -5695,12 +5691,8 @@ msgid "traversed %lu commits\n" msgstr "%lu Commits durchlaufen\n" #, c-format -msgid "" -"more than %i tags found; listed %i most recent\n" -"gave up search at %s\n" -msgstr "" -"mehr als %i Tags gefunden; führe die ersten %i auf\n" -"Suche bei %s aufgegeben\n" +msgid "found %i tags; gave up search at %s\n" +msgstr "%i Tags gefunden; Suche bei %s aufgegeben\n" #, c-format msgid "describe %s\n" @@ -6142,6 +6134,20 @@ msgstr "%s ist kein gültiges Objekt" msgid "the object %s does not exist" msgstr "das Objekt %s ist nicht vorhanden" +#, c-format +msgid "" +"Run 'git remote set-head %s %s' to follow the change, or set\n" +"'remote.%s.followRemoteHEAD' configuration option to a different value\n" +"if you do not want to see this message. Specifically running\n" +"'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n" +"until the remote changes HEAD to something else." +msgstr "" +"Führen Sie 'git remote set-head %s %s' aus, um der Änderung zu folgen,\n" +"oder setzen Sie die Konfiguration 'remote.%s.followRemoteHEAD' auf einen\n" +"anderen Wert, wenn Sie diese Meldung nicht sehen wollen. Konkret wird diese\n" +"Warnung mit 'git config set remote.%s.followRemoteHEAD %s' deaktiviert\n" +"bis die Gegenstelle HEAD in etwas anderes ändert." + msgid "multiple branches detected, incompatible with --set-upstream" msgstr "mehrere Branches erkannt, inkompatibel mit --set-upstream" @@ -6287,6 +6293,9 @@ msgstr "Refmap" msgid "specify fetch refmap" msgstr "Refmap für 'fetch' angeben" +msgid "revision" +msgstr "Commit" + msgid "report that we have only objects reachable from this object" msgstr "" "ausgeben, dass wir nur Objekte haben, die von diesem Objekt aus erreichbar " @@ -7030,8 +7039,26 @@ msgstr "weder Timer von systemd, noch crontab ist verfügbar" msgid "%s scheduler is not available" msgstr "%s Scheduler ist nicht verfügbar" -msgid "another process is scheduling background maintenance" -msgstr "ein anderer Prozess plant die Hintergrundwartung" +#, c-format +msgid "" +"unable to create '%s.lock': %s.\n" +"\n" +"Another scheduled git-maintenance(1) process seems to be running in this\n" +"repository. Please make sure no other maintenance processes are running and\n" +"then try again. If it still fails, a git-maintenance(1) process may have\n" +"crashed in this repository earlier: remove the file manually to continue." +msgstr "" +"Konnte '%s.lock' nicht erstellen: %s.\n" +"\n" +"Ein weiterer geplanter git-maintenance(1)-Prozess scheint in diesem\n" +"Repository zu laufen. Bitte stellen Sie sicher, dass keine anderen\n" +"Wartungsprozesse laufen und versuchen Sie es dann erneut. Wenn es\n" +"immer noch fehlschlägt, ist möglicherweise ein git-maintenance(1)-Prozess\n" +"in diesem Repository abgestürzt: Entfernen Sie die Datei manuell, um\n" +"fortzufahren." + +msgid "cannot acquire lock for scheduled background maintenance" +msgstr "kann keine Sperre für die geplante Hintergrundwartung erhalten" msgid "git maintenance start [--scheduler=]" msgstr "git maintenance start [--scheduler=]" @@ -7612,6 +7639,22 @@ msgid_plural "chain length = %d: %lu objects" msgstr[0] "Länge der Objekt-Liste = %d: %lu Objekt" msgstr[1] "Länge der Objekt-Liste = %d: %lu Objekte" +msgid "could not start pack-objects to repack local links" +msgstr "" +"konnte pack-objects nicht starten, um lokale Verknüpfungen neu zu packen" + +msgid "failed to feed local object to pack-objects" +msgstr "lokales Objekt konnte nicht an pack-objects übergeben werden" + +msgid "index-pack: Expecting full hex object ID lines only from pack-objects." +msgstr "" +"index-pack: Erwarte vollständige Hex-Objekt-ID-Zeilen nur von pack-objects." + +msgid "could not finish pack-objects to repack local links" +msgstr "" +"konnte pack-objects nicht vollständig ausführen, um lokale Verknüpfungen neu " +"zu packen" + msgid "Cannot come back to cwd" msgstr "Kann nicht zurück zum Arbeitsverzeichnis wechseln" @@ -7623,6 +7666,9 @@ msgstr "%s ist ungültig" msgid "unknown hash algorithm '%s'" msgstr "unbekannter Hash-Algorithmus '%s'" +msgid "--promisor cannot be used with a pack name" +msgstr "--promisor kann nicht mit einem Paketnamen verwendet werden" + msgid "--stdin requires a git repository" msgstr "--stdin erfordert ein Git-Repository" @@ -9003,11 +9049,11 @@ msgstr "git notes [--ref ] [list []]" msgid "" "git notes [--ref ] add [-f] [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" msgstr "" "git notes [--ref ] add [-f] [--allow-empty] [--" "[no-]separator|--separator=] [--[no-]stripspace] [-m " -" | -F | (-c | -C) ] []" +" | -F | (-c | -C) ] [] [-e]" msgid "git notes [--ref ] copy [-f] " msgstr "" @@ -9016,11 +9062,11 @@ msgstr "" msgid "" "git notes [--ref ] append [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" msgstr "" "git notes [--ref ] append [--allow-empty] [--" "[no-]separator|--separator=] [--[no-]stripspace] [-m " -" | -F | (-c | -C) ] []" +" | -F | (-c | -C) ] [] [-e]" msgid "git notes [--ref ] edit [--allow-empty] []" msgstr "git notes [--ref ] edit [--allow-empty] []" @@ -9142,6 +9188,9 @@ msgstr "Notizinhalte in einer Datei" msgid "reuse and edit specified note object" msgstr "Wiederverwendung und Bearbeitung des angegebenen Notiz-Objektes" +msgid "edit note message in editor" +msgstr "Notizmeldung im Editor bearbeiten" + msgid "reuse specified note object" msgstr "Wiederverwendung des angegebenen Notiz-Objektes" @@ -9655,6 +9704,9 @@ msgstr "" "keine Objekte aus Packdateien von partiell geklonten Remote-Repositories " "packen" +msgid "implies --missing=allow-any" +msgstr "impliziert --missing=allow-any" + msgid "respect islands during delta compression" msgstr "Delta-Islands bei Delta-Kompression beachten" @@ -11317,6 +11369,30 @@ msgid_plural " Local refs configured for 'git push'%s:" msgstr[0] " Lokale Referenz konfiguriert für 'git push'%s:" msgstr[1] " Lokale Referenzen konfiguriert für 'git push'%s:" +#, c-format +msgid "'%s/HEAD' is unchanged and points to '%s'\n" +msgstr "'%s/HEAD' ist unverändert und zeigt auf '%s'\n" + +#, c-format +msgid "'%s/HEAD' has changed from '%s' and now points to '%s'\n" +msgstr "'%s/HEAD' hat sich von '%s' geändert und zeigt jetzt auf '%s'\n" + +#, c-format +msgid "'%s/HEAD' is now created and points to '%s'\n" +msgstr "'%s/HEAD' ist nun erstellt und zeigt auf '%s'\n" + +#, c-format +msgid "'%s/HEAD' was detached at '%s' and now points to '%s'\n" +msgstr "'%s/HEAD' war losgelöst bei '%s' und zeigt nun auf '%s'\n" + +#, c-format +msgid "" +"'%s/HEAD' used to point to '%s' (which is not a remote branch), but now " +"points to '%s'\n" +msgstr "" +"'%s/HEAD' zeigte vorher auf '%s' (was kein Remote-Branch ist), zeigt jetzt " +"aber auf '%s'\n" + msgid "set refs/remotes//HEAD according to remote" msgstr "setzt refs/remotes//HEAD gemäß dem Remote-Repository" @@ -11340,7 +11416,7 @@ msgid "Not a valid ref: %s" msgstr "keine gültige Referenz: %s" #, c-format -msgid "Could not setup %s" +msgid "Could not set up %s" msgstr "Konnte %s nicht einrichten" #, c-format @@ -14142,6 +14218,9 @@ msgstr "" "versuchen, eine Übereinstimmung des Branchnamens mit einem\n" "Remote-Tracking-Branch herzustellen" +msgid "use relative paths for worktrees" +msgstr "relative Pfade für Arbeitsverzeichnisse verwenden" + #, c-format msgid "options '%s', '%s', and '%s' cannot be used together" msgstr "" @@ -14426,6 +14505,28 @@ msgstr "kann '%s' nicht erstellen" msgid "index-pack died" msgstr "Erstellung der Paketindexdatei abgebrochen" +#, c-format +msgid "directory '%s' is present in index, but not sparse" +msgstr "Verzeichnis '%s' ist im Index vorhanden, aber nicht partiell" + +msgid "corrupted cache-tree has entries not present in index" +msgstr "" +"das beschädigte Cache-Verzeichnis enthält Einträge, die nicht im Index " +"enthalten sind" + +#, c-format +msgid "%s with flags 0x%x should not be in cache-tree" +msgstr "%s mit Flags 0x%x sollte nicht im Cache-Verzeichnis sein" + +#, c-format +msgid "bad subtree '%.*s'" +msgstr "ungültiges Unterverzeichnis '%.*s'" + +#, c-format +msgid "cache-tree for path %.*s does not match. Expected %s got %s" +msgstr "" +"Cache-Verzeichnis für Pfad %.*s stimmt nicht überein. Erwartete %s bekam %s" + msgid "terminating chunk id appears earlier than expected" msgstr "abschließende Chunk-ID erscheint eher als erwartet" @@ -15322,17 +15423,18 @@ msgid "" "to convert the grafts into replace refs.\n" "\n" "Turn this message off by running\n" -"\"git config advice.graftFileDeprecated false\"" +"\"git config set advice.graftFileDeprecated false\"" msgstr "" "Die Unterstützung für /info/grafts ist veraltet\n" -"und wird in zukünftigen Git Versionen entfernt.\n" +"und wird in einer zukünftigen Git-Version entfernt.\n" "\n" -"Bitte benutzen Sie \"git replace --convert-graft-file\"\n" -"zum Konvertieren der künstlichen Vorgänger (\"grafts\")\n" -"in ersetzende Referenzen.<\n" +"Bitte verwenden Sie \"git replace --convert-graft-file\"\n" +"um die künstlichen Vorgänger (\"graft\") in ersetzende Referenzen\n" +"zu konvertieren.\n" "\n" -"Sie können diese Meldung unterdrücken, indem Sie\n" -"\"git config advice.graftFileDeprecated false\" ausführen." +"Deaktivieren Sie diese Meldung, indem Sie\n" +"\"git config set advice.graftFileDeprecated false\"\n" +"ausführen." #, c-format msgid "commit %s exists in commit-graph but not in the object database" @@ -16166,6 +16268,18 @@ msgstr "URL hat kein Schema: %s" msgid "credential url cannot be parsed: %s" msgstr "URL mit Zugangsdaten konnte nicht geparst werden: %s" +#, c-format +msgid "invalid timeout '%s', expecting a non-negative integer" +msgstr "ungültiger timeout '%s', nicht-negative ganze Zahl erwartet" + +#, c-format +msgid "invalid init-timeout '%s', expecting a non-negative integer" +msgstr "ungültiger init-timeout '%s', nicht-negative ganze Zahl erwartet" + +#, c-format +msgid "invalid max-connections '%s', expecting an integer" +msgstr "ungültiges max-connections '%s', ganze Zahl erwartet" + msgid "in the future" msgstr "in der Zukunft" @@ -16896,6 +17010,22 @@ msgstr "ungültiger Git-Namespace-Pfad \"%s\"" msgid "too many args to run %s" msgstr "zu viele Argumente angegeben, um %s auszuführen" +#, c-format +msgid "" +"You are attempting to fetch %s, which is in the commit graph file but not in " +"the object database.\n" +"This is probably due to repo corruption.\n" +"If you are attempting to repair this repo corruption by refetching the " +"missing object, use 'git fetch --refetch' with the missing object." +msgstr "" +"Sie versuchen %s zu holen, welches sich in der Commit-Graph-Datei, aber " +"nicht in der Objektdatenbank befindet.\n" +"Dies ist wahrscheinlich auf eine Beschädigung des Repositories " +"zurückzuführen.\n" +"Wenn Sie versuchen, die Beschädigung des Repositories zu beheben, indem Sie " +"das fehlende Objekt erneut holen,\n" +"verwenden Sie 'git fetch --refetch' mit dem fehlenden Objekt." + msgid "git fetch-pack: expected shallow list" msgstr "git fetch-pack: erwartete shallow-Liste" @@ -17329,8 +17459,8 @@ msgid "" "given pattern contains NULL byte (via -f ). This is only supported " "with -P under PCRE v2" msgstr "" -"Angegebenes Muster enthält NULL Byte (über -f ). Das wird nur mit -" -"Punter PCRE v2 unterstützt." +"Angegebenes Muster enthält NULL Byte (über -f ). Das wird nur mit -P " +"unter PCRE v2 unterstützt." #, c-format msgid "'%s': unable to read %s" @@ -17483,10 +17613,11 @@ msgstr[1] "" #, c-format msgid "" "The '%s' hook was ignored because it's not set as executable.\n" -"You can disable this warning with `git config advice.ignoredHook false`." +"You can disable this warning with `git config set advice.ignoredHook false`." msgstr "" -"Der '%s' Hook wurde ignoriert, weil er nicht als ausführbar markiert ist.\n" -"Sie können diese Warnung mit `git config advice.ignoredHook false` " +"Der '%s'-Hook wurde ignoriert, weil er nicht als ausführbar eingestellt " +"ist.\n" +"Sie können diese Warnung mit `git config set advice.ignoredHook false` " "deaktivieren." msgid "not a git repository" @@ -17503,17 +17634,9 @@ msgstr "negativer Wert für http.postBuffer; benutze Standardwert %d" msgid "Delegation control is not supported with cURL < 7.22.0" msgstr "Kontrolle über Delegation wird mit cURL < 7.22.0 nicht unterstützt" -msgid "Public key pinning not supported with cURL < 7.39.0" -msgstr "" -"Das Anheften des öffentlichen Schlüssels wird mit cURL < 7.39.0 nicht " -"unterstützt" - msgid "Unknown value for http.proactiveauth" msgstr "Unbekannter Wert für http.proactiveauth" -msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0" -msgstr "CURLSSLOPT_NO_REVOKE wird mit cURL < 7.44.0 nicht unterstützt." - #, c-format msgid "Unsupported SSL backend '%s'. Supported SSL backends:" msgstr "Nicht unterstütztes SSL-Backend '%s'. Unterstützte SSL-Backends:" @@ -17700,6 +17823,10 @@ msgstr "angeführtes CRLF entdeckt" msgid "unable to format message: %s" msgstr "Meldung kann nicht formatiert werden: %s" +#, c-format +msgid "invalid marker-size '%s', expecting an integer" +msgstr "ungültige marker-size '%s', ganze Zahl erwartet" + #, c-format msgid "Failed to merge submodule %s (not checked out)" msgstr "Fehler beim Merge von Submodul %s (nicht ausgecheckt)." @@ -18837,19 +18964,18 @@ msgid "" "\n" "where \"$br\" is somehow empty and a 40-hex ref is created. Please\n" "examine these refs and maybe delete them. Turn this message off by\n" -"running \"git config advice.objectNameWarning false\"" +"running \"git config set advice.objectNameWarning false\"" msgstr "" -"Git erzeugt normalerweise keine Referenzen die mit\n" -"40 Hex-Zeichen enden, da diese ignoriert werden wenn\n" -"Sie diese angeben. Diese Referenzen könnten aus Versehen\n" -"erzeugt worden sein. Zum Beispiel,\n" +"Git erstellt normalerweise nie eine Referenz, die mit 40-Hex-Zeichen endet,\n" +"weil sie ignoriert wird, wenn Sie nur 40-Hex-Zeichen angeben. Diese\n" +"Referenzen können aus Versehen erstellt werden. Zum Beispiel,\n" "\n" " git switch -c $br $(git rev-parse ...)\n" "\n" -"wobei \"$br\" leer ist und eine 40-Hex-Referenz erzeugt\n" -"wurde. Bitte prüfen Sie diese Referenzen und löschen\n" -"Sie sie gegebenenfalls. Unterdrücken Sie diese Meldung\n" -"indem Sie \"git config advice.objectNameWarning false\"\n" +"wobei \"$br\" irgendwie leer ist und eine 40-Hex-Referenz erstellt wird.\n" +"Bitte überprüfen Sie die Referenzen und löschen Sie diese gegebenenfalls.\n" +"Schalten Sie diese Meldung aus, indem Sie\n" +"\"git config set advice.objectNameWarning false\"\n" "ausführen." #, c-format @@ -19010,13 +19136,6 @@ msgstr "Multi-Pack-Bitmap fehlt erforderlicher Reverse-Index" msgid "could not open pack %s" msgstr "konnte Paket '%s' nicht öffnen" -msgid "could not determine MIDX preferred pack" -msgstr "konnte das von MIDX bevorzugte Paket nicht ermitteln" - -#, c-format -msgid "preferred pack (%s) is invalid" -msgstr "bevorzugtes Paket (%s) ist ungültig" - msgid "corrupt bitmap lookup table: triplet position out of index" msgstr "Bitmap-Lookup-Tabelle beschädigt: Triplet-Position außerhalb des Index" @@ -20151,17 +20270,25 @@ msgstr "Log für Referenz %s unerwartet bei %s beendet." msgid "log for %s is empty" msgstr "Log für %s ist leer." -msgid "refusing to force and skip creation of reflog" -msgstr "Erzwingen der Aktion verweigert; überspringe Erstellung des Reflogs" - #, c-format -msgid "refusing to update ref with bad name '%s'" -msgstr "verweigere Aktualisierung einer Referenz mit fehlerhaftem Namen '%s'" +msgid "refusing to update reflog for pseudoref '%s'" +msgstr "Aktualisierung des Reflogs für Pseudoreferenz '%s' verweigert" #, c-format msgid "refusing to update pseudoref '%s'" msgstr "Aktualisierung von Pseudoreferenz '%s' verweigert" +#, c-format +msgid "refusing to update reflog with bad name '%s'" +msgstr "Aktualisierung des Reflogs mit fehlerhaftem Namen '%s' verweigert" + +#, c-format +msgid "refusing to update ref with bad name '%s'" +msgstr "verweigere Aktualisierung einer Referenz mit fehlerhaftem Namen '%s'" + +msgid "refusing to force and skip creation of reflog" +msgstr "Erzwingen der Aktion verweigert; überspringe Erstellung des Reflogs" + #, c-format msgid "update_ref failed for ref '%s': %s" msgstr "update_ref für Referenz '%s' fehlgeschlagen: %s" @@ -20215,6 +20342,10 @@ msgstr "" "kann Referenz '%s' nicht sperren: erwartete symbolische Referenz mit Ziel " "'%s': ist aber eine reguläre Referenz" +#, c-format +msgid "cannot read ref file '%s'" +msgstr "kann Ref-Datei '%s' nicht lesen" + #, c-format msgid "cannot open directory %s" msgstr "Verzeichnis %s kann nicht geöffnet werden" @@ -20430,6 +20561,10 @@ msgstr "Mehr als ein receivepack-Befehl angegeben, benutze den ersten." msgid "more than one uploadpack given, using the first" msgstr "Mehr als ein uploadpack-Befehl angegeben, benutze den ersten." +#, c-format +msgid "unrecognized followRemoteHEAD value '%s' ignored" +msgstr "nicht erkannter followRemoteHEAD-Wert '%s' ignoriert" + #, c-format msgid "unrecognized value transfer.credentialsInUrl: '%s'" msgstr "unbekannter Wert transfer.credentialsInUrl: '%s'" @@ -22391,6 +22526,9 @@ msgstr "Commit %s ist nicht als erreichbar gekennzeichnet." msgid "too many commits marked reachable" msgstr "Zu viele Commits als erreichbar gekennzeichnet." +msgid "could not determine MIDX preferred pack" +msgstr "konnte das von MIDX bevorzugte Paket nicht ermitteln" + msgid "test-tool serve-v2 []" msgstr "test-tool serve-v2 []" @@ -23061,6 +23199,9 @@ msgstr ".git-Datei kaputt" msgid ".git file incorrect" msgstr ".git-Datei fehlerhaft" +msgid ".git file absolute/relative path mismatch" +msgstr "absoluter/relativer Pfad der .git-Datei stimmt nicht überein" + msgid "not a valid path" msgstr "kein gültiger Pfad" @@ -23077,6 +23218,9 @@ msgstr "Konnte Repository nicht finden; .git-Datei ist kaputt" msgid "gitdir unreadable" msgstr "gitdir nicht lesbar" +msgid "gitdir absolute/relative path mismatch" +msgstr "absolute/relative Pfadabweichung in gitdir" + msgid "gitdir incorrect" msgstr "gitdir fehlerhaft" @@ -23111,6 +23255,14 @@ msgstr "konnte %s nicht in '%s' aufheben" msgid "failed to set extensions.worktreeConfig setting" msgstr "Einstellung für extensions.worktreeConfig konnte nicht gesetzt werden" +msgid "unable to upgrade repository format to support relative worktrees" +msgstr "" +"Repository-Format konnte nicht aktualisiert werden, um relative " +"Arbeitsverzeichnisse zu unterstützen" + +msgid "unable to set extensions.relativeWorktrees setting" +msgstr "Einstellung extensions.relativeWorktrees kann nicht gesetzt werden" + #, c-format msgid "could not setenv '%s'" msgstr "konnte '%s' nicht setzen" @@ -24038,3 +24190,7 @@ msgstr "Lasse %s mit Backup-Suffix '%s' aus.\n" #, perl-format msgid "Do you really want to send %s? [y|N]: " msgstr "Wollen Sie %s wirklich versenden? [y|N]: " + +#, c-format +#~ msgid "preferred pack (%s) is invalid" +#~ msgstr "bevorzugtes Paket (%s) ist ungültig" -- cgit v1.2.3 From 866ea877036ce581e0d3c130f527631cd8b36bdf Mon Sep 17 00:00:00 2001 From: Matteo Bagnolini Date: Fri, 3 Jan 2025 14:00:35 +0100 Subject: t7110: replace `test -f` with `test_path_is_*` helpers `test -f` and `! test -f` do not provide clear error messages when they fail. To enhance debuggability, use `test_path_is_file` and `test_path_is_missing`, which instead provide more informative error messages. Note that `! test -f` checks if a path is not a file, while `test_path_is_missing` verifies that a path does not exist. In this specific case the tests are meant to check the absence of the path, making `test_path_is_missing` a valid replacement. Signed-off-by: Matteo Bagnolini Signed-off-by: Junio C Hamano --- t/t7110-reset-merge.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/t/t7110-reset-merge.sh b/t/t7110-reset-merge.sh index 61669a2d21..9a335071af 100755 --- a/t/t7110-reset-merge.sh +++ b/t/t7110-reset-merge.sh @@ -270,13 +270,13 @@ test_expect_success '--merge is ok with added/deleted merge' ' git reset --hard third && rm -f file2 && test_must_fail git merge branch3 && - ! test -f file2 && - test -f file3 && + test_path_is_missing file2 && + test_path_is_file file3 && git diff --exit-code file3 && git diff --exit-code branch3 file3 && git reset --merge HEAD && - ! test -f file3 && - ! test -f file2 && + test_path_is_missing file3 && + test_path_is_missing file2 && git diff --exit-code --cached ' @@ -284,8 +284,8 @@ test_expect_success '--keep fails with added/deleted merge' ' git reset --hard third && rm -f file2 && test_must_fail git merge branch3 && - ! test -f file2 && - test -f file3 && + test_path_is_missing file2 && + test_path_is_file file3 && git diff --exit-code file3 && git diff --exit-code branch3 file3 && test_must_fail git reset --keep HEAD 2>err.log && -- cgit v1.2.3 From a2df58fb15aa6319e1f4159d0218814245e48e35 Mon Sep 17 00:00:00 2001 From: Vũ Tiến Hưng Date: Sun, 5 Jan 2025 01:54:04 +0700 Subject: l10n: vi: Updated translation for 2.48 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Vũ Tiến Hưng --- po/vi.po | 336 +++++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 241 insertions(+), 95 deletions(-) diff --git a/po/vi.po b/po/vi.po index 00008b50f5..80a5f191a8 100644 --- a/po/vi.po +++ b/po/vi.po @@ -4,11 +4,11 @@ # https://raw.githubusercontent.com/git-l10n/git-po/pot/main/po/git.pot # --- # Copyright (C) 2012-2022, Translation Project, Vietnamese Team -# Copyright (C) 2024, Vũ Tiến Hưng +# Copyright (C) 2024-2025, Vũ Tiến Hưng # Nguyễn Thái Ngọc Duy , 2012. # Đoàn Trần Công Danh , 2020. # Trần Ngọc Quân , 2012-2022. -# Vũ Tiến Hưng , 2024. +# Vũ Tiến Hưng , 2024-2025. # --- # BẢNG THUẬT NGỮ / TERMINOLOGY # Updated: 2024-07-26, git 2.46 @@ -64,10 +64,10 @@ # +------------------------------------------------------------------+ msgid "" msgstr "" -"Project-Id-Version: git 2.47\n" +"Project-Id-Version: git 2.48\n" "Report-Msgid-Bugs-To: Git Mailing List \n" -"POT-Creation-Date: 2024-10-05 01:20+0000\n" -"PO-Revision-Date: 2024-10-05 16:48+0700\n" +"POT-Creation-Date: 2024-12-23 18:57+0000\n" +"PO-Revision-Date: 2025-01-05 01:20+0700\n" "Last-Translator: Vũ Tiến Hưng \n" "Language-Team: Vietnamese \n" "Language: vi\n" @@ -686,10 +686,10 @@ msgstr "Chỉ có các tập tin nhị phân thay đổi." #, c-format msgid "" "\n" -"Disable this message with \"git config advice.%s false\"" +"Disable this message with \"git config set advice.%s false\"" msgstr "" "\n" -"Tắt lời nhắn này bằng \"git config advice.%s false\"" +"Tắt lời nhắn này bằng \"git config set advice.%s false\"" #, c-format msgid "%shint:%s%.*s%s\n" @@ -1904,7 +1904,7 @@ msgid "update tracked files" msgstr "cập nhật các tập tin được theo dõi" msgid "renormalize EOL of tracked files (implies -u)" -msgstr "thường hóa lại EOL của các tập tin được theo dõi (ngụ ý -u)" +msgstr "thường hóa lại EOL của các tập tin được theo dõi (ngầm chỉ định -u)" msgid "record only the fact that the path will be added later" msgstr "chỉ ghi lại sự việc mà đường dẫn sẽ được thêm vào sau" @@ -2017,7 +2017,7 @@ msgstr "không hiểu cú pháp %s" #, c-format msgid "'%s' was deleted by the applypatch-msg hook" -msgstr "'%s' bị xóa bởi móc applypatch-msg" +msgstr "'%s' bị xóa bởi hook applypatch-msg" #, c-format msgid "Malformed input line: '%s'." @@ -3040,11 +3040,11 @@ msgid "HEAD not found below refs/heads!" msgstr "Không tìm thấy HEAD ở dưới refs/heads!" msgid "" -"branch with --recurse-submodules can only be used if submodule." -"propagateBranches is enabled" +"branch with --recurse-submodules can only be used if " +"submodule.propagateBranches is enabled" msgstr "" -"nhánh với --recurse-submodules chỉ có thể được sử dụng nếu submodule." -"propagateBranches được kích hoạt" +"nhánh với --recurse-submodules chỉ có thể được sử dụng nếu " +"submodule.propagateBranches được kích hoạt" msgid "--recurse-submodules can only be used to create branches" msgstr "--recurse-submodules chỉ có thể được sử dụng để tạo ra các nhánh" @@ -3125,7 +3125,7 @@ msgid "libc info: " msgstr "thông tin libc: " msgid "not run from a git repository - no hooks to show\n" -msgstr "không chạy từ một kho git - nên chẳng có móc nào để hiển thị cả\n" +msgstr "không chạy từ một kho git - nên chẳng có hook nào để hiển thị cả\n" msgid "" "git bugreport [(-o | --output-directory) ]\n" @@ -3200,7 +3200,7 @@ msgid "System Info" msgstr "Thông tin hệ thống" msgid "Enabled Hooks" -msgstr "Các Móc đã được bật" +msgstr "Các hook đã được bật" #, c-format msgid "unable to write to %s" @@ -3880,8 +3880,8 @@ msgstr "nhánh chưa sinh mới" msgid "update ignored files (default)" msgstr "cập nhật các tập tin bị bỏ qua (mặc định)" -msgid "do not check if another worktree is holding the given ref" -msgstr "không kiểm tra nếu cây làm việc khác đang giữ tham chiếu đã cho" +msgid "do not check if another worktree is using this branch" +msgstr "không kiểm tra nếu cây làm việc khác đang sử dụng nhánh này" msgid "checkout our version for unmerged files" msgstr "checkout phiên bản của ta cho các tập tin chưa được hòa trộn" @@ -4129,7 +4129,7 @@ msgid "create a bare repository" msgstr "tạo kho bare" msgid "create a mirror repository (implies --bare)" -msgstr "tạo kho bản sao (ngụ ý --bare)" +msgstr "tạo kho bản sao (ngầm chỉ định --bare)" msgid "to clone from a local repository" msgstr "để nhân bản từ kho nội bộ" @@ -4182,11 +4182,11 @@ msgstr "tạo bản sao không đầy đủ cho mức sâu đã cho" msgid "create a shallow clone since a specific time" msgstr "tạo bản sao không đầy đủ từ thời điểm đã cho" -msgid "revision" -msgstr "điểm xét duyệt" +msgid "ref" +msgstr "ref" -msgid "deepen history of shallow clone, excluding rev" -msgstr "làm sâu hơn lịch sử của bản sao shallow, bằng điểm xét duyệt loại trừ" +msgid "deepen history of shallow clone, excluding ref" +msgstr "làm sâu hơn lịch sử của bản sao shallow, loại trừ tham chiếu" msgid "clone only one branch, HEAD or --branch" msgstr "chỉ nhân bản một nhánh, HEAD hoặc --branch" @@ -5068,7 +5068,7 @@ msgid "commit only specified files" msgstr "chỉ chuyển giao các tập tin đã chỉ ra" msgid "bypass pre-commit and commit-msg hooks" -msgstr "vòng qua móc (hook) pre-commit và commit-msg" +msgstr "bỏ qua hook pre-commit và commit-msg" msgid "show what would be committed" msgstr "hiển thị xem cái gì có thể được chuyển giao" @@ -5077,7 +5077,7 @@ msgid "amend previous commit" msgstr "'tu bổ' (amend) lần commit trước" msgid "bypass post-rewrite hook" -msgstr "vòng qua móc (hook) post-rewrite" +msgstr "bỏ qua hook post-rewrite" msgid "ok to record an empty change" msgstr "ok để ghi lại một thay đổi trống rỗng" @@ -5143,10 +5143,10 @@ msgstr "" msgid "" "git config unset [] [--all] [--value=] [--fixed-value] " -" " +"" msgstr "" "git config unset [] [--all] [--value=] [--fixed-value] " -" " +"" msgid "git config rename-section [] " msgstr "git config rename-section [] " @@ -5579,12 +5579,8 @@ msgid "traversed %lu commits\n" msgstr "đã xuyên %lu qua lần chuyển giao\n" #, c-format -msgid "" -"more than %i tags found; listed %i most recent\n" -"gave up search at %s\n" -msgstr "" -"tìm thấy nhiều hơn %i thẻ; đã liệt kê %i cái gần\n" -"đây nhất bỏ đi tìm kiếm tại %s\n" +msgid "found %i tags; gave up search at %s\n" +msgstr "tìm thấy %i thẻ; từ bỏ tìm kiếm tại %s\n" #, c-format msgid "describe %s\n" @@ -6020,6 +6016,19 @@ msgstr "%s không phải là một đối tượng hợp lệ" msgid "the object %s does not exist" msgstr "đối tượng '%s' không tồn tại" +#, c-format +msgid "" +"Run 'git remote set-head %s %s' to follow the change, or set\n" +"'remote.%s.followRemoteHEAD' configuration option to a different value\n" +"if you do not want to see this message. Specifically running\n" +"'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n" +"until the remote changes HEAD to something else." +msgstr "" +"Chạy 'git remote set-head %s %s' để làm theo thay đổi, hoặc đặt tuỳ chọn\n" +"'remote.%s.followRemoteHEAD' sang giá trị khác nếu bạn không muốn thấy\n" +"thông báo này. Cụ thể, 'git config set remote.%s.followRemoteHEAD %s'\n" +"sẽ vô hiệu cảnh báo này tới khi máy chủ đổi HEAD về chỗ khác." + msgid "multiple branches detected, incompatible with --set-upstream" msgstr "phát hiện nhiều nhánh, không tương thích với --set-upstream" @@ -6157,6 +6166,9 @@ msgstr "refmap" msgid "specify fetch refmap" msgstr "chỉ ra refmap cần lấy về" +msgid "revision" +msgstr "điểm xét duyệt" + msgid "report that we have only objects reachable from this object" msgstr "báo rằng ta chỉ có các đối tượng tiếp cận được từ đối tượng này" @@ -6209,11 +6221,11 @@ msgid "protocol does not support --negotiate-only, exiting" msgstr "giao thức không hỗ trợ --negotiate-only, nên thoát" msgid "" -"--filter can only be used with the remote configured in extensions." -"partialclone" +"--filter can only be used with the remote configured in " +"extensions.partialclone" msgstr "" -"--filter chỉ có thể được dùng với máy chủ được cấu hình bằng extensions." -"partialclone" +"--filter chỉ có thể được dùng với máy chủ được cấu hình bằng " +"extensions.partialclone" msgid "--atomic can only be used when fetching from one remote" msgstr "--atomic chỉ có thể dùng khi lấy về từ một máy chủ" @@ -6882,8 +6894,24 @@ msgstr "hoặc là bộ lập lịch systemd hoặc là crontab không sẵn có msgid "%s scheduler is not available" msgstr "bộ lên lịch %s không sẵn có" -msgid "another process is scheduling background maintenance" -msgstr "một tiến trình khác được lập kế hoạch chạy nền để bảo trì" +#, c-format +msgid "" +"unable to create '%s.lock': %s.\n" +"\n" +"Another scheduled git-maintenance(1) process seems to be running in this\n" +"repository. Please make sure no other maintenance processes are running and\n" +"then try again. If it still fails, a git-maintenance(1) process may have\n" +"crashed in this repository earlier: remove the file manually to continue." +msgstr "" +"Không thể tạo '%s.lock': %s.\n" +"\n" +"Tiến trình git-maintenance(1) khác có lẽ đang chạy ở kho này. Vui lòng\n" +"chắc chắn rằng mọi tiến trình đã kết thúc và sau đó thử lại. Nếu vẫn lỗi,\n" +"một tiến trình git-maintenance(1) có lẽ đã crash ở kho này trước đó:\n" +"gõ bỏ tập tin thủ công để tiếp tục." + +msgid "cannot acquire lock for scheduled background maintenance" +msgstr "không thể lấy được lock để bảo trì nền theo kế hoạch" msgid "git maintenance start [--scheduler=]" msgstr "git maintenance start [--scheduler=]" @@ -7250,8 +7278,8 @@ msgid "" "git hook run [--ignore-missing] [--to-stdin=] [-- ]" msgstr "" -"git hook run [--ignore-missing] [--to-stdin=] [-- " -"]" +"git hook run [--ignore-missing] [--to-stdin=] [-- " +"]" msgid "silently ignore missing requested " msgstr "âm thầm bỏ qua các đã yêu cầu còn thiếu" @@ -7445,6 +7473,20 @@ msgid "chain length = %d: %lu object" msgid_plural "chain length = %d: %lu objects" msgstr[0] "chiều dài chuỗi = %d: %lu đối tượng" +msgid "could not start pack-objects to repack local links" +msgstr "không thể bắt đầu pack-objects để đóng gói lại các link cục bộ" + +msgid "failed to feed local object to pack-objects" +msgstr "gặp lỗi khi đưa local object cho pack-objects" + +msgid "index-pack: Expecting full hex object ID lines only from pack-objects." +msgstr "" +"index-pack: Đang chỉ cần các dòng ID đối tượng dạng hexa đầy đủ từ pack-" +"objects." + +msgid "could not finish pack-objects to repack local links" +msgstr "không thể hoàn tất pack-objects để đóng gói các link cục bộ" + msgid "Cannot come back to cwd" msgstr "Không thể quay lại thư mục hiện hành" @@ -7456,6 +7498,9 @@ msgstr "%s sai" msgid "unknown hash algorithm '%s'" msgstr "không hiểu thuật toán băm dữ liệu '%s'" +msgid "--promisor cannot be used with a pack name" +msgstr "không được dùng --promisor với tên pack" + msgid "--stdin requires a git repository" msgstr "--stdin cần một kho git" @@ -8101,7 +8146,8 @@ msgid "use full path names" msgstr "dùng tên đường dẫn đầy đủ" msgid "list entire tree; not just current directory (implies --full-name)" -msgstr "liệt kê cây mục tin; không chỉ thư mục hiện hành (ngụ ý --full-name)" +msgstr "" +"liệt kê cây mục tin; không chỉ thư mục hiện hành (ngầm chỉ định --full-name)" msgid "--format can't be combined with other format-altering options" msgstr "" @@ -8390,10 +8436,10 @@ msgid "continue the current in-progress merge" msgstr "tiếp tục quá trình hòa trộn hiện tại đang thực hiện" msgid "bypass pre-merge-commit and commit-msg hooks" -msgstr "vòng qua móc (hook) pre-merge-commit và commit-msg" +msgstr "bỏ qua hook pre-merge-commit và commit-msg" msgid "could not run stash." -msgstr "không thể chạy stash." +msgstr "không thể chạy tạm cất." msgid "stash failed" msgstr "lệnh tạm cất gặp lỗi" @@ -8815,11 +8861,11 @@ msgstr "git notes [--ref ] [list [<đối-tượng>]]" msgid "" "git notes [--ref ] add [-f] [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" msgstr "" "git notes [--ref ] add [-f] [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c | -C) <đối-tượng>] [<đối-tượng>]" +"tin> | (-c | -C) <đối-tượng>] [<đối-tượng>] [-e]" msgid "git notes [--ref ] copy [-f] " msgstr "git notes [--ref ] copy [-f] <đến-đối-tượng>" @@ -8827,11 +8873,11 @@ msgstr "git notes [--ref ] copy [-f] <đến- msgid "" "git notes [--ref ] append [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" msgstr "" "git notes [--ref ] append [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c | -C) <đối-tượng>] [<đối-tượng>]" +"tin> | (-c | -C) <đối-tượng>] [<đối-tượng>] [-e]" msgid "git notes [--ref ] edit [--allow-empty] []" msgstr "git notes [--ref ] edit [--allow-empty] [<đối-tượng>]" @@ -8950,6 +8996,9 @@ msgstr "nội dung ghi chú (note) nằm trong một tập tin" msgid "reuse and edit specified note object" msgstr "dùng lại nhưng có sửa chữa đối tượng note đã chỉ ra" +msgid "edit note message in editor" +msgstr "sửa lại chú thích trong trình soạn thảo" + msgid "reuse specified note object" msgstr "dùng lại đối tượng ghi chú (note) đã chỉ ra" @@ -8988,7 +9037,7 @@ msgid "read objects from stdin" msgstr "đọc các đối tượng từ stdin" msgid "load rewriting config for (implies --stdin)" -msgstr "tải cấu hình chép lại cho (ngụ ý --stdin)" +msgstr "tải cấu hình chép lại cho (ngầm chỉ định --stdin)" msgid "too few arguments" msgstr "quá ít đối số" @@ -9355,7 +9404,7 @@ msgid "limit pack window by memory in addition to object limit" msgstr "giới hạn cửa sổ đóng gói theo bộ nhớ cộng thêm với giới hạn đối tượng" msgid "maximum length of delta chain allowed in the resulting pack" -msgstr "độ dài tối đa của chuỗi móc xích 'delta' được phép trong gói kết quả" +msgstr "độ dài tối đa của chuỗi delta được phép trong gói kết quả" msgid "reuse existing deltas" msgstr "dùng lại các delta sẵn có" @@ -9448,8 +9497,11 @@ msgstr "xử lý cho thiếu đối tượng" msgid "do not pack objects in promisor packfiles" msgstr "không thể đóng gói các đối tượng trong các tập tin gói promisor" +msgid "implies --missing=allow-any" +msgstr "ngầm chỉ định --missing=allow-any" + msgid "respect islands during delta compression" -msgstr "tôn trọng island trong suốt quá trình nén 'delta'" +msgstr "tôn trọng island trong suốt quá trình nén delta" msgid "protocol" msgstr "giao thức" @@ -9584,7 +9636,7 @@ msgid "allow fast-forward" msgstr "cho phép chuyển-tiếp-nhanh" msgid "control use of pre-merge-commit and commit-msg hooks" -msgstr "điều khiển cách dùng các móc (hook) pre-merge-commit và commit-msg" +msgstr "điều khiển cách dùng các hook pre-merge-commit và commit-msg" msgid "automatically stash/stash pop before and after" msgstr "tự động stash/stash pop trước và sau" @@ -9785,8 +9837,8 @@ msgid "" msgstr "" "\n" "Để tránh tự động cấu hình nhánh thượng nguồn khi tên của chúng\n" -"không khớp với nhánh nội bộ, xem tùy chọn 'simple' của branch." -"autoSetupMerge\n" +"không khớp với nhánh nội bộ, xem tùy chọn 'simple' của " +"branch.autoSetupMerge\n" "trong 'git help config'.\n" #, c-format @@ -9994,7 +10046,7 @@ msgid "prune locally removed refs" msgstr "xén tỉa những tham chiếu bị gỡ bỏ" msgid "bypass pre-push hook" -msgstr "vòng qua móc tiền-đẩy (pre-push)" +msgstr "bỏ qua hook tiền-đẩy (pre-push)" msgid "push missing but relevant tags" msgstr "push phần bị thiếu nhưng các thẻ lại thích hợp" @@ -10289,10 +10341,10 @@ msgid "use the merge-base of upstream and branch as the current base" msgstr "sử dụng gốc hòa trộn của thượng nguồn và nhánh làm gốc hiện tại" msgid "allow pre-rebase hook to run" -msgstr "cho phép móc (hook) pre-rebase được chạy" +msgstr "cho phép hook pre-rebase được chạy" msgid "be quiet. implies --no-stat" -msgstr "im lặng. ngụ ý --no-stat" +msgstr "im lặng. ngầm chỉ định --no-stat" msgid "display a diffstat of what changed upstream" msgstr "hiển thị diffstat của những thay đổi thượng nguồn" @@ -10526,14 +10578,14 @@ msgid "Current branch %s is up to date.\n" msgstr "Nhánh hiện tại %s đã được cập nhật rồi.\n" msgid "HEAD is up to date, rebase forced." -msgstr "HEAD hiện đã được cập nhật rồi, bị ép buộc rebase." +msgstr "HEAD hiện đã được cập nhật rồi, ép buộc rebase." #, c-format msgid "Current branch %s is up to date, rebase forced.\n" -msgstr "Nhánh hiện tại %s đã được cập nhật rồi, lệnh rebase ép buộc.\n" +msgstr "Nhánh hiện tại %s đã được cập nhật rồi, ép buộc rebase.\n" msgid "The pre-rebase hook refused to rebase." -msgstr "Móc (hook) pre-rebase từ chối rebase." +msgstr "Hook pre-rebase từ chối rebase." #, c-format msgid "Changes to %s:\n" @@ -10546,7 +10598,7 @@ msgstr "Thay đổi từ %s thành %s:\n" #, c-format msgid "First, rewinding head to replay your work on top of it...\n" msgstr "" -"Trước tiên, di chuyển head để xem lại các công việc trên đỉnh của nó...\n" +"Trước tiên, di chuyển lại head để thực hiện lại các thay đổi trên nó...\n" msgid "Could not detach HEAD" msgstr "Không thể tách rời HEAD" @@ -11048,6 +11100,29 @@ msgid " Local ref configured for 'git push'%s:" msgid_plural " Local refs configured for 'git push'%s:" msgstr[0] " Những tham chiếu nội bộ được cấu hình cho lệnh 'git push'%s:" +#, c-format +msgid "'%s/HEAD' is unchanged and points to '%s'\n" +msgstr "'%s/HEAD' không đổi và trỏ đến '%s'\n" + +#, c-format +msgid "'%s/HEAD' has changed from '%s' and now points to '%s'\n" +msgstr "'%s/HEAD' đã đổi từ '%s' để trỏ đến '%s'\n" + +#, c-format +msgid "'%s/HEAD' is now created and points to '%s'\n" +msgstr "'%s/HEAD' đã tạo và trỏ đến '%s'\n" + +#, c-format +msgid "'%s/HEAD' was detached at '%s' and now points to '%s'\n" +msgstr "'%s/HEAD' đã tách ra ở '%s' và trỏ đến '%s'\n" + +#, c-format +msgid "" +"'%s/HEAD' used to point to '%s' (which is not a remote branch), but now " +"points to '%s'\n" +msgstr "" +"'%s/HEAD' từng trỏ đến '%s' (không phải nhánh máy chủ) và giờ trỏ đến '%s'\n" + msgid "set refs/remotes//HEAD according to remote" msgstr "đặt refs/remotes//HEAD cho phù hợp với máy chủ" @@ -11069,7 +11144,7 @@ msgid "Not a valid ref: %s" msgstr "Không phải là tham chiếu hợp lệ: %s" #, c-format -msgid "Could not setup %s" +msgid "Could not set up %s" msgstr "Không thể cài đặt %s" #, c-format @@ -12955,7 +13030,7 @@ msgid "don't print cloning progress" msgstr "đừng in tiến trình nhân bản" msgid "disallow cloning into non-empty directory, implies --init" -msgstr "không cho phép nhân bản vào thư mục trống, ngụ ý --init" +msgstr "không cho phép nhân bản vào thư mục trống, ngầm chỉ định --init" msgid "" "git submodule [--quiet] update [--init [--filter=]] [--remote] " @@ -13778,6 +13853,9 @@ msgstr "cài đặt chế độ theo dõi (xem git-branch(1))" msgid "try to match the new branch name with a remote-tracking branch" msgstr "có khớp tên tên nhánh mới với một nhánh theo dõi máy chủ" +msgid "use relative paths for worktrees" +msgstr "dùng đường dẫn tương đối cho thư mục làm việc" + #, c-format msgid "options '%s', '%s', and '%s' cannot be used together" msgstr "tùy chọn '%s', '%s' và '%s' không thể dùng cùng nhau" @@ -14049,6 +14127,25 @@ msgstr "không thể tạo '%s'" msgid "index-pack died" msgstr "index-pack đã chết" +#, c-format +msgid "directory '%s' is present in index, but not sparse" +msgstr "Thư mục '%s' có ở trong chỉ mục, mà không phải dạng sparse?" + +msgid "corrupted cache-tree has entries not present in index" +msgstr "cache-tree bị hỏng, chứa mục không có trong chỉ mục" + +#, c-format +msgid "%s with flags 0x%x should not be in cache-tree" +msgstr "%s với cờ 0x%x không nên có trong cache-tree" + +#, c-format +msgid "bad subtree '%.*s'" +msgstr "subtree sai '%.*s'" + +#, c-format +msgid "cache-tree for path %.*s does not match. Expected %s got %s" +msgstr "cache-tree cho đường dẫn %.*s không khớp. Cần %s nhưng có %s" + msgid "terminating chunk id appears earlier than expected" msgstr "id chunk kết thúc sớm hơn bình thường" @@ -14264,7 +14361,7 @@ msgid "Display help information about Git" msgstr "Hiển thị thông tin trợ giúp về Git" msgid "Run git hooks" -msgstr "Chạy các móc git" +msgstr "Chạy các hook git" msgid "Server side implementation of Git over HTTP" msgstr "Hỗ trợ phía máy chủ của Git qua HTTP" @@ -14930,7 +15027,7 @@ msgid "" "to convert the grafts into replace refs.\n" "\n" "Turn this message off by running\n" -"\"git config advice.graftFileDeprecated false\"" +"\"git config set advice.graftFileDeprecated false\"" msgstr "" "Hỗ trợ cho /info/grafts đã không còn\n" "và sẽ bị xóa bỏ ở phiên bản Git tương lai.\n" @@ -14939,7 +15036,7 @@ msgstr "" "để chuyển đổi các graft thành các tham chiếu thay thế.\n" "\n" "Tắt lời nhắn này bằng cách chạy\n" -"\"git config advice.graftFileDeprecated false\"" +"\"git config set advice.graftFileDeprecated false\"" #, c-format msgid "commit %s exists in commit-graph but not in the object database" @@ -15750,6 +15847,18 @@ msgstr "url không có lược đồ: %s" msgid "credential url cannot be parsed: %s" msgstr "không hiểu cú pháp giấy chứng thực url: %s" +#, c-format +msgid "invalid timeout '%s', expecting a non-negative integer" +msgstr "timeout không hợp lệ '%s', cần số nguyên không âm" + +#, c-format +msgid "invalid init-timeout '%s', expecting a non-negative integer" +msgstr "init-timeout không hợp lệ '%s', cần số nguyên không âm" + +#, c-format +msgid "invalid max-connections '%s', expecting an integer" +msgstr "max-connections không hợp lệ '%s', cần số nguyên" + msgid "in the future" msgstr "ở tương lai" @@ -16445,6 +16554,20 @@ msgstr "đường dẫn không gian tên git \"%s\" sai" msgid "too many args to run %s" msgstr "quá nhiều tham số để chạy %s" +#, c-format +msgid "" +"You are attempting to fetch %s, which is in the commit graph file but not in " +"the object database.\n" +"This is probably due to repo corruption.\n" +"If you are attempting to repair this repo corruption by refetching the " +"missing object, use 'git fetch --refetch' with the missing object." +msgstr "" +"Bạn đang muốn lấy về %s, nằm trong tập tin đồ-thị-chuyển-giao nhưng nằm " +"ngoài cơ sở dữ liệu đối tượng.\n" +"Nhiều khả năng kho chứa đã bị hỏng.\n" +"Nếu bạn đang cần sửa chữa lại kho chứa bằng cách lấy về đối tượng còn thiếu, " +"dùng 'git fetch --refetch' với đối tượng đó." + msgid "git fetch-pack: expected shallow list" msgstr "git fetch-pack: cần danh sách shallow" @@ -16878,8 +17001,8 @@ msgid "" "given pattern contains NULL byte (via -f ). This is only supported " "with -P under PCRE v2" msgstr "" -"mẫu đã cho có chứa NULL byte (qua -f ). Điều này chỉ được hỗ trợ với -" -"P dưới PCRE v2" +"mẫu đã cho có chứa NULL byte (qua -f ). Điều này chỉ được hỗ trợ với " +"-P dưới PCRE v2" #, c-format msgid "'%s': unable to read %s" @@ -17023,10 +17146,10 @@ msgstr[0] "" #, c-format msgid "" "The '%s' hook was ignored because it's not set as executable.\n" -"You can disable this warning with `git config advice.ignoredHook false`." +"You can disable this warning with `git config set advice.ignoredHook false`." msgstr "" -"Móc '%s' bị bỏ qua bởi vì nó không có cờ thực thi được.\n" -"Bạn có thể tắt cảnh báo này bằng 'git config advice.ignoredHook false'." +"Hook '%s' bị bỏ qua bởi vì nó không có cờ thực thi được.\n" +"Bạn có thể tắt cảnh báo này bằng 'git config set advice.ignoredHook false'." msgid "not a git repository" msgstr "không phải là kho git" @@ -17042,15 +17165,9 @@ msgstr "giá trị âm cho http.postBuffer; đặt thành mặc định là %d" msgid "Delegation control is not supported with cURL < 7.22.0" msgstr "Điều khiển giao quyền không được hỗ trợ với cURL < 7.22.0" -msgid "Public key pinning not supported with cURL < 7.39.0" -msgstr "Chốt khóa công không được hỗ trợ với cURL < 7.39.0" - msgid "Unknown value for http.proactiveauth" msgstr "không hiểu giá trị cho http.proactiveauth" -msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0" -msgstr "CURLSSLOPT_NO_REVOKE không được hỗ trợ với cURL < 7.44.0" - #, c-format msgid "Unsupported SSL backend '%s'. Supported SSL backends:" msgstr "" @@ -17204,7 +17321,7 @@ msgstr "" "Tiến trình git khác có lẽ đang chạy ở kho này, ví dụ\n" "một trình soạn thảo được mở bởi 'git commit'. Vui lòng chắc chắn\n" "rằng mọi tiến trình đã kết thúc và sau đó thử lại. Nếu vẫn lỗi,\n" -"một tiến trình git có lẽ đã crash khi thực hiện ở kho này trước đó:\n" +"một tiến trình git có lẽ đã crash ở kho này trước đó:\n" "gõ bỏ tập tin một cách thủ công để tiếp tục." #, c-format @@ -17236,9 +17353,13 @@ msgstr "phát hiện CRLF được trích dẫn" msgid "unable to format message: %s" msgstr "không thể định dạng thông điệp: %s" +#, c-format +msgid "invalid marker-size '%s', expecting an integer" +msgstr "marker-size không hợp lệ '%s', cần số nguyên" + #, c-format msgid "Failed to merge submodule %s (not checked out)" -msgstr "Gặp lỗi khi hòa trộn mô-đun-con %s (không checkout được)" +msgstr "Gặp lỗi khi hòa trộn mô-đun-con %s (không checkout)" #, c-format msgid "Failed to merge submodule %s (no merge base)" @@ -18335,7 +18456,7 @@ msgid "" "\n" "where \"$br\" is somehow empty and a 40-hex ref is created. Please\n" "examine these refs and maybe delete them. Turn this message off by\n" -"running \"git config advice.objectNameWarning false\"" +"running \"git config set advice.objectNameWarning false\"" msgstr "" "Git thường không bao giờ tạo tham chiếu kết thúc với 40 ký tự hex\n" "bởi vì nó sẽ bị bỏ qua khi bạn chỉ định 40 ký tự hex. Những tham chiếu\n" @@ -18344,8 +18465,8 @@ msgstr "" " git switch -c $br $(git rev-parse ...)\n" "\n" "với \"$br\" không hiểu lý do vì sao rỗng và tạo ra tham chiếu 40-hex.\n" -" Xin hãy kiểm tra những tham chiếu này và xóa chúng đi nếu cần. Tắt\n" -"lời nhắn này bằng cách chạy lệnh \"git config advice.objectNameWarning " +"Xin hãy kiểm tra những tham chiếu này và xóa chúng đi nếu cần. Tắt\n" +"lời nhắn này bằng cách chạy lệnh \"git config set advice.objectNameWarning " "false\"" #, c-format @@ -18502,13 +18623,6 @@ msgstr "bitmap multi-pack thiếu chỉ mục để dành cần thiết" msgid "could not open pack %s" msgstr "không thể mở gói '%s'" -msgid "could not determine MIDX preferred pack" -msgstr "không thể xác định gói MIDX ưa dùng" - -#, c-format -msgid "preferred pack (%s) is invalid" -msgstr "preferred pack (%s) không hợp lệ" - msgid "corrupt bitmap lookup table: triplet position out of index" msgstr "bảng tìm kiếm bitmap bị hỏng: vị trí bộ ba nằm ngoài chỉ mục" @@ -19619,17 +19733,25 @@ msgstr "nhật ký cho tham chiếu %s kết thúc bất ngờ trên %s" msgid "log for %s is empty" msgstr "nhật ký cho %s trống rỗng" -msgid "refusing to force and skip creation of reflog" -msgstr "từ chối bỏ qua việc tạo log tham chiếu" - #, c-format -msgid "refusing to update ref with bad name '%s'" -msgstr "từ chối cập nhật tham chiếu với tên sai '%s'" +msgid "refusing to update reflog for pseudoref '%s'" +msgstr "từ chối cập nhật reflog cho tham chiếu ảo '%s'" #, c-format msgid "refusing to update pseudoref '%s'" msgstr "từ chối cập nhật tham chiếu ảo '%s'" +#, c-format +msgid "refusing to update reflog with bad name '%s'" +msgstr "từ chối cập nhật reflog với tên sai '%s'" + +#, c-format +msgid "refusing to update ref with bad name '%s'" +msgstr "từ chối cập nhật tham chiếu với tên sai '%s'" + +msgid "refusing to force and skip creation of reflog" +msgstr "từ chối bỏ qua việc tạo log tham chiếu" + #, c-format msgid "update_ref failed for ref '%s': %s" msgstr "update_ref bị lỗi cho ref '%s': %s" @@ -19642,7 +19764,7 @@ msgid "ref updates forbidden inside quarantine environment" msgstr "cập nhật tham chiếu bị cấm trong môi trường kiểm tra" msgid "ref updates aborted by hook" -msgstr "các cập nhật tham chiếu bị huỷ bỏ bởi móc" +msgstr "các cập nhật tham chiếu bị huỷ bỏ bởi hook" #, c-format msgid "'%s' exists; cannot create '%s'" @@ -19679,6 +19801,10 @@ msgstr "" "không thể lock tham chiếu '%s': cần tham chiếu mềm tới '%s': nhưng lại là " "tham chiếu thường" +#, c-format +msgid "cannot read ref file '%s'" +msgstr "không thể đọc tập tin ref '%s'" + #, c-format msgid "cannot open directory %s" msgstr "không thể mở thư mục %s" @@ -19886,6 +20012,10 @@ msgstr "đã đưa ra nhiều hơn một gói nhận về, đang sử dụng cá msgid "more than one uploadpack given, using the first" msgstr "đã đưa ra nhiều hơn một gói tải lên, đang sử dụng cái đầu tiên" +#, c-format +msgid "unrecognized followRemoteHEAD value '%s' ignored" +msgstr "bỏ qua giá trị không chấp nhận cho followRemoteHEAD '%s'" + #, c-format msgid "unrecognized value transfer.credentialsInUrl: '%s'" msgstr "không chấp nhận giá trị transfer.credentialsInUrl: '%s'" @@ -20650,7 +20780,7 @@ msgstr "" " git rebase --continue\n" msgid "'prepare-commit-msg' hook failed" -msgstr "móc 'prepare-commit-msg' bị lỗi" +msgstr "hook 'prepare-commit-msg' bị lỗi" msgid "" "Your name and email address were configured automatically based\n" @@ -21812,6 +21942,9 @@ msgstr "lần chuyển giao %s chưa được đánh dấu là tiếp cận đư msgid "too many commits marked reachable" msgstr "có quá nhiều lần chuyển giao được đánh dấu là tiếp cận được" +msgid "could not determine MIDX preferred pack" +msgstr "không thể xác định gói MIDX ưa dùng" + msgid "test-tool serve-v2 []" msgstr "test-tool serve-v2 []" @@ -22478,6 +22611,9 @@ msgstr "tập tin .git bị hỏng" msgid ".git file incorrect" msgstr "tập tin .git không chính xác" +msgid ".git file absolute/relative path mismatch" +msgstr "đường dẫn tương đối/tuyệt đối đến file .git không khớp" + msgid "not a valid path" msgstr "không phải là một đường dẫn hợp lệ" @@ -22493,6 +22629,9 @@ msgstr "không thể định vị kho chứa; tập tin .git bị hỏng" msgid "gitdir unreadable" msgstr "gitdir không thể đọc được" +msgid "gitdir absolute/relative path mismatch" +msgstr "đường dẫn tương đối/tuyệt đối đến gitdir không khớp" + msgid "gitdir incorrect" msgstr "gitdir không chính xác" @@ -22527,6 +22666,13 @@ msgstr "không thể bỏ đặt %s trong '%s'" msgid "failed to set extensions.worktreeConfig setting" msgstr "gặp lỗi khi đặt cài đặt extensions.worktreeConfig" +msgid "unable to upgrade repository format to support relative worktrees" +msgstr "" +"không thể nâng cấp định định dạng kho chứa để hỗ trợ cây làm việc tương đối" + +msgid "unable to set extensions.relativeWorktrees setting" +msgstr "gặp lỗi khi đặt cài đặt extensions.relativeWorktrees" + #, c-format msgid "could not setenv '%s'" msgstr "không thể setenv '%s'" -- cgit v1.2.3 From 087ac486745129377a04d6921cddeac291c664aa Mon Sep 17 00:00:00 2001 From: Fredrik Date: Sat, 4 Jan 2025 19:29:05 +0100 Subject: l10n: sv.po, fixed swedish typos Signed-off-by: Peter Krefting --- po/sv.po | 138 +++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/po/sv.po b/po/sv.po index e36f035bf4..5377b3ece7 100644 --- a/po/sv.po +++ b/po/sv.po @@ -1300,7 +1300,7 @@ msgstr "fel i deflate (%d)" #, c-format msgid "unable to start '%s' filter" -msgstr "kane inte starta filtret ”%s”" +msgstr "kan inte starta filtret ”%s”" msgid "unable to redirect descriptor" msgstr "kan inte omdirigera handtag" @@ -2812,7 +2812,7 @@ msgstr "kunde inte slå upp HEAD" #, c-format msgid "HEAD (%s) points outside of refs/heads/" -msgstr "HEAD (%s) pekar utenför refs/heads/" +msgstr "HEAD (%s) pekar utanför refs/heads/" #, c-format msgid "branch %s is being rebased at %s" @@ -2828,7 +2828,7 @@ msgstr "HEAD i arbetskatalogen %s har inte uppdaterats" #, c-format msgid "invalid branch name: '%s'" -msgstr "gelaktigt namn på gren: ”%s”" +msgstr "felaktigt namn på gren: ”%s”" #, c-format msgid "no commit on branch '%s' yet" @@ -3301,7 +3301,7 @@ msgid "read commands from stdin" msgstr "läs kommandon från standard in" msgid "with --batch[-check]: ignores stdin, batches all known objects" -msgstr "med --batch[-check]: ignorear standard in, buntar alla kända objekt" +msgstr "med --batch[-check]: ignorerar standard in, buntar alla kända objekt" msgid "Change or optimize batch output" msgstr "Ändra eller optimera buntutdata" @@ -3687,13 +3687,13 @@ msgid "" "one remote, e.g. the 'origin' remote, consider setting\n" "checkout.defaultRemote=origin in your config." msgstr "" -"Om du menade checka ut en spårad fjärrgren på t.ex ”origin”, kan du\n" +"Om du menade checka ut en spårad fjärrgren på t.ex. ”origin”, kan du\n" "göra det genom att ange hela namnet med flaggan --track:\n" "\n" " git checkout --track origin/\n" "\n" "Om du alltid vill att utcheckningar med tvetydiga ska\n" -"föredra en fjärr, t.ex fjärren ”origin” kan du ställa in\n" +"föredra en fjärr, t.ex. fjärren ”origin” kan du ställa in\n" "checkout.defaultRemote=origin i din konfiguration." #, c-format @@ -3799,7 +3799,7 @@ msgid "Cannot switch branch to a non-commit '%s'" msgstr "Kan inte växla gren till icke-incheckningen ”%s”" msgid "missing branch or commit argument" -msgstr "saknar gren- eller incheckingsargument" +msgstr "saknar gren- eller incheckningsargument" #, c-format msgid "unknown conflict style '%s'" @@ -4425,7 +4425,7 @@ msgid "the object directory to store the graph" msgstr "objektkatalogen där grafen ska lagras" msgid "if the commit-graph is split, only verify the tip file" -msgstr "om inchecknignsgrafen är delad, kontrollera bara spetsfilen" +msgstr "om incheckningsgrafen är delad, kontrollera bara spetsfilen" #, c-format msgid "Could not open commit-graph '%s'" @@ -4471,7 +4471,7 @@ msgstr "tillåt skriva en inkrementell incheckningsgraffil" msgid "maximum number of commits in a non-base split commit-graph" msgstr "" -"maximalt antal incheckningar i en delad incheckingsgraf som inte är bad" +"maximalt antal incheckningar i en delad incheckningsgraf som inte är bad" msgid "maximum ratio between two levels of a split commit-graph" msgstr "maximalt förhållande mellan två nivåer av en delad incheckningsgraf" @@ -4480,7 +4480,7 @@ msgid "only expire files older than a given date-time" msgstr "låt tid endast gå ut för filer äldre än givet datum och tid" msgid "maximum number of changed-path Bloom filters to compute" -msgstr "maximalt antal Bloom-filer med ändrad sökväg att beräkna" +msgstr "maximalt antal Bloom-filter med ändrad sökväg att beräkna" msgid "use at most one of --reachable, --stdin-commits, or --stdin-packs" msgstr "använd som mest en av --reachable, --stdin-commits och --stdin-packs" @@ -5426,7 +5426,7 @@ msgstr "”credential-cache” ej tillgänglig; stöd för unix-uttag saknas" #, c-format msgid "unable to get credential storage lock in %d ms" -msgstr "kan inte erhålla låset för lagring av inlogginsuppgifter på %d ms" +msgstr "kan inte erhålla låset för lagring av inloggningsuppgifter på %d ms" msgid "" "git describe [--all] [--tags] [--contains] [--abbrev=] [...]" @@ -5782,7 +5782,7 @@ msgid "Expected 'to' command, got %s" msgstr "Förväntade ”to”-kommando, fick %s" msgid "Expected format name:filename for submodule rewrite option" -msgstr "Förvändae formatet namn:filnamn för undermodul-omskrivningsflaggan" +msgstr "Förväntade formatet namn:filnamn för undermodul-omskrivningsflaggan" #, c-format msgid "feature '%s' forbidden in input without --allow-unsafe-features" @@ -6093,7 +6093,7 @@ msgid "check for forced-updates on all updated branches" msgstr "se efter tvingade uppdateringar i alla uppdaterade grenar" msgid "write the commit-graph after fetching" -msgstr "skriv incheckingsgrafen efter hämtning" +msgstr "skriv incheckningsgrafen efter hämtning" msgid "accept refspecs from stdin" msgstr "ta emot referenser från standard in" @@ -6141,7 +6141,7 @@ msgid "--atomic can only be used when fetching from one remote" msgstr "--atomic kan bara användas vid hämtning från en fjärr" msgid "--stdin can only be used when fetching from one remote" -msgstr "--stdin kan bara användas vid hämtning fårn en fjärr" +msgstr "--stdin kan bara användas vid hämtning från en fjärr" msgid "" "git fmt-merge-msg [-m ] [--log[=] | --no-log] [--file ]" @@ -6438,7 +6438,7 @@ msgid "report root nodes" msgstr "rapportera rotnoder" msgid "make index objects head nodes" -msgstr "gör indexojekt till huvudnoder" +msgstr "gör indexobjekt till huvudnoder" msgid "make reflogs head nodes (default)" msgstr "gör refloggar till huvudnoder (standard)" @@ -7732,7 +7732,7 @@ msgid "cover-from-description-mode" msgstr "cover-from-description-läge" msgid "generate parts of a cover letter based on a branch's description" -msgstr "skapa delar av omslagsbrevet baserat på grenbeskrivelsen" +msgstr "skapa delar av omslagsbrevet baserat på grenbeskrivningen" msgid "use branch description from file" msgstr "använd grenbeskrivningar från fil" @@ -7974,7 +7974,7 @@ msgid "show debugging data" msgstr "visa felsökningsutdata" msgid "suppress duplicate entries" -msgstr "undertyck dublettposter" +msgstr "undertryck dublettposter" msgid "show sparse directories in the presence of a sparse index" msgstr "visa glesa kataloger när et glest index existerar" @@ -8066,7 +8066,7 @@ msgid "keep subject" msgstr "behåll ärenderad" msgid "keep non patch brackets in subject" -msgstr "behåll hakparanterser som inte är ”patch” i ärenderaden" +msgstr "behåll hakparenteser som inte är ”patch” i ärenderaden" msgid "copy Message-ID to the end of commit message" msgstr "kopiera Message-ID till slutet av incheckningsmeddelandet" @@ -8221,7 +8221,7 @@ msgid "git merge-tree [--write-tree] [] " msgstr "git merge-tree [--write-tree] [] " msgid "git merge-tree [--trivial-merge] " -msgstr "git merge-tree [--trivial-merge] " +msgstr "git merge-tree [--trivial-merge] " msgid "do a real merge instead of a trivial merge" msgstr "gör en riktig sammanslagning istället för en enkel sammanslagning" @@ -9244,7 +9244,7 @@ msgstr "kan inte öppna paketfilen" #, c-format msgid "loose object at %s could not be examined" -msgstr "lösa objekt på %s kunde inte underökas" +msgstr "lösa objekt på %s kunde inte undersökas" msgid "unable to force loose object" msgstr "kan inte tvinga lösa objekt" @@ -9693,7 +9693,7 @@ msgid "Need to specify how to reconcile divergent branches." msgstr "Måste ange hur avvikande grenar skall förlikas." msgid "cannot rebase with locally recorded submodule modifications" -msgstr "kan inte ombasera med lokalt lagrade ändringar i undermoful" +msgstr "kan inte ombasera med lokalt lagrade ändringar i undermodul" msgid "git push [] [ [...]]" msgstr "git push [] [ [...]]" @@ -10211,7 +10211,7 @@ msgid "empty exec command" msgstr "tomt exec-kommando" msgid "rebase onto given branch instead of upstream" -msgstr "ombasera mot given grenen istället för uppström" +msgstr "ombasera mot given gren istället för uppström" msgid "use the merge-base of upstream and branch as the current base" msgstr "använd sammanslagningsbasen mellan uppströms och gren som aktuell bas" @@ -10603,7 +10603,7 @@ msgid "process the reflogs of all references" msgstr "hantera referensloggar för alla referenser" msgid "limits processing to reflogs from the current worktree only" -msgstr "begränsar hantering av referensloggar till endst aktuell arbetskatalog" +msgstr "begränsar hantering av referensloggar till endast aktuell arbetskatalog" #, c-format msgid "Marking reachable objects..." @@ -11866,7 +11866,7 @@ msgstr "Ingen sökvägsangivelse gavs. Vilka filer ska jag ta bort?" msgid "please stage your changes to .gitmodules or stash them to proceed" msgstr "" -"löa dina ändringar i .gitmodules eller använd ”stash” för att fortsätta" +"köa dina ändringar i .gitmodules eller använd ”stash” för att fortsätta" #, c-format msgid "not removing '%s' recursively without -r" @@ -11940,7 +11940,7 @@ msgid "linewrap output" msgstr "radbryt utdata" msgid "field" -msgstr "föt" +msgstr "fält" msgid "group by field" msgstr "gruppera efter fält" @@ -12101,7 +12101,7 @@ msgid "stricter reference checking, requires exact ref path" msgstr "striktare referenskontroll, kräver exakt referenssökväg" msgid "show the HEAD reference, even if it would be filtered out" -msgstr "visa HEAD-refrens, även när den skulle filtreras ut" +msgstr "visa HEAD-referens, även när den skulle filtreras ut" msgid "dereference tags into object IDs" msgstr "avreferera taggar till objekt-id" @@ -12158,7 +12158,7 @@ msgid "initialize the sparse-checkout in cone mode" msgstr "initiera sparse-checkout i konläge" msgid "toggle the use of a sparse index" -msgstr "slå på/av använding av glest index" +msgstr "slå på/av användning av glest index" #, c-format msgid "unable to create leading directories of %s" @@ -12329,7 +12329,7 @@ msgstr "Inga ”stash”-poster hittades." #, c-format msgid "%s is not a valid reference" -msgstr "%s är inte en giltigt referens" +msgstr "%s är inte en giltig referens" msgid "git stash clear with arguments is unimplemented" msgstr "”git stash clear” med argument har inte implementerats" @@ -12580,7 +12580,7 @@ msgstr "" "HEAD" msgid "git submodule status [--quiet] [--cached] [--recursive] [...]" -msgstr "git submodule status [--quitet] [--cached] [--recursive] [...]" +msgstr "git submodule status [--quiet] [--cached] [--recursive] [...]" #, c-format msgid "* %s %s(blob)->%s(submodule)" @@ -12603,7 +12603,7 @@ msgid "unexpected mode %o" msgstr "okänt läge %o" msgid "use the commit stored in the index instead of the submodule HEAD" -msgstr "använd incechkning lagrad i indexet istället för undermodulens HEAD" +msgstr "använd incheckning lagrad i indexet istället för undermodulens HEAD" msgid "compare the commit in the index with that in the submodule HEAD" msgstr "jämför incheckningen i indexet med den i undermodulens HEAD" @@ -13884,7 +13884,7 @@ msgstr "misslyckades lagra maximal skaparsymbol" #, c-format msgid "unrecognized bundle mode from URI '%s'" -msgstr "okänt buntlägre från URI:en ”%s”" +msgstr "okänt buntläge från URI:en ”%s”" #, c-format msgid "exceeded bundle URI recursion limit (%d)" @@ -14233,7 +14233,7 @@ msgid "Send a collection of patches from stdin to an IMAP folder" msgstr "Sänd en samling patchar från stdin till en IMAP-mapp" msgid "Build pack index file for an existing packed archive" -msgstr "SKapa pack-indexfiler för ett befintligt packat arkiv" +msgstr "Skapa pack-indexfiler för ett befintligt packat arkiv" msgid "Create an empty Git repository or reinitialize an existing one" msgstr "Skapa tomt Git-arkiv eller ominitiera ett befintligt" @@ -14455,7 +14455,7 @@ msgid "Creates a temporary file with a blob's contents" msgstr "Skapar temporära filer med innehållet från en blob" msgid "Unpack objects from a packed archive" -msgstr "Packa upp objekt från ett pakat arkiv" +msgstr "Packa upp objekt från ett packat arkiv" msgid "Register file contents in the working tree to the index" msgstr "Registrera filinnehållet från arbetskatalogen i indexet" @@ -14512,7 +14512,7 @@ msgid "Git for CVS users" msgstr "Git för CVS-användare" msgid "Tweaking diff output" -msgstr "Justrea diff-utdata" +msgstr "Justera diff-utdata" msgid "A useful minimum set of commands for Everyday Git" msgstr "Ett användbart minsta uppsättning kommandon för vardags-Git" @@ -14620,7 +14620,7 @@ msgid "commit-graph generations chunk is wrong size" msgstr "incheckningsgrafens generationsstycke har fel storlek" msgid "commit-graph changed-path index chunk is too small" -msgstr "incheckningsgrafens ändrade-sökvägar-indexstycke är förö litet" +msgstr "incheckningsgrafens ändrade-sökvägar-indexstycke är för litet" #, c-format msgid "" @@ -14684,10 +14684,10 @@ msgstr "incheckningsgrafens kedjefil är för liten" #, c-format msgid "invalid commit-graph chain: line '%s' not a hash" -msgstr "ogiltig incheckingsgrafkedja: rad ”%s” är inte ett hash-värde" +msgstr "ogiltig incheckningsgrafkedja: rad ”%s” är inte ett hash-värde" msgid "unable to find all commit-graph files" -msgstr "kan inte hitta alla incheckingsgraffiler" +msgstr "kan inte hitta alla incheckningsgraffiler" msgid "invalid commit position. commit-graph is likely corrupt" msgstr "ogiltig incheckningsposition. incheckningsgrafen är troligtvis trasig" @@ -14729,8 +14729,8 @@ msgstr "Samlar refererade incheckningar" #, c-format msgid "Finding commits for commit graph in % pack" msgid_plural "Finding commits for commit graph in % packs" -msgstr[0] "Söker incheckningar för incheckingsgraf i % paket" -msgstr[1] "Söker incheckningar för incheckingsgraf i % paket" +msgstr[0] "Söker incheckningar för incheckningsgraf i % paket" +msgstr[1] "Söker incheckningar för incheckningsgraf i % paket" #, c-format msgid "error adding pack %s" @@ -14741,10 +14741,10 @@ msgid "error opening index for %s" msgstr "fel vid öppning av indexet för %s" msgid "Finding commits for commit graph among packed objects" -msgstr "Söker incheckningar för incheckingsgraf i packade objekt" +msgstr "Söker incheckningar för incheckningsgraf i packade objekt" msgid "Finding extra edges in commit graph" -msgstr "Söker ytterligare kanter i incheckingsgraf" +msgstr "Söker ytterligare kanter i incheckningsgraf" msgid "failed to write correct number of base graph ids" msgstr "misslyckades skriva korrekt antal bas-graf-id:n" @@ -14766,7 +14766,7 @@ msgid "unable to open commit-graph chain file" msgstr "kan inte öppna incheckningsgrafkedjefilen" msgid "failed to rename base commit-graph file" -msgstr "misslyckades byta namn på bas-incheckingsgraffilen" +msgstr "misslyckades byta namn på bas-incheckningsgraffilen" msgid "failed to rename temporary commit-graph file" msgstr "misslyckades byta namn på temporär incheckningsgraffil" @@ -15335,7 +15335,7 @@ msgstr "referensen ”%s” pekar inte på en blob" #, c-format msgid "unable to resolve config blob '%s'" -msgstr "kan inte slå upp konfigurerings-bloben ”%s”" +msgstr "kan inte slå upp konfigurerings-blobben ”%s”" msgid "unable to parse command-line config" msgstr "kan inte tolka kommandoradskonfiguration" @@ -15697,7 +15697,7 @@ msgstr "url saknar protokoll: %s" #, c-format msgid "credential url cannot be parsed: %s" -msgstr "kan inte tolka url för inloggingsuppgifter: %s" +msgstr "kan inte tolka url för inloggningsuppgifter: %s" #, c-format msgid "invalid timeout '%s', expecting a non-negative integer" @@ -16102,7 +16102,7 @@ msgid "use default prefixes a/ and b/" msgstr "använd standardprefixen a/ och b/" msgid "show context between diff hunks up to the specified number of lines" -msgstr "visa sammnhang mellan diff-stycken upp till angivet antal rader" +msgstr "visa sammanhang mellan diff-stycken upp till angivet antal rader" msgid "" msgstr "" @@ -16622,7 +16622,7 @@ msgstr "Servern tillåter inte förfrågan om ej tillkännagivet objekt %s" #, c-format msgid "fsmonitor_ipc__send_query: invalid path '%s'" -msgstr "fsmonitor_ipc__send_query: ogilitg sökväg ”%s”" +msgstr "fsmonitor_ipc__send_query: ogiltig sökväg ”%s”" #, c-format msgid "fsmonitor_ipc__send_query: unspecified error on '%s'" @@ -16896,7 +16896,7 @@ msgid "Interacting with Others" msgstr "Interaktion med andra" msgid "Low-level Commands / Manipulators" -msgstr "Lågnivåkommandon / maniupulerare" +msgstr "Lågnivåkommandon / manipulerare" msgid "Low-level Commands / Interrogators" msgstr "Lågnivåkommandon / frågare" @@ -16936,7 +16936,7 @@ msgid "External commands" msgstr "Externa kommandon" msgid "Command aliases" -msgstr "Kommadoalias" +msgstr "Kommandoalias" msgid "See 'git help ' to read about a specific subcommand" msgstr "Se ”git help ” för att läsa om ett specifikt underkommando" @@ -17279,7 +17279,7 @@ msgid "" "CONFLICT (implicit dir rename): Existing file/dir at %s in the way of " "implicit directory rename(s) putting the following path(s) there: %s." msgstr "" -"KONFLIKT (implicit nämnändrad kat): Befintlig fil/kat vid %s är i vägen för " +"KONFLIKT (implicit namnändrad kat): Befintlig fil/kat vid %s är i vägen för " "implicit namnändrad(e) katalog(er) som lägger dit följande sökväg(ar): %s." #, c-format @@ -17441,7 +17441,7 @@ msgid "" " - resolve any other conflicts in the superproject\n" " - commit the resulting index in the superproject\n" msgstr "" -"Rekursiv sammanslaning med undermoduler stöder för närvarande endast enkla " +"Rekursiv sammanslagning med undermoduler stöder för närvarande endast enkla " "fall.\n" "Du måste hantera sammanslagning av undermoduler i konflikt manuellt.\n" "Detta kan göras genom att utföra följande steg:\n" @@ -18174,7 +18174,7 @@ msgstr "kan inte utföra ”deflate” på nytt strömobjekt (%d)" #, c-format msgid "deflateEnd on stream object failed (%d)" -msgstr "”deflatEend” på strömobjektet misslyckades (%d)" +msgstr "”deflateEnd” på strömobjektet misslyckades (%d)" #, c-format msgid "unable to create directory %s" @@ -18444,7 +18444,7 @@ msgid "" "corrupted bitmap index file (too short to fit pseudo-merge table header)" msgstr "" "trasig bitkarteindexfil (för kort för att få plats för pseudo-" -"sammanslagningsatbellhuvudet)" +"sammanslagningstabellhuvudet)" msgid "corrupted bitmap index file (too short to fit pseudo-merge table)" msgstr "" @@ -18538,7 +18538,7 @@ msgstr "bitkarteresultat stämmer inte överens" #, c-format msgid "pseudo-merge index out of range (% >= %)" -msgstr "pseudosammanslaningsindex utenför intervallet (% ≥ %)" +msgstr "pseudosammanslagningsindex utanför intervallet (% ≥ %)" #, c-format msgid "could not find '%s' in pack '%s' at offset %" @@ -18633,7 +18633,7 @@ msgstr "offset före slutet av packindex för %s (trasigt index?)" #, c-format msgid "offset beyond end of pack index for %s (truncated index?)" -msgstr "offset borton slutet av packindex för %s (trunkerat index?)" +msgstr "offset bortom slutet av packindex för %s (trunkerat index?)" #, c-format msgid "malformed expiration date '%s'" @@ -19009,7 +19009,7 @@ msgid "" "could not parse first line of `log` output: did not start with 'commit ': " "'%s'" msgstr "" -"kunde inte tolka första raden i ”log”-updata: börjar inte med ”commit ”: ”%s”" +"kunde inte tolka första raden i ”log”-utdata: börjar inte med ”commit ”: ”%s”" #, c-format msgid "could not parse git header '%.*s'" @@ -19124,7 +19124,7 @@ msgstr "%s: öppning av indexfilen misslyckades" #, c-format msgid "%s: cannot stat the open index" -msgstr "%s: kan inte ta startus på det öppna indexet" +msgstr "%s: kan inte ta status på det öppna indexet" #, c-format msgid "%s: index file smaller than expected" @@ -19393,7 +19393,7 @@ msgstr "kan inte helt tolka %s=%s" #, c-format msgid "value expected %s=" -msgstr "vädre förväntades %s=" +msgstr "värde förväntades %s=" #, c-format msgid "positive value expected '%s' in %%(%s)" @@ -19932,7 +19932,7 @@ msgid "" "\n" "Neither worked, so we gave up. You must fully qualify the ref." msgstr "" -"Målet du angav är inte ett komplett referensamn (dvs.,\n" +"Målet du angav är inte ett komplett referensnamn (dvs.,\n" "startar med ”refs/”). Vi försökte gissa vad du menade genom att:\n" "\n" "- Se efter en referens som motsvarar ”%s” på fjärrsidan.\n" @@ -20190,7 +20190,7 @@ msgstr "misslyckades hitta trädet för %s." #, c-format msgid "unsupported section for hidden refs: %s" -msgstr "sktionen för dolda referenser stöds ej: %s" +msgstr "sektionen för dolda referenser stöds ej: %s" msgid "--exclude-hidden= passed more than once" msgstr "--exclude-hidden= angavs mer än en gång" @@ -20473,7 +20473,7 @@ msgid "" "not sending a push certificate since the receiving end does not support --" "signed push" msgstr "" -"sänder inte push-certifikat eftersom mottagarsidan inte stlder push med --" +"sänder inte push-certifikat eftersom mottagarsidan inte stöder push med --" "signed" msgid "the receiving end does not support --atomic push" @@ -20833,7 +20833,7 @@ msgstr "”%s” är inte ett giltigt referensnamn" #, c-format msgid "update-ref requires a fully qualified refname e.g. refs/heads/%s" -msgstr "update-ref kräver ett fullständigt referensnamn, t.ex refs/heads/%s" +msgstr "update-ref kräver ett fullständigt referensnamn, t.ex. refs/heads/%s" #, c-format msgid "'%s' does not accept merge commits" @@ -21841,7 +21841,7 @@ msgstr "" "[]" msgid "name or pathname of unix domain socket" -msgstr "namn eller sövkäg till unixdomän-uttag" +msgstr "namn eller sökväg till unixdomän-uttag" msgid "named-pipe name" msgstr "namn på namngivet rör" @@ -21943,10 +21943,10 @@ msgstr "kunde inte läsa referensen %s" #, c-format msgid "unknown response to connect: %s" -msgstr "okänt svar på ansluntning: %s" +msgstr "okänt svar på anslutning: %s" msgid "setting remote service path not supported by protocol" -msgstr "protkollet stöder inte att sätta sökväg till fjärrtjänst" +msgstr "protokollet stöder inte att sätta sökväg till fjärrtjänst" msgid "invalid remote service path" msgstr "felaktig sökväg till fjärrtjänst" @@ -21959,7 +21959,7 @@ msgid "--negotiate-only requires protocol v2" msgstr "--negotiate-only kräver protokoll v2" msgid "'option' without a matching 'ok/error' directive" -msgstr "”option” utan mostsvarande ”ok/error”-direktiv" +msgstr "”option” utan motsvarande ”ok/error”-direktiv" #, c-format msgid "expected ok/error, helper said '%s'" @@ -23022,7 +23022,7 @@ msgstr "Kan inte byta katalog till $cdup, toppnivån på arbetskatalogen" #, sh-format msgid "fatal: $program_name cannot be used without a working tree." -msgstr "ödesdigetrt: $program_name kan inte användas utan arbetskatalog." +msgstr "ödesdigert: $program_name kan inte användas utan arbetskatalog." msgid "Cannot rewrite branches: You have unstaged changes." msgstr "Kan inte skriva om grenar: Du har oköade ändringar." @@ -23071,7 +23071,7 @@ msgid "--dump-aliases incompatible with other options\n" msgstr "--dump-aliases är inkompatibelt med andra flaggor\n" msgid "--dump-aliases and --translate-aliases are mutually exclusive\n" -msgstr "--dump-aliases och --translate-aliases är ömsesidigt utelsutande\n" +msgstr "--dump-aliases och --translate-aliases är ömsesidigt uteslutande\n" msgid "" "fatal: found configuration options for 'sendmail'\n" @@ -23112,7 +23112,7 @@ msgstr "varning: ”:include:” stöds inte: %s\n" #, perl-format msgid "warning: `/file` or `|pipe` redirection not supported: %s\n" -msgstr "varning: omdirigering til ”/fil” eller ”|rör” stöds inte: %s\n" +msgstr "varning: omdirigering till ”/fil” eller ”|rör” stöds inte: %s\n" #, perl-format msgid "warning: sendmail line is not recognized: %s\n" @@ -23340,7 +23340,7 @@ msgid "cannot send message as 7bit" msgstr "kan inte sända brev som sjubitars" msgid "invalid transfer encoding" -msgstr "ogiltig överföringskondning" +msgstr "ogiltig överföringskodning" #, perl-format msgid "" -- cgit v1.2.3 From 10fd0e120317de28002e510d6becc049b81b851f Mon Sep 17 00:00:00 2001 From: Arkadii Yakovets Date: Sat, 4 Jan 2025 19:26:33 -0800 Subject: l10n: uk: v2.48 update Co-authored-by: Kate Golovanova Signed-off-by: Arkadii Yakovets Signed-off-by: Kate Golovanova --- po/uk.po | 599 ++++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 443 insertions(+), 156 deletions(-) diff --git a/po/uk.po b/po/uk.po index 297f7b0687..5f68f36c7d 100644 --- a/po/uk.po +++ b/po/uk.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: Git v2.46\n" "Report-Msgid-Bugs-To: Git Mailing List \n" -"POT-Creation-Date: 2023-04-11 09:55-0700\n" -"PO-Revision-Date: 2024-07-24 08:45-0700\n" -"Last-Translator: Arkadii Yakovets \n" +"POT-Creation-Date: 2025-01-04 19:26-0800\n" +"PO-Revision-Date: 2025-01-03 14:17-0800\n" +"Last-Translator: Kateryna Golovanova \n" "Language-Team: Ukrainian \n" "Language: uk\n" "MIME-Version: 1.0\n" @@ -18,7 +18,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" -"X-Generator: Poedit 3.4.2\n" +"X-Generator: Poedit 3.5\n" #, c-format msgid "Huh (%s)?" @@ -41,7 +41,7 @@ msgstr "Оновити" #, c-format msgid "could not stage '%s'" -msgstr "не вдалося додати до індексу %s" +msgstr "не вдалося додати до індексу \"%s\"" msgid "could not write index" msgstr "не вдалося записати індекс" @@ -549,7 +549,7 @@ msgid "" "/ - search for a hunk matching the given regex\n" "s - split the current hunk into smaller hunks\n" "e - manually edit the current hunk\n" -"p - print the current hunk\n" +"p - print the current hunk, 'P' to use the pager\n" "? - print help\n" msgstr "" "j - залишити цей шматок невизначеним, перейти до наступного невизначеного " @@ -562,7 +562,7 @@ msgstr "" "/ - шукати шматок, що відповідає заданому регвиру\n" "s - розбити поточний шматок на менші шматки\n" "e - редагувати поточний шматок вручну\n" -"p - показати поточний шматок\n" +"p - показати поточний шматок, \"P\" для гортання сторінок\n" "? - показати довідку\n" #, c-format @@ -634,10 +634,11 @@ msgstr "Змінено лише бінарні файли." #, c-format msgid "" "\n" -"Disable this message with \"git config advice.%s false\"" +"Disable this message with \"git config set advice.%s false\"" msgstr "" "\n" -"Вимкнути це повідомлення можна за допомогою \"git config advice.%s false\"" +"Вимкнути це повідомлення можна за допомогою \"git config set advice.%s " +"false\"" #, c-format msgid "%shint:%s%.*s%s\n" @@ -761,8 +762,8 @@ msgstr "" "\n" " git switch -\n" "\n" -"Щоб вимкнути цю пораду, встановіть конфігураційний параметр advice." -"detachedHead у false\n" +"Щоб вимкнути цю пораду, встановіть конфігураційний параметр " +"advice.detachedHead у false\n" #, c-format msgid "" @@ -1255,6 +1256,15 @@ msgstr "" "спробувати тристороннє злиття, повернутися до звичайного латання, якщо це не " "вдасться" +msgid "for conflicts, use our version" +msgstr "у разі конфліктів використовувати нашу версію" + +msgid "for conflicts, use their version" +msgstr "у разі конфліктів використовувати їхню версію" + +msgid "for conflicts, use a union version" +msgstr "у разі конфліктів використовувати обʼєднану версію" + msgid "build a temporary index based on embedded index information" msgstr "створити тимчасовий індекс на основі вбудованої індексної інформації" @@ -1300,6 +1310,9 @@ msgstr "додати <корінь> до всіх назв файлів" msgid "don't return error for empty patches" msgstr "не повертати помилку для порожніх латок" +msgid "--ours, --theirs, and --union require --3way" +msgstr "--ours, --theirs, та --union вимагають --3way" + #, c-format msgid "cannot stream blob %s" msgstr "неможливо транслювати blob %s" @@ -1371,6 +1384,10 @@ msgstr "невірне ім’я об’єкта: %s" msgid "not a tree object: %s" msgstr "не є об’єктом дерева: %s" +#, c-format +msgid "failed to unpack tree object %s" +msgstr "не вдалося розпакувати обʼєкт дерева %s" + #, c-format msgid "File not found: %s" msgstr "Файл не знайдено: %s" @@ -2174,7 +2191,7 @@ msgstr "" #, c-format msgid "Could not parse object '%s'." -msgstr "Не вдалося розібрати об'єкт '%s'." +msgstr "Не вдалося розібрати обʼєкт \"%s\"." msgid "failed to clean index" msgstr "не вдалося очистити індекс" @@ -2484,9 +2501,6 @@ msgstr "" "неприпустимий аргумент %s для \"git bisect terms\".\n" "Підтримувані опції: --term-good|--term-old і --term-bad|--term-new." -msgid "revision walk setup failed\n" -msgstr "не вдалося налаштувати проходження по ревізіям\n" - #, c-format msgid "could not open '%s' for appending" msgstr "не вдалося відкрити \"%s\" для додавання" @@ -3026,8 +3040,8 @@ msgid "HEAD not found below refs/heads!" msgstr "HEAD не знайдено під refs/heads!" msgid "" -"branch with --recurse-submodules can only be used if submodule." -"propagateBranches is enabled" +"branch with --recurse-submodules can only be used if " +"submodule.propagateBranches is enabled" msgstr "" "гілку з --recurse-submodules можна використовувати лише якщо увімкнено " "submodule.propagateBranches" @@ -3478,9 +3492,14 @@ msgstr "git check-mailmap [<опції>] <контакт>..." msgid "also read contacts from stdin" msgstr "також читати контакти з stdin" -#, c-format -msgid "unable to parse contact: %s" -msgstr "не вдалося розібрати контакт: %s" +msgid "read additional mailmap entries from file" +msgstr "зчитувати додаткові записи mailmap з файлу" + +msgid "blob" +msgstr "blob" + +msgid "read additional mailmap entries from blob" +msgstr "зчитувати додаткові записи mailmap з blob" msgid "no contacts specified" msgstr "контакти не вказані" @@ -3648,7 +3667,7 @@ msgstr "Вже на \"%s\"\n" #, c-format msgid "Switched to and reset branch '%s'\n" -msgstr "Переключено на та скинуто гілку '%s'\n" +msgstr "Переключено на та скинуто гілку \"%s\"\n" #, c-format msgid "Switched to a new branch '%s'\n" @@ -3842,19 +3861,23 @@ msgstr "шляхи не можуть використовуватись при #, c-format msgid "'%s' cannot be used with switching branches" -msgstr "'%s' не може використовуватись при переключенні гілок" +msgstr "\"%s\" не може використовуватись при переключенні гілок" + +#, c-format +msgid "'%s' needs the paths to check out" +msgstr "\"%s\" потрібні шляхи для переходу" #, c-format msgid "'%s' cannot be used with '%s'" -msgstr "'%s' не може використовуватись з '%s'" +msgstr "\"%s\" не може використовуватись з \"%s\"" #, c-format msgid "'%s' cannot take " -msgstr "'%s' не може прийняти <стартова-точка>" +msgstr "\"%s\" не може прийняти <стартова-точка>" #, c-format msgid "Cannot switch branch to a non-commit '%s'" -msgstr "Неможливо переключити гілку на не коміт '%s'" +msgstr "Неможливо переключити гілку на не коміт \"%s\"" msgid "missing branch or commit argument" msgstr "відсутня гілка або коміт" @@ -3887,8 +3910,8 @@ msgstr "нова ненароджена гілка" msgid "update ignored files (default)" msgstr "оновити ігноровані файли (за замовчуванням)" -msgid "do not check if another worktree is holding the given ref" -msgstr "не перевіряти, чи інше робоче дерево містить дане посилання" +msgid "do not check if another worktree is using this branch" +msgstr "не перевіряти, чи використовує цю гілку інше робоче дерево" msgid "checkout our version for unmerged files" msgstr "використовувати нашу версію для не злитих файлів" @@ -3919,11 +3942,11 @@ msgstr "неприпустиме зазначення шляху" #, c-format msgid "'%s' is not a commit and a branch '%s' cannot be created from it" -msgstr "'%s' не є комітом, і з нього не можна створити гілку '%s'" +msgstr "\"%s\" не є комітом, і з нього не можна створити гілку \"%s\"" #, c-format msgid "git checkout: --detach does not take a path argument '%s'" -msgstr "git checkout: --detach не приймає аргумент шляху '%s'" +msgstr "git checkout: --detach не приймає аргумент шляху \"%s\"" msgid "" "git checkout: --ours/--theirs, --force and --merge are incompatible when\n" @@ -4191,11 +4214,11 @@ msgstr "створити неглибокий клон вказаної глиб msgid "create a shallow clone since a specific time" msgstr "створити неглибокий клон з певного часу" -msgid "revision" -msgstr "ревізія" +msgid "ref" +msgstr "посилання" -msgid "deepen history of shallow clone, excluding rev" -msgstr "поглибити історію неглибокого клону, за винятком ревізії" +msgid "deepen history of shallow clone, excluding ref" +msgstr "поглибити історію неглибокого клону, за винятком посилання" msgid "clone only one branch, HEAD or --branch" msgstr "клонувати лише одну гілку, HEAD або --branch" @@ -4428,7 +4451,7 @@ msgstr "не вдалося ініціалізувати сховище, URI п #, c-format msgid "failed to fetch objects from bundle URI '%s'" -msgstr "не вдалося отримати обʼєкти з пакунка URI '%s'" +msgstr "не вдалося отримати обʼєкти з пакунка URI \"%s\"" msgid "failed to fetch advertised bundles" msgstr "не вдалося отримати обіцяні пакунки" @@ -4618,7 +4641,7 @@ msgstr "git commit-tree: не вдалося прочитати" msgid "" "git commit [-a | --interactive | --patch] [-s] [-v] [-u] [--amend]\n" " [--dry-run] [(-c | -C | --squash) | --fixup [(amend|" -"reword):])]\n" +"reword):]]\n" " [-F | -m ] [--reset-author] [--allow-empty]\n" " [--allow-empty-message] [--no-verify] [-e] [--author=]\n" " [--date=] [--cleanup=] [--[no-]status]\n" @@ -4628,14 +4651,14 @@ msgid "" msgstr "" "git commit [-a | --interactive | --patch] [-s] [-v] [-u<режим>] [--amend]\n" " [--dry-run] [(-c | -C | --squash) <коміт> | --fixup [(amend|" -"reword):]<коміт>)]\n" +"reword):]<коміт>]\n" " [-F <файл> | -m <допис>] [--reset-author] [--allow-empty]\n" " [--allow-empty-message] [--no-verify] [-e] [--author=<автор>]\n" " [--date=<дата>] [--cleanup=<режим>] [--[no-]status]\n" " [-i | -o] [--pathspec-from-file=<файл> [--pathspec-file-nul]]\n" -" [(--trailer <токен>[(=|:)<значення>])...] [-S[<ідентифікатор " +" [(--trailer <токен>[(=|:)<значення>])...] [-S[<ідентифікатор-" "ключа>]]\n" -" [--] [<визначник шляху>...]" +" [--] [<визначник-шляху>...]" msgid "git status [] [--] [...]" msgstr "git status [<опції>] [--] [<визначник шляху>...]" @@ -5121,12 +5144,11 @@ msgstr "git config list [<опція-файлу>] [<опція-відображ msgid "" "git config get [] [] [--includes] [--all] [--" -"regexp=] [--value=] [--fixed-value] [--default=] " -"" +"regexp] [--value=] [--fixed-value] [--default=] " msgstr "" "git config get [<опція-файлу>] [<опція-відображення>] [--includes] [--all] " -"[--regexp=<регвир>] [--value=<значення>] [--fixed-value] [--" -"default=<значення -за-умовчанням>] <назва>" +"[--regexp] [--value=<значення>] [--fixed-value] [--default=<за " +"замовчуванням>] <назва>" msgid "" "git config set [] [--type=] [--all] [--value=] [--" @@ -5137,10 +5159,10 @@ msgstr "" msgid "" "git config unset [] [--all] [--value=] [--fixed-value] " -" " +"" msgstr "" "git config unset [<опція-файлу>] [--all] [--value=<значення>] [--fixed-" -"value] <назва> <значення>" +"value] <назва>" msgid "git config rename-section [] " msgstr "git config rename-section [<опція-файлу>] <стара-назва> <нова-назва>" @@ -5154,6 +5176,15 @@ msgstr "git config edit [<опція-файлу>]" msgid "git config [] --get-colorbool []" msgstr "git config [<опція-файлу>] --get-colorbool <назва> []" +msgid "" +"git config get [] [] [--includes] [--all] [--" +"regexp=] [--value=] [--fixed-value] [--default=] " +"" +msgstr "" +"git config get [<опція-файлу>] [<опція-відображення>] [--includes] [--all] " +"[--regexp=<регвир>] [--value=<значення>] [--fixed-value] [--default=<за-" +"замовчуванням>] <назва>" + msgid "" "git config set [] [--type=] [--comment=] [--all] " "[--value=] [--fixed-value] " @@ -5574,12 +5605,8 @@ msgid "traversed %lu commits\n" msgstr "пройдено через %lu комітів\n" #, c-format -msgid "" -"more than %i tags found; listed %i most recent\n" -"gave up search at %s\n" -msgstr "" -"знайдено більше %i тегів; показані %i останніх\n" -"припинено пошук на %s\n" +msgid "found %i tags; gave up search at %s\n" +msgstr "знайдено %i тегів; припинено пошук на %s\n" #, c-format msgid "describe %s\n" @@ -5964,13 +5991,13 @@ msgid "" "to avoid this check\n" msgstr "" "перевірка примусових оновлень зайняла %.2f секунд; ви можете скористатися\n" -"\"--no-show-forced-updates\" або виконати \"git config fetch." -"showForcedUpdates false\"\n" +"\"--no-show-forced-updates\" або виконати \"git config " +"fetch.showForcedUpdates false\"\n" "щоб уникнути цієї перевірки\n" #, c-format -msgid "%s did not send all necessary objects\n" -msgstr "%s не надіслав всіх необхідних обʼєктів\n" +msgid "%s did not send all necessary objects" +msgstr "%s не надіслав усі необхідні обʼєкти" #, c-format msgid "rejected %s because shallow roots are not allowed to be updated" @@ -6007,8 +6034,8 @@ msgid "option \"%s\" value \"%s\" is not valid for %s" msgstr "значення \"%s\" опції \"%s\" неприпустиме для %s" #, c-format -msgid "option \"%s\" is ignored for %s\n" -msgstr "опція \"%s\" ігнорується для %s\n" +msgid "option \"%s\" is ignored for %s" +msgstr "опція \"%s\" ігнорується для %s" #, c-format msgid "%s is not a valid object" @@ -6018,6 +6045,21 @@ msgstr "%s не є припустимим об’єктом" msgid "the object %s does not exist" msgstr "об’єкт %s не існує" +#, c-format +msgid "" +"Run 'git remote set-head %s %s' to follow the change, or set\n" +"'remote.%s.followRemoteHEAD' configuration option to a different value\n" +"if you do not want to see this message. Specifically running\n" +"'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n" +"until the remote changes HEAD to something else." +msgstr "" +"Запустіть \"git remote set-head %s %s\", щоб відстежити зміни, або " +"встановіть\n" +"\"remote.%s.followRemoteHEAD\" параметр конфігурації на інше значення\n" +"якщо ви не хочете бачити це повідомлення. Зокрема, виконання команди\n" +"\"git config set remote.%s.followRemoteHEAD %s\" вимкне попередження\n" +"доки віддалений сервер не змінить HEAD на щось інше." + msgid "multiple branches detected, incompatible with --set-upstream" msgstr "виявлено кілька гілок, несумісних з --set-upstream" @@ -6158,6 +6200,9 @@ msgstr "refmap" msgid "specify fetch refmap" msgstr "вказати мапу посилань для fetch" +msgid "revision" +msgstr "ревізія" + msgid "report that we have only objects reachable from this object" msgstr "звітувати, що у нас є тільки обʼєкти, доступні з цього обʼєкта" @@ -6212,8 +6257,8 @@ msgid "protocol does not support --negotiate-only, exiting" msgstr "протокол не підтримує --negotiate-only, вихід" msgid "" -"--filter can only be used with the remote configured in extensions." -"partialclone" +"--filter can only be used with the remote configured in " +"extensions.partialclone" msgstr "" "--filter можна використовувати лише з віддаленим призначенням, налаштованим " "у extensions.partialclone" @@ -6686,6 +6731,9 @@ msgstr "працювати ретельніше (збільшує час вик msgid "enable auto-gc mode" msgstr "увімкнути режим автоматичного збору сміття" +msgid "perform garbage collection in the background" +msgstr "виконувати прибирання сміття у фоновому режимі" + msgid "force running gc even if there may be another gc running" msgstr "примусово запускати збирач сміття, навіть якщо інший збирач вже працює" @@ -6786,6 +6834,9 @@ msgstr "завдання \"%s\" не можна вибрати кілька ра msgid "run tasks based on the state of the repository" msgstr "запускати завдання на основі стану сховища" +msgid "perform maintenance in the background" +msgstr "виконувати технічне обслуговування у фоновому режимі" + msgid "frequency" msgstr "частота" @@ -6883,8 +6934,26 @@ msgstr "недоступні ні systemd таймери, ні crontab" msgid "%s scheduler is not available" msgstr "%s планувальник недоступний" -msgid "another process is scheduling background maintenance" -msgstr "ще один процес планує фонове обслуговування" +#, c-format +msgid "" +"unable to create '%s.lock': %s.\n" +"\n" +"Another scheduled git-maintenance(1) process seems to be running in this\n" +"repository. Please make sure no other maintenance processes are running and\n" +"then try again. If it still fails, a git-maintenance(1) process may have\n" +"crashed in this repository earlier: remove the file manually to continue." +msgstr "" +"не вдалося створити \"%s.lock\": %s.\n" +"\n" +"Здається, у цьому сховищі запущено ще один запланований процес git-" +"maintenance(1). Будь ласка, переконайтеся, що у сховищі не запущено інших " +"процесів обслуговування, і\n" +"і спробуйте ще раз. Якщо все одно не вдасться, можливо, \n" +"раніше у цьому сховищі аварійно завершився git-maintenance(1) процес: " +"видаліть файл вручну, щоб продовжити роботу." + +msgid "cannot acquire lock for scheduled background maintenance" +msgstr "не може отримати блокування для планового фонового обслуговування" msgid "git maintenance start [--scheduler=]" msgstr "git maintenance start [--scheduler=<планувальник>]" @@ -7418,19 +7487,19 @@ msgstr "локальний обʼєкт %s пошкоджено" #, c-format msgid "packfile name '%s' does not end with '.%s'" -msgstr "ім’я файла пакунка '%s' не закінчується на '.%s'" +msgstr "ім’я файла пакунка \"%s\" не закінчується на '.%s'" #, c-format msgid "cannot write %s file '%s'" -msgstr "неможливо записати %s файл '%s'" +msgstr "неможливо записати %s файл \"%s\"" #, c-format msgid "cannot close written %s file '%s'" -msgstr "неможливо закрити записаний %s файл '%s'" +msgstr "неможливо закрити записаний %s файл \"%s\"" #, c-format msgid "unable to rename temporary '*.%s' file to '%s'" -msgstr "не вдається перейменувати тимчасовий файл '*.%s' на '%s'" +msgstr "не вдається перейменувати тимчасовий файл \"*.%s\" на \"%s\"" msgid "error while closing pack file" msgstr "помилка під час закриття файлу пакунка" @@ -7441,11 +7510,11 @@ msgstr "невірний pack.indexVersion=%" #, c-format msgid "Cannot open existing pack file '%s'" -msgstr "Неможливо відкрити існуючий файл пакунка '%s" +msgstr "Неможливо відкрити існуючий файл пакунка \"%s\"" #, c-format msgid "Cannot open existing pack idx file for '%s'" -msgstr "Неможливо відкрити існуючий індексний файл пакунка для '%s" +msgstr "Неможливо відкрити існуючий індексний файл пакунка для \"%s\"" #, c-format msgid "non delta: %d object" @@ -7461,6 +7530,20 @@ msgstr[0] "довжина ланцюжка = %d: %lu об’єкт" msgstr[1] "довжина ланцюжка = %d: %lu об’єкти" msgstr[2] "довжина ланцюжка = %d: %lu об’єктів" +msgid "could not start pack-objects to repack local links" +msgstr "не вдалося розпочати pack-objects для перепакування локальних посилань" + +msgid "failed to feed local object to pack-objects" +msgstr "не вдалося передати локальний обʼєкт до pack-objects" + +msgid "index-pack: Expecting full hex object ID lines only from pack-objects." +msgstr "" +"index-pack: очікуються повні рядки шістнадцяткових ідентифікаторів обʼєктів " +"тільки від pack-objects." + +msgid "could not finish pack-objects to repack local links" +msgstr "не вдалося завершити pack-objects для перепакування локальних посилань" + msgid "Cannot come back to cwd" msgstr "Неможливо повернутися до поточної робочої директорії" @@ -7470,7 +7553,10 @@ msgstr "невірний %s" #, c-format msgid "unknown hash algorithm '%s'" -msgstr "невідомий хеш-алгоритм '%s'" +msgstr "невідомий хеш-алгоритм \"%s\"" + +msgid "--promisor cannot be used with a pack name" +msgstr "--promisor не можна використовувати з назвою пакунка" msgid "--stdin requires a git repository" msgstr "--stdin потребує наявності git сховища" @@ -7656,9 +7742,6 @@ msgstr "-L<діапазон>:<файл> не можна використовув msgid "Final output: %d %s\n" msgstr "Кінцевий результат: %d %s\n" -msgid "unable to create temporary object directory" -msgstr "не вдалося створити тимчасову директорію об’єкта" - #, c-format msgid "git show %s: bad file" msgstr "git show %s: невірний файл" @@ -8231,15 +8314,6 @@ msgstr "використовувати злиття на основі diff3" msgid "use a zealous diff3 based merge" msgstr "використовувати ретельне злиття на основі diff3" -msgid "for conflicts, use our version" -msgstr "у разі конфліктів використовувати нашу версію" - -msgid "for conflicts, use their version" -msgstr "у разі конфліктів використовувати їхню версію" - -msgid "for conflicts, use a union version" -msgstr "у разі конфліктів використовувати об’єднану версію" - msgid "" msgstr "<алгоритм>" @@ -8709,6 +8783,9 @@ msgstr "" msgid "write multi-pack bitmap" msgstr "записати multi-pack bitmap" +msgid "write a new incremental MIDX" +msgstr "записати новий інкрементний MIDX" + msgid "write multi-pack index containing only given indexes" msgstr "записати multi-pack індекс, що містить лише задані індекси" @@ -8843,11 +8920,11 @@ msgstr "git notes [--ref <посилання-нотатки>] [list [<об’є msgid "" "git notes [--ref ] add [-f] [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" msgstr "" "git notes [--ref <посилання-нотатки>] add [-f] [--allow-empty] [--" "[no-]separator|--separator=<розділювач-абзаців>] [--[no-]stripspace] [-m " -"<допис> | -F <файл> | (-c | -C) <обʼєкт>] [<обʼєкт>]" +"<допис> | -F <файл> | (-c | -C) <обʼєкт>] [<обʼєкт>] [-e]" msgid "git notes [--ref ] copy [-f] " msgstr "" @@ -8856,11 +8933,11 @@ msgstr "" msgid "" "git notes [--ref ] append [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" msgstr "" "git notes [--ref <посилання-нотатки>] append [--allow-empty] [--" "[no-]separator|--separator=<розділювач-абзаців>] [--[no-]stripspace] [-m " -"<допис> | -F <файл> | (-c | -C) <обʼєкт>] [<обʼєкт>]" +"<допис> | -F <файл> | (-c | -C) <обʼєкт>] [<обʼєкт>] [-e]" msgid "git notes [--ref ] edit [--allow-empty] []" msgstr "git notes [--ref <посилання-нотатки>] edit [--allow-empty] [<об’єкт>]" @@ -8979,6 +9056,9 @@ msgstr "вміст нотатки у файлі" msgid "reuse and edit specified note object" msgstr "повторно використати та редагувати вказаний обʼєкт нотатки" +msgid "edit note message in editor" +msgstr "редагувати допис нотатки в редакторі" + msgid "reuse specified note object" msgstr "повторно використати вказаний обʼєкт нотатки" @@ -9195,8 +9275,8 @@ msgstr "очікувався обʼєкт на зміщенні % па msgid "disabling bitmap writing, packs are split due to pack.packSizeLimit" msgstr "" -"вимкнення bitmap запису, пакунки розбиваються на частини через pack." -"packSizeLimit" +"вимкнення bitmap запису, пакунки розбиваються на частини через " +"pack.packSizeLimit" msgid "Writing objects" msgstr "Запис обʼєктів" @@ -9478,6 +9558,9 @@ msgstr "обробка для відсутніх обʼєктів" msgid "do not pack objects in promisor packfiles" msgstr "не пакувати обʼєкти у promisor пакунки" +msgid "implies --missing=allow-any" +msgstr "мається на увазі --missing=allow-any" + msgid "respect islands during delta compression" msgstr "поважати острови під час дельта компресії" @@ -9974,7 +10057,7 @@ msgstr "Надсилання до %s\n" #, c-format msgid "failed to push some refs to '%s'" -msgstr "не вдалося надіслати деякі посилання до '%s'" +msgstr "не вдалося надіслати деякі посилання до \"%s\"" msgid "" "recursing into submodule with push.recurseSubmodules=only; using on-demand " @@ -9985,7 +10068,7 @@ msgstr "" #, c-format msgid "invalid value for '%s'" -msgstr "неприпустиме значення для '%s'" +msgstr "неприпустиме значення для \"%s\"" msgid "repository" msgstr "сховище" @@ -10746,6 +10829,9 @@ msgstr "неприпустимий формат посилання: %s" msgid "git refs migrate --ref-format= [--dry-run]" msgstr "git refs migrate --ref-format=<формат> [--dry-run]" +msgid "git refs verify [--strict] [--verbose]" +msgstr "git refs verify [--strict] [--verbose]" + msgid "specify the reference format to convert to" msgstr "вкажіть формат посилання, в який потрібно конвертувати" @@ -10759,6 +10845,12 @@ msgstr "відсутній --ref-format=<формат>" msgid "repository already uses '%s' format" msgstr "сховище вже використовує формат \"%s\"" +msgid "enable strict checking" +msgstr "увімкнути сувору перевірку" + +msgid "'git refs verify' takes no arguments" +msgstr "\"git refs verify\" не потребує аргументів" + msgid "" "git remote add [-t ] [-m ] [-f] [--tags | --no-tags] [--" "mirror=] " @@ -11100,6 +11192,30 @@ msgstr[0] " Локальне посилання налаштовано для \ msgstr[1] " Локальних посилання налаштовано для \"git push\"%s:" msgstr[2] " Локальних посилань налаштовано для \"git push\"%s:" +#, c-format +msgid "'%s/HEAD' is unchanged and points to '%s'\n" +msgstr "\"%s/HEAD\" не змінився і вказує на \"%s\"\n" + +#, c-format +msgid "'%s/HEAD' has changed from '%s' and now points to '%s'\n" +msgstr "\"%s/HEAD\" змінився з \"%s\" і тепер вказує на \"%s\"\n" + +#, c-format +msgid "'%s/HEAD' is now created and points to '%s'\n" +msgstr "Створено \"%s/HEAD\", який вказує на \"%s\"\n" + +#, c-format +msgid "'%s/HEAD' was detached at '%s' and now points to '%s'\n" +msgstr "\"%s/HEAD\" був відʼєднаний на \"%s\" і тепер вказує на \"%s\"\n" + +#, c-format +msgid "" +"'%s/HEAD' used to point to '%s' (which is not a remote branch), but now " +"points to '%s'\n" +msgstr "" +"\"%s/HEAD\" раніше вказував на \"%s\" (який не є віддаленою гілкою), але " +"тепер вказує на \"%s\"\n" + msgid "set refs/remotes//HEAD according to remote" msgstr "" "встановити refs/remotes/<назва>/HEAD відповідно до віддаленого призначення" @@ -11124,7 +11240,7 @@ msgid "Not a valid ref: %s" msgstr "Не є припустимим посиланням: %s" #, c-format -msgid "Could not setup %s" +msgid "Could not set up %s" msgstr "Не вдалося налаштувати %s" #, c-format @@ -11696,11 +11812,11 @@ msgstr "записати лише той факт, що вилучені шля #, c-format msgid "Failed to resolve '%s' as a valid revision." -msgstr "Не вдалося розпізнати '%s' як припустиму ревізію." +msgstr "Не вдалося розпізнати \"%s\" як припустиму ревізію." #, c-format msgid "Failed to resolve '%s' as a valid tree." -msgstr "Не вдалося розпізнати '%s' як припустиме дерево." +msgstr "Не вдалося розпізнати \"%s\" як припустиме дерево." msgid "--mixed with paths is deprecated; use 'git reset -- ' instead." msgstr "" @@ -11729,7 +11845,7 @@ msgstr "" #, c-format msgid "Could not reset index file to revision '%s'." -msgstr "Не вдалося скинути індексний файл до ревізії '%s'." +msgstr "Не вдалося скинути індексний файл до ревізії \"%s\"." msgid "Could not write new index file." msgstr "Не вдалося записати новий індексний файл." @@ -12211,11 +12327,11 @@ msgstr "посилання не існує" msgid "failed to look up reference" msgstr "не вдалося знайти посилання" -msgid "only show tags (can be combined with branches)" -msgstr "показати тільки теги (можна комбінувати з гілками)" +msgid "only show tags (can be combined with --branches)" +msgstr "показувати тільки теги (можна комбінувати з --branches)" -msgid "only show branches (can be combined with tags)" -msgstr "показати тільки гілки (можна комбінувати з тегами)" +msgid "only show branches (can be combined with --tags)" +msgstr "показувати тільки гілки (можна комбінувати з --tags)" msgid "check for reference existence without resolving" msgstr "перевіряти наявність посилання без розвʼязання" @@ -12268,6 +12384,10 @@ msgstr "не вдалося видалити директорію \"%s\"" msgid "failed to create directory for sparse-checkout file" msgstr "не вдалося створити директорію для файлу розрідженого переходу" +#, c-format +msgid "unable to fdopen %s" +msgstr "не вдалося fdopen %s" + msgid "failed to initialize worktree config" msgstr "не вдалося ініціалізувати конфігурацію робочого дерева" @@ -12726,8 +12846,8 @@ msgid "couldn't hash object from '%s'" msgstr "не вдалося хешувати обʼєкт з \"%s\"" #, c-format -msgid "unexpected mode %o\n" -msgstr "неочікуваний режим %o\n" +msgid "unexpected mode %o" +msgstr "неочікуваний режим %o" msgid "use the commit stored in the index instead of the submodule HEAD" msgstr "використати коміт, збережений в індексі, замість підмодуля HEAD" @@ -12771,8 +12891,8 @@ msgid "" "Submodule work tree '%s' contains a .git directory. This will be replaced " "with a .git file by using absorbgitdirs." msgstr "" -"Робоче дерево підмодуля \"%s\" містить директорію .git. Її буде замінено на ." -"git файл за допомогою absorbgitdirs." +"Робоче дерево підмодуля \"%s\" містить директорію .git. Її буде замінено " +"на .git файл за допомогою absorbgitdirs." #, c-format msgid "" @@ -13871,6 +13991,9 @@ msgid "try to match the new branch name with a remote-tracking branch" msgstr "" "спробуйте співставити нову назву гілки з назвою віддалено відстежуваної гілки" +msgid "use relative paths for worktrees" +msgstr "використовувати відносні шляхи для робочих дерев" + #, c-format msgid "options '%s', '%s', and '%s' cannot be used together" msgstr "опції \"%s\", \"%s\" та \"%s\" не можна використовувати разом" @@ -14149,6 +14272,25 @@ msgstr "неможливо створити \"%s\"" msgid "index-pack died" msgstr "index-pack завершився невдало" +#, c-format +msgid "directory '%s' is present in index, but not sparse" +msgstr "Директорія \"%s\" присутня в індексі, але не є розрідженою" + +msgid "corrupted cache-tree has entries not present in index" +msgstr "пошкоджене cache-tree має записи, яких немає в індексі" + +#, c-format +msgid "%s with flags 0x%x should not be in cache-tree" +msgstr "%s з прапорцями 0x%x не слід бути в cache-tree" + +#, c-format +msgid "bad subtree '%.*s'" +msgstr "невірне піддерево \"%.*s\"" + +#, c-format +msgid "cache-tree for path %.*s does not match. Expected %s got %s" +msgstr "cache-tree для шляху %.*s не співпадає. Очікувалось %s отримано %s" + msgid "terminating chunk id appears earlier than expected" msgstr "ідентифікатор завершення фрагмента зʼявився раніше, ніж очікувалось" @@ -15007,16 +15149,16 @@ msgid "" "to convert the grafts into replace refs.\n" "\n" "Turn this message off by running\n" -"\"git config advice.graftFileDeprecated false\"" +"\"git config set advice.graftFileDeprecated false\"" msgstr "" "Підтримка /info/grafts застаріла\n" -"і буде вилучена в одній з наступних версій Git.\n" +"і буде вилучена у наступній версії Git'у.\n" "\n" -"Будь ласка, скористайтесь \"git replace --convert-graft-file\"\n" -"щоб перетворити щепи на заміни посилань.\n" +"Будь ласка, використовуйте \"git replace --convert-graft-file\"\n" +"щоб перетворити прищепи на замінювані посилання.\n" "\n" "Щоб вимкнути це повідомлення, виконайте\n" -"\"git config advice.graftFileDeprecated false\"" +"\"git config set advice.graftFileDeprecated false\"" #, c-format msgid "commit %s exists in commit-graph but not in the object database" @@ -15834,6 +15976,19 @@ msgstr "url не має схеми: %s" msgid "credential url cannot be parsed: %s" msgstr "неможливо розібрати url облікових даних: %s" +#, c-format +msgid "invalid timeout '%s', expecting a non-negative integer" +msgstr "неприпустимий таймаут \"%s\", очікується невідʼємне ціле число" + +#, c-format +msgid "invalid init-timeout '%s', expecting a non-negative integer" +msgstr "" +"неприпустимий початковий таймаут \"%s\", очікується невідʼємне ціле число" + +#, c-format +msgid "invalid max-connections '%s', expecting an integer" +msgstr "неприпустимі максимальні з'єднання \"%s\", очікується число" + msgid "in the future" msgstr "у майбутньому" @@ -16552,6 +16707,21 @@ msgstr "невірний шлях до простору імен git \"%s\"" msgid "too many args to run %s" msgstr "забагато аргументів для запуску %s" +#, c-format +msgid "" +"You are attempting to fetch %s, which is in the commit graph file but not in " +"the object database.\n" +"This is probably due to repo corruption.\n" +"If you are attempting to repair this repo corruption by refetching the " +"missing object, use 'git fetch --refetch' with the missing object." +msgstr "" +"Ви намагаєтеся отримати %s, який знаходиться у файлі коміт-графа, але не в " +"базі даних обʼєктів.\n" +"Ймовірно, це повʼязано з пошкодженням репозиторію.\n" +"Якщо ви намагаєтеся виправити це пошкодження репозиторію повторним " +"отриманням відсутнього обʼєкта, скористайтеся командою \"git fetch --" +"refetch\" з відсутнім обʼєктом." + msgid "git fetch-pack: expected shallow list" msgstr "git fetch-pack: очікувався неглибокий список" @@ -17140,11 +17310,12 @@ msgstr[2] "" #, c-format msgid "" "The '%s' hook was ignored because it's not set as executable.\n" -"You can disable this warning with `git config advice.ignoredHook false`." +"You can disable this warning with `git config set advice.ignoredHook false`." msgstr "" -"Гачок \"%s\" було проігноровано, оскільки він не визначений як виконуваний.\n" -"Ви можете вимкнути це попередження за допомогою \"git config advice." -"ignoredHook false\"." +"Гачок \"%s\" було проігноровано, оскільки він не визначений як придатний для " +"виконання.\n" +"Ви можете вимкнути це попередження за допомогою \"git config set " +"advice.ignoredHook false\"." msgid "not a git repository" msgstr "не є git сховищем" @@ -17161,15 +17332,9 @@ msgstr "" msgid "Delegation control is not supported with cURL < 7.22.0" msgstr "Контроль делегування не підтримується з cURL < 7.22.0" -msgid "Public key pinning not supported with cURL < 7.39.0" -msgstr "Закріплення відкритих ключів не підтримується з cURL < 7.39.0" - msgid "Unknown value for http.proactiveauth" msgstr "Невідоме значення для http.proactiveauth" -msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0" -msgstr "CURLSSLOPT_NO_REVOKE не підтримується з cURL < 7.44.0" - #, c-format msgid "Unsupported SSL backend '%s'. Supported SSL backends:" msgstr "Непідтримуваний SSL обробник \"%s\". Підтримувані SSL обробники:" @@ -17330,13 +17495,16 @@ msgstr "" msgid "Unable to create '%s.lock': %s" msgstr "Не вдалося створити \"%s.lock\": %s" +msgid "unable to create temporary object directory" +msgstr "не вдалося створити тимчасову директорію обʼєкта" + #, c-format msgid "could not write loose object index %s" msgstr "не вдалося записати індекс вільного обʼєкта %s" #, c-format -msgid "failed to write loose object index %s\n" -msgstr "не вдалося записати індекс вільного обʼєкта %s\n" +msgid "failed to write loose object index %s" +msgstr "не вдалося записати індекс вільного обʼєкта %s" #, c-format msgid "unexpected line: '%s'" @@ -17352,6 +17520,10 @@ msgstr "виявлено цитований CRLF" msgid "unable to format message: %s" msgstr "не вдалося відформатувати допис: %s" +#, c-format +msgid "invalid marker-size '%s', expecting an integer" +msgstr "неправильний розмір маркера \"%s\", очікується число" + #, c-format msgid "Failed to merge submodule %s (not checked out)" msgstr "Не вдалося обʼєднати підмодуль %s (не активне)" @@ -17887,6 +18059,17 @@ msgstr "не вдалося завантажити пакунок" msgid "could not open index for %s" msgstr "не вдалося відкрити індекс для %s" +#, c-format +msgid "unable to link '%s' to '%s'" +msgstr "не вдалося звʼязати \"%s\" з \"%s\"" + +#, c-format +msgid "failed to clear multi-pack-index at %s" +msgstr "не вдалося очистити multi-pack-index при %s" + +msgid "cannot write incremental MIDX with bitmap" +msgstr "неможливо записати інкрементний MIDX з bitmap" + msgid "ignoring existing multi-pack-index; checksum mismatch" msgstr "" "ігнорування існуючого multi-pack-index; невідповідність контрольних сум" @@ -17916,18 +18099,33 @@ msgstr "немає файлів пакунків для індексації." msgid "refusing to write multi-pack .bitmap without any objects" msgstr "відмовлено в записі мультіпакункового .bitmap без обʼєктів" +msgid "unable to create temporary MIDX layer" +msgstr "не вдалося створити тимчасовий шар MIDX" + msgid "could not write multi-pack bitmap" msgstr "не вдалося записати мультіпакунковий bitmap" +msgid "unable to open multi-pack-index chain file" +msgstr "не вдалося відкрити ланцюжковий файл multi-pack-index" + +msgid "unable to rename new multi-pack-index layer" +msgstr "не вдалося перейменувати новий multi-pack-index шар" + msgid "could not write multi-pack-index" msgstr "не вдалося записати multi-pack-index" +msgid "cannot expire packs from an incremental multi-pack-index" +msgstr "неможливо видалити пакунки з інкрементним multi-pack-index" + msgid "Counting referenced objects" msgstr "Підрахунок обʼєктів, на які є посилання" msgid "Finding and deleting unreferenced packfiles" msgstr "Пошук і видалення файлів пакунків без посилань" +msgid "cannot repack an incremental multi-pack-index" +msgstr "неможливо перепакувати інкрементний multi-pack-index" + msgid "could not start pack-objects" msgstr "не вдалося розпочати pack-objects" @@ -17990,6 +18188,27 @@ msgstr "" "multi-pack-index назви пакунків знаходяться у невірній послідовності: \"%s\" " "перед \"%s\"" +msgid "multi-pack-index chain file too small" +msgstr "ланцюжковий файл multi-pack-index занадто малий" + +#, c-format +msgid "pack count in base MIDX too high: %" +msgstr "кількість пакунків у базовому MIDX занадто велика: %" + +#, c-format +msgid "object count in base MIDX too high: %" +msgstr "кількість обʼєктів у базовому MIDX занадто велика: %" + +#, c-format +msgid "invalid multi-pack-index chain: line '%s' not a hash" +msgstr "неприпустимий multi-pack-index ланцюжок: рядок \"%s\" не є хешем" + +msgid "unable to find all multi-pack index files" +msgstr "не вдалося знайти всі файли multi-pack-index" + +msgid "invalid MIDX object position, MIDX is likely corrupt" +msgstr "неприпустима позиція MIDX обʼєкта, ймовірно, MIDX пошкоджено" + #, c-format msgid "bad pack-int-id: %u (%u total packs)" msgstr "невірний pack-int-id: %u (%u всього пакунків)" @@ -18008,10 +18227,6 @@ msgstr "" msgid "multi-pack-index large offset out of bounds" msgstr "large offset multi-pack-index виходить за межі" -#, c-format -msgid "failed to clear multi-pack-index at %s" -msgstr "не вдалося очистити multi-pack-index при %s" - msgid "multi-pack-index file exists, but failed to parse" msgstr "multi-pack-index файл існує, але його не вдалося розібрати" @@ -18220,6 +18435,14 @@ msgstr "упакований обʼєкт %s (що зберігається у % msgid "missing mapping of %s to %s" msgstr "відсутнє зіставлення %s до %s" +#, c-format +msgid "unable to open %s" +msgstr "не вдалося відкрити %s" + +#, c-format +msgid "files '%s' and '%s' differ in contents" +msgstr "файли \"%s\" та \"%s\" відрізняються за вмістом" + #, c-format msgid "unable to write file %s" msgstr "не вдалося записати файл %s" @@ -18304,10 +18527,6 @@ msgstr "%s: непідтримуваний тип файлу" msgid "%s is not a valid '%s' object" msgstr "%s не є допустимим \"%s\" обʼєктом" -#, c-format -msgid "unable to open %s" -msgstr "не вдалося відкрити %s" - #, c-format msgid "hash mismatch for %s (expected %s)" msgstr "невідповідність хешу для %s (очікувалось %s)" @@ -18409,7 +18628,7 @@ msgid "" "\n" "where \"$br\" is somehow empty and a 40-hex ref is created. Please\n" "examine these refs and maybe delete them. Turn this message off by\n" -"running \"git config advice.objectNameWarning false\"" +"running \"git config set advice.objectNameWarning false\"" msgstr "" "Зазвичай Git ніколи не створює посилання, яке закінчується 40-hex " "символами,\n" @@ -18584,13 +18803,6 @@ msgstr "у мультіпакунковому bitmap відсутній необ msgid "could not open pack %s" msgstr "не вдалося відкрити пакунок %s" -msgid "could not determine MIDX preferred pack" -msgstr "не вдалося визначити бажаний пакунок MIDX" - -#, c-format -msgid "preferred pack (%s) is invalid" -msgstr "бажаний пакунок (%s) є неприпустимим" - msgid "corrupt bitmap lookup table: triplet position out of index" msgstr "пошкоджена bitmap таблиця пошуку: триплетна позиція поза індексом" @@ -19223,7 +19435,7 @@ msgstr "багатоступеневі записи для злитого фай #, c-format msgid "unordered stage entries for '%s'" -msgstr "невпорядковані записи індексу для '%s'" +msgstr "невпорядковані записи індексу для \"%s\"" #, c-format msgid "unable to create load_cache_entries thread: %s" @@ -19536,6 +19748,10 @@ msgstr "очікувалась додатна ширина з %%(align) част msgid "expected format: %%(ahead-behind:)" msgstr "очікуваний формат: %%(ahead-behind:<комітоподібне>)" +#, c-format +msgid "expected format: %%(is-base:)" +msgstr "очікуваний формат: %%(is-base:<комітоподібне>)" + #, c-format msgid "malformed field name: %.*s" msgstr "невірно сформована назва поля: %.*s" @@ -19711,17 +19927,25 @@ msgstr "лог для посилання %s несподівано заверш msgid "log for %s is empty" msgstr "лог для %s порожній" -msgid "refusing to force and skip creation of reflog" -msgstr "відмовлено в примусовому пропуску створення рефлогу" - #, c-format -msgid "refusing to update ref with bad name '%s'" -msgstr "відмовлено в оновленні посилання з невірною назвою \"%s\"" +msgid "refusing to update reflog for pseudoref '%s'" +msgstr "відмовлено в оновленні псевдопосилання \"%s\"" #, c-format msgid "refusing to update pseudoref '%s'" msgstr "відмовлено в оновленні псевдопосилання \"%s\"" +#, c-format +msgid "refusing to update reflog with bad name '%s'" +msgstr "відмовлено в оновленні reflog з невірною назвою \"%s\"" + +#, c-format +msgid "refusing to update ref with bad name '%s'" +msgstr "відмовлено в оновленні посилання з невірною назвою \"%s\"" + +msgid "refusing to force and skip creation of reflog" +msgstr "відмовлено в примусовому пропуску створення рефлогу" + #, c-format msgid "update_ref failed for ref '%s': %s" msgstr "update_ref завершився невдало для посилання \"%s\": %s" @@ -19771,6 +19995,17 @@ msgstr "" "неможливо заблокувати посилання \"%s\": очікувалось символьне посилання з " "призначенням \"%s\", але це звичайне посилання" +#, c-format +msgid "cannot read ref file '%s'" +msgstr "неможливо прочитати файл посилання \"%s\"" + +#, c-format +msgid "cannot open directory %s" +msgstr "неможливо відкрити директорію %s" + +msgid "Checking references consistency" +msgstr "Перевірка співпадіння посилань" + #, c-format msgid "refname is dangerous: %s" msgstr "refname є небезпечним: %s" @@ -19897,8 +20132,8 @@ msgstr "віддалений сервер надіслав неочікуван msgid "unable to rewind rpc post data - try increasing http.postBuffer" msgstr "" -"не вдалося перемотати вперед rpc post дані - спробуйте збільшити http." -"postBuffer" +"не вдалося перемотати вперед rpc post дані - спробуйте збільшити " +"http.postBuffer" #, c-format msgid "remote-curl: bad line length character: %.4s" @@ -19973,7 +20208,7 @@ msgstr "remote-curl: невідома команда \"%s\" з git" #, c-format msgid "config remote shorthand cannot begin with '/': %s" -msgstr "скорочення віддаленої конфігураціі не може починатися з '/': %s" +msgstr "скорочення віддаленої конфігураціі не може починатися з \"/\": %s" msgid "more than one receivepack given, using the first" msgstr "надано більше одного пакунка для отримання, використано перший" @@ -19981,9 +20216,13 @@ msgstr "надано більше одного пакунка для отрим msgid "more than one uploadpack given, using the first" msgstr "надано більше одного пакунка для завантаження, використано перший" +#, c-format +msgid "unrecognized followRemoteHEAD value '%s' ignored" +msgstr "нерозпізнане followRemoteHEAD значення \"%s\" було проігноровано" + #, c-format msgid "unrecognized value transfer.credentialsInUrl: '%s'" -msgstr "нерозпізнане значення transfer.credentialsInUrl: '%s'" +msgstr "нерозпізнане значення transfer.credentialsInUrl: \"%s\"" #, c-format msgid "URL '%s' uses plaintext credentials" @@ -20003,11 +20242,11 @@ msgstr "%s відстежує як %s, так і %s" #, c-format msgid "key '%s' of pattern had no '*'" -msgstr "ключ '%s' шаблону не містив '*'" +msgstr "ключ \"%s\" шаблону не містив '*'" #, c-format msgid "value '%s' of pattern has no '*'" -msgstr "значення '%s' шаблону не містить '*'" +msgstr "значення \"%s\" шаблону не містить '*'" #, c-format msgid "src refspec %s does not match any" @@ -20106,11 +20345,11 @@ msgstr "HEAD не вказує на гілку" #, c-format msgid "no such branch: '%s'" -msgstr "немає такої гілки: '%s'" +msgstr "немає такої гілки: \"%s\"" #, c-format msgid "no upstream configured for branch '%s'" -msgstr "першоджерельне сховище не налаштовано для гілки '%s'" +msgstr "першоджерельне сховище не налаштовано для гілки \"%s\"" #, c-format msgid "upstream branch '%s' not stored as a remote-tracking branch" @@ -20131,7 +20370,7 @@ msgid "push refspecs for '%s' do not include '%s'" msgstr "надіслані визначники посилань для \"%s\" не включають \"%s\"" msgid "push has no destination (push.default is 'nothing')" -msgstr "надсилання не має призначення (push.default дорівнює 'nothing')" +msgstr "надсилання не має призначення (push.default дорівнює \"nothing\")" msgid "cannot resolve 'simple' push to a single destination" msgstr "" @@ -20184,7 +20423,7 @@ msgstr[0] "" msgstr[1] "" "Ваша гілка відстає від \"%s\" на %d коміти, і її можна перемотати вперед.\n" msgstr[2] "" -"Ваша гілка відстає від гілки '%s' на %d комітів, і її можна перемотати " +"Ваша гілка відстає від гілки \"%s\" на %d комітів, і її можна перемотати " "вперед.\n" msgid " (use \"git pull\" to update your local branch)\n" @@ -20219,7 +20458,7 @@ msgstr "неможливо розібрати очікувану назву об #, c-format msgid "cannot strip one component off url '%s'" -msgstr "неможливо вилучити один компонент з url '%s'" +msgstr "неможливо вилучити один компонент з url \"%s\"" #, c-format msgid "bad replace ref name: %s" @@ -20429,12 +20668,15 @@ msgstr "" msgid "create repository within 'src' directory" msgstr "створити сховище в директорії \"src\"" +msgid "specify if tags should be fetched during clone" +msgstr "вказати, чи потрібно отримувати теги під час клонування" + msgid "" "scalar clone [--single-branch] [--branch ] [--full-clone]\n" -"\t[--[no-]src] []" +"\t[--[no-]src] [--[no-]tags] []" msgstr "" "scalar clone [--single-branch] [--branch <головна-гілка>] [--full-clone]\n" -"\t[--[no-]src] [<коренева-директорія>]" +"\t[--[no-]src] [--[no-]tags] [<коренева-директорія-проекту>]" #, c-format msgid "cannot deduce worktree name from '%s'" @@ -20452,6 +20694,10 @@ msgstr "не вдалося отримати гілку за замовчува msgid "could not configure remote in '%s'" msgstr "не вдалося налаштувати віддалене сховище в \"%s\"" +#, c-format +msgid "could not disable tags in '%s'" +msgstr "не вдалося вимкнути теги в \"%s\"" + #, c-format msgid "could not configure '%s'" msgstr "не вдалося налаштувати \"%s\"" @@ -20983,7 +21229,7 @@ msgid "" msgstr "" "\"reword\" не приймає коміти злиття. Якщо ви хочете\n" "відтворити злиття та змінити текст допису, використовуйте\n" -"\"merge -c\" для коміта." +"\"merge -c\" для коміта" #. TRANSLATORS: 'edit', 'merge -C' and 'break' should #. not be translated. @@ -21525,6 +21771,10 @@ msgstr "неможливо повернутися до поточної робо msgid "failed to stat '%*s%s%s'" msgstr "не вдалося записати \"%*s%s%s\"" +#, c-format +msgid "safe.directory '%s' not absolute" +msgstr "safe.directory \"%s\" не є абсолютною" + #, c-format msgid "" "detected dubious ownership in repository at '%s'\n" @@ -21863,7 +22113,7 @@ msgstr "Не вдалося оновити підмодуль \"%s\"." #, c-format msgid "submodule git dir '%s' is inside git dir '%.*s'" -msgstr "підмодуль git dir \"%s\" знаходиться всередині git директорії \"%*s\"" +msgstr "підмодуль git dir \"%s\" знаходиться всередині git директорії \"%.*s\"" #, c-format msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link" @@ -21936,6 +22186,9 @@ msgstr "коміт %s не позначений як досяжний" msgid "too many commits marked reachable" msgstr "забагато комітів позначено як досяжні" +msgid "could not determine MIDX preferred pack" +msgstr "не вдалося визначити бажаний пакунок MIDX" + msgid "test-tool serve-v2 []" msgstr "test-tool serve-v2 [<опції>]" @@ -22001,6 +22254,24 @@ msgstr "токен" msgid "command token to send to the server" msgstr "токен команди для відправки на сервер" +msgid "unit-test []" +msgstr "unit-test [<опції>]" + +msgid "immediately exit upon the first failed test" +msgstr "вихід відразу після першого невдалого тесту" + +msgid "suite[::test]" +msgstr "suite[::test]" + +msgid "run only test suite or individual test " +msgstr "запустити тільки набір тестів або окремий тест " + +msgid "suite" +msgstr "набір" + +msgid "exclude test suite " +msgstr "виключити набір тестів " + #, c-format msgid "running trailer command '%s' failed" msgstr "не вдалося виконати команду трейлера \"%s\"" @@ -22580,6 +22851,9 @@ msgstr ".git файл пошкоджено" msgid ".git file incorrect" msgstr ".git файл не є коректним" +msgid ".git file absolute/relative path mismatch" +msgstr "неспівпадіння абсолютного/відносного шляху до .git файлу" + msgid "not a valid path" msgstr "неприпустимий шлях" @@ -22595,6 +22869,9 @@ msgstr "не вдалося знайти сховище; файл .git пошк msgid "gitdir unreadable" msgstr "нечитабельна git директорія" +msgid "gitdir absolute/relative path mismatch" +msgstr "неспівпадіння абсолютного/відносного шляху git директорії" + msgid "gitdir incorrect" msgstr "невірна git директорія" @@ -22630,6 +22907,13 @@ msgstr "не вдалося скинути %s в \"%s\"" msgid "failed to set extensions.worktreeConfig setting" msgstr "не вдалося встановити extensions.worktreeConfig параметр" +msgid "unable to upgrade repository format to support relative worktrees" +msgstr "" +"не вдалося оновити формат сховища для підтримки відносних робочих дерев" + +msgid "unable to set extensions.relativeWorktrees setting" +msgstr "не вдалося встановити параметр extensions.relativeWorktrees" + #, c-format msgid "could not setenv '%s'" msgstr "не вдалося встановити змінну оточення \"%s\"" @@ -22965,7 +23249,7 @@ msgstr "" #, c-format msgid "You are currently bisecting, started from branch '%s'." -msgstr "Наразі ви робите бісекцію, починаючи з гілки '%s'." +msgstr "Наразі ви робите бісекцію, починаючи з гілки \"%s\"." msgid "You are currently bisecting." msgstr "Наразі ви робите бісекцію." @@ -23198,6 +23482,9 @@ msgstr "\"%s.final\" містить створений лист.\n" msgid "--dump-aliases incompatible with other options\n" msgstr "--dump-aliases несумісна з іншими опціями\n" +msgid "--dump-aliases and --translate-aliases are mutually exclusive\n" +msgstr "--dump-aliases і --translate-aliases є взаємовиключними\n" + msgid "" "fatal: found configuration options for 'sendmail'\n" "git-send-email is configured with the sendemail.* options - note the 'e'.\n" @@ -23370,8 +23657,8 @@ msgstr "" " Наведений вище список копій було розширено додатковими\n" " адресами, знайденими у дописі до коміту латки. Зазвичай\n" " send-email запитує перед надсиланням, коли це трапляється.\n" -" Цю поведінку можна контролювати за допомогою параметра sendemail." -"confirm\n" +" Цю поведінку можна контролювати за допомогою параметра " +"sendemail.confirm\n" " налаштування конфігурації.\n" "\n" " Для отримання додаткової інформації виконайте команду \"git send-email --" -- cgit v1.2.3 From bba9dd6a96c464e2b32226be81cb1f30257c78c0 Mon Sep 17 00:00:00 2001 From: Teng Long Date: Sat, 4 Jan 2025 00:30:11 +0800 Subject: l10n: zh_CN: updated translation for 2.48 Signed-off-by: Teng Long --- po/zh_CN.po | 301 +++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 238 insertions(+), 63 deletions(-) diff --git a/po/zh_CN.po b/po/zh_CN.po index 55d2aee627..12a0fb510b 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -154,8 +154,8 @@ msgid "" msgstr "" "Project-Id-Version: Git\n" "Report-Msgid-Bugs-To: Git Mailing List \n" -"POT-Creation-Date: 2024-10-05 03:31+0800\n" -"PO-Revision-Date: 2024-10-05 03:32+0800\n" +"POT-Creation-Date: 2025-01-02 20:43+0800\n" +"PO-Revision-Date: 2025-01-05 19:01+0800\n" "Last-Translator: Teng Long \n" "Language-Team: GitHub \n" "Language: zh_CN\n" @@ -886,10 +886,10 @@ msgstr "只有二进制文件被修改。" #, c-format msgid "" "\n" -"Disable this message with \"git config advice.%s false\"" +"Disable this message with \"git config set advice.%s false\"" msgstr "" "\n" -"使用 \"git config advice.%s false\" 来关闭此消息" +"使用 \"git config set advice.%s false\" 来关闭此消息" #: advice.c #, c-format @@ -1778,9 +1778,10 @@ msgstr "不是一个有效的对象名:%s" msgid "not a tree object: %s" msgstr "不是一个树对象:%s" -#: archive.c builtin/clone.c -msgid "unable to checkout working tree" -msgstr "不能检出工作区" +#: archive.c +#, c-format +msgid "failed to unpack tree object %s" +msgstr "无法解包树对象 %s" #: archive.c #, c-format @@ -1957,7 +1958,7 @@ msgstr "忽略过大的 gitattributes 数据对象 '%s'" #: attr.c msgid "cannot use --attr-source or GIT_ATTR_SOURCE without repo" -msgstr "无法在没有存储库的情况下使用 --attr-source 或 GIT_ATTR_SOURCE" +msgstr "无法在没有仓库的情况下使用 --attr-source 或 GIT_ATTR_SOURCE" #: attr.c msgid "bad --attr-source or GIT_ATTR_SOURCE" @@ -4813,7 +4814,7 @@ msgstr "未知的冲突风格 '%s'" msgid "perform a 3-way merge with the new branch" msgstr "和新的分支执行三方合并" -#: builtin/checkout.c builtin/log.c parse-options.h +#: builtin/checkout.c builtin/log.c builtin/range-diff.c parse-options.h msgid "style" msgstr "风格" @@ -4842,8 +4843,8 @@ msgid "update ignored files (default)" msgstr "更新忽略的文件(默认)" #: builtin/checkout.c -msgid "do not check if another worktree is holding the given ref" -msgstr "不检查指定的引用是否被其他工作区所占用" +msgid "do not check if another worktree is using this branch" +msgstr "不检查其他工作区是否正在使用该分支" #: builtin/checkout.c msgid "checkout our version for unmerged files" @@ -5222,14 +5223,13 @@ msgstr "创建一个指定深度的浅克隆" msgid "create a shallow clone since a specific time" msgstr "从一个特定时间创建一个浅克隆" -#: builtin/clone.c builtin/fetch.c builtin/pull.c builtin/rebase.c -#: builtin/replay.c -msgid "revision" -msgstr "版本" +#: builtin/clone.c builtin/fetch.c builtin/pull.c +msgid "ref" +msgstr "引用" #: builtin/clone.c builtin/fetch.c builtin/pull.c -msgid "deepen history of shallow clone, excluding rev" -msgstr "深化浅克隆的历史,除了特定版本" +msgid "deepen history of shallow clone, excluding ref" +msgstr "深化浅克隆的历史,除了给定的引用" #: builtin/clone.c builtin/submodule--helper.c msgid "clone only one branch, HEAD or --branch" @@ -5390,6 +5390,10 @@ msgstr "无法初始化稀疏检出" msgid "remote HEAD refers to nonexistent ref, unable to checkout" msgstr "远程 HEAD 指向一个不存在的引用,无法检出" +#: builtin/clone.c +msgid "unable to checkout working tree" +msgstr "不能检出工作区" + #: builtin/clone.c msgid "unable to write parameters to config file" msgstr "无法将参数写入配置文件" @@ -6368,10 +6372,9 @@ msgstr "" #: builtin/config.c msgid "" "git config unset [] [--all] [--value=] [--fixed-value] " -" " +"" msgstr "" -"git config unset [<文件选项>] [--all] [--value=<值>] [--fixed-value] <名称> <" -"值>" +"git config unset [<文件选项>] [--all] [--value=<值>] [--fixed-value] <名称>" #: builtin/config.c msgid "git config rename-section [] " @@ -6915,12 +6918,8 @@ msgstr "已遍历 %lu 个提交\n" #: builtin/describe.c #, c-format -msgid "" -"more than %i tags found; listed %i most recent\n" -"gave up search at %s\n" -msgstr "" -"发现多于 %i 个标签,列出最近的 %i 个\n" -"在 %s 放弃搜索\n" +msgid "found %i tags; gave up search at %s\n" +msgstr "找到 %i 个标签;在 %s 处放弃搜索\n" #: builtin/describe.c #, c-format @@ -7468,6 +7467,21 @@ msgstr "%s 不是一个有效的对象" msgid "the object %s does not exist" msgstr "对象 '%s' 不存在" +#: builtin/fetch.c +#, c-format +msgid "" +"Run 'git remote set-head %s %s' to follow the change, or set\n" +"'remote.%s.followRemoteHEAD' configuration option to a different value\n" +"if you do not want to see this message. Specifically running\n" +"'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n" +"until the remote changes HEAD to something else." +msgstr "" +"运行 'git remote set-head %s %s' 以跟随更改,或者\n" +"如果您不想看到此消息,则将'remote.%s.followRemoteHEAD' 配置选项设置为不同的" +"值。\n" +"特别地,运行 'git config set remote.%s.followRemoteHEAD %s' 将禁用警告,直到" +"远程将 HEAD 更改为其他内容。\"" + #: builtin/fetch.c msgid "multiple branches detected, incompatible with --set-upstream" msgstr "检测到多分支,和 --set-upstream 不兼容" @@ -7635,6 +7649,10 @@ msgstr "引用映射" msgid "specify fetch refmap" msgstr "指定获取操作的引用映射" +#: builtin/fetch.c builtin/pull.c builtin/rebase.c builtin/replay.c +msgid "revision" +msgstr "版本" + #: builtin/fetch.c builtin/pull.c msgid "report that we have only objects reachable from this object" msgstr "报告我们只拥有从该对象开始可达的对象" @@ -7830,7 +7848,7 @@ msgstr "存储着仓库路径列表的配置项键名" #: builtin/for-each-repo.c msgid "keep going even if command fails in a repository" -msgstr "即使存储库中的命令失败,仍继续执行" +msgstr "即使仓库中的命令失败,仍继续执行" #: builtin/for-each-repo.c msgid "missing --config=" @@ -8546,8 +8564,24 @@ msgid "%s scheduler is not available" msgstr "%s 调度器不可用" #: builtin/gc.c -msgid "another process is scheduling background maintenance" -msgstr "另外一个进程正运行于后台维护" +#, c-format +msgid "" +"unable to create '%s.lock': %s.\n" +"\n" +"Another scheduled git-maintenance(1) process seems to be running in this\n" +"repository. Please make sure no other maintenance processes are running and\n" +"then try again. If it still fails, a git-maintenance(1) process may have\n" +"crashed in this repository earlier: remove the file manually to continue." +msgstr "" +"无法创建 '%s.lock':%s。\n" +"\n" +"另一个已计划的 git-maintenance(1) 进程似乎正在该仓库中运行。\n" +"请确保没有其他维护进程正在运行,然后重试。如果仍然运行失败,则\n" +"git-maintenance(1) 进程可能之前已在此仓库中崩溃:请手动删除该文件以继续。" + +#: builtin/gc.c +msgid "cannot acquire lock for scheduled background maintenance" +msgstr "无法获取计划的后台维护锁" #: builtin/gc.c msgid "git maintenance start [--scheduler=]" @@ -9272,6 +9306,23 @@ msgid_plural "chain length = %d: %lu objects" msgstr[0] "链长 = %d: %lu 对象" msgstr[1] "链长 = %d: %lu 对象" +#: builtin/index-pack.c +msgid "could not start pack-objects to repack local links" +msgstr "无法启动 pack-objects 来重新打包本地链接" + +#: builtin/index-pack.c +msgid "failed to feed local object to pack-objects" +msgstr "无法将本地对象提供给 pack-objects" + +#: builtin/index-pack.c +msgid "index-pack: Expecting full hex object ID lines only from pack-objects." +msgstr "" +"index-pack:期望仅从 pack-objects 的输出行中获得完整的十六进制对象 ID。" + +#: builtin/index-pack.c +msgid "could not finish pack-objects to repack local links" +msgstr "无法完成 pack-objects 来重新打包本地链接" + #: builtin/index-pack.c msgid "Cannot come back to cwd" msgstr "无法返回当前工作目录" @@ -9286,6 +9337,10 @@ msgstr "错误选项 %s" msgid "unknown hash algorithm '%s'" msgstr "未知的哈希算法 '%s'" +#: builtin/index-pack.c +msgid "--promisor cannot be used with a pack name" +msgstr "--promisor 无法与包名称一起使用" + #: builtin/index-pack.c msgid "--stdin requires a git repository" msgstr "--stdin 需要 git 仓库" @@ -11002,11 +11057,11 @@ msgstr "git notes [--ref <注解引用>] [list [<对象>]]" msgid "" "git notes [--ref ] add [-f] [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" msgstr "" "git notes [--ref <注解引用>] add [-f] [--allow-empty] [--[no-]separator|--" "separator=<分段符>] [--[no-]stripspace] [-m <说明> | -F <文件> | (-c | -C) <" -"对象>] [<对象>]" +"对象>] [<对象>] [-e]" #: builtin/notes.c msgid "git notes [--ref ] copy [-f] " @@ -11016,11 +11071,11 @@ msgstr "git notes [--ref <注解引用>] copy [-f] <源对象> <目标对象>" msgid "" "git notes [--ref ] append [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" msgstr "" "git notes [--ref <注解引用>] append [--allow-empty] [--[no-]separator|--" "separator=<分段符>] [--[no-]stripspace] [-m <说明> | -F <文件> | (-c | -C) <" -"对象>] [<对象>]" +"对象>] [<对象>] [-e]" #: builtin/notes.c msgid "git notes [--ref ] edit [--allow-empty] []" @@ -11171,6 +11226,10 @@ msgstr "注解内容到一个文件中" msgid "reuse and edit specified note object" msgstr "重用和编辑指定的注解对象" +#: builtin/notes.c +msgid "edit note message in editor" +msgstr "在编辑器中编辑注释说明" + #: builtin/notes.c msgid "reuse specified note object" msgstr "重用指定的注解对象" @@ -11784,6 +11843,10 @@ msgstr "处理丢失的对象" msgid "do not pack objects in promisor packfiles" msgstr "不要打包 promisor 包文件中的对象" +#: builtin/pack-objects.c +msgid "implies --missing=allow-any" +msgstr "暗含 --missing=allow-any" + #: builtin/pack-objects.c msgid "respect islands during delta compression" msgstr "在增量压缩时参考数据岛" @@ -13668,6 +13731,33 @@ msgid_plural " Local refs configured for 'git push'%s:" msgstr[0] " 为 'git push' 配置的本地引用%s:" msgstr[1] " 为 'git push' 配置的本地引用%s:" +#: builtin/remote.c +#, c-format +msgid "'%s/HEAD' is unchanged and points to '%s'\n" +msgstr "'%s/HEAD' 未改变并指向 '%s'\n" + +#: builtin/remote.c +#, c-format +msgid "'%s/HEAD' has changed from '%s' and now points to '%s'\n" +msgstr "'%s/HEAD' 已从 '%s' 更改,现在指向 '%s'\n" + +#: builtin/remote.c +#, c-format +msgid "'%s/HEAD' is now created and points to '%s'\n" +msgstr "'%s/HEAD' 现已创建并指向 '%s'\n" + +#: builtin/remote.c +#, c-format +msgid "'%s/HEAD' was detached at '%s' and now points to '%s'\n" +msgstr "'%s/HEAD' 在 '%s' 处分离并且现在指向 '%s'\n" + +#: builtin/remote.c +#, c-format +msgid "" +"'%s/HEAD' used to point to '%s' (which is not a remote branch), but now " +"points to '%s'\n" +msgstr "'%s/HEAD' 曾指向 '%s'(不是远程分支),但现在指向 '%s'\n" + #: builtin/remote.c msgid "set refs/remotes//HEAD according to remote" msgstr "根据远程设置 refs/remotes/<名称>/HEAD" @@ -13696,7 +13786,7 @@ msgstr "不是一个有效引用:%s" #: builtin/remote.c #, c-format -msgid "Could not setup %s" +msgid "Could not set up %s" msgstr "不能设置 %s" # 译者:注意保持前导空格 @@ -17034,6 +17124,10 @@ msgstr "设置跟踪模式(参见 git-branch(1))" msgid "try to match the new branch name with a remote-tracking branch" msgstr "尝试为新分支名匹配一个远程跟踪分支" +#: builtin/worktree.c +msgid "use relative paths for worktrees" +msgstr "对工作区使用相对路径" + #: builtin/worktree.c diff.c parse-options.c #, c-format msgid "options '%s', '%s', and '%s' cannot be used together" @@ -17370,6 +17464,30 @@ msgstr "不能创建 '%s'" msgid "index-pack died" msgstr "index-pack 终止" +#: cache-tree.c +#, c-format +msgid "directory '%s' is present in index, but not sparse" +msgstr "目录 '%s' 存在于索引中,但不是稀疏的" + +#: cache-tree.c unpack-trees.c +msgid "corrupted cache-tree has entries not present in index" +msgstr "损坏的缓存树包含索引中不存在的条目" + +#: cache-tree.c +#, c-format +msgid "%s with flags 0x%x should not be in cache-tree" +msgstr "标志位为 0x%2$x 的 %1$s 不应位于缓存树中" + +#: cache-tree.c +#, c-format +msgid "bad subtree '%.*s'" +msgstr "损坏的子树 '%.*s'" + +#: cache-tree.c +#, c-format +msgid "cache-tree for path %.*s does not match. Expected %s got %s" +msgstr "路径 %.*s 的缓存树不匹配。预期为 %s,实际为 %s" + #: chunk-format.c msgid "terminating chunk id appears earlier than expected" msgstr "终止块 ID 比预期更早出现" @@ -18477,15 +18595,15 @@ msgid "" "to convert the grafts into replace refs.\n" "\n" "Turn this message off by running\n" -"\"git config advice.graftFileDeprecated false\"" +"\"git config set advice.graftFileDeprecated false\"" msgstr "" "对 /info/grafts 的支持已过时,并将在\n" "未来的Git版本中被移除。\n" "\n" "请使用 \"git replace --convert-graft-file\" 将\n" -"grafts 转换为替换引用。\n" +"(提交)移植转换为替换引用。\n" "\n" -"设置 \"git config advice.graftFileDeprecated false\"\n" +"运行 \"git config set advice.graftFileDeprecated false\"\n" "可关闭本消息" #: commit.c @@ -19485,6 +19603,21 @@ msgstr "URL 没有 scheme:%s" msgid "credential url cannot be parsed: %s" msgstr "不能解析凭据 URL:%s" +#: daemon.c +#, c-format +msgid "invalid timeout '%s', expecting a non-negative integer" +msgstr "无效的超时值 '%s',应为非负整数" + +#: daemon.c +#, c-format +msgid "invalid init-timeout '%s', expecting a non-negative integer" +msgstr "无效的初始超时值 '%s',应为非负整数" + +#: daemon.c +#, c-format +msgid "invalid max-connections '%s', expecting an integer" +msgstr "无效的最大连接数 '%s',应为一个整数" + #: date.c msgid "in the future" msgstr "在将来" @@ -20351,6 +20484,20 @@ msgstr "错误的 git 名字空间路径 \"%s\"" msgid "too many args to run %s" msgstr "执行 %s 的参数太多" +#: fetch-pack.c +#, c-format +msgid "" +"You are attempting to fetch %s, which is in the commit graph file but not in " +"the object database.\n" +"This is probably due to repo corruption.\n" +"If you are attempting to repair this repo corruption by refetching the " +"missing object, use 'git fetch --refetch' with the missing object." +msgstr "" +"您正在尝试获取 %s,它位于提交图文件中,但不在对象数据库中。\n" +"这可能是由于仓库损坏造成的。\n" +"如果您尝试通过重新获取丢失的对象来修复此仓库损坏,请对丢失的对象使用 'git " +"fetch --refetch'。" + #: fetch-pack.c msgid "git fetch-pack: expected shallow list" msgstr "git fetch-pack:应为 shallow 列表" @@ -21062,10 +21209,10 @@ msgstr[1] "" #, c-format msgid "" "The '%s' hook was ignored because it's not set as executable.\n" -"You can disable this warning with `git config advice.ignoredHook false`." +"You can disable this warning with `git config set advice.ignoredHook false`." msgstr "" "因为没有将钩子 '%s' 设置为可执行,钩子被忽略。您可以通过\n" -"配置 `git config advice.ignoredHook false` 来关闭这条警告。" +"配置 `git config set advice.ignoredHook false` 来关闭这条警告。" #: http-fetch.c msgid "not a git repository" @@ -21085,18 +21232,10 @@ msgstr "http.postBuffer 为负值,默认为 %d" msgid "Delegation control is not supported with cURL < 7.22.0" msgstr "不支持委托控制,因为 cURL < 7.22.0" -#: http.c -msgid "Public key pinning not supported with cURL < 7.39.0" -msgstr "不支持公钥文件锁定,因为 cURL < 7.39.0" - #: http.c msgid "Unknown value for http.proactiveauth" msgstr "http.proactiveauth 为未知取值" -#: http.c -msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0" -msgstr "不支持 CURLSSLOPT_NO_REVOKE,因为 cURL < 7.44.0" - #: http.c #, c-format msgid "Unsupported SSL backend '%s'. Supported SSL backends:" @@ -21316,6 +21455,11 @@ msgstr "检测到被引用的 CRLF" msgid "unable to format message: %s" msgstr "无法格式化消息:%s" +#: merge-ll.c +#, c-format +msgid "invalid marker-size '%s', expecting an integer" +msgstr "无效的标记大小 '%s',应为一个整数" + #: merge-ort.c merge-recursive.c #, c-format msgid "Failed to merge submodule %s (not checked out)" @@ -22623,7 +22767,7 @@ msgid "" "\n" "where \"$br\" is somehow empty and a 40-hex ref is created. Please\n" "examine these refs and maybe delete them. Turn this message off by\n" -"running \"git config advice.objectNameWarning false\"" +"running \"git config set advice.objectNameWarning false\"" msgstr "" "Git 通常不会创建一个以40个十六进制字符结尾的引用,因为当您只提供40\n" "个十六进制字符时将被忽略。这些引用可能被错误地创建。例如:\n" @@ -22631,7 +22775,7 @@ msgstr "" " git switch -c $br $(git rev-parse ...)\n" "\n" "当 \"$br\" 某种原因空白时,一个40位十六进制的引用将被创建。请检查这些\n" -"引用,可能需要删除它们。运行 \"git config advice.objectNameWarning\n" +"引用,可能需要删除它们。运行 \"git config set advice.objectNameWarning\n" "false\" 命令关闭本消息通知。" #: object-name.c @@ -22826,15 +22970,6 @@ msgstr "多包位图缺少必需的反向索引" msgid "could not open pack %s" msgstr "不能打开包 %s" -#: pack-bitmap.c t/helper/test-read-midx.c -msgid "could not determine MIDX preferred pack" -msgstr "不能确定多包索引的首选包" - -#: pack-bitmap.c -#, c-format -msgid "preferred pack (%s) is invalid" -msgstr "首选包 (%s) 无效" - #: pack-bitmap.c msgid "corrupt bitmap lookup table: triplet position out of index" msgstr "损坏的位图查询表:三元组位置超出索引" @@ -24170,8 +24305,19 @@ msgid "log for %s is empty" msgstr "%s 的日志为空" #: refs.c -msgid "refusing to force and skip creation of reflog" -msgstr "拒绝既强制又跳过创建引用日志" +#, c-format +msgid "refusing to update reflog for pseudoref '%s'" +msgstr "拒绝为伪引用 '%s' 更新引用日志" + +#: refs.c +#, c-format +msgid "refusing to update pseudoref '%s'" +msgstr "拒绝更新伪引用 '%s'" + +#: refs.c +#, c-format +msgid "refusing to update reflog with bad name '%s'" +msgstr "拒绝使用错误名称 '%s' 更新引用日志" #: refs.c #, c-format @@ -24179,9 +24325,8 @@ msgid "refusing to update ref with bad name '%s'" msgstr "拒绝更新有错误名称 '%s' 的引用" #: refs.c -#, c-format -msgid "refusing to update pseudoref '%s'" -msgstr "拒绝更新伪引用 '%s'" +msgid "refusing to force and skip creation of reflog" +msgstr "拒绝强制跳过创建引用日志" #: refs.c #, c-format @@ -24242,6 +24387,11 @@ msgid "" "cannot lock ref '%s': expected symref with target '%s': but is a regular ref" msgstr "无法锁定引用 '%s':预期目标为 '%s' 的符号引用:但是是普通引用" +#: refs/files-backend.c +#, c-format +msgid "cannot read ref file '%s'" +msgstr "无法读取引用文件 '%s'" + #: refs/files-backend.c #, c-format msgid "cannot open directory %s" @@ -24498,6 +24648,11 @@ msgstr "提供了一个以上的 receivepack,使用第一个" msgid "more than one uploadpack given, using the first" msgstr "提供了一个以上的 uploadpack,使用第一个" +#: remote.c +#, c-format +msgid "unrecognized followRemoteHEAD value '%s' ignored" +msgstr "已忽略无法识别的 followRemoteHEAD 值 '%s'" + #: remote.c #, c-format msgid "unrecognized value transfer.credentialsInUrl: '%s'" @@ -26810,6 +26965,10 @@ msgstr "提交 %s 没有标记为可达" msgid "too many commits marked reachable" msgstr "太多提交标记为可达" +#: t/helper/test-read-midx.c +msgid "could not determine MIDX preferred pack" +msgstr "不能确定多包索引的首选包" + #: t/helper/test-serve-v2.c msgid "test-tool serve-v2 []" msgstr "test-tool serve-v2 [<选项>]" @@ -27584,6 +27743,10 @@ msgstr ".git 文件损坏" msgid ".git file incorrect" msgstr ".git 文件不正确" +#: worktree.c +msgid ".git file absolute/relative path mismatch" +msgstr ".git 文件绝对/相对路径不匹配" + #: worktree.c msgid "not a valid path" msgstr "不是一个有效的路径" @@ -27604,6 +27767,10 @@ msgstr "无法定位仓库,.git 文件损坏" msgid "gitdir unreadable" msgstr "gitdir 不可读" +#: worktree.c +msgid "gitdir absolute/relative path mismatch" +msgstr "gitdir 绝对/相对路径不匹配" + #: worktree.c msgid "gitdir incorrect" msgstr "gitdir 不正确" @@ -27648,6 +27815,14 @@ msgstr "无法在 '%2$s' 中取消设置 %1$s" msgid "failed to set extensions.worktreeConfig setting" msgstr "无法设置 extensions.worktreeConfig" +#: worktree.c +msgid "unable to upgrade repository format to support relative worktrees" +msgstr "无法升级仓库格式以支持相对工作区" + +#: worktree.c +msgid "unable to set extensions.relativeWorktrees setting" +msgstr "无法设定 extensions.relativeWorktrees 的设置" + #: wrapper.c #, c-format msgid "could not setenv '%s'" -- cgit v1.2.3 From 238c0c095f21f919fd268d8519d6b1b07ffc1540 Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Wed, 18 Dec 2024 14:16:48 +0700 Subject: l10n: po-id for 2.48 Update following components: * advice.c * archive.c * builtin/checkout.c * builtin/clone.c * builtin/config.c * builtin/describe.c * builtin/fetch.c * builtin/gc.c * builtin/index-pack.c * builtin/notes.c * builtin/pack-objects.c * builtin/remote.c * builtin/worktree.c * commit.c * fetch-pack.c * hook.c * object-name.c * refs.c * refs/files-backend.c * remote.c * worktree.c Translate following new components: * cache-tree.c * daemon.c * merge-ll.c Signed-off-by: Bagas Sanjaya --- po/id.po | 338 ++++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 259 insertions(+), 79 deletions(-) diff --git a/po/id.po b/po/id.po index fc34140776..3965c9e941 100644 --- a/po/id.po +++ b/po/id.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: Git\n" "Report-Msgid-Bugs-To: Git Mailing List \n" -"POT-Creation-Date: 2024-10-04 08:33+0700\n" -"PO-Revision-Date: 2024-10-04 08:52+0700\n" +"POT-Creation-Date: 2024-12-23 18:57+0000\n" +"PO-Revision-Date: 2025-01-06 15:50+0700\n" "Last-Translator: Bagas Sanjaya \n" "Language-Team: Indonesian\n" "Language: id\n" @@ -755,10 +755,10 @@ msgstr "Hanya berkas biner yang berubah." #, c-format msgid "" "\n" -"Disable this message with \"git config advice.%s false\"" +"Disable this message with \"git config set advice.%s false\"" msgstr "" "\n" -"Nonaktifkan pesan ini dengan \"git config advice.%s false\"" +"Nonaktifkan pesan ini dengan \"git config set advice.%s false\"" #: advice.c #, c-format @@ -1670,9 +1670,10 @@ msgstr "bukan nama objek valid: %s" msgid "not a tree object: %s" msgstr "bukan objek pohon: %s" -#: archive.c builtin/clone.c -msgid "unable to checkout working tree" -msgstr "tidak dapat men-checkout pohon kerja" +#: archive.c +#, c-format +msgid "failed to unpack tree object %s" +msgstr "gagal membuka objek pohon %s" #: archive.c #, c-format @@ -3734,11 +3735,11 @@ msgstr "HEAD tidak ditemukan di bawah refs/heads!" #: builtin/branch.c msgid "" -"branch with --recurse-submodules can only be used if submodule." -"propagateBranches is enabled" +"branch with --recurse-submodules can only be used if " +"submodule.propagateBranches is enabled" msgstr "" -"cabang dengan --recurse-submodules hanya dapat digunakan jika submodule." -"propagateBranches diaktifkan" +"cabang dengan --recurse-submodules hanya dapat digunakan jika " +"submodule.propagateBranches diaktifkan" #: builtin/branch.c msgid "--recurse-submodules can only be used to create branches" @@ -4767,7 +4768,7 @@ msgstr "gaya konflik '%s' tidak dikenal" msgid "perform a 3-way merge with the new branch" msgstr "lakukan penggabungan 3 arah dengan cabang baru" -#: builtin/checkout.c builtin/log.c parse-options.h +#: builtin/checkout.c builtin/log.c builtin/range-diff.c parse-options.h msgid "style" msgstr "gaya" @@ -4796,9 +4797,8 @@ msgid "update ignored files (default)" msgstr "perbarui berkas yang diabaikan (default)" #: builtin/checkout.c -msgid "do not check if another worktree is holding the given ref" -msgstr "" -"jangan periksa jika pohon kerja yang lain mempunyai referensi yang diberikan" +msgid "do not check if another worktree is using this branch" +msgstr "jangan periksa jika pohon kerja yang lain menggunakan cabang ini" #: builtin/checkout.c msgid "checkout our version for unmerged files" @@ -5179,14 +5179,13 @@ msgstr "buat klon dangkal sedalam kedalaman tersebut" msgid "create a shallow clone since a specific time" msgstr "buat klon dangkal sejak waktu yang disebutkan" -#: builtin/clone.c builtin/fetch.c builtin/pull.c builtin/rebase.c -#: builtin/replay.c -msgid "revision" -msgstr "revisi" +#: builtin/clone.c builtin/fetch.c builtin/pull.c +msgid "ref" +msgstr "referensi" #: builtin/clone.c builtin/fetch.c builtin/pull.c -msgid "deepen history of shallow clone, excluding rev" -msgstr "perdalam riwayat klon dangkal, tidak termasuk rev" +msgid "deepen history of shallow clone, excluding ref" +msgstr "perdalam riwayat klon dangkal, kecualikan referensi" #: builtin/clone.c builtin/submodule--helper.c msgid "clone only one branch, HEAD or --branch" @@ -5348,6 +5347,10 @@ msgstr "gagal menginisalisasi checkout tipis" msgid "remote HEAD refers to nonexistent ref, unable to checkout" msgstr "HEAD remote merujuk pada ref yang tidak ada, tidak dapat men-checkout" +#: builtin/clone.c +msgid "unable to checkout working tree" +msgstr "tidak dapat men-checkout pohon kerja" + #: builtin/clone.c msgid "unable to write parameters to config file" msgstr "tidak dapat menulis parameter ke berkas konfigurasi" @@ -6347,10 +6350,10 @@ msgstr "" #: builtin/config.c msgid "" "git config unset [] [--all] [--value=] [--fixed-value] " -" " +"" msgstr "" -"git config unset [] [--fixed-value] " -" " +"git config unset [] [--all] [--value=] [--fixed-value] " +"" #: builtin/config.c msgid "git config rename-section [] " @@ -6907,12 +6910,8 @@ msgstr "%lu komit dilintasi\n" #: builtin/describe.c #, c-format -msgid "" -"more than %i tags found; listed %i most recent\n" -"gave up search at %s\n" -msgstr "" -"lebih dari %i tag ditemukan; %i terbaru didaftarkan\n" -"menyerah mencari pada %s\n" +msgid "found %i tags; gave up search at %s\n" +msgstr "dapat %i tag; menyerah mencari pada %s\n" #: builtin/describe.c #, c-format @@ -7389,8 +7388,8 @@ msgstr "" "fetch secara normal mengindikasikan cabang mana ada pembaruan terpaksa,\n" "tapi pemeriksaan tersebut sudah dinonaktifkan. Untuk aktifkan kembali, " "gunakan\n" -"bendera '--show-forced-updates' atau jalankan 'git config fetch." -"showForcedUpdates true'." +"bendera '--show-forced-updates' atau jalankan 'git config " +"fetch.showForcedUpdates true'." #: builtin/fetch.c #, c-format @@ -7467,6 +7466,21 @@ msgstr "%s bukan sebuah objek valid" msgid "the object %s does not exist" msgstr "objek '%s' tidak ada" +#: builtin/fetch.c +#, c-format +msgid "" +"Run 'git remote set-head %s %s' to follow the change, or set\n" +"'remote.%s.followRemoteHEAD' configuration option to a different value\n" +"if you do not want to see this message. Specifically running\n" +"'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n" +"until the remote changes HEAD to something else." +msgstr "" +"Jalankan 'git remote set-head %s %s' untuk mengikuti perubahan, atau setel\n" +"opsi konfigurasi 'remote.%s.followRemoteHEAD' ke nilai yang berbeda jika\n" +"Anda tidak ingin melihat pesan ini lagi. Secara rinci menjalakan\n" +"'git config set remote.%s followRemoteHEAD %s' akan mematikan peringatan\n" +"ini sampai remote mengubah HEAD ke yang lain." + #: builtin/fetch.c msgid "multiple branches detected, incompatible with --set-upstream" msgstr "banyak cabang terdeteksi, tidak kompatibel dengan --set-upstream" @@ -7641,6 +7655,10 @@ msgstr "peta referensi" msgid "specify fetch refmap" msgstr "sebutkan ambil peta referensi" +#: builtin/fetch.c builtin/pull.c builtin/rebase.c builtin/replay.c +msgid "revision" +msgstr "revisi" + #: builtin/fetch.c builtin/pull.c msgid "report that we have only objects reachable from this object" msgstr "" @@ -7711,8 +7729,8 @@ msgstr "protokol tidak mendukung --negotiate-only, keluar." #: builtin/fetch.c msgid "" -"--filter can only be used with the remote configured in extensions." -"partialclone" +"--filter can only be used with the remote configured in " +"extensions.partialclone" msgstr "" "--filter hanya dapat digunakan dengan remote yang terkonfigurasi di " "extensions.partialclone" @@ -8565,8 +8583,25 @@ msgid "%s scheduler is not available" msgstr "penjadwal %s tidak tersedia" #: builtin/gc.c -msgid "another process is scheduling background maintenance" -msgstr "proses lainnya sedang menjadwalkan peme" +#, c-format +msgid "" +"unable to create '%s.lock': %s.\n" +"\n" +"Another scheduled git-maintenance(1) process seems to be running in this\n" +"repository. Please make sure no other maintenance processes are running and\n" +"then try again. If it still fails, a git-maintenance(1) process may have\n" +"crashed in this repository earlier: remove the file manually to continue." +msgstr "" +"Tidak dapat membuat '%s.lock': %s.\n" +"\n" +"Sepertinya proses git-maintenance(1) lainnya berjalan pada repositori ini.\n" +"Pastikan tidak ada proses pemeliharaan lainnya yang berjalan dan coba lagi.\n" +"Jika masih gagal, suatu proses git-maintenance(1) bisa jadi hancur pada\n" +"repositori ini sebelumnya: hapus berkas secara manual untuk melanjutkan." + +#: builtin/gc.c +msgid "cannot acquire lock for scheduled background maintenance" +msgstr "tidak dapat memperoleh kunci untuk pemeliharran balik layar terjadwal" #: builtin/gc.c msgid "git maintenance start [--scheduler=]" @@ -9297,6 +9332,23 @@ msgid_plural "chain length = %d: %lu objects" msgstr[0] "panjang rantai = %d: %lu objek" msgstr[1] "panjang rantai = %d: %lu objek" +#: builtin/index-pack.c +msgid "could not start pack-objects to repack local links" +msgstr "tidak dapat memulai pack-objects untuk mempak ulang tautan lokal" + +#: builtin/index-pack.c +msgid "failed to feed local object to pack-objects" +msgstr "tidak dapat memasukkan objek ke pada pack-objects" + +#: builtin/index-pack.c +msgid "index-pack: Expecting full hex object ID lines only from pack-objects." +msgstr "" +"index-pack: Mengharapkan hanya baris hex ID objek penuh daripack-objects." + +#: builtin/index-pack.c +msgid "could not finish pack-objects to repack local links" +msgstr "tidak dapat menyelesaikan pack-objects untuk mempak ulang tautan lokal" + #: builtin/index-pack.c msgid "Cannot come back to cwd" msgstr "tidak dapat kembali ke direktori kerja saat ini" @@ -9311,6 +9363,10 @@ msgstr "%s jelek" msgid "unknown hash algorithm '%s'" msgstr "algoritma hash tak dikenal '%s'" +#: builtin/index-pack.c +msgid "--promisor cannot be used with a pack name" +msgstr "--promisor tidak dapat digunakan dengan nama pak" + #: builtin/index-pack.c msgid "--stdin requires a git repository" msgstr "--stdin memerlukan repositori git" @@ -11055,11 +11111,11 @@ msgstr "git notes [--ref ] [list []]" msgid "" "git notes [--ref ] add [-f] [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" msgstr "" "git notes [--ref ] add [-f] [--allow-empty] [--" "[no-]separator|--separator=] [--[no-]stripspace] [-m " -" | (-c | -C) ] []" +" | -F | (-c | -C) ] [] [-e]" #: builtin/notes.c msgid "git notes [--ref ] copy [-f] " @@ -11070,11 +11126,11 @@ msgstr "" msgid "" "git notes [--ref ] append [--allow-empty] [--[no-]separator|--" "separator=] [--[no-]stripspace] [-m | -F | (-c " -"| -C) ] []" +"| -C) ] [] [-e]" msgstr "" "git notes [--ref ] append [--alow-empty] [--" "[no]separator|--separator=] [--[no-]stripspace] [-m " -" | -F | (-c | -C) ] []" +" | -F | (-c | -C) ] [] [-e]" #: builtin/notes.c msgid "git notes [--ref ] edit [--allow-empty] []" @@ -11227,6 +11283,10 @@ msgstr "isi catatan di dalam berkas" msgid "reuse and edit specified note object" msgstr "gunakan ulang dan sunting objek catatan yang disebutkan" +#: builtin/notes.c +msgid "edit note message in editor" +msgstr "sunting pesan catatan dalam penyunting" + #: builtin/notes.c msgid "reuse specified note object" msgstr "gunakan ulang objek catatan yang disebutkan" @@ -11856,6 +11916,10 @@ msgstr "penanganan untuk objek yang hilang" msgid "do not pack objects in promisor packfiles" msgstr "jangan pak objek di dalam pak penjanji" +#: builtin/pack-objects.c +msgid "implies --missing=allow-any" +msgstr "mengimplikasikan --missing=allow-any" + #: builtin/pack-objects.c msgid "respect islands during delta compression" msgstr "patuhi pulau selama pemampatan delta" @@ -12269,8 +12333,8 @@ msgid "" msgstr "" "\n" "Untuk menghindari konfigurasi cabang hulu otomatis ketika namanya\n" -"tidak akan cocok dengan cabang lokal, lihat opsi 'simple' dari branch." -"autoSetupMerge\n" +"tidak akan cocok dengan cabang lokal, lihat opsi 'simple' dari " +"branch.autoSetupMerge\n" "di 'git help config'.\n" #: builtin/push.c @@ -13810,6 +13874,35 @@ msgid_plural " Local refs configured for 'git push'%s:" msgstr[0] " Referensi lokal dikonfigurasi untuk 'git push'%s:" msgstr[1] " Referensi lokal dikonfigurasi untuk 'git push'%s:" +#: builtin/remote.c +#, c-format +msgid "'%s/HEAD' is unchanged and points to '%s'\n" +msgstr "'%s/HEAD' tak berubah dan menunjuk pada '%s'\n" + +#: builtin/remote.c +#, c-format +msgid "'%s/HEAD' has changed from '%s' and now points to '%s'\n" +msgstr "'%s/HEAD' berubah dari '%s' dan sekarang menunjuk pada '%s'\n" + +#: builtin/remote.c +#, c-format +msgid "'%s/HEAD' is now created and points to '%s'\n" +msgstr "'%s/HEAD' sekarang dibuat dan menunjuk pada '%s'\n" + +#: builtin/remote.c +#, c-format +msgid "'%s/HEAD' was detached at '%s' and now points to '%s'\n" +msgstr "%s/HEAD' terlepas pada '%s' dan sekarang menunjuk pada '%s'\n" + +#: builtin/remote.c +#, c-format +msgid "" +"'%s/HEAD' used to point to '%s' (which is not a remote branch), but now " +"points to '%s'\n" +msgstr "" +"'%s/HEAD' dulunya menunjuk pada '%s' (yang bukan cabang remote), tetapi " +"sekarang menunjuk pada '%s'\n" + #: builtin/remote.c msgid "set refs/remotes//HEAD according to remote" msgstr "setel refs/remotes//HEAD tergantung remote" @@ -13838,8 +13931,8 @@ msgstr "Bukan referensi valid: %s" #: builtin/remote.c #, c-format -msgid "Could not setup %s" -msgstr "Tidak dapat mengatur %s" +msgid "Could not set up %s" +msgstr "Tidak dapat menyiapkan %s" #: builtin/remote.c #, c-format @@ -17247,6 +17340,10 @@ msgstr "pasang mode pelacakan (lihat git-branch(1))" msgid "try to match the new branch name with a remote-tracking branch" msgstr "coba cocokkan nama cabang baru dengan sebuah cabang pelacakan remote" +#: builtin/worktree.c +msgid "use relative paths for worktrees" +msgstr "gunakan jalur relatif untuk pohon kerja" + #: builtin/worktree.c diff.c parse-options.c #, c-format msgid "options '%s', '%s', and '%s' cannot be used together" @@ -17588,6 +17685,31 @@ msgstr "tidak dapat membuat '%s'" msgid "index-pack died" msgstr "index-pack mati" +#: cache-tree.c +#, c-format +msgid "directory '%s' is present in index, but not sparse" +msgstr "direktori '%s' ada pada indeks, tapi bukan tipis" + +#: cache-tree.c unpack-trees.c +msgid "corrupted cache-tree has entries not present in index" +msgstr "pohon tembolok rusak mempunyai entri yang tidak ada pada indeks" + +#: cache-tree.c +#, c-format +msgid "%s with flags 0x%x should not be in cache-tree" +msgstr "%s dengan bendera 0x%x tidak boleh ada di pohon tembolok" + +#: cache-tree.c +#, c-format +msgid "bad subtree '%.*s'" +msgstr "subpohon jelek '%.*s'" + +#: cache-tree.c +#, c-format +msgid "cache-tree for path %.*s does not match. Expected %s got %s" +msgstr "" +"pohon tembolok untuk jalur %.*s tidak cocok. %s diharapkan tapi dapat %s" + #: chunk-format.c msgid "terminating chunk id appears earlier than expected" msgstr "id bingkah pengakhiran muncul lebih awal dari yang diharapkan" @@ -18714,16 +18836,16 @@ msgid "" "to convert the grafts into replace refs.\n" "\n" "Turn this message off by running\n" -"\"git config advice.graftFileDeprecated false\"" +"\"git config set advice.graftFileDeprecated false\"" msgstr "" "Dukungan untuk /info/grafts usang dan akan dihapus\n" -"pada versi Git di masa yang akan datang.\n" +"pada versi Git mendatang.\n" "\n" "Mohon gunakan \"git replace --convert-graft-file\"\n" "untuk mengkonversi cangkuk ke referensi penggantian.\n" "\n" "Matikan pesan ini dengan menjalankan\n" -"\"git config advice.graftFileDeprecated false\"" +"\"git config set advice.graftFileDeprecated false\"" #: commit.c #, c-format @@ -19739,6 +19861,21 @@ msgstr "url tidak punya skema: %s" msgid "credential url cannot be parsed: %s" msgstr "url kredensial tidak dapat diuraikan: %s" +#: daemon.c +#, c-format +msgid "invalid timeout '%s', expecting a non-negative integer" +msgstr "timeout '%s' tidak valid, bilangan bulat non-negatif diharapkan" + +#: daemon.c +#, c-format +msgid "invalid init-timeout '%s', expecting a non-negative integer" +msgstr "init-timeout '%s' tidak valid, bilangan bulat non-negatif diharapkan" + +#: daemon.c +#, c-format +msgid "invalid max-connections '%s', expecting an integer" +msgstr "max-connections '%s' tidak valid, bilangan bulat diharapkan" + #: date.c msgid "in the future" msgstr "di masa depan" @@ -20631,6 +20768,21 @@ msgstr "jalur ruang nama git jelek \"%s\"" msgid "too many args to run %s" msgstr "terlalu banyak argumen untuk menjalankan %s" +#: fetch-pack.c +#, c-format +msgid "" +"You are attempting to fetch %s, which is in the commit graph file but not in " +"the object database.\n" +"This is probably due to repo corruption.\n" +"If you are attempting to repair this repo corruption by refetching the " +"missing object, use 'git fetch --refetch' with the missing object." +msgstr "" +"Anda mencoba mengambil %s, yang ada di dalam berkas grafik komit tapi bukan " +"di dalam basis data objek.\n" +"Bisa jadi ini dikarenakan kerusakan repositori.\n" +"Apabila Anda mencoba memperbaiki keruskanan repositori ini dengan mengambil " +"ulang objek yang hilang, gunakan 'git fetch --refetch' dengan objek tersebut." + #: fetch-pack.c msgid "git fetch-pack: expected shallow list" msgstr "git fetch-pack: daftar dangkal diharapkan" @@ -21351,11 +21503,11 @@ msgstr[1] "" #, c-format msgid "" "The '%s' hook was ignored because it's not set as executable.\n" -"You can disable this warning with `git config advice.ignoredHook false`." +"You can disable this warning with `git config set advice.ignoredHook false`." msgstr "" -"Kait '%s' diabaikan karena tidak disetel sebagai dapat dieksekusi.\n" -"Anda dapat menonaktifkan peringatan ini dengan `git config advice." -"ignoredHook false`." +"Kait '%s' diabaikan karena tidak disetel sebagai berkas yang dapat\n" +"dieksekusi. Anda dapat menonaktifkan peringatan ini dengan\n" +"`git config set advice.ignoredHook false`." #: http-fetch.c msgid "not a git repository" @@ -21375,18 +21527,10 @@ msgstr "nilai negatif untuk http.postBuffer; asalkan ke %d" msgid "Delegation control is not supported with cURL < 7.22.0" msgstr "Kontrol delegasi tidak didukung oleh cURL < 7.22.0" -#: http.c -msgid "Public key pinning not supported with cURL < 7.39.0" -msgstr "Penyematan kunci publik tidak didukung oleh cURL < 7.39.0" - #: http.c msgid "Unknown value for http.proactiveauth" msgstr "nilai tidak dikenal untuk http.proactiveauth" -#: http.c -msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0" -msgstr "CURLSSLOPT_NO_REVOKE tidak didukung dengan cURL < 7.44.0" - #: http.c #, c-format msgid "Unsupported SSL backend '%s'. Supported SSL backends:" @@ -21609,6 +21753,11 @@ msgstr "CRLF terkutip terdeteksi" msgid "unable to format message: %s" msgstr "tidak dapat memformat pesan: %s" +#: merge-ll.c +#, c-format +msgid "invalid marker-size '%s', expecting an integer" +msgstr "marker-size '%s' tidak valid, bilangan bulat diharapkan" + #: merge-ort.c merge-recursive.c #, c-format msgid "Failed to merge submodule %s (not checked out)" @@ -22955,19 +23104,17 @@ msgid "" "\n" "where \"$br\" is somehow empty and a 40-hex ref is created. Please\n" "examine these refs and maybe delete them. Turn this message off by\n" -"running \"git config advice.objectNameWarning false\"" +"running \"git config set advice.objectNameWarning false\"" msgstr "" "Biasanya Git tidak pernah membuat sebuah referensi yang diakhiri dengan\n" -"40 karakter hex, karena akan diabaikan ketika Anda hanya menyebutkan 40-" -"hex.\n" +"40 karakter hex, karena akan diabaikan ketika Anda hanya merincikan 40-hex.\n" "Referensi tersebut bisa tidak sengaja dibuat. Misalnya,\n" "\n" " git switch -c $br $(git rev-parse ...)\n" "\n" "dimana \"$br\" entah bagaimana kosong dan referensi 40-hex dibuat.\n" -"Mohon periksa referensi tersebut dan mungkin hapus. Matikan pesan ini " -"dengan\n" -"menjalankan \"git config advice.objectNameWarning false\"" +"Mohon periksa referensi tersebut dan mungkin hapus. Matikan pesan ini\n" +"dengan menjalankan \"git config set advice.objectNameWarning false\"" #: object-name.c #, c-format @@ -23166,15 +23313,6 @@ msgstr "bitmap multipak kehilangan indeks balik yang diperlukan" msgid "could not open pack %s" msgstr "tidak dapat membuka '%s'" -#: pack-bitmap.c t/helper/test-read-midx.c -msgid "could not determine MIDX preferred pack" -msgstr "tidak dapat menentukan pak MIDX terpilih" - -#: pack-bitmap.c -#, c-format -msgid "preferred pack (%s) is invalid" -msgstr "pak yang disukai '%s' kadaluarsa" - #: pack-bitmap.c msgid "corrupt bitmap lookup table: triplet position out of index" msgstr "tabel pencarian bitmap rusak: posisi kembar tiga di luar indeks" @@ -24546,8 +24684,19 @@ msgid "log for %s is empty" msgstr "log untuk %s kosong" #: refs.c -msgid "refusing to force and skip creation of reflog" -msgstr "menolak memaksa dan melewatkan pembuatan reflog" +#, c-format +msgid "refusing to update reflog for pseudoref '%s'" +msgstr "menolak memperbarui reflog untuk referensi semu '%s'" + +#: refs.c +#, c-format +msgid "refusing to update pseudoref '%s'" +msgstr "menolak memperbarui referensi semu '%s'" + +#: refs.c +#, c-format +msgid "refusing to update reflog with bad name '%s'" +msgstr "menolak memperbarui reflog dengan nama jelek '%s'" #: refs.c #, c-format @@ -24555,9 +24704,8 @@ msgid "refusing to update ref with bad name '%s'" msgstr "menolak memperbarui referensi dengan nama jelek '%s'" #: refs.c -#, c-format -msgid "refusing to update pseudoref '%s'" -msgstr "menolak memperbarui referensi semu '%s'" +msgid "refusing to force and skip creation of reflog" +msgstr "menolak memaksa dan melewatkan pembuatan reflog" #: refs.c #, c-format @@ -24620,6 +24768,11 @@ msgstr "" "tidak dapat mengunci referensi '%s': diharapkan referensi simbolik dengan " "target '%s': tetapi bukan referensi reguler" +#: refs/files-backend.c +#, c-format +msgid "cannot read ref file '%s'" +msgstr "tidak dapat membaca berkas referensi '%s'" + #: refs/files-backend.c #, c-format msgid "cannot open directory %s" @@ -24883,6 +25036,11 @@ msgstr "lebih dari satu paket terima diberikan, gunakan yang pertama" msgid "more than one uploadpack given, using the first" msgstr "lebih dari satu paket unggah diberikan, gunakan yang pertama" +#: remote.c +#, c-format +msgid "unrecognized followRemoteHEAD value '%s' ignored" +msgstr "nilai followRemoteHEAD yang tak dikenal '%s' diabaikan" + #: remote.c #, c-format msgid "unrecognized value transfer.credentialsInUrl: '%s'" @@ -27240,6 +27398,10 @@ msgstr "komit %s tidak ditandai sebagai dapat dicapai" msgid "too many commits marked reachable" msgstr "terlalu banyak komit yang ditandai sebagai dapat dicapai" +#: t/helper/test-read-midx.c +msgid "could not determine MIDX preferred pack" +msgstr "tidak dapat menentukan pak MIDX terpilih" + #: t/helper/test-serve-v2.c msgid "test-tool serve-v2 []" msgstr "test-tool serve-v2 []" @@ -28026,6 +28188,10 @@ msgstr "berkas .git rusak" msgid ".git file incorrect" msgstr "berkas .git salah" +#: worktree.c +msgid ".git file absolute/relative path mismatch" +msgstr "jalur absolut/relative berkas .git tidak cocok" + #: worktree.c msgid "not a valid path" msgstr "bukan jalur valid" @@ -28047,6 +28213,10 @@ msgstr "tidak dapat menempatkan repositori; berkas .git rusak" msgid "gitdir unreadable" msgstr "gitdir tidak dapat dibaca" +#: worktree.c +msgid "gitdir absolute/relative path mismatch" +msgstr "jalur absolut/relatif gitdir tidak cocok" + #: worktree.c msgid "gitdir incorrect" msgstr "gitdir salah" @@ -28091,6 +28261,16 @@ msgstr "tidak dapat menyetel balik %s di '%s'" msgid "failed to set extensions.worktreeConfig setting" msgstr "gagal menyetel setelan extensions.worktreeConfig" +#: worktree.c +msgid "unable to upgrade repository format to support relative worktrees" +msgstr "" +"tidak dapat meningkatkan format repositori untuk mendukung pohon kerja " +"relatif" + +#: worktree.c +msgid "unable to set extensions.relativeWorktrees setting" +msgstr "gagal menyetel setelan extensions.relativeWorktrees" + #: wrapper.c #, c-format msgid "could not setenv '%s'" -- cgit v1.2.3 From 233d48f5de1d6cdba0eb64165212dfbf6fa444d7 Mon Sep 17 00:00:00 2001 From: Bence Ferdinandy Date: Sun, 5 Jan 2025 17:09:40 +0100 Subject: fetch: fix erroneous set_head advice message 9e2b7005be (fetch set_head: add warn-if-not-$branch option, 2024-12-05) tried to expand the advice message for set_head with the new option, but unfortunately did not manage to add the right incantation. Fix the advice message with the correct usage of warn-if-not-$branch. Reported-by: Teng Long Signed-off-by: Bence Ferdinandy Signed-off-by: Junio C Hamano --- builtin/fetch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builtin/fetch.c b/builtin/fetch.c index c4257a7ead..ba464d5521 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1585,8 +1585,8 @@ static void set_head_advice_msg(const char *remote, const char *head_name) N_("Run 'git remote set-head %s %s' to follow the change, or set\n" "'remote.%s.followRemoteHEAD' configuration option to a different value\n" "if you do not want to see this message. Specifically running\n" - "'git config set remote.%s.followRemoteHEAD %s' will disable the warning\n" - "until the remote changes HEAD to something else."); + "'git config set remote.%s.followRemoteHEAD warn-if-not-branch-%s'\n" + "will disable the warning until the remote changes HEAD to something else."); advise_if_enabled(ADVICE_FETCH_SET_HEAD_WARN, _(message_advice_set_head), remote, head_name, remote, remote, head_name); -- cgit v1.2.3 From c1acf1a31761d0cfddc3ea6d39c92a6528cd9c5c Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 6 Jan 2025 10:24:25 +0100 Subject: object-file: rename variables in `check_collision()` Rename variables used in `check_collision()` to clearly identify which file is the source and which is the destination. This will make the next step easier to reason about when we start to treat those files different from one another. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- object-file.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/object-file.c b/object-file.c index 0293b93bbc..e2fa1be303 100644 --- a/object-file.c +++ b/object-file.c @@ -1974,56 +1974,56 @@ static void write_object_file_prepare_literally(const struct git_hash_algo *algo hash_object_body(algo, &c, buf, len, oid, hdr, hdrlen); } -static int check_collision(const char *filename_a, const char *filename_b) +static int check_collision(const char *source, const char *dest) { - char buf_a[4096], buf_b[4096]; - int fd_a = -1, fd_b = -1; + char buf_source[4096], buf_dest[4096]; + int fd_source = -1, fd_dest = -1; int ret = 0; - fd_a = open(filename_a, O_RDONLY); - if (fd_a < 0) { + fd_source = open(source, O_RDONLY); + if (fd_source < 0) { if (errno != ENOENT) - ret = error_errno(_("unable to open %s"), filename_a); + ret = error_errno(_("unable to open %s"), source); goto out; } - fd_b = open(filename_b, O_RDONLY); - if (fd_b < 0) { + fd_dest = open(dest, O_RDONLY); + if (fd_dest < 0) { if (errno != ENOENT) - ret = error_errno(_("unable to open %s"), filename_b); + ret = error_errno(_("unable to open %s"), dest); goto out; } while (1) { ssize_t sz_a, sz_b; - sz_a = read_in_full(fd_a, buf_a, sizeof(buf_a)); + sz_a = read_in_full(fd_source, buf_source, sizeof(buf_source)); if (sz_a < 0) { - ret = error_errno(_("unable to read %s"), filename_a); + ret = error_errno(_("unable to read %s"), source); goto out; } - sz_b = read_in_full(fd_b, buf_b, sizeof(buf_b)); + sz_b = read_in_full(fd_dest, buf_dest, sizeof(buf_dest)); if (sz_b < 0) { - ret = error_errno(_("unable to read %s"), filename_b); + ret = error_errno(_("unable to read %s"), dest); goto out; } - if (sz_a != sz_b || memcmp(buf_a, buf_b, sz_a)) { + if (sz_a != sz_b || memcmp(buf_source, buf_dest, sz_a)) { ret = error(_("files '%s' and '%s' differ in contents"), - filename_a, filename_b); + source, dest); goto out; } - if (sz_a < sizeof(buf_a)) + if (sz_a < sizeof(buf_source)) break; } out: - if (fd_a > -1) - close(fd_a); - if (fd_b > -1) - close(fd_b); + if (fd_source > -1) + close(fd_source); + if (fd_dest > -1) + close(fd_dest); return ret; } -- cgit v1.2.3 From cfae50e40eb72d6116ad56c616b3322474df4a75 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 6 Jan 2025 10:24:26 +0100 Subject: object-file: don't special-case missing source file in collision check In 0ad3d65652 (object-file: fix race in object collision check, 2024-12-30) we have started to ignore ENOENT when opening either the source or destination file of the collision check. This was done to handle races more gracefully in case either of the potentially-colliding disappears. The fix is overly broad though: while the destination file may indeed vanish racily, this shouldn't ever happen for the source file, which is a temporary object file (either loose or in packfile format) that we have just created. So if any concurrent process would have removed that temporary file it would indicate an actual issue. Stop treating ENOENT specially for the source file so that we always bubble up this error. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- object-file.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/object-file.c b/object-file.c index e2fa1be303..c1bd746d9e 100644 --- a/object-file.c +++ b/object-file.c @@ -1982,8 +1982,7 @@ static int check_collision(const char *source, const char *dest) fd_source = open(source, O_RDONLY); if (fd_source < 0) { - if (errno != ENOENT) - ret = error_errno(_("unable to open %s"), source); + ret = error_errno(_("unable to open %s"), source); goto out; } -- cgit v1.2.3 From d7fcbe2c56468ac780c689b02c6a9e056ce39c12 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 6 Jan 2025 10:24:27 +0100 Subject: object-file: retry linking file into place when occluding file vanishes Prior to 0ad3d65652 (object-file: fix race in object collision check, 2024-12-30), callers could expect that a successful return from `finalize_object_file()` means that either the file was moved into place, or the identical bytes were already present. If neither of those happens, we'd return an error. Since that commit, if the destination file disappears between our link(3p) call and the collision check, we'd return success without actually checking the contents, and without retrying the link. This solves the common case that the files were indeed the same, but it means that we may corrupt the repository if they weren't (this implies a hash collision, but the whole point of this function is protecting against hash collisions). We can't be pessimistic and assume they're different; that hurts the common case that the mentioned commit was trying to fix. But after seeing that the destination file went away, we can retry linking again. Adapt the code to do so when we see that the destination file has racily vanished. This should generally succeed as we have just observed that the destination file does not exist anymore, except in the very unlikely event that it gets recreated by another concurrent process again. Helped-by: Jeff King Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- object-file.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/object-file.c b/object-file.c index c1bd746d9e..008ddf59a5 100644 --- a/object-file.c +++ b/object-file.c @@ -1974,6 +1974,8 @@ static void write_object_file_prepare_literally(const struct git_hash_algo *algo hash_object_body(algo, &c, buf, len, oid, hdr, hdrlen); } +#define CHECK_COLLISION_DEST_VANISHED -2 + static int check_collision(const char *source, const char *dest) { char buf_source[4096], buf_dest[4096]; @@ -1990,6 +1992,8 @@ static int check_collision(const char *source, const char *dest) if (fd_dest < 0) { if (errno != ENOENT) ret = error_errno(_("unable to open %s"), dest); + else + ret = CHECK_COLLISION_DEST_VANISHED; goto out; } @@ -2037,8 +2041,11 @@ int finalize_object_file(const char *tmpfile, const char *filename) int finalize_object_file_flags(const char *tmpfile, const char *filename, enum finalize_object_file_flags flags) { - struct stat st; - int ret = 0; + unsigned retries = 0; + int ret; + +retry: + ret = 0; if (object_creation_mode == OBJECT_CREATION_USES_RENAMES) goto try_rename; @@ -2059,6 +2066,8 @@ int finalize_object_file_flags(const char *tmpfile, const char *filename, * left to unlink. */ if (ret && ret != EEXIST) { + struct stat st; + try_rename: if (!stat(filename, &st)) ret = EEXIST; @@ -2074,9 +2083,17 @@ int finalize_object_file_flags(const char *tmpfile, const char *filename, errno = saved_errno; return error_errno(_("unable to write file %s"), filename); } - if (!(flags & FOF_SKIP_COLLISION_CHECK) && - check_collision(tmpfile, filename)) + if (!(flags & FOF_SKIP_COLLISION_CHECK)) { + ret = check_collision(tmpfile, filename); + if (ret == CHECK_COLLISION_DEST_VANISHED) { + if (retries++ > 5) + return error(_("unable to write repeatedly vanishing file %s"), + filename); + goto retry; + } + else if (ret) return -1; + } unlink_or_warn(tmpfile); } -- cgit v1.2.3 From b74ff38af58464688b211140b90ec90598d340c6 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 6 Jan 2025 08:24:43 -0800 Subject: Git 2.48-rc2 Signed-off-by: Junio C Hamano --- GIT-VERSION-GEN | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 194ec0f9ad..6d1cb66d69 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,6 +1,6 @@ #!/bin/sh -DEF_VER=v2.48.0-rc1 +DEF_VER=v2.48.0-rc2 LF=' ' -- cgit v1.2.3 From 8776470cf379f31d483d8512d28a0eaa47d2e3f2 Mon Sep 17 00:00:00 2001 From: "D. Ben Knoble" Date: Mon, 6 Jan 2025 21:47:06 +0000 Subject: completion: repair config completion for Zsh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 1e0ee4087e (completion: add and use __git_compute_first_level_config_vars_for_section, 2024-02-10) uses an indirect variable syntax that is only valid for Bash, but the Zsh completion code relies on the Bash completion code to function. Zsh supports a different indirect variable expansion using ${(P)var}, but in `emulate ksh` mode does not support Bash's ${!var}. This manifests as completing strange config options like "__git_first_level_config_vars_for_section_remote" as a choice for the command line git config set remote. Using Zsh's C-x ? _complete_debug widget with the cursor at the end of that command line captures a trace, in which we see (some details elided): +__git_complete_config_variable_name:7> __git_compute_first_level_config_vars_for_section remote +__git_compute_first_level_config_vars_for_section:7> local section=remote +__git_compute_first_level_config_vars_for_section:7> __git_compute_config_vars +__git_compute_config_vars:7> test -n $'add.ignoreErrors\nadvice.addEmbeddedRepo\nadvice.addEmptyPathspec\nadvice.addIgnoredFile[…]' +__git_compute_first_level_config_vars_for_section:7> local this_section=__git_first_level_config_vars_for_section_remote +__git_compute_first_level_config_vars_for_section:7> test -n __git_first_level_config_vars_for_section_remote +__git_complete_config_variable_name:7> local this_section=__git_first_level_config_vars_for_section_remote +__git_complete_config_variable_name:7> __gitcomp_nl_append __git_first_level_config_vars_for_section_remote remote. '' ' ' +__gitcomp_nl_append:7> __gitcomp_nl __git_first_level_config_vars_for_section_remote remote. '' ' ' +__gitcomp_nl:7> emulate -L zsh +__gitcomp_nl:7> compset -P '*[=:]' +__gitcomp_nl:7> compadd -Q -S ' ' -p remote. -- __git_first_level_config_vars_for_section_remote We perform the test for __git_compute_config_vars correctly, but the ${!this_section} references are not expanded as expected. Instead, portably expand indirect references through the new __git_indirect. Contrary to some versions you might find online [1], this version avoids echo non-portabilities [2] [3] and correctly quotes the indirect expansion after eval (so that the result is not split or globbed before being handed to printf). [1]: https://unix.stackexchange.com/a/41409/301073 [2]: https://askubuntu.com/questions/715765/mysterious-behavior-of-echo-command#comment1056038_715769 [3]: https://mywiki.wooledge.org/CatEchoLs The following demo program demonstrates how this works: b=1 indirect() { eval printf '%s' "\"\$$1\"" } f() { # Comment this out to see that it works for globals, too. Or, use # a value with spaces like '2 3 4' to see how it handles those. local b=2 local a=b test -n "$(indirect $a)" && echo nice } f When placed in a file "demo", then both bash -x demo and zsh -xc 'emulate ksh -c ". ./demo"' |& tail provide traces showing that "$(indirect $a)" produces 2 (or 1, with the global, or "2 3 4" as a single string, etc.). Signed-off-by: D. Ben Knoble Acked-by: Philippe Blain Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 75193ded4b..c0c980d8ae 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -2723,12 +2723,17 @@ __git_compute_config_vars_all () __git_config_vars_all="$(git --no-pager help --config)" } +__git_indirect() +{ + eval printf '%s' "\"\$$1\"" +} + __git_compute_first_level_config_vars_for_section () { local section="$1" __git_compute_config_vars local this_section="__git_first_level_config_vars_for_section_${section}" - test -n "${!this_section}" || + test -n "$(__git_indirect "${this_section}")" || printf -v "__git_first_level_config_vars_for_section_${section}" %s \ "$(echo "$__git_config_vars" | awk -F. "/^${section}\.[a-z]/ { print \$2 }")" } @@ -2738,7 +2743,7 @@ __git_compute_second_level_config_vars_for_section () local section="$1" __git_compute_config_vars_all local this_section="__git_second_level_config_vars_for_section_${section}" - test -n "${!this_section}" || + test -n "$(__git_indirect "${this_section}")" || printf -v "__git_second_level_config_vars_for_section_${section}" %s \ "$(echo "$__git_config_vars_all" | awk -F. "/^${section}\. Date: Tue, 7 Jan 2025 02:05:01 -0500 Subject: test-lib: invert return value of check_test_results_san_file_empty We have a function to check whether LSan logged any leaks. It returns success for no leaks, and non-zero otherwise. This is the simplest thing for its callers, who want to say "if no leaks then return early". But because it's implemented as a shell pipeline, you end up with the awkward: ! find ... | xargs grep leaks | grep -v false-positives where the "!" is actually negating the final grep. Switch the return value (and name) to return success when there are leaks. This should make the code a little easier to read, and the negation in the callers still reads pretty naturally. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/test-lib-functions.sh | 2 +- t/test-lib.sh | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index 78e054ab50..c25cee0ad8 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -927,7 +927,7 @@ test_expect_success () { test -n "$test_skip_test_preamble" || say >&3 "expecting success of $TEST_NUMBER.$test_count '$1': $test_body" if test_run_ "$test_body" && - check_test_results_san_file_empty_ + ! check_test_results_san_file_has_entries_ then test_ok_ "$1" else diff --git a/t/test-lib.sh b/t/test-lib.sh index d1f62adbf8..be3553e40e 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -1169,12 +1169,12 @@ test_atexit_handler () { teardown_malloc_check } -check_test_results_san_file_empty_ () { - test -z "$TEST_RESULTS_SAN_FILE" && return 0 +check_test_results_san_file_has_entries_ () { + test -z "$TEST_RESULTS_SAN_FILE" && return 1 # stderr piped to /dev/null because the directory may have # been "rmdir"'d already. - ! find "$TEST_RESULTS_SAN_DIR" \ + find "$TEST_RESULTS_SAN_DIR" \ -type f \ -name "$TEST_RESULTS_SAN_FILE_PFX.*" 2>/dev/null | xargs grep ^DEDUP_TOKEN | @@ -1182,7 +1182,7 @@ check_test_results_san_file_empty_ () { } check_test_results_san_file_ () { - if check_test_results_san_file_empty_ + if ! check_test_results_san_file_has_entries_ then return fi && -- cgit v1.2.3 From b9a9df93a3f5580c7f7b8cc099aad1c204ced8a4 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Tue, 7 Jan 2025 02:07:52 -0500 Subject: test-lib: simplify lsan results check We want to know if there are any leaks logged by LSan in the results directory, so we run "find" on the containing directory and pipe it to xargs. We can accomplish the same thing by just globbing in the shell and passing the result to grep, which has a few advantages: - it's one fewer process to run - we can glob on the TEST_RESULTS_SAN_FILE pattern, which is what we checked at the beginning of the function, and is the same glob used to show the logs in check_test_results_san_file_ - this correctly handles the case where TEST_OUTPUT_DIRECTORY has a space in it. For example doing: mkdir "/tmp/foo bar" TEST_OUTPUT_DIRECTORY="/tmp/foo bar" make SANITIZE=leak test would yield a lot of: grep: /tmp/foo: No such file or directory grep: bar/test-results/t0006-date.leak/trace.test-tool.582311: No such file or directory when there are leaks. We could do the same thing with "xargs --null", but that isn't portable. We are now subject to command-line length limits, but that is also true of the globbing cat used to show the logs themselves. This hasn't been a problem in practice. We do need to use "grep -s" for the case that the glob does not expand (i.e., there are not any log files at all). This option is in POSIX, and has been used in t7407 for several years without anybody complaining. This also also naturally handles the case where the surrounding directory has already been removed (in which case there are likewise no files!), dropping the need to comment about it. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/test-lib.sh | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/t/test-lib.sh b/t/test-lib.sh index be3553e40e..898c2267b8 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -1172,12 +1172,7 @@ test_atexit_handler () { check_test_results_san_file_has_entries_ () { test -z "$TEST_RESULTS_SAN_FILE" && return 1 - # stderr piped to /dev/null because the directory may have - # been "rmdir"'d already. - find "$TEST_RESULTS_SAN_DIR" \ - -type f \ - -name "$TEST_RESULTS_SAN_FILE_PFX.*" 2>/dev/null | - xargs grep ^DEDUP_TOKEN | + grep -s ^DEDUP_TOKEN "$TEST_RESULTS_SAN_FILE".* | grep -qv sanitizer::GetThreadStackTopAndBottom } -- cgit v1.2.3 From 164a2516eb622fdf032ce526ec97e79a53bf2893 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Tue, 7 Jan 2025 02:08:31 -0500 Subject: test-lib: add a few comments to LSan log checking Commit b119a687d4 (test-lib: ignore leaks in the sanitizer's thread code, 2025-01-01) added code to suppress a false positive in the leak checker. But if you're just reading the code, the obscure grep call is a bit of a head-scratcher. Let's add a brief comment explaining what's going on (and anybody digging further can find this commit or that one for all the details). Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/test-lib.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 898c2267b8..9f27a49995 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -1172,6 +1172,11 @@ test_atexit_handler () { check_test_results_san_file_has_entries_ () { test -z "$TEST_RESULTS_SAN_FILE" && return 1 + # Lines marked with DEDUP_TOKEN show unique leaks. We only care that we + # found at least one. + # + # But also suppress any false positives caused by bugs or races in the + # sanitizer itself. grep -s ^DEDUP_TOKEN "$TEST_RESULTS_SAN_FILE".* | grep -qv sanitizer::GetThreadStackTopAndBottom } -- cgit v1.2.3 From ddb5287894c491686e6dc1a82e1c3d0f34e56a7f Mon Sep 17 00:00:00 2001 From: Jeff King Date: Tue, 7 Jan 2025 02:18:24 -0500 Subject: t7407: use test_grep There are a few grep calls here that can benefit from test_grep, which produces more user-friendly output when it fails. One of these calls also passes "-sq", which is curious. The "-q" option suppresses the matched output. But test output is either already redirected to /dev/null in non-verbose mode, and in verbose mode it's better to see the output. The "-s" option suppresses errors opening files, but we are just grepping in the "expected" file we just generated, so it should not be needed. Neither of these was really hurting anything, but they are not a style we'd like to see emulated. So get rid of them. (It is also curious to grep in the expected file in the first place, but that is because we are auto-generating the expectation from a Git command. So this is double-checking it did what we wanted). Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t7407-submodule-foreach.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index 8d7b234beb..77b6d0040e 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -426,14 +426,14 @@ test_expect_success 'option-like arguments passed to foreach commands are not lo git submodule foreach "echo be --quiet" > ../expected && git submodule foreach echo be --quiet > ../actual ) && - grep -sq -e "--quiet" expected && + test_grep -e "--quiet" expected && test_cmp expected actual ' test_expect_success 'option-like arguments passed to foreach recurse correctly' ' git -C clone2 submodule foreach --recursive "echo be --an-option" >expect && git -C clone2 submodule foreach --recursive echo be --an-option >actual && - grep -e "--an-option" expect && + test_grep -e "--an-option" expect && test_cmp expect actual ' -- cgit v1.2.3 From 1568d1562eecc31d2062b6d22e37ec03fc3d6747 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 7 Jan 2025 16:26:59 +0100 Subject: wrapper: allow generating insecure random bytes The `csprng_bytes()` function generates randomness and writes it into a caller-provided buffer. It abstracts over a couple of implementations, where the exact one that is used depends on the platform. These implementations have different guarantees: while some guarantee to never fail (arc4random(3)), others may fail. There are two significant failures to distinguish from one another: - Systemic failure, where e.g. opening "/dev/urandom" fails or when OpenSSL doesn't have a provider configured. - Entropy failure, where the entropy pool is exhausted, and thus the function cannot guarantee strong cryptographic randomness. While we cannot do anything about the former, the latter failure can be acceptable in some situations where we don't care whether or not the randomness can be predicted. Introduce a new `CSPRNG_BYTES_INSECURE` flag that allows callers to opt into weak cryptographic randomness. The exact behaviour of the flag depends on the underlying implementation: - `arc4random_buf()` never returns an error, so it doesn't change. - `getrandom()` pulls from "/dev/urandom" by default, which never blocks on modern systems even when the entropy pool is empty. - `getentropy()` seems to block when there is not enough randomness available, and there is no way of changing that behaviour. - `GtlGenRandom()` doesn't mention anything about its specific failure mode. - The fallback reads from "/dev/urandom", which also returns bytes in case the entropy pool is drained in modern Linux systems. That only leaves OpenSSL with `RAND_bytes()`, which returns an error in case the returned data wouldn't be cryptographically safe. This function is replaced with a call to `RAND_pseudo_bytes()`, which can indicate whether or not the returned data is cryptographically secure via its return value. If it is insecure, and if the `CSPRNG_BYTES_INSECURE` flag is set, then we ignore the insecurity and return the data regardless. It is somewhat questionable whether we really need the flag in the first place, or whether we wouldn't just ignore the potentially-insecure data. But the risk of doing that is that we might have or grow callsites that aren't aware of the potential insecureness of the data in places where it really matters. So using a flag to opt-in to that behaviour feels like the more secure choice. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/gc.c | 2 +- reftable/stack.c | 2 +- t/helper/test-csprng.c | 2 +- t/unit-tests/t-reftable-readwrite.c | 6 +++--- wrapper.c | 24 ++++++++++++++---------- wrapper.h | 16 ++++++++++++---- 6 files changed, 32 insertions(+), 20 deletions(-) diff --git a/builtin/gc.c b/builtin/gc.c index a9b1c36de2..3e754f25bb 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -1909,7 +1909,7 @@ static int get_random_minute(void) if (getenv("GIT_TEST_MAINT_SCHEDULER")) return 13; - return git_rand() % 60; + return git_rand(0) % 60; } static int is_launchctl_available(void) diff --git a/reftable/stack.c b/reftable/stack.c index 531660a49f..6d0aa774e7 100644 --- a/reftable/stack.c +++ b/reftable/stack.c @@ -659,7 +659,7 @@ int reftable_stack_add(struct reftable_stack *st, static int format_name(struct reftable_buf *dest, uint64_t min, uint64_t max) { char buf[100]; - uint32_t rnd = (uint32_t)git_rand(); + uint32_t rnd = (uint32_t)git_rand(0); snprintf(buf, sizeof(buf), "0x%012" PRIx64 "-0x%012" PRIx64 "-%08x", min, max, rnd); reftable_buf_reset(dest); diff --git a/t/helper/test-csprng.c b/t/helper/test-csprng.c index a4a0aca617..c86dcc4870 100644 --- a/t/helper/test-csprng.c +++ b/t/helper/test-csprng.c @@ -15,7 +15,7 @@ int cmd__csprng(int argc, const char **argv) while (count) { unsigned long chunk = count < sizeof(buf) ? count : sizeof(buf); - if (csprng_bytes(buf, chunk) < 0) { + if (csprng_bytes(buf, chunk, 0) < 0) { perror("failed to read"); return 5; } diff --git a/t/unit-tests/t-reftable-readwrite.c b/t/unit-tests/t-reftable-readwrite.c index 6b75a419b9..f22b977563 100644 --- a/t/unit-tests/t-reftable-readwrite.c +++ b/t/unit-tests/t-reftable-readwrite.c @@ -108,8 +108,8 @@ static void t_log_buffer_size(void) hash, to ensure that the compressed part is larger than the original. */ for (i = 0; i < REFTABLE_HASH_SIZE_SHA1; i++) { - log.value.update.old_hash[i] = (uint8_t)(git_rand() % 256); - log.value.update.new_hash[i] = (uint8_t)(git_rand() % 256); + log.value.update.old_hash[i] = (uint8_t)(git_rand(0) % 256); + log.value.update.new_hash[i] = (uint8_t)(git_rand(0) % 256); } reftable_writer_set_limits(w, update_index, update_index); err = reftable_writer_add_log(w, &log); @@ -325,7 +325,7 @@ static void t_log_zlib_corruption(void) }; for (i = 0; i < sizeof(message) - 1; i++) - message[i] = (uint8_t)(git_rand() % 64 + ' '); + message[i] = (uint8_t)(git_rand(0) % 64 + ' '); reftable_writer_set_limits(w, 1, 1); diff --git a/wrapper.c b/wrapper.c index fa79fd6ec9..8b98593149 100644 --- a/wrapper.c +++ b/wrapper.c @@ -479,7 +479,7 @@ int git_mkstemps_mode(char *pattern, int suffix_len, int mode) for (count = 0; count < TMP_MAX; ++count) { int i; uint64_t v; - if (csprng_bytes(&v, sizeof(v)) < 0) + if (csprng_bytes(&v, sizeof(v), 0) < 0) return error_errno("unable to get random bytes for temporary file"); /* Fill in the random bits. */ @@ -750,7 +750,7 @@ int open_nofollow(const char *path, int flags) #endif } -int csprng_bytes(void *buf, size_t len) +int csprng_bytes(void *buf, size_t len, MAYBE_UNUSED unsigned flags) { #if defined(HAVE_ARC4RANDOM) || defined(HAVE_ARC4RANDOM_LIBBSD) /* This function never returns an error. */ @@ -785,14 +785,18 @@ int csprng_bytes(void *buf, size_t len) return -1; return 0; #elif defined(HAVE_OPENSSL_CSPRNG) - int res = RAND_bytes(buf, len); - if (res == 1) + switch (RAND_pseudo_bytes(buf, len)) { + case 1: return 0; - if (res == -1) - errno = ENOTSUP; - else + case 0: + if (flags & CSPRNG_BYTES_INSECURE) + return 0; errno = EIO; - return -1; + return -1; + default: + errno = ENOTSUP; + return -1; + } #else ssize_t res; char *p = buf; @@ -816,11 +820,11 @@ int csprng_bytes(void *buf, size_t len) #endif } -uint32_t git_rand(void) +uint32_t git_rand(unsigned flags) { uint32_t result; - if (csprng_bytes(&result, sizeof(result)) < 0) + if (csprng_bytes(&result, sizeof(result), flags) < 0) die(_("unable to get random bytes")); return result; diff --git a/wrapper.h b/wrapper.h index a6b3e1f09e..7df824e34a 100644 --- a/wrapper.h +++ b/wrapper.h @@ -127,18 +127,26 @@ int open_nofollow(const char *path, int flags); void sleep_millisec(int millisec); +enum { + /* + * Accept insecure bytes, which some CSPRNG implementations may return + * in case the entropy pool has been exhausted. + */ + CSPRNG_BYTES_INSECURE = (1 << 0), +}; + /* * Generate len bytes from the system cryptographically secure PRNG. * Returns 0 on success and -1 on error, setting errno. The inability to - * satisfy the full request is an error. + * satisfy the full request is an error. Accepts CSPRNG flags. */ -int csprng_bytes(void *buf, size_t len); +int csprng_bytes(void *buf, size_t len, unsigned flags); /* * Returns a random uint32_t, uniformly distributed across all possible - * values. + * values. Accepts CSPRNG flags. */ -uint32_t git_rand(void); +uint32_t git_rand(unsigned flags); /* Provide log2 of the given `size_t`. */ static inline unsigned log2u(uintmax_t sz) -- cgit v1.2.3 From 0b4f8afef6b744d5aa92883c5a6c1985be67cc7c Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 7 Jan 2025 16:27:00 +0100 Subject: reftable/stack: accept insecure random bytes The reftable library uses randomness in two call paths: - When reading a stack in case some of the referenced tables disappears. The randomness is used to delay the next read by a couple of milliseconds. - When writing a new table, where the randomness gets appended to the table name (e.g. "0x000000000001-0x000000000002-0b1d8ddf.ref"). In neither of these cases do we need strong randomness. Unfortunately though, we have observed test failures caused by the former case. In t0610 we have a test that spawns a 100 processes at once, all of which try to write a new table to the stack. And given that all of the processes will require randomness, it can happen that these processes make the entropy pool run dry, which will then cause us to die: + test_seq 100 + printf %s commit\trefs/heads/branch-%s\n 68d032e9edd3481ac96382786ececc37ec28709e 1 + printf %s commit\trefs/heads/branch-%s\n 68d032e9edd3481ac96382786ececc37ec28709e 2 ... + git update-ref refs/heads/branch-98 HEAD + git update-ref refs/heads/branch-97 HEAD + git update-ref refs/heads/branch-99 HEAD + git update-ref refs/heads/branch-100 HEAD fatal: unable to get random bytes fatal: unable to get random bytes fatal: unable to get random bytes fatal: unable to get random bytes fatal: unable to get random bytes fatal: unable to get random bytes fatal: unable to get random bytes The report was for NonStop, which uses OpenSSL as the backend for randomness. In the preceding commit we have adapted that backend to also return randomness in case the entropy pool is empty and the caller passes the `CSPRNG_BYTES_INSECURE` flag. Do so to fix the issue. Reported-by: Randall S. Becker Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- reftable/stack.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reftable/stack.c b/reftable/stack.c index 6d0aa774e7..572a74e00f 100644 --- a/reftable/stack.c +++ b/reftable/stack.c @@ -493,7 +493,7 @@ static int reftable_stack_reload_maybe_reuse(struct reftable_stack *st, close(fd); fd = -1; - delay = delay + (delay * rand()) / RAND_MAX + 1; + delay = delay + (delay * git_rand(CSPRNG_BYTES_INSECURE)) / UINT32_MAX + 1; sleep_millisec(delay); } @@ -659,7 +659,7 @@ int reftable_stack_add(struct reftable_stack *st, static int format_name(struct reftable_buf *dest, uint64_t min, uint64_t max) { char buf[100]; - uint32_t rnd = (uint32_t)git_rand(0); + uint32_t rnd = git_rand(CSPRNG_BYTES_INSECURE); snprintf(buf, sizeof(buf), "0x%012" PRIx64 "-0x%012" PRIx64 "-%08x", min, max, rnd); reftable_buf_reset(dest); -- cgit v1.2.3 From ca7158076f9f6e0ee1c84595aaf44194a9880a72 Mon Sep 17 00:00:00 2001 From: Justin Tobler Date: Tue, 7 Jan 2025 10:29:15 -0600 Subject: fsck: reject misconfigured fsck.skipList In Git, fsck operations can ignore known broken objects via the `fsck.skipList` configuration. This option expects a path to a file with the list of object names. When the configuration is specified without a path, an error message is printed, but the command continues as if the configuration was not set. Configuring `fsck.skipList` without a value is a misconfiguration so config parsing should be more strict and reject it. Update `git_fsck_config()` to no longer ignore misconfiguration of `fsck.skipList`. The same behavior is also present for `fetch.fsck.skipList` and `receive.fsck.skipList` so the configuration parsers for these are updated to ensure the related operations remain consistent. Signed-off-by: Justin Tobler Signed-off-by: Junio C Hamano --- builtin/receive-pack.c | 2 +- fetch-pack.c | 2 +- fsck.c | 2 +- t/t5504-fetch-receive-strict.sh | 10 ++++++++++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index c2e9103f11..0158faf537 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -174,7 +174,7 @@ static int receive_pack_config(const char *var, const char *value, char *path; if (git_config_pathname(&path, var, value)) - return 1; + return -1; strbuf_addf(&fsck_msg_types, "%cskiplist=%s", fsck_msg_types.len ? ',' : '=', path); free(path); diff --git a/fetch-pack.c b/fetch-pack.c index 3a227721ed..055e8c3643 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -1867,7 +1867,7 @@ int fetch_pack_fsck_config(const char *var, const char *value, char *path ; if (git_config_pathname(&path, var, value)) - return 0; + return -1; strbuf_addf(msg_types, "%cskiplist=%s", msg_types->len ? ',' : '=', path); free(path); diff --git a/fsck.c b/fsck.c index 87ce999a49..9fc4c25ffd 100644 --- a/fsck.c +++ b/fsck.c @@ -1353,7 +1353,7 @@ int git_fsck_config(const char *var, const char *value, struct strbuf sb = STRBUF_INIT; if (git_config_pathname(&path, var, value)) - return 1; + return -1; strbuf_addf(&sb, "skiplist=%s", path); free(path); fsck_set_msg_types(options, sb.buf); diff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh index 8212a70be8..e273ab29c7 100755 --- a/t/t5504-fetch-receive-strict.sh +++ b/t/t5504-fetch-receive-strict.sh @@ -167,6 +167,8 @@ test_expect_success 'fsck with unsorted skipList' ' test_expect_success 'fsck with invalid or bogus skipList input' ' git -c fsck.skipList=/dev/null -c fsck.missingEmail=ignore fsck && + test_must_fail git -c fsck.skipList -c fsck.missingEmail=ignore fsck 2>err && + test_grep "unable to parse '\'fsck.skiplist\'' from command-line config" err && test_must_fail git -c fsck.skipList=does-not-exist -c fsck.missingEmail=ignore fsck 2>err && test_grep "could not open.*: does-not-exist" err && test_must_fail git -c fsck.skipList=.git/config -c fsck.missingEmail=ignore fsck 2>err && @@ -213,6 +215,11 @@ test_expect_success 'fsck with exhaustive accepted skipList input (various types test_must_be_empty err ' +test_expect_success 'receive-pack with missing receive.fsck.skipList path' ' + test_must_fail git -c receive.fsck.skipList receive-pack dst 2>err && + test_grep "unable to parse '\'receive.fsck.skiplist\'' from command-line config" err +' + test_expect_success 'push with receive.fsck.skipList' ' git push . $commit:refs/heads/bogus && rm -rf dst && @@ -255,6 +262,9 @@ test_expect_success 'fetch with fetch.fsck.skipList' ' test_must_fail git --git-dir=dst/.git fetch "file://$(pwd)" $refspec && # Invalid and/or bogus skipList input + test_must_fail git --git-dir=dst/.git -c fetch.fsck.skipList fetch \ + "file://$(pwd)" $refspec 2>err && + test_grep "unable to parse '\'fetch.fsck.skiplist\'' from command-line config" err && git --git-dir=dst/.git config fetch.fsck.skipList /dev/null && test_must_fail git --git-dir=dst/.git fetch "file://$(pwd)" $refspec && git --git-dir=dst/.git config fetch.fsck.skipList does-not-exist && -- cgit v1.2.3 From 14650065b76b28d3cfa9453356ac5669b19e706e Mon Sep 17 00:00:00 2001 From: Kristoffer Haugsbakk Date: Tue, 7 Jan 2025 18:37:06 +0100 Subject: RelNotes/2.48.0: fix typos etc. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correct verb tense, add missing words, avoid double blank lines, and rephrase things that don’t read well to me like “Turn this linkage to relative paths”. Signed-off-by: Kristoffer Haugsbakk Signed-off-by: Junio C Hamano --- Documentation/RelNotes/2.48.0.txt | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/Documentation/RelNotes/2.48.0.txt b/Documentation/RelNotes/2.48.0.txt index d62c62dc17..eff93be37a 100644 --- a/Documentation/RelNotes/2.48.0.txt +++ b/Documentation/RelNotes/2.48.0.txt @@ -47,15 +47,15 @@ Performance, Internal Implementation, Development Support etc. * The way AsciiDoc is used for SYNOPSIS part of the manual pages has been revamped. The sources, at least for the simple cases, got - vastly pleasant to work with. + vastly more pleasant to work with. * The reftable library is now prepared to expect that the memory allocation function given to it may fail to allocate and to deal with such an error. * An extra worktree attached to a repository points at each other to - allow finding the repository from the worktree and vice versa - possible. Turn this linkage to relative paths. + allow finding the repository from the worktree (and vice versa) + possible. Use relative paths for this linkage. * Enable Windows-based CI in GitLab. @@ -94,7 +94,7 @@ Performance, Internal Implementation, Development Support etc. * Update the project's CodingGuidelines to discourage naming functions with a "_1()" suffix. - * Updates the '.clang-format' to match project conventions. + * Update '.clang-format' to match project conventions. * Centralize documentation for repository extensions into a single place. @@ -116,7 +116,7 @@ Performance, Internal Implementation, Development Support etc. * The migration procedure between two ref backends has been optimized. * "git fsck" learned to issue warnings on "curiously formatted" ref - contents that have always been taken valid but something Git + contents that have always been treated as valid but that Git wouldn't have written itself (e.g., missing terminating end-of-line after the full object name). @@ -127,13 +127,13 @@ Performance, Internal Implementation, Development Support etc. * Drop support for ancient environments in various CI jobs. - * Isolates the reftable subsystem from the rest of Git's codebase by + * Isolate the reftable subsystem from the rest of Git's codebase by using fewer pieces of Git's infrastructure. * Optimize reading random references out of the reftable backend by allowing reuse of iterator objects. - * Backport oss-fuzz tests for us to our codebase. + * Backport oss-fuzz tests to our codebase. * Introduce a new repository extension to prevent older Git versions from mis-interpreting worktrees created with relative paths. @@ -173,13 +173,13 @@ Fixes since v2.47 ----------------- * Doc update to clarify how periodical maintenance are scheduled, - spread across time to avoid thundering hurds. + spread across time to avoid thundering herds. * Use after free and double freeing at the end in "git log -L... -p" had been identified and fixed. * On macOS, fsmonitor can fall into a race condition that results in - a client waiting forever to be notified for an event that have + a client waiting forever to be notified about an event that has already happened. This problem has been corrected. * "git maintenance start" crashed due to an uninitialized variable @@ -203,7 +203,7 @@ Fixes since v2.47 * The dumb-http code regressed when the result of re-indexing a pack yielded an *.idx file that differs in content from the *.idx file it downloaded from the remote. This has been corrected by no longer - relying on: the *.idx file we got from the remote. + relying on the *.idx file we got from the remote. * When called with '--left-right' and '--use-bitmap-index', 'rev-list' will produce output without any left/right markers, which has been @@ -227,7 +227,7 @@ Fixes since v2.47 * "git gc" discards any objects that are outside promisor packs that are referred to by an object in a promisor pack, and we do not refetch them from the promisor at runtime, resulting an unusable - repository. Work it around by including these objects in the + repository. Work around it by including these objects in the referring promisor pack at the receiving end of the fetch. * Avoid build/test breakage on a system without working malloc debug @@ -282,9 +282,8 @@ Fixes since v2.47 on the path, which was not documented, which has been corrected. (merge bc1a980759 kk/doc-ancestry-path later to maint). - * "git tag" has been taught to refuse to create refs/tags/HEAD - as such a tag will be confusing in the context of UI provided by + since such a tag will be confusing in the context of the UI provided by the Git Porcelain commands. (merge bbd445d5ef jc/forbid-head-as-tagname later to maint). -- cgit v1.2.3 From 6a63995335e7a941d34bdafb93a56f789ebeed75 Mon Sep 17 00:00:00 2001 From: Matthew Hughes Date: Tue, 7 Jan 2025 21:24:21 +0000 Subject: docs: fix typesetting of merge driver placeholders Following the `CodingGuidlines`, since these placeholders are literal they should be typeset verbatim, so fix some that aren't. Signed-off-by: Matthew Hughes Signed-off-by: Junio C Hamano --- Documentation/gitattributes.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index e6150595af..5d12b78549 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -1166,7 +1166,7 @@ internal merge and the final merge. The merge driver can learn the pathname in which the merged result will be stored via placeholder `%P`. The conflict labels to be used for the common ancestor, local head and other head can be passed by -using '%S', '%X' and '%Y` respectively. +using `%S`, `%X` and `%Y` respectively. `conflict-marker-size` ^^^^^^^^^^^^^^^^^^^^^^ -- cgit v1.2.3 From 45c0897204cfb5d0d88370a4907e41b0eb717b6c Mon Sep 17 00:00:00 2001 From: Sam James Date: Wed, 8 Jan 2025 03:42:37 +0000 Subject: meson: fix perl dependencies `generate_perl_command` needs `depends: [git_version_file]` and the uses in top-level meson.build were fine, but the ones in perl/ weren't, causing parallel build failures in some cases as GIT-BUILD-OPTIONS wasn't yet available. Signed-off-by: Sam James Acked-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- perl/FromCPAN/Mail/meson.build | 1 + perl/FromCPAN/meson.build | 1 + perl/Git/LoadCPAN/Mail/meson.build | 1 + perl/Git/LoadCPAN/meson.build | 1 + perl/Git/SVN/Memoize/meson.build | 1 + perl/Git/SVN/meson.build | 1 + perl/Git/meson.build | 1 + perl/meson.build | 1 + 8 files changed, 8 insertions(+) diff --git a/perl/FromCPAN/Mail/meson.build b/perl/FromCPAN/Mail/meson.build index 129cff161c..b4ff2fc0b2 100644 --- a/perl/FromCPAN/Mail/meson.build +++ b/perl/FromCPAN/Mail/meson.build @@ -4,4 +4,5 @@ test_dependencies += custom_target( command: generate_perl_command, install: true, install_dir: get_option('datadir') / 'perl5/FromCPAN/Mail', + depends: [git_version_file], ) diff --git a/perl/FromCPAN/meson.build b/perl/FromCPAN/meson.build index 4e7ea909df..1f9ea6ce8e 100644 --- a/perl/FromCPAN/meson.build +++ b/perl/FromCPAN/meson.build @@ -4,6 +4,7 @@ test_dependencies += custom_target( command: generate_perl_command, install: true, install_dir: get_option('datadir') / 'perl5/FromCPAN', + depends: [git_version_file], ) subdir('Mail') diff --git a/perl/Git/LoadCPAN/Mail/meson.build b/perl/Git/LoadCPAN/Mail/meson.build index 7da5b37adb..89cde56be8 100644 --- a/perl/Git/LoadCPAN/Mail/meson.build +++ b/perl/Git/LoadCPAN/Mail/meson.build @@ -4,4 +4,5 @@ test_dependencies += custom_target( command: generate_perl_command, install: true, install_dir: get_option('datadir') / 'perl5/Git/LoadCPAN/Mail', + depends: [git_version_file], ) diff --git a/perl/Git/LoadCPAN/meson.build b/perl/Git/LoadCPAN/meson.build index 9468c073ae..1ee915c650 100644 --- a/perl/Git/LoadCPAN/meson.build +++ b/perl/Git/LoadCPAN/meson.build @@ -4,6 +4,7 @@ test_dependencies += custom_target( command: generate_perl_command, install: true, install_dir: get_option('datadir') / 'perl5/Git/LoadCPAN', + depends: [git_version_file], ) subdir('Mail') diff --git a/perl/Git/SVN/Memoize/meson.build b/perl/Git/SVN/Memoize/meson.build index 515ab3dd92..233ec670d7 100644 --- a/perl/Git/SVN/Memoize/meson.build +++ b/perl/Git/SVN/Memoize/meson.build @@ -4,4 +4,5 @@ test_dependencies += custom_target( command: generate_perl_command, install: true, install_dir: get_option('datadir') / 'perl5/Git/SVN', + depends: [git_version_file], ) diff --git a/perl/Git/SVN/meson.build b/perl/Git/SVN/meson.build index 8338531041..44abaf42b7 100644 --- a/perl/Git/SVN/meson.build +++ b/perl/Git/SVN/meson.build @@ -14,6 +14,7 @@ foreach source : [ command: generate_perl_command, install: true, install_dir: get_option('datadir') / 'perl5/Git/SVN', + depends: [git_version_file], ) endforeach diff --git a/perl/Git/meson.build b/perl/Git/meson.build index 259209d730..b21fa5591e 100644 --- a/perl/Git/meson.build +++ b/perl/Git/meson.build @@ -11,6 +11,7 @@ foreach source : [ command: generate_perl_command, install: true, install_dir: get_option('datadir') / 'perl5/Git', + depends: [git_version_file], ) endforeach diff --git a/perl/meson.build b/perl/meson.build index c22d6f8a1a..2d4ab1c4a9 100644 --- a/perl/meson.build +++ b/perl/meson.build @@ -4,6 +4,7 @@ test_dependencies += custom_target( command: generate_perl_command, install: true, install_dir: get_option('datadir') / 'perl5', + depends: [git_version_file], ) subdir('Git') -- cgit v1.2.3 From d02c37c3e6baf1515e7d1372afa5941b9518ca5b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 8 Jan 2025 16:00:05 +0000 Subject: t-reftable-basics: allow for `malloc` to be `#define`d MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As indicated by the `#undef malloc` line in `reftable/basics.h`, it is quite common to use allocators other than the default one by defining `malloc` constants and friends. This pattern is used e.g. in Git for Windows, which uses the powerful and performant `mimalloc` allocator. Furthermore, in `reftable/basics.c` this `#undef malloc` is _specifically_ disabled by virtue of defining the `REFTABLE_ALLOW_BANNED_ALLOCATORS` constant before including `reftable/basic.h`, to ensure that such a custom allocator is also used in the reftable code. However, in 8db127d43f5b (reftable: avoid leaks on realloc error, 2024-12-28) and in 2cca185e8517 (reftable: fix allocation count on realloc error, 2024-12-28), `reftable_set_alloc()` function calls were introduced that pass `malloc`, `realloc` and `free` function pointers as parameters _after_ `reftable/basics.h` ensured that they were no longer `#define`d. This would override the custom allocator and re-set it to the default allocator provided by, say, libc or MSVCRT. This causes problems because those calls happen after the initial allocator has already been used to initialize an array, which is subsequently resized using the overridden default `realloc()` allocator. You cannot mix and match allocators like that, which leads to a `STATUS_HEAP_CORRUPTION` (C0000374) on Windows, and when running this unit test through shell and/or `prove` (which only support 7-bit status codes), it surfaces as exit code 127. It is actually unnecessary to use those function pointers to `malloc`/`realloc`/`free`, though: The `reftable` code goes out of its way to fall back to the initial allocator when passing `NULL` parameters instead. So let's do that instead of causing heap corruptions. Signed-off-by: Johannes Schindelin Acked-by: René Scharfe Signed-off-by: Junio C Hamano --- t/unit-tests/t-reftable-basics.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/t/unit-tests/t-reftable-basics.c b/t/unit-tests/t-reftable-basics.c index 990dc1a244..1d640b280f 100644 --- a/t/unit-tests/t-reftable-basics.c +++ b/t/unit-tests/t-reftable-basics.c @@ -157,13 +157,13 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED) old_alloc = alloc; old_arr = arr; - reftable_set_alloc(malloc, realloc_stub, free); + reftable_set_alloc(NULL, realloc_stub, NULL); check(REFTABLE_ALLOC_GROW(arr, old_alloc + 1, alloc)); check(arr == old_arr); check_uint(alloc, ==, old_alloc); old_alloc = alloc; - reftable_set_alloc(malloc, realloc, free); + reftable_set_alloc(NULL, NULL, NULL); check(!REFTABLE_ALLOC_GROW(arr, old_alloc + 1, alloc)); check(arr != NULL); check_uint(alloc, >, old_alloc); @@ -188,11 +188,11 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED) arr[alloc - 1] = 42; old_alloc = alloc; - reftable_set_alloc(malloc, realloc_stub, free); + reftable_set_alloc(NULL, realloc_stub, NULL); REFTABLE_ALLOC_GROW_OR_NULL(arr, old_alloc + 1, alloc); check(arr == NULL); check_uint(alloc, ==, 0); - reftable_set_alloc(malloc, realloc, free); + reftable_set_alloc(NULL, NULL, NULL); reftable_free(arr); } -- cgit v1.2.3 From 43850dcf9c4ca6407abdd167aa3acc098e0e0f7c Mon Sep 17 00:00:00 2001 From: Seyi Kuforiji Date: Thu, 9 Jan 2025 15:09:52 +0100 Subject: t/unit-tests: convert hash to use clar test framework Adapt the hash test functions to clar framework by using clar assertions where necessary. Following the consensus to convert the unit-tests scripts found in the t/unit-tests folder to clar driven by Patrick Steinhardt. Test functions are structured as a standalone to test individual hash string and literal case. Mentored-by: Patrick Steinhardt Signed-off-by: Seyi Kuforiji Signed-off-by: Junio C Hamano --- Makefile | 2 +- t/meson.build | 2 +- t/unit-tests/t-hash.c | 84 -------------------------------------- t/unit-tests/u-hash.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 86 deletions(-) delete mode 100644 t/unit-tests/t-hash.c create mode 100644 t/unit-tests/u-hash.c diff --git a/Makefile b/Makefile index 97e8385b66..d3011e30f7 100644 --- a/Makefile +++ b/Makefile @@ -1338,6 +1338,7 @@ THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/% THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/clar/% CLAR_TEST_SUITES += u-ctype +CLAR_TEST_SUITES += u-hash CLAR_TEST_SUITES += u-strvec CLAR_TEST_PROG = $(UNIT_TEST_BIN)/unit-tests$(X) CLAR_TEST_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(CLAR_TEST_SUITES)) @@ -1345,7 +1346,6 @@ CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/clar/clar.o CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/unit-test.o UNIT_TEST_PROGRAMS += t-example-decorate -UNIT_TEST_PROGRAMS += t-hash UNIT_TEST_PROGRAMS += t-hashmap UNIT_TEST_PROGRAMS += t-mem-pool UNIT_TEST_PROGRAMS += t-oid-array diff --git a/t/meson.build b/t/meson.build index 602ebfe6a2..7b35eadbc8 100644 --- a/t/meson.build +++ b/t/meson.build @@ -1,5 +1,6 @@ clar_test_suites = [ 'unit-tests/u-ctype.c', + 'unit-tests/u-hash.c', 'unit-tests/u-strvec.c', ] @@ -41,7 +42,6 @@ test('unit-tests', clar_unit_tests) unit_test_programs = [ 'unit-tests/t-example-decorate.c', - 'unit-tests/t-hash.c', 'unit-tests/t-hashmap.c', 'unit-tests/t-mem-pool.c', 'unit-tests/t-oid-array.c', diff --git a/t/unit-tests/t-hash.c b/t/unit-tests/t-hash.c deleted file mode 100644 index e62647019b..0000000000 --- a/t/unit-tests/t-hash.c +++ /dev/null @@ -1,84 +0,0 @@ -#include "test-lib.h" -#include "hex.h" -#include "strbuf.h" - -static void check_hash_data(const void *data, size_t data_length, - const char *expected_hashes[]) -{ - if (!check(data != NULL)) { - test_msg("BUG: NULL data pointer provided"); - return; - } - - for (size_t i = 1; i < ARRAY_SIZE(hash_algos); i++) { - git_hash_ctx ctx; - unsigned char hash[GIT_MAX_HEXSZ]; - const struct git_hash_algo *algop = &hash_algos[i]; - - algop->init_fn(&ctx); - algop->update_fn(&ctx, data, data_length); - algop->final_fn(hash, &ctx); - - if (!check_str(hash_to_hex_algop(hash, algop), expected_hashes[i - 1])) - test_msg("result does not match with the expected for %s\n", hash_algos[i].name); - } -} - -/* Works with a NUL terminated string. Doesn't work if it should contain a NUL character. */ -#define TEST_HASH_STR(data, expected_sha1, expected_sha256) do { \ - const char *expected_hashes[] = { expected_sha1, expected_sha256 }; \ - TEST(check_hash_data(data, strlen(data), expected_hashes), \ - "SHA1 and SHA256 (%s) works", #data); \ - } while (0) - -/* Only works with a literal string, useful when it contains a NUL character. */ -#define TEST_HASH_LITERAL(literal, expected_sha1, expected_sha256) do { \ - const char *expected_hashes[] = { expected_sha1, expected_sha256 }; \ - TEST(check_hash_data(literal, (sizeof(literal) - 1), expected_hashes), \ - "SHA1 and SHA256 (%s) works", #literal); \ - } while (0) - -int cmd_main(int argc UNUSED, const char **argv UNUSED) -{ - struct strbuf aaaaaaaaaa_100000 = STRBUF_INIT; - struct strbuf alphabet_100000 = STRBUF_INIT; - - strbuf_addstrings(&aaaaaaaaaa_100000, "aaaaaaaaaa", 100000); - strbuf_addstrings(&alphabet_100000, "abcdefghijklmnopqrstuvwxyz", 100000); - - TEST_HASH_STR("", - "da39a3ee5e6b4b0d3255bfef95601890afd80709", - "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); - TEST_HASH_STR("a", - "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", - "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"); - TEST_HASH_STR("abc", - "a9993e364706816aba3e25717850c26c9cd0d89d", - "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); - TEST_HASH_STR("message digest", - "c12252ceda8be8994d5fa0290a47231c1d16aae3", - "f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650"); - TEST_HASH_STR("abcdefghijklmnopqrstuvwxyz", - "32d10c7b8cf96570ca04ce37f2a19d84240d3a89", - "71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73"); - TEST_HASH_STR(aaaaaaaaaa_100000.buf, - "34aa973cd4c4daa4f61eeb2bdbad27316534016f", - "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"); - TEST_HASH_STR(alphabet_100000.buf, - "e7da7c55b3484fdf52aebec9cbe7b85a98f02fd4", - "e406ba321ca712ad35a698bf0af8d61fc4dc40eca6bdcea4697962724ccbde35"); - TEST_HASH_LITERAL("blob 0\0", - "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", - "473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813"); - TEST_HASH_LITERAL("blob 3\0abc", - "f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f", - "c1cf6e465077930e88dc5136641d402f72a229ddd996f627d60e9639eaba35a6"); - TEST_HASH_LITERAL("tree 0\0", - "4b825dc642cb6eb9a060e54bf8d69288fbee4904", - "6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321"); - - strbuf_release(&aaaaaaaaaa_100000); - strbuf_release(&alphabet_100000); - - return test_done(); -} diff --git a/t/unit-tests/u-hash.c b/t/unit-tests/u-hash.c new file mode 100644 index 0000000000..a0320efe4b --- /dev/null +++ b/t/unit-tests/u-hash.c @@ -0,0 +1,109 @@ +#include "unit-test.h" +#include "hex.h" +#include "strbuf.h" + +static void check_hash_data(const void *data, size_t data_length, + const char *expected_hashes[]) +{ + cl_assert(data != NULL); + + for (size_t i = 1; i < ARRAY_SIZE(hash_algos); i++) { + git_hash_ctx ctx; + unsigned char hash[GIT_MAX_HEXSZ]; + const struct git_hash_algo *algop = &hash_algos[i]; + + algop->init_fn(&ctx); + algop->update_fn(&ctx, data, data_length); + algop->final_fn(hash, &ctx); + + cl_assert_equal_s(hash_to_hex_algop(hash,algop), expected_hashes[i - 1]); + } +} + +/* Works with a NUL terminated string. Doesn't work if it should contain a NUL character. */ +#define TEST_HASH_STR(data, expected_sha1, expected_sha256) do { \ + const char *expected_hashes[] = { expected_sha1, expected_sha256 }; \ + check_hash_data(data, strlen(data), expected_hashes); \ + } while (0) + +/* Only works with a literal string, useful when it contains a NUL character. */ +#define TEST_HASH_LITERAL(literal, expected_sha1, expected_sha256) do { \ + const char *expected_hashes[] = { expected_sha1, expected_sha256 }; \ + check_hash_data(literal, (sizeof(literal) - 1), expected_hashes); \ + } while (0) + +void test_hash__empty_string(void) +{ + TEST_HASH_STR("", + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); +} + +void test_hash__single_character(void) +{ + TEST_HASH_STR("a", + "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", + "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"); +} + +void test_hash__multi_character(void) +{ + TEST_HASH_STR("abc", + "a9993e364706816aba3e25717850c26c9cd0d89d", + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); +} + +void test_hash__message_digest(void) +{ + TEST_HASH_STR("message digest", + "c12252ceda8be8994d5fa0290a47231c1d16aae3", + "f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650"); +} + +void test_hash__alphabet(void) +{ + TEST_HASH_STR("abcdefghijklmnopqrstuvwxyz", + "32d10c7b8cf96570ca04ce37f2a19d84240d3a89", + "71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73"); +} + +void test_hash__aaaaaaaaaa_100000(void) +{ + struct strbuf aaaaaaaaaa_100000 = STRBUF_INIT; + strbuf_addstrings(&aaaaaaaaaa_100000, "aaaaaaaaaa", 100000); + TEST_HASH_STR(aaaaaaaaaa_100000.buf, + "34aa973cd4c4daa4f61eeb2bdbad27316534016f", + "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"); + strbuf_release(&aaaaaaaaaa_100000); +} + +void test_hash__alphabet_100000(void) +{ + struct strbuf alphabet_100000 = STRBUF_INIT; + strbuf_addstrings(&alphabet_100000, "abcdefghijklmnopqrstuvwxyz", 100000); + TEST_HASH_STR(alphabet_100000.buf, + "e7da7c55b3484fdf52aebec9cbe7b85a98f02fd4", + "e406ba321ca712ad35a698bf0af8d61fc4dc40eca6bdcea4697962724ccbde35"); + strbuf_release(&alphabet_100000); +} + +void test_hash__zero_blob_literal(void) +{ + TEST_HASH_LITERAL("blob 0\0", + "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813"); +} + +void test_hash__three_blob_literal(void) +{ + TEST_HASH_LITERAL("blob 3\0abc", + "f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f", + "c1cf6e465077930e88dc5136641d402f72a229ddd996f627d60e9639eaba35a6"); +} + +void test_hash__zero_tree_literal(void) +{ + TEST_HASH_LITERAL("tree 0\0", + "4b825dc642cb6eb9a060e54bf8d69288fbee4904", + "6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321"); +} -- cgit v1.2.3 From 21e1b4486586d3a15d2d7bf0479e77636359b816 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Wed, 8 Jan 2025 23:35:23 +0000 Subject: difftool docs: restore correct position of tool list 2a9dfdf260 (difftool docs: de-duplicate configuration sections, 2022-09-07) moved the difftool documentation, but missed moving this "include" line that includes the generated list of diff tools, as referenced in the moved text. Restore the correct position of the included list. Signed-off-by: Adam Johnson Signed-off-by: Junio C Hamano --- Documentation/config/diff.txt | 2 -- Documentation/config/difftool.txt | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/config/diff.txt b/Documentation/config/diff.txt index fdae13a212..1135a62a0a 100644 --- a/Documentation/config/diff.txt +++ b/Documentation/config/diff.txt @@ -218,8 +218,6 @@ endif::git-diff[] Set this option to `true` to make the diff driver cache the text conversion outputs. See linkgit:gitattributes[5] for details. -include::{build_dir}/mergetools-diff.txt[] - `diff.indentHeuristic`:: Set this option to `false` to disable the default heuristics that shift diff hunk boundaries to make patches easier to read. diff --git a/Documentation/config/difftool.txt b/Documentation/config/difftool.txt index 447c40d85a..6cd47331a9 100644 --- a/Documentation/config/difftool.txt +++ b/Documentation/config/difftool.txt @@ -13,6 +13,8 @@ diff.guitool:: and requires that a corresponding difftool..cmd variable is defined. +include::{build_dir}/mergetools-diff.txt[] + difftool..cmd:: Specify the command to invoke the specified diff tool. The specified command is evaluated in shell with the following -- cgit v1.2.3 From 949bb8f74f6db7405d6ad8bbf02ebc42a947801d Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 9 Jan 2025 03:28:18 -0500 Subject: run_diff_files(): delay allocation of combine_diff_path While looping over the index entries, when we see a higher level stage the first thing we do is allocate a combine_diff_path struct for it. But this can leak; if check_removed() returns an error, we'll continue to the next iteration of the loop without cleaning up. We can fix this by just delaying the allocation by a few lines. I don't think this leak is triggered in the test suite, but it's pretty easy to see by inspection. My ulterior motive here is that the delayed allocation means we have all of the data needed to initialize "dpath" at the time of malloc, making it easier to factor out a constructor function. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- diff-lib.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/diff-lib.c b/diff-lib.c index c6d3bc4d37..85b8f1fa59 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -156,18 +156,6 @@ void run_diff_files(struct rev_info *revs, unsigned int option) size_t path_len; struct stat st; - path_len = ce_namelen(ce); - - dpath = xmalloc(combine_diff_path_size(5, path_len)); - dpath->path = (char *) &(dpath->parent[5]); - - dpath->next = NULL; - memcpy(dpath->path, ce->name, path_len); - dpath->path[path_len] = '\0'; - oidclr(&dpath->oid, the_repository->hash_algo); - memset(&(dpath->parent[0]), 0, - sizeof(struct combine_diff_parent)*5); - changed = check_removed(ce, &st); if (!changed) wt_mode = ce_mode_from_stat(ce, st.st_mode); @@ -178,7 +166,19 @@ void run_diff_files(struct rev_info *revs, unsigned int option) } wt_mode = 0; } + + path_len = ce_namelen(ce); + + dpath = xmalloc(combine_diff_path_size(5, path_len)); + dpath->path = (char *) &(dpath->parent[5]); + + dpath->next = NULL; + memcpy(dpath->path, ce->name, path_len); + dpath->path[path_len] = '\0'; + oidclr(&dpath->oid, the_repository->hash_algo); dpath->mode = wt_mode; + memset(&(dpath->parent[0]), 0, + sizeof(struct combine_diff_parent)*5); while (i < entries) { struct cache_entry *nce = istate->cache[i]; -- cgit v1.2.3 From 706779344155823518745a19515601905877c41f Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 9 Jan 2025 03:32:36 -0500 Subject: combine-diff: add combine_diff_path_new() The combine_diff_path struct has variable size, since it embeds both the memory allocation for the path field as well as a variable-sized parent array. This makes allocating one a bit tricky. We have a helper to compute the required size, but it's up to individual sites to actually initialize all of the fields. Let's provide a constructor function to make that a little nicer. Besides being shorter, it also hides away tricky bits like the computation of the "path" pointer (which is right after the "parent" flex array). As a bonus, using the same constructor everywhere means that we'll consistently initialize all parts of the struct. A few code paths left the parent array unitialized. This didn't cause any bugs, but we'll be able to simplify some code in the next few patches knowing that the parent fields have all been zero'd. This also gets rid of some questionable uses of "int" to store buffer lengths. Though we do use them to allocate, I don't think there are any integer overflow vulnerabilities here (the allocation helper promotes them to size_t and checks arithmetic for overflow, and the actual memcpy of the bytes is done using the possibly-truncated "int" value). Sadly we can't use the FLEX_* macros to simplify the allocation here, because there are two variable-sized parts to the struct (and those macros only handle one). Nor can we get stop publicly declaring combine_diff_path_size(). This patch does not touch the code in path_appendnew() at all, which is not ready to be moved to our new constructor for a few reasons: - path_appendnew() has a memory-reuse optimization where it tries to reuse combine_diff_path structs rather than freeing and reallocating. - path_appendnew() does not create the struct from a single path string, but rather allocates and copies into the buffer from multiple sources. These can be addressed by some refactoring, but let's leave it as-is for now. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- combine-diff.c | 40 ++++++++++++++++++++++++++-------------- diff-lib.c | 29 ++++++----------------------- diff.h | 5 +++++ 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/combine-diff.c b/combine-diff.c index 641bc92dbd..45548fd438 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -47,22 +47,13 @@ static struct combine_diff_path *intersect_paths( if (!n) { for (i = 0; i < q->nr; i++) { - int len; - const char *path; if (diff_unmodified_pair(q->queue[i])) continue; - path = q->queue[i]->two->path; - len = strlen(path); - p = xmalloc(combine_diff_path_size(num_parent, len)); - p->path = (char *) &(p->parent[num_parent]); - memcpy(p->path, path, len); - p->path[len] = 0; - p->next = NULL; - memset(p->parent, 0, - sizeof(p->parent[0]) * num_parent); - - oidcpy(&p->oid, &q->queue[i]->two->oid); - p->mode = q->queue[i]->two->mode; + p = combine_diff_path_new(q->queue[i]->two->path, + strlen(q->queue[i]->two->path), + q->queue[i]->two->mode, + &q->queue[i]->two->oid, + num_parent); oidcpy(&p->parent[n].oid, &q->queue[i]->one->oid); p->parent[n].mode = q->queue[i]->one->mode; p->parent[n].status = q->queue[i]->status; @@ -1667,3 +1658,24 @@ void diff_tree_combined_merge(const struct commit *commit, diff_tree_combined(&commit->object.oid, &parents, rev); oid_array_clear(&parents); } + +struct combine_diff_path *combine_diff_path_new(const char *path, + size_t path_len, + unsigned int mode, + const struct object_id *oid, + size_t num_parents) +{ + struct combine_diff_path *p; + + p = xmalloc(combine_diff_path_size(num_parents, path_len)); + p->path = (char *)&(p->parent[num_parents]); + memcpy(p->path, path, path_len); + p->path[path_len] = 0; + p->next = NULL; + p->mode = mode; + oidcpy(&p->oid, oid); + + memset(p->parent, 0, sizeof(p->parent[0]) * num_parents); + + return p; +} diff --git a/diff-lib.c b/diff-lib.c index 85b8f1fa59..471ef99614 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -153,7 +153,6 @@ void run_diff_files(struct rev_info *revs, unsigned int option) struct diff_filepair *pair; unsigned int wt_mode = 0; int num_compare_stages = 0; - size_t path_len; struct stat st; changed = check_removed(ce, &st); @@ -167,18 +166,8 @@ void run_diff_files(struct rev_info *revs, unsigned int option) wt_mode = 0; } - path_len = ce_namelen(ce); - - dpath = xmalloc(combine_diff_path_size(5, path_len)); - dpath->path = (char *) &(dpath->parent[5]); - - dpath->next = NULL; - memcpy(dpath->path, ce->name, path_len); - dpath->path[path_len] = '\0'; - oidclr(&dpath->oid, the_repository->hash_algo); - dpath->mode = wt_mode; - memset(&(dpath->parent[0]), 0, - sizeof(struct combine_diff_parent)*5); + dpath = combine_diff_path_new(ce->name, ce_namelen(ce), + wt_mode, null_oid(), 5); while (i < entries) { struct cache_entry *nce = istate->cache[i]; @@ -405,16 +394,10 @@ static int show_modified(struct rev_info *revs, if (revs->combine_merges && !cached && (!oideq(oid, &old_entry->oid) || !oideq(&old_entry->oid, &new_entry->oid))) { struct combine_diff_path *p; - int pathlen = ce_namelen(new_entry); - - p = xmalloc(combine_diff_path_size(2, pathlen)); - p->path = (char *) &p->parent[2]; - p->next = NULL; - memcpy(p->path, new_entry->name, pathlen); - p->path[pathlen] = 0; - p->mode = mode; - oidclr(&p->oid, the_repository->hash_algo); - memset(p->parent, 0, 2 * sizeof(struct combine_diff_parent)); + + p = combine_diff_path_new(new_entry->name, + ce_namelen(new_entry), + mode, null_oid(), 2); p->parent[0].status = DIFF_STATUS_MODIFIED; p->parent[0].mode = new_entry->ce_mode; oidcpy(&p->parent[0].oid, &new_entry->oid); diff --git a/diff.h b/diff.h index 6e6007c17b..5cddd5a870 100644 --- a/diff.h +++ b/diff.h @@ -486,6 +486,11 @@ struct combine_diff_path { #define combine_diff_path_size(n, l) \ st_add4(sizeof(struct combine_diff_path), (l), 1, \ st_mult(sizeof(struct combine_diff_parent), (n))) +struct combine_diff_path *combine_diff_path_new(const char *path, + size_t path_len, + unsigned int mode, + const struct object_id *oid, + size_t num_parents); void show_combined_diff(struct combine_diff_path *elem, int num_parent, struct rev_info *); -- cgit v1.2.3 From 5173099aae25bedf7a87225891d124569cba7076 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 9 Jan 2025 03:33:10 -0500 Subject: tree-diff: clear parent array in path_appendnew() All of the other functions which allocate a combine_diff_path struct zero out the parent array, but this code path does not. There's no bug, since our caller will fill in most of the fields. But leaving the unused fields (like combine_diff_parent.path) uninitialized makes working with the struct more error-prone than it needs to be. Let's just zero the parent field to be consistent with the combine_diff_path_new() allocator. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- tree-diff.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tree-diff.c b/tree-diff.c index d9237ffd9b..24f7b5912c 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -151,8 +151,6 @@ static int emit_diff_first_parent_only(struct diff_options *opt, struct combine_ * process(p); * p = pprev; * ; don't forget to free tail->next in the end - * - * p->parent[] remains uninitialized. */ static struct combine_diff_path *path_appendnew(struct combine_diff_path *last, int nparent, const struct strbuf *base, const char *path, int pathlen, @@ -187,6 +185,8 @@ static struct combine_diff_path *path_appendnew(struct combine_diff_path *last, p->mode = mode; oidcpy(&p->oid, oid ? oid : null_oid()); + memset(p->parent, 0, sizeof(p->parent[0]) * nparent); + return p; } -- cgit v1.2.3 From 3a0599788fd38822dcd2f32de538afdd36a478aa Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 9 Jan 2025 03:42:29 -0500 Subject: combine-diff: use pointer for parent paths Commit d76ce4f734 (log,diff-tree: add --combined-all-paths option, 2019-02-07) added a "path" field to each combine_diff_parent struct. It's defined as a strbuf, but this is overkill. We never manipulate the buffer beyond inserting a single string into it. And in fact there's a small bug: we zero the parent structs, including the path strbufs. For the 0th parent, we strbuf_init() the strbuf before adding to it. But for subsequent parents, we never do the init. This is technically violating the strbuf API, though the code there is resilient enough to handle this zero'd state. This patch switches us to just store an allocated string pointer. Zeroing it is enough to properly initialize it there (modulo the usual assumption we make that a NULL pointer is all-zeroes). And as a bonus, we can just check for a non-NULL value to see if it is present, rather than repeating the combined_all_paths logic at each site. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- combine-diff.c | 30 +++++++++++------------------- diff.h | 2 +- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/combine-diff.c b/combine-diff.c index 45548fd438..ae3cbfc699 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -60,9 +60,7 @@ static struct combine_diff_path *intersect_paths( if (combined_all_paths && filename_changed(p->parent[n].status)) { - strbuf_init(&p->parent[n].path, 0); - strbuf_addstr(&p->parent[n].path, - q->queue[i]->one->path); + p->parent[n].path = xstrdup(q->queue[i]->one->path); } *tail = p; tail = &p->next; @@ -83,9 +81,7 @@ static struct combine_diff_path *intersect_paths( /* p->path not in q->queue[]; drop it */ *tail = p->next; for (j = 0; j < num_parent; j++) - if (combined_all_paths && - filename_changed(p->parent[j].status)) - strbuf_release(&p->parent[j].path); + free(p->parent[j].path); free(p); continue; } @@ -101,8 +97,7 @@ static struct combine_diff_path *intersect_paths( p->parent[n].status = q->queue[i]->status; if (combined_all_paths && filename_changed(p->parent[n].status)) - strbuf_addstr(&p->parent[n].path, - q->queue[i]->one->path); + p->parent[n].path = xstrdup(q->queue[i]->one->path); tail = &p->next; i++; @@ -987,8 +982,9 @@ static void show_combined_header(struct combine_diff_path *elem, if (rev->combined_all_paths) { for (i = 0; i < num_parent; i++) { - char *path = filename_changed(elem->parent[i].status) - ? elem->parent[i].path.buf : elem->path; + const char *path = elem->parent[i].path ? + elem->parent[i].path : + elem->path; if (elem->parent[i].status == DIFF_STATUS_ADDED) dump_quoted_path("--- ", "", "/dev/null", line_prefix, c_meta, c_reset); @@ -1269,12 +1265,10 @@ static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct re for (i = 0; i < num_parent; i++) if (rev->combined_all_paths) { - if (filename_changed(p->parent[i].status)) - write_name_quoted(p->parent[i].path.buf, stdout, - inter_name_termination); - else - write_name_quoted(p->path, stdout, - inter_name_termination); + const char *path = p->parent[i].path ? + p->parent[i].path : + p->path; + write_name_quoted(path, stdout, inter_name_termination); } write_name_quoted(p->path, stdout, line_termination); } @@ -1636,9 +1630,7 @@ void diff_tree_combined(const struct object_id *oid, struct combine_diff_path *tmp = paths; paths = paths->next; for (i = 0; i < num_parent; i++) - if (rev->combined_all_paths && - filename_changed(tmp->parent[i].status)) - strbuf_release(&tmp->parent[i].path); + free(tmp->parent[i].path); free(tmp); } diff --git a/diff.h b/diff.h index 5cddd5a870..f5f6ea00fb 100644 --- a/diff.h +++ b/diff.h @@ -480,7 +480,7 @@ struct combine_diff_path { char status; unsigned int mode; struct object_id oid; - struct strbuf path; + char *path; } parent[FLEX_ARRAY]; }; #define combine_diff_path_size(n, l) \ -- cgit v1.2.3 From 30f7414ca17bc675105d3d731a827778d7367b11 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 9 Jan 2025 03:42:48 -0500 Subject: diff: add a comment about combine_diff_path.parent.path We only fill in the per-parent "path" field when it differs from what's in combine_diff_path.path (and even then only when the option is appropriate). Let's document that. Suggested-by: Wink Saville Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- diff.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/diff.h b/diff.h index f5f6ea00fb..60e7db4ad6 100644 --- a/diff.h +++ b/diff.h @@ -480,6 +480,12 @@ struct combine_diff_path { char status; unsigned int mode; struct object_id oid; + /* + * This per-parent path is filled only when doing a combined + * diff with revs.combined_all_paths set, and only if the path + * differs from the post-image (e.g., a rename or copy). + * Otherwise it is left NULL. + */ char *path; } parent[FLEX_ARRAY]; }; -- cgit v1.2.3 From ca3abe41d71c4789ca00cba0ca2b6c22d67f08a3 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 9 Jan 2025 03:44:21 -0500 Subject: run_diff_files(): de-mystify the size of combine_diff_path struct We allocate a combine_diff_path struct with space for 5 parents. Why 5? The history is not particularly enlightening. The allocation comes from b4b1550315 (Don't instantiate structures with FAMs., 2006-06-18), which just switched to xmalloc from a stack struct with 5 elements. That struct changed to 5 from 4 in 2454c962fb (combine-diff: show mode changes as well., 2006-02-06), when we also moved from storing raw sha1 bytes to the combine_diff_parent struct. But no explanation is given. That 4 comes from the earliest code in ea726d02e9 (diff-files: -c and --cc options., 2006-01-28). One might guess it is for the 4 stages we can store in the index. But this code path only ever diffs the current state against stages 2 and 3. So we only need two slots. And it's easy to see this is still the case. We fill the parent slots by subtracting 2 from the ce_stage() values, ignoring values below 2. And since ce_stage() is only 2 bits, there are 4 values, and thus we need 2 slots. Let's use the correct value (saving a tiny bit of memory) and add a comment explaining what's going on (saving a tiny bit of programmer brain power). Arguably we could use: 1 + (STAGEMASK >> STAGESHIFT) - 2 which lets the compiler enforce that we will not go out-of-bounds if we see an unexpected value from ce_stage(). But that is more confusing to explain, and the constant "2" is baked into other parts of the function. It is a fundamental constant, not something where somebody might bump a macro and forget to update this code. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- diff-lib.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/diff-lib.c b/diff-lib.c index 471ef99614..353b473ed5 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -166,8 +166,13 @@ void run_diff_files(struct rev_info *revs, unsigned int option) wt_mode = 0; } + /* + * Allocate space for two parents, which will come from + * index stages #2 and #3, if present. Below we'll fill + * these from (stage - 2). + */ dpath = combine_diff_path_new(ce->name, ce_namelen(ce), - wt_mode, null_oid(), 5); + wt_mode, null_oid(), 2); while (i < entries) { struct cache_entry *nce = istate->cache[i]; -- cgit v1.2.3 From a8dda1af6ab400d45b7524bc46b64e04d14fc912 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 9 Jan 2025 03:46:49 -0500 Subject: tree-diff: drop path_appendnew() alloc optimization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we're diffing trees, we create a list of combine_diff_path structs that represent changed paths. We allocate each struct and add it to the list with path_appendnew(), which we then feed to opt->pathchange(). That function tells us whether the path is of interest or not; if not, then we can throw away the struct we allocated. So there's an optimization to avoid extra allocations: instead of throwing away the new entry, we try to reuse it. If it was large enough to store the next path we care about, we can do so. And if not, we fall back to freeing and re-allocating a new struct. This comes from 72441af7c4 (tree-diff: rework diff_tree() to generate diffs for multiparent cases as well, 2014-04-07), where the goal was to have even the 2-parent diff code use the combine-diff infrastructure, but without taking a performance hit. The implementation causes some complexities in the interface (as we store the allocation length inside the "next" pointer), and prevents us from using the regular combine_diff_path_new() constructor. The complexity is mostly contained inside two functions, but it's worth re-evaluating how much it's helping. That commit claims it helps ~1% on generating two-parent diffs in linux.git. Here are the timings I get on the same command today ("old" is the current tip of master, and "new" has this patch applied): Benchmark 1: ./git.old log --raw --no-abbrev --no-renames v3.10..v3.11 Time (mean ± σ): 532.9 ms ± 5.8 ms [User: 472.7 ms, System: 59.6 ms] Range (min … max): 525.9 ms … 543.3 ms 10 runs Benchmark 2: ./git.new log --raw --no-abbrev --no-renames v3.10..v3.11 Time (mean ± σ): 538.3 ms ± 5.7 ms [User: 478.0 ms, System: 59.7 ms] Range (min … max): 528.5 ms … 545.3 ms 10 runs Summary ./git.old log --raw --no-abbrev --no-renames v3.10..v3.11 ran 1.01 ± 0.02 times faster than ./git.new log --raw --no-abbrev --no-renames v3.10..v3.11 So we do end up on average 1% faster, but with 2% of noise. I tried to focus more on diff performance by running the commit traversal separately, like: git rev-list v3.10..v3.11 >in and then timing just the diffs: Benchmark 1: ./git.old diff-tree --stdin -r