diff options
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/coccinelle/commit.cocci | 4 | ||||
-rw-r--r-- | contrib/coccinelle/object_id.cocci | 151 | ||||
-rw-r--r-- | contrib/coccinelle/preincr.cocci | 5 | ||||
-rw-r--r-- | contrib/completion/git-completion.bash | 31 | ||||
-rwxr-xr-x | contrib/coverage-diff.sh | 108 | ||||
-rw-r--r-- | contrib/credential/wincred/git-credential-wincred.c | 3 | ||||
-rwxr-xr-x | contrib/mw-to-git/t/t9360-mw-to-git-clone.sh | 2 | ||||
-rw-r--r-- | contrib/subtree/Makefile | 4 | ||||
-rwxr-xr-x | contrib/subtree/git-subtree.sh | 129 | ||||
-rwxr-xr-x | contrib/subtree/t/t7900-subtree.sh | 121 | ||||
-rw-r--r-- | contrib/vscode/.gitattributes | 1 | ||||
-rw-r--r-- | contrib/vscode/README.md | 14 | ||||
-rwxr-xr-x | contrib/vscode/init.sh | 375 |
13 files changed, 740 insertions, 208 deletions
diff --git a/contrib/coccinelle/commit.cocci b/contrib/coccinelle/commit.cocci index aec3345adb..c49aa558f0 100644 --- a/contrib/coccinelle/commit.cocci +++ b/contrib/coccinelle/commit.cocci @@ -15,10 +15,10 @@ expression c; identifier f !~ "^(get_commit_tree|get_commit_tree_in_graph_one|load_tree_for_commit)$"; expression c; @@ - f(...) {... + f(...) {<... - c->maybe_tree + get_commit_tree(c) - ...} + ...>} @@ expression c; diff --git a/contrib/coccinelle/object_id.cocci b/contrib/coccinelle/object_id.cocci index 09afdbf994..6a7cf3e02d 100644 --- a/contrib/coccinelle/object_id.cocci +++ b/contrib/coccinelle/object_id.cocci @@ -1,110 +1,149 @@ @@ -expression E1; +struct object_id OID; @@ -- is_null_sha1(E1.hash) -+ is_null_oid(&E1) +- is_null_sha1(OID.hash) ++ is_null_oid(&OID) @@ -expression E1; +struct object_id *OIDPTR; @@ -- is_null_sha1(E1->hash) -+ is_null_oid(E1) +- is_null_sha1(OIDPTR->hash) ++ is_null_oid(OIDPTR) @@ -expression E1; +struct object_id OID; @@ -- sha1_to_hex(E1.hash) -+ oid_to_hex(&E1) +- sha1_to_hex(OID.hash) ++ oid_to_hex(&OID) @@ identifier f != oid_to_hex; -expression E1; +struct object_id *OIDPTR; @@ - f(...) {... -- sha1_to_hex(E1->hash) -+ oid_to_hex(E1) - ...} + f(...) {<... +- sha1_to_hex(OIDPTR->hash) ++ oid_to_hex(OIDPTR) + ...>} @@ -expression E1, E2; +expression E; +struct object_id OID; @@ -- sha1_to_hex_r(E1, E2.hash) -+ oid_to_hex_r(E1, &E2) +- sha1_to_hex_r(E, OID.hash) ++ oid_to_hex_r(E, &OID) @@ identifier f != oid_to_hex_r; -expression E1, E2; +expression E; +struct object_id *OIDPTR; @@ - f(...) {... -- sha1_to_hex_r(E1, E2->hash) -+ oid_to_hex_r(E1, E2) - ...} + f(...) {<... +- sha1_to_hex_r(E, OIDPTR->hash) ++ oid_to_hex_r(E, OIDPTR) + ...>} @@ -expression E1; +struct object_id OID; @@ -- hashclr(E1.hash) -+ oidclr(&E1) +- hashclr(OID.hash) ++ oidclr(&OID) @@ identifier f != oidclr; -expression E1; +struct object_id *OIDPTR; @@ - f(...) {... -- hashclr(E1->hash) -+ oidclr(E1) - ...} + f(...) {<... +- hashclr(OIDPTR->hash) ++ oidclr(OIDPTR) + ...>} @@ -expression E1, E2; +struct object_id OID1, OID2; @@ -- hashcmp(E1.hash, E2.hash) -+ oidcmp(&E1, &E2) +- hashcmp(OID1.hash, OID2.hash) ++ oidcmp(&OID1, &OID2) @@ identifier f != oidcmp; -expression E1, E2; +struct object_id *OIDPTR1, OIDPTR2; @@ - f(...) {... -- hashcmp(E1->hash, E2->hash) -+ oidcmp(E1, E2) - ...} + f(...) {<... +- hashcmp(OIDPTR1->hash, OIDPTR2->hash) ++ oidcmp(OIDPTR1, OIDPTR2) + ...>} @@ -expression E1, E2; +struct object_id *OIDPTR; +struct object_id OID; @@ -- hashcmp(E1->hash, E2.hash) -+ oidcmp(E1, &E2) +- hashcmp(OIDPTR->hash, OID.hash) ++ oidcmp(OIDPTR, &OID) @@ -expression E1, E2; +struct object_id *OIDPTR; +struct object_id OID; @@ -- hashcmp(E1.hash, E2->hash) -+ oidcmp(&E1, E2) +- hashcmp(OID.hash, OIDPTR->hash) ++ oidcmp(&OID, OIDPTR) @@ -expression E1, E2; +struct object_id OID1, OID2; @@ -- hashcpy(E1.hash, E2.hash) -+ oidcpy(&E1, &E2) +- hashcpy(OID1.hash, OID2.hash) ++ oidcpy(&OID1, &OID2) @@ identifier f != oidcpy; -expression E1, E2; +struct object_id *OIDPTR1; +struct object_id *OIDPTR2; +@@ + f(...) {<... +- hashcpy(OIDPTR1->hash, OIDPTR2->hash) ++ oidcpy(OIDPTR1, OIDPTR2) + ...>} + @@ - f(...) {... -- hashcpy(E1->hash, E2->hash) -+ oidcpy(E1, E2) - ...} +struct object_id *OIDPTR; +struct object_id OID; +@@ +- hashcpy(OIDPTR->hash, OID.hash) ++ oidcpy(OIDPTR, &OID) + +@@ +struct object_id *OIDPTR; +struct object_id OID; +@@ +- hashcpy(OID.hash, OIDPTR->hash) ++ oidcpy(&OID, OIDPTR) + +@@ +struct object_id *OIDPTR1; +struct object_id *OIDPTR2; +@@ +- oidcmp(OIDPTR1, OIDPTR2) == 0 ++ oideq(OIDPTR1, OIDPTR2) @@ +identifier f != hasheq; expression E1, E2; @@ -- hashcpy(E1->hash, E2.hash) -+ oidcpy(E1, &E2) + f(...) {<... +- hashcmp(E1, E2) == 0 ++ hasheq(E1, E2) + ...>} + +@@ +struct object_id *OIDPTR1; +struct object_id *OIDPTR2; +@@ +- oidcmp(OIDPTR1, OIDPTR2) != 0 ++ !oideq(OIDPTR1, OIDPTR2) @@ +identifier f != hasheq; expression E1, E2; @@ -- hashcpy(E1.hash, E2->hash) -+ oidcpy(&E1, E2) + f(...) {<... +- hashcmp(E1, E2) != 0 ++ !hasheq(E1, E2) + ...>} diff --git a/contrib/coccinelle/preincr.cocci b/contrib/coccinelle/preincr.cocci new file mode 100644 index 0000000000..7fe1e8d2d9 --- /dev/null +++ b/contrib/coccinelle/preincr.cocci @@ -0,0 +1,5 @@ +@ preincrement @ +identifier i; +@@ +- ++i > 1 ++ i++ diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 94c95516eb..86b8f474c8 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -943,6 +943,7 @@ __git_complete_remote_or_refspec () *) ;; esac ;; + --multiple) no_complete_refspec=1; break ;; -*) ;; *) remote="$i"; break ;; esac @@ -1340,17 +1341,6 @@ _git_checkout () esac } -_git_cherry () -{ - case "$cur" in - --*) - __gitcomp_builtin cherry - return - esac - - __git_complete_refs -} - __git_cherry_pick_inprogress_options="--continue --quit --abort" _git_cherry_pick () @@ -1832,7 +1822,7 @@ _git_mergetool () return ;; --*) - __gitcomp "--tool= --prompt --no-prompt" + __gitcomp "--tool= --prompt --no-prompt --gui --no-gui" return ;; esac @@ -1976,6 +1966,20 @@ _git_push () __git_complete_remote_or_refspec } +_git_range_diff () +{ + case "$cur" in + --*) + __gitcomp " + --creation-factor= --no-dual-color + $__git_diff_common_options + " + return + ;; + esac + __git_complete_revlist +} + _git_rebase () { __git_find_repo_path @@ -2553,6 +2557,9 @@ _git_stash () drop,--*) __gitcomp "--quiet" ;; + list,--*) + __gitcomp "--name-status --oneline --patch-with-stat" + ;; show,--*|branch,--*) ;; branch,*) diff --git a/contrib/coverage-diff.sh b/contrib/coverage-diff.sh new file mode 100755 index 0000000000..4ec419f900 --- /dev/null +++ b/contrib/coverage-diff.sh @@ -0,0 +1,108 @@ +#!/bin/sh + +# Usage: Run 'contrib/coverage-diff.sh <version1> <version2>' from source-root +# after running +# +# make coverage-test +# make coverage-report +# +# while checked out at <version2>. This script combines the *.gcov files +# generated by the 'make' commands above with 'git diff <version1> <version2>' +# to report new lines that are not covered by the test suite. + +V1=$1 +V2=$2 + +diff_lines () { + perl -e ' + my $line_num; + while (<>) { + # Hunk header? Grab the beginning in postimage. + if (/^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/) { + $line_num = $1; + next; + } + + # Have we seen a hunk? Ignore "diff --git" etc. + next unless defined $line_num; + + # Deleted line? Ignore. + if (/^-/) { + next; + } + + # Show only the line number of added lines. + if (/^\+/) { + print "$line_num\n"; + } + # Either common context or added line appear in + # the postimage. Count it. + $line_num++; + } + ' +} + +files=$(git diff --name-only "$V1" "$V2" -- \*.c) + +# create empty file +>coverage-data.txt + +for file in $files +do + git diff "$V1" "$V2" -- "$file" | + diff_lines | + sort >new_lines.txt + + if ! test -s new_lines.txt + then + continue + fi + + hash_file=$(echo $file | sed "s/\//\#/") + + if ! test -s "$hash_file.gcov" + then + continue + fi + + sed -ne '/#####:/{ + s/ #####:// + s/:.*// + s/ //g + p + }' "$hash_file.gcov" | + sort >uncovered_lines.txt + + comm -12 uncovered_lines.txt new_lines.txt | + sed -e 's/$/\)/' | + sed -e 's/^/ /' >uncovered_new_lines.txt + + grep -q '[^[:space:]]' <uncovered_new_lines.txt && + echo $file >>coverage-data.txt && + git blame -s "$V2" -- "$file" | + sed 's/\t//g' | + grep -f uncovered_new_lines.txt >>coverage-data.txt && + echo >>coverage-data.txt + + rm -f new_lines.txt uncovered_lines.txt uncovered_new_lines.txt +done + +cat coverage-data.txt + +echo "Commits introducing uncovered code:" + +commit_list=$(cat coverage-data.txt | + grep -E '^[0-9a-f]{7,} ' | + awk '{print $1;}' | + sort | + uniq) + +( + for commit in $commit_list + do + git log --no-decorate --pretty=format:'%an %h: %s' -1 $commit + echo + done +) | sort + +rm coverage-data.txt diff --git a/contrib/credential/wincred/git-credential-wincred.c b/contrib/credential/wincred/git-credential-wincred.c index 86518cd93d..5bdad41de1 100644 --- a/contrib/credential/wincred/git-credential-wincred.c +++ b/contrib/credential/wincred/git-credential-wincred.c @@ -75,7 +75,8 @@ static CredDeleteWT CredDeleteW; static void load_cred_funcs(void) { /* load DLLs */ - advapi = LoadLibrary("advapi32.dll"); + advapi = LoadLibraryExA("advapi32.dll", NULL, + LOAD_LIBRARY_SEARCH_SYSTEM32); if (!advapi) die("failed to load advapi32.dll"); diff --git a/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh b/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh index 22f069db48..cfbfe7ddf6 100755 --- a/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh +++ b/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh @@ -247,7 +247,7 @@ test_expect_success 'Test of resistance to modification of category on wiki for wiki_editpage Notconsidered "this page will not appear on local" false && wiki_editpage Othercategory "this page will not appear on local" false -c=Cattwo && wiki_editpage Tobeedited "this page have been modified" true -c=Catone && - wiki_delete_page Tobedeleted + wiki_delete_page Tobedeleted && git clone -c remote.origin.categories="Catone" \ mediawiki::'"$WIKI_URL"' mw_dir_14 && wiki_getallpage ref_page_14 Catone && diff --git a/contrib/subtree/Makefile b/contrib/subtree/Makefile index 5c6cc4ab2c..6906aae441 100644 --- a/contrib/subtree/Makefile +++ b/contrib/subtree/Makefile @@ -59,6 +59,10 @@ $(GIT_SUBTREE): $(GIT_SUBTREE_SH) doc: $(GIT_SUBTREE_DOC) $(GIT_SUBTREE_HTML) +man: $(GIT_SUBTREE_DOC) + +html: $(GIT_SUBTREE_HTML) + install: $(GIT_SUBTREE) $(INSTALL) -d -m 755 $(DESTDIR)$(gitexecdir) $(INSTALL) -m 755 $(GIT_SUBTREE) $(DESTDIR)$(gitexecdir) diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh index d3f39a862a..147201dc6c 100755 --- a/contrib/subtree/git-subtree.sh +++ b/contrib/subtree/git-subtree.sh @@ -231,12 +231,14 @@ cache_miss () { } check_parents () { - missed=$(cache_miss "$@") + missed=$(cache_miss "$1") + local indent=$(($2 + 1)) for miss in $missed do if ! test -r "$cachedir/notree/$miss" then debug " incorrect order: $miss" + process_split_commit "$miss" "" "$indent" fi done } @@ -340,7 +342,12 @@ find_existing_splits () { revs="$2" main= sub= - git log --grep="^git-subtree-dir: $dir/*\$" \ + local grep_format="^git-subtree-dir: $dir/*\$" + if test -n "$ignore_joins" + then + grep_format="^Add '$dir/' from commit '" + fi + git log --grep="$grep_format" \ --no-show-signature --pretty=format:'START %H%n%s%n%n%b%nEND%n' $revs | while read a b junk do @@ -534,6 +541,7 @@ copy_or_skip () { nonidentical= p= gotparents= + copycommit= for parent in $newparents do ptree=$(toptree_for_commit $parent) || exit $? @@ -541,7 +549,24 @@ copy_or_skip () { if test "$ptree" = "$tree" then # an identical parent could be used in place of this rev. - identical="$parent" + if test -n "$identical" + then + # if a previous identical parent was found, check whether + # one is already an ancestor of the other + mergebase=$(git merge-base $identical $parent) + if test "$identical" = "$mergebase" + then + # current identical commit is an ancestor of parent + identical="$parent" + elif test "$parent" != "$mergebase" + then + # no common history; commit must be copied + copycommit=1 + fi + else + # first identical parent detected + identical="$parent" + fi else nonidentical="$parent" fi @@ -564,7 +589,6 @@ copy_or_skip () { fi done - copycommit= if test -n "$identical" && test -n "$nonidentical" then extras=$(git rev-list --count $identical..$nonidentical) @@ -598,6 +622,58 @@ ensure_valid_ref_format () { die "'$1' does not look like a ref" } +process_split_commit () { + local rev="$1" + local parents="$2" + local indent=$3 + + if test $indent -eq 0 + then + revcount=$(($revcount + 1)) + else + # processing commit without normal parent information; + # fetch from repo + parents=$(git rev-parse "$rev^@") + extracount=$(($extracount + 1)) + fi + + progress "$revcount/$revmax ($createcount) [$extracount]" + + debug "Processing commit: $rev" + exists=$(cache_get "$rev") + if test -n "$exists" + then + debug " prior: $exists" + return + fi + createcount=$(($createcount + 1)) + debug " parents: $parents" + check_parents "$parents" "$indent" + newparents=$(cache_get $parents) + debug " newparents: $newparents" + + tree=$(subtree_for_commit "$rev" "$dir") + debug " tree is: $tree" + + # ugly. is there no better way to tell if this is a subtree + # vs. a mainline commit? Does it matter? + if test -z "$tree" + then + set_notree "$rev" + if test -n "$newparents" + then + cache_set "$rev" "$rev" + fi + return + fi + + newrev=$(copy_or_skip "$rev" "$tree" "$newparents") || exit $? + debug " newrev is: $newrev" + cache_set "$rev" "$newrev" + cache_set latest_new "$newrev" + cache_set latest_old "$rev" +} + cmd_add () { if test -e "$dir" then @@ -689,12 +765,7 @@ cmd_split () { done fi - if test -n "$ignore_joins" - then - unrevs= - else - unrevs="$(find_existing_splits "$dir" "$revs")" - fi + unrevs="$(find_existing_splits "$dir" "$revs")" # We can't restrict rev-list to only $dir here, because some of our # parents have the $dir contents the root, and those won't match. @@ -703,45 +774,11 @@ cmd_split () { revmax=$(eval "$grl" | wc -l) revcount=0 createcount=0 + extracount=0 eval "$grl" | while read rev parents do - revcount=$(($revcount + 1)) - progress "$revcount/$revmax ($createcount)" - debug "Processing commit: $rev" - exists=$(cache_get "$rev") - if test -n "$exists" - then - debug " prior: $exists" - continue - fi - createcount=$(($createcount + 1)) - debug " parents: $parents" - newparents=$(cache_get $parents) - debug " newparents: $newparents" - - tree=$(subtree_for_commit "$rev" "$dir") - debug " tree is: $tree" - - check_parents $parents - - # ugly. is there no better way to tell if this is a subtree - # vs. a mainline commit? Does it matter? - if test -z "$tree" - then - set_notree "$rev" - if test -n "$newparents" - then - cache_set "$rev" "$rev" - fi - continue - fi - - newrev=$(copy_or_skip "$rev" "$tree" "$newparents") || exit $? - debug " newrev is: $newrev" - cache_set "$rev" "$newrev" - cache_set latest_new "$newrev" - cache_set latest_old "$rev" + process_split_commit "$rev" "$parents" 0 done || exit $? latest_new=$(cache_get latest_new) diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh index d05c613c97..57ff4b25c1 100755 --- a/contrib/subtree/t/t7900-subtree.sh +++ b/contrib/subtree/t/t7900-subtree.sh @@ -540,26 +540,10 @@ test_expect_success 'make sure exactly the right set of files ends up in the sub git fetch .. subproj-br && git merge FETCH_HEAD && - chks="sub1 -sub2 -sub3 -sub4" && - chks_sub=$(cat <<TXT | sed '\''s,^,sub dir/,'\'' -$chks -TXT -) && - chkms="main-sub1 -main-sub2 -main-sub3 -main-sub4" && - chkms_sub=$(cat <<TXT | sed '\''s,^,sub dir/,'\'' -$chkms -TXT -) && - - subfiles=$(git ls-files) && - check_equal "$subfiles" "$chkms -$chks" + test_write_lines main-sub1 main-sub2 main-sub3 main-sub4 \ + sub1 sub2 sub3 sub4 >expect && + git ls-files >actual && + test_cmp expect actual ) ' @@ -606,25 +590,11 @@ test_expect_success 'make sure the subproj *only* contains commits that affect t git fetch .. subproj-br && git merge FETCH_HEAD && - chks="sub1 -sub2 -sub3 -sub4" && - chks_sub=$(cat <<TXT | sed '\''s,^,sub dir/,'\'' -$chks -TXT -) && - chkms="main-sub1 -main-sub2 -main-sub3 -main-sub4" && - chkms_sub=$(cat <<TXT | sed '\''s,^,sub dir/,'\'' -$chkms -TXT -) && - allchanges=$(git log --name-only --pretty=format:"" | sort | sed "/^$/d") && - check_equal "$allchanges" "$chkms -$chks" + test_write_lines main-sub1 main-sub2 main-sub3 main-sub4 \ + sub1 sub2 sub3 sub4 >expect && + git log --name-only --pretty=format:"" >log && + sort <log | sed "/^\$/ d" >actual && + test_cmp expect actual ) ' @@ -675,29 +645,16 @@ test_expect_success 'make sure exactly the right set of files ends up in the mai cd "$subtree_test_count" && git subtree pull --prefix="sub dir" ./"sub proj" master && - chkm="main1 -main2" && - chks="sub1 -sub2 -sub3 -sub4" && - chks_sub=$(cat <<TXT | sed '\''s,^,sub dir/,'\'' -$chks -TXT -) && - chkms="main-sub1 -main-sub2 -main-sub3 -main-sub4" && - chkms_sub=$(cat <<TXT | sed '\''s,^,sub dir/,'\'' -$chkms -TXT -) && - mainfiles=$(git ls-files) && - check_equal "$mainfiles" "$chkm -$chkms_sub -$chks_sub" -) + test_write_lines main1 main2 >chkm && + test_write_lines main-sub1 main-sub2 main-sub3 main-sub4 >chkms && + sed "s,^,sub dir/," chkms >chkms_sub && + test_write_lines sub1 sub2 sub3 sub4 >chks && + sed "s,^,sub dir/," chks >chks_sub && + + cat chkm chkms_sub chks_sub >expect && + git ls-files >actual && + test_cmp expect actual + ) ' next_test @@ -708,7 +665,7 @@ test_expect_success 'make sure each filename changed exactly once in the entire test_create_commit "$subtree_test_count/sub proj" sub1 && ( cd "$subtree_test_count" && - git config log.date relative + git config log.date relative && git fetch ./"sub proj" master && git subtree add --prefix="sub dir" FETCH_HEAD ) && @@ -748,37 +705,21 @@ test_expect_success 'make sure each filename changed exactly once in the entire cd "$subtree_test_count" && git subtree pull --prefix="sub dir" ./"sub proj" master && - chkm="main1 -main2" && - chks="sub1 -sub2 -sub3 -sub4" && - chks_sub=$(cat <<TXT | sed '\''s,^,sub dir/,'\'' -$chks -TXT -) && - chkms="main-sub1 -main-sub2 -main-sub3 -main-sub4" && - chkms_sub=$(cat <<TXT | sed '\''s,^,sub dir/,'\'' -$chkms -TXT -) && + test_write_lines main1 main2 >chkm && + test_write_lines sub1 sub2 sub3 sub4 >chks && + test_write_lines main-sub1 main-sub2 main-sub3 main-sub4 >chkms && + sed "s,^,sub dir/," chkms >chkms_sub && # main-sub?? and /"sub dir"/main-sub?? both change, because those are the # changes that were split into their own history. And "sub dir"/sub?? never # change, since they were *only* changed in the subtree branch. - allchanges=$(git log --name-only --pretty=format:"" | sort | sed "/^$/d") && - expected=''"$(cat <<TXT | sort -$chkms -$chkm -$chks -$chkms_sub -TXT -)"'' && - check_equal "$allchanges" "$expected" + git log --name-only --pretty=format:"" >log && + sort <log >sorted-log && + sed "/^$/ d" sorted-log >actual && + + cat chkms chkm chks chkms_sub >expect-unsorted && + sort expect-unsorted >expect && + test_cmp expect actual ) ' diff --git a/contrib/vscode/.gitattributes b/contrib/vscode/.gitattributes new file mode 100644 index 0000000000..e89f2236ef --- /dev/null +++ b/contrib/vscode/.gitattributes @@ -0,0 +1 @@ +init.sh whitespace=-indent-with-non-tab diff --git a/contrib/vscode/README.md b/contrib/vscode/README.md new file mode 100644 index 0000000000..8202d62035 --- /dev/null +++ b/contrib/vscode/README.md @@ -0,0 +1,14 @@ +Configuration for VS Code +========================= + +[VS Code](https://code.visualstudio.com/) is a lightweight but powerful source +code editor which runs on your desktop and is available for +[Windows](https://code.visualstudio.com/docs/setup/windows), +[macOS](https://code.visualstudio.com/docs/setup/mac) and +[Linux](https://code.visualstudio.com/docs/setup/linux). Among other languages, +it has [support for C/C++ via an extension](https://github.com/Microsoft/vscode-cpptools). + +To start developing Git with VS Code, simply run the Unix shell script called +`init.sh` in this directory, which creates the configuration files in +`.vscode/` that VS Code consumes. `init.sh` needs access to `make` and `gcc`, +so run the script in a Git SDK shell if you are using Windows. diff --git a/contrib/vscode/init.sh b/contrib/vscode/init.sh new file mode 100755 index 0000000000..27de94994b --- /dev/null +++ b/contrib/vscode/init.sh @@ -0,0 +1,375 @@ +#!/bin/sh + +die () { + echo "$*" >&2 + exit 1 +} + +cd "$(dirname "$0")"/../.. || +die "Could not cd to top-level directory" + +mkdir -p .vscode || +die "Could not create .vscode/" + +# General settings + +cat >.vscode/settings.json.new <<\EOF || +{ + "C_Cpp.intelliSenseEngine": "Default", + "C_Cpp.intelliSenseEngineFallback": "Disabled", + "[git-commit]": { + "editor.wordWrap": "wordWrapColumn", + "editor.wordWrapColumn": 72 + }, + "[c]": { + "editor.detectIndentation": false, + "editor.insertSpaces": false, + "editor.tabSize": 8, + "editor.wordWrap": "wordWrapColumn", + "editor.wordWrapColumn": 80, + "files.trimTrailingWhitespace": true + }, + "files.associations": { + "*.h": "c", + "*.c": "c" + }, + "cSpell.ignorePaths": [ + ], + "cSpell.words": [ + "DATAW", + "DBCACHED", + "DFCHECK", + "DTYPE", + "Hamano", + "HCAST", + "HEXSZ", + "HKEY", + "HKLM", + "IFGITLINK", + "IFINVALID", + "ISBROKEN", + "ISGITLINK", + "ISSYMREF", + "Junio", + "LPDWORD", + "LPPROC", + "LPWSTR", + "MSVCRT", + "NOARG", + "NOCOMPLETE", + "NOINHERIT", + "RENORMALIZE", + "STARTF", + "STARTUPINFOEXW", + "Schindelin", + "UCRT", + "YESNO", + "argcp", + "beginthreadex", + "committish", + "contentp", + "cpath", + "cpidx", + "ctim", + "dequote", + "envw", + "ewah", + "fdata", + "fherr", + "fhin", + "fhout", + "fragp", + "fsmonitor", + "hnsec", + "idents", + "includeif", + "interpr", + "iprog", + "isexe", + "iskeychar", + "kompare", + "mksnpath", + "mktag", + "mktree", + "mmblob", + "mmbuffer", + "mmfile", + "noenv", + "nparents", + "ntpath", + "ondisk", + "ooid", + "oplen", + "osdl", + "pnew", + "pold", + "ppinfo", + "pushf", + "pushv", + "rawsz", + "rebasing", + "reencode", + "repo", + "rerere", + "scld", + "sharedrepo", + "spawnv", + "spawnve", + "spawnvpe", + "strdup'ing", + "submodule", + "submodules", + "topath", + "topo", + "tpatch", + "unexecutable", + "unhide", + "unkc", + "unkv", + "unmark", + "unmatch", + "unsets", + "unshown", + "untracked", + "untrackedcache", + "unuse", + "upos", + "uval", + "vreportf", + "wargs", + "wargv", + "wbuffer", + "wcmd", + "wcsnicmp", + "wcstoutfdup", + "wdeltaenv", + "wdir", + "wenv", + "wenvblk", + "wenvcmp", + "wenviron", + "wenvpos", + "wenvsz", + "wfile", + "wfilename", + "wfopen", + "wfreopen", + "wfullpath", + "which'll", + "wlink", + "wmain", + "wmkdir", + "wmktemp", + "wnewpath", + "wotype", + "wpath", + "wpathname", + "wpgmptr", + "wpnew", + "wpointer", + "wpold", + "wpos", + "wputenv", + "wrmdir", + "wship", + "wtarget", + "wtemplate", + "wunlink", + "xcalloc", + "xgetcwd", + "xmallocz", + "xmemdupz", + "xmmap", + "xopts", + "xrealloc", + "xsnprintf", + "xutftowcs", + "xutftowcsn", + "xwcstoutf" + ], + "cSpell.ignoreRegExpList": [ + "\\\"(DIRC|FSMN|REUC|UNTR)\\\"", + "\\\\u[0-9a-fA-Fx]{4}\\b", + "\\b(filfre|frotz|xyzzy)\\b", + "\\bCMIT_FMT_DEFAULT\\b", + "\\bde-munge\\b", + "\\bGET_OID_DISAMBIGUATORS\\b", + "\\bHASH_RENORMALIZE\\b", + "\\bTREESAMEness\\b", + "\\bUSE_STDEV\\b", + "\\Wchar *\\*\\W*utfs\\W", + "cURL's", + "nedmalloc'ed", + "ntifs\\.h", + ], +} +EOF +die "Could not write settings.json" + +# Infer some setup-specific locations/names + +GCCPATH="$(which gcc)" +GDBPATH="$(which gdb)" +MAKECOMMAND="make -j5 DEVELOPER=1" +OSNAME= +X= +case "$(uname -s)" in +MINGW*) + GCCPATH="$(cygpath -am "$GCCPATH")" + GDBPATH="$(cygpath -am "$GDBPATH")" + MAKE_BASH="$(cygpath -am /git-cmd.exe) --command=usr\\\\bin\\\\bash.exe" + MAKECOMMAND="$MAKE_BASH -lc \\\"$MAKECOMMAND\\\"" + OSNAME=Win32 + X=.exe + ;; +Linux) + OSNAME=Linux + ;; +Darwin) + OSNAME=macOS + ;; +esac + +# Default build task + +cat >.vscode/tasks.json.new <<EOF || +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "make", + "type": "shell", + "command": "$MAKECOMMAND", + "group": { + "kind": "build", + "isDefault": true + } + } + ] +} +EOF +die "Could not install default build task" + +# Debugger settings + +cat >.vscode/launch.json.new <<EOF || +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: + // https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) Launch", + "type": "cppdbg", + "request": "launch", + "program": "\${workspaceFolder}/git$X", + "args": [], + "stopAtEntry": false, + "cwd": "\${workspaceFolder}", + "environment": [], + "externalConsole": true, + "MIMode": "gdb", + "miDebuggerPath": "$GDBPATH", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + } + ] +} +EOF +die "Could not write launch configuration" + +# C/C++ extension settings + +make -f - OSNAME=$OSNAME GCCPATH="$GCCPATH" vscode-init \ + >.vscode/c_cpp_properties.json <<\EOF || +include Makefile + +vscode-init: + @mkdir -p .vscode && \ + incs= && defs= && \ + for e in $(ALL_CFLAGS) \ + '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \ + '-DGIT_LOCALE_PATH="$(localedir_relative_SQ)"' \ + '-DBINDIR="$(bindir_relative_SQ)"' \ + '-DFALLBACK_RUNTIME_PREFIX="$(prefix_SQ)"' \ + '-DDEFAULT_GIT_TEMPLATE_DIR="$(template_dir_SQ)"' \ + '-DETC_GITCONFIG="$(ETC_GITCONFIG_SQ)"' \ + '-DETC_GITATTRIBUTES="$(ETC_GITATTRIBUTES_SQ)"' \ + '-DGIT_LOCALE_PATH="$(localedir_relative_SQ)"' \ + '-DCURL_DISABLE_TYPECHECK', \ + '-DGIT_HTML_PATH="$(htmldir_relative_SQ)"' \ + '-DGIT_MAN_PATH="$(mandir_relative_SQ)"' \ + '-DGIT_INFO_PATH="$(infodir_relative_SQ)"'; do \ + case "$$e" in \ + -I.) \ + incs="$$(printf '% 16s"$${workspaceRoot}",\n%s' \ + "" "$$incs")" \ + ;; \ + -I/*) \ + incs="$$(printf '% 16s"%s",\n%s' \ + "" "$${e#-I}" "$$incs")" \ + ;; \ + -I*) \ + incs="$$(printf '% 16s"$${workspaceRoot}/%s",\n%s' \ + "" "$${e#-I}" "$$incs")" \ + ;; \ + -D*) \ + defs="$$(printf '% 16s"%s",\n%s' \ + "" "$$(echo "$${e#-D}" | sed 's/"/\\&/g')" \ + "$$defs")" \ + ;; \ + esac; \ + done && \ + echo '{' && \ + echo ' "configurations": [' && \ + echo ' {' && \ + echo ' "name": "$(OSNAME)",' && \ + echo ' "intelliSenseMode": "clang-x64",' && \ + echo ' "includePath": [' && \ + echo "$$incs" | sort | sed '$$s/,$$//' && \ + echo ' ],' && \ + echo ' "defines": [' && \ + echo "$$defs" | sort | sed '$$s/,$$//' && \ + echo ' ],' && \ + echo ' "browse": {' && \ + echo ' "limitSymbolsToIncludedHeaders": true,' && \ + echo ' "databaseFilename": "",' && \ + echo ' "path": [' && \ + echo ' "$${workspaceRoot}"' && \ + echo ' ]' && \ + echo ' },' && \ + echo ' "cStandard": "c11",' && \ + echo ' "cppStandard": "c++17",' && \ + echo ' "compilerPath": "$(GCCPATH)"' && \ + echo ' }' && \ + echo ' ],' && \ + echo ' "version": 4' && \ + echo '}' +EOF +die "Could not write settings for the C/C++ extension" + +for file in .vscode/settings.json .vscode/tasks.json .vscode/launch.json +do + if test -f $file + then + if git diff --no-index --quiet --exit-code $file $file.new + then + rm $file.new + else + printf "The file $file.new has these changes:\n\n" + git --no-pager diff --no-index $file $file.new + printf "\n\nMaybe \`mv $file.new $file\`?\n\n" + fi + else + mv $file.new $file + fi +done |