Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.kernel.org/pub/scm/git/git.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rw-r--r--contrib/README4
-rw-r--r--contrib/buildsystems/CMakeLists.txt38
-rw-r--r--contrib/completion/git-completion.bash19
-rw-r--r--contrib/credential/libsecret/git-credential-libsecret.c95
-rw-r--r--contrib/credential/wincred/git-credential-wincred.c20
-rwxr-xr-xcontrib/git-jump/git-jump2
-rwxr-xr-xcontrib/mw-to-git/t/t9363-mw-to-git-export-import.sh2
-rwxr-xr-xcontrib/subtree/git-subtree.sh44
-rwxr-xr-xcontrib/subtree/t/t7900-subtree.sh2
9 files changed, 187 insertions, 39 deletions
diff --git a/contrib/README b/contrib/README
index 05f291c1f1..21d3d0e7de 100644
--- a/contrib/README
+++ b/contrib/README
@@ -23,7 +23,7 @@ This is the same way as how I have been treating gitk, and to a
lesser degree various foreign SCM interfaces, so you know the
drill.
-I expect that things that start their life in the contrib/ area
+I expect things that start their life in the contrib/ area
to graduate out of contrib/ once they mature, either by becoming
projects on their own, or moving to the toplevel directory. On
the other hand, I expect I'll be proposing removal of disused
@@ -31,7 +31,7 @@ and inactive ones from time to time.
If you have new things to add to this area, please first propose
it on the git mailing list, and after a list discussion proves
-there are some general interests (it does not have to be a
+there is general interest (it does not have to be a
list-wide consensus for a tool targeted to a relatively narrow
audience -- for example I do not work with projects whose
upstream is svn, so I have no use for git-svn myself, but it is
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index 6b819e2fbd..804629c525 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -974,6 +974,35 @@ target_link_libraries(test-fake-ssh common-main)
parse_makefile_for_sources(test-reftable_SOURCES "REFTABLE_TEST_OBJS")
list(TRANSFORM test-reftable_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/")
+#unit-tests
+add_library(unit-test-lib OBJECT ${CMAKE_SOURCE_DIR}/t/unit-tests/test-lib.c)
+
+parse_makefile_for_scripts(unit_test_PROGRAMS "UNIT_TEST_PROGRAMS" "")
+foreach(unit_test ${unit_test_PROGRAMS})
+ add_executable("${unit_test}" "${CMAKE_SOURCE_DIR}/t/unit-tests/${unit_test}.c")
+ target_link_libraries("${unit_test}" unit-test-lib common-main)
+ set_target_properties("${unit_test}"
+ PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/t/unit-tests/bin)
+ if(MSVC)
+ set_target_properties("${unit_test}"
+ PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/t/unit-tests/bin)
+ set_target_properties("${unit_test}"
+ PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/t/unit-tests/bin)
+ endif()
+ list(APPEND PROGRAMS_BUILT "${unit_test}")
+
+ # t-basic intentionally fails tests, to validate the unit-test infrastructure.
+ # Therefore, it should only be run as part of t0080, which verifies that it
+ # fails only in the expected ways.
+ #
+ # All other unit tests should be run.
+ if(NOT ${unit_test} STREQUAL "t-basic")
+ add_test(NAME "t.unit-tests.${unit_test}"
+ COMMAND "./${unit_test}"
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/t/unit-tests/bin)
+ endif()
+endforeach()
+
#test-tool
parse_makefile_for_sources(test-tool_SOURCES "TEST_BUILTINS_OBJS")
@@ -1093,17 +1122,18 @@ if(NOT ${CMAKE_BINARY_DIR}/CMakeCache.txt STREQUAL ${CACHE_PATH})
file(COPY ${CMAKE_SOURCE_DIR}/contrib/completion/git-completion.bash DESTINATION ${CMAKE_BINARY_DIR}/contrib/completion/)
endif()
-file(GLOB test_scipts "${CMAKE_SOURCE_DIR}/t/t[0-9]*.sh")
+file(GLOB test_scripts "${CMAKE_SOURCE_DIR}/t/t[0-9]*.sh")
#test
-foreach(tsh ${test_scipts})
- add_test(NAME ${tsh}
+foreach(tsh ${test_scripts})
+ string(REGEX REPLACE ".*/(.*)\\.sh" "\\1" test_name ${tsh})
+ add_test(NAME "t.suite.${test_name}"
COMMAND ${SH_EXE} ${tsh} --no-bin-wrappers --no-chain-lint -vx
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/t)
endforeach()
# This test script takes an extremely long time and is known to time out even
# on fast machines because it requires in excess of one hour to run
-set_tests_properties("${CMAKE_SOURCE_DIR}/t/t7112-reset-submodule.sh" PROPERTIES TIMEOUT 4000)
+set_tests_properties("t.suite.t7112-reset-submodule" PROPERTIES TIMEOUT 4000)
endif()#BUILD_TESTING
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 133ec92bfa..13a39ebd2e 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -28,6 +28,8 @@
# completion style. For example '!f() { : git commit ; ... }; f' will
# tell the completion to use commit completion. This also works with aliases
# of form "!sh -c '...'". For example, "!sh -c ': git commit ; ... '".
+# Note that "git" is optional --- '!f() { : commit; ...}; f' would complete
+# just like the 'git commit' command.
#
# If you have a command that is not part of git, but you would still
# like completion, you can use __git_complete:
@@ -1182,7 +1184,7 @@ __git_aliased_command ()
:) : skip null command ;;
\'*) : skip opening quote after sh -c ;;
*)
- cur="$word"
+ cur="${word%;}"
break
esac
done
@@ -1607,7 +1609,7 @@ _git_checkout ()
if [ -n "$(__git_find_on_cmdline "-b -B -d --detach --orphan")" ]; then
__git_complete_refs --mode="refs"
- elif [ -n "$(__git_find_on_cmdline "--track")" ]; then
+ elif [ -n "$(__git_find_on_cmdline "-t --track")" ]; then
__git_complete_refs --mode="remote-heads"
else
__git_complete_refs $dwim_opt --mode="refs"
@@ -1677,6 +1679,11 @@ _git_clone ()
__git_untracked_file_modes="all no normal"
+__git_trailer_tokens ()
+{
+ __git config --name-only --get-regexp '^trailer\..*\.key$' | cut -d. -f 2- | rev | cut -d. -f2- | rev
+}
+
_git_commit ()
{
case "$prev" in
@@ -1701,6 +1708,10 @@ _git_commit ()
__gitcomp "$__git_untracked_file_modes" "" "${cur##--untracked-files=}"
return
;;
+ --trailer=*)
+ __gitcomp_nl "$(__git_trailer_tokens)" "" "${cur##--trailer=}" ":"
+ return
+ ;;
--*)
__gitcomp_builtin commit
return
@@ -2042,7 +2053,7 @@ __git_log_shortlog_options="
"
# Options accepted by log and show
__git_log_show_options="
- --diff-merges --diff-merges= --no-diff-merges --remerge-diff
+ --diff-merges --diff-merges= --no-diff-merges --dd --remerge-diff
"
__git_diff_merges_opts="off none on first-parent 1 separate m combined c dense-combined cc remerge r"
@@ -2514,7 +2525,7 @@ _git_switch ()
if [ -n "$(__git_find_on_cmdline "-c -C -d --detach")" ]; then
__git_complete_refs --mode="refs"
- elif [ -n "$(__git_find_on_cmdline "--track")" ]; then
+ elif [ -n "$(__git_find_on_cmdline "-t --track")" ]; then
__git_complete_refs --mode="remote-heads"
else
__git_complete_refs $dwim_opt --mode="heads"
diff --git a/contrib/credential/libsecret/git-credential-libsecret.c b/contrib/credential/libsecret/git-credential-libsecret.c
index ef681f29d5..215a81d8ba 100644
--- a/contrib/credential/libsecret/git-credential-libsecret.c
+++ b/contrib/credential/libsecret/git-credential-libsecret.c
@@ -39,6 +39,8 @@ struct credential {
char *path;
char *username;
char *password;
+ char *password_expiry_utc;
+ char *oauth_refresh_token;
};
#define CREDENTIAL_INIT { 0 }
@@ -52,8 +54,29 @@ struct credential_operation {
#define CREDENTIAL_OP_END { NULL, NULL }
+static void credential_clear(struct credential *c);
+
/* ----------------- Secret Service functions ----------------- */
+static const SecretSchema schema = {
+ "org.git.Password",
+ /* Ignore schema name during search for backwards compatibility */
+ SECRET_SCHEMA_DONT_MATCH_NAME,
+ {
+ /*
+ * libsecret assumes attribute values are non-confidential and
+ * unchanging, so we can't include oauth_refresh_token or
+ * password_expiry_utc.
+ */
+ { "user", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { "object", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { "protocol", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { "port", SECRET_SCHEMA_ATTRIBUTE_INTEGER },
+ { "server", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { NULL, 0 },
+ }
+};
+
static char *make_label(struct credential *c)
{
if (c->port)
@@ -101,7 +124,7 @@ static int keyring_get(struct credential *c)
attributes = make_attr_list(c);
items = secret_service_search_sync(service,
- SECRET_SCHEMA_COMPAT_NETWORK,
+ &schema,
attributes,
SECRET_SEARCH_LOAD_SECRETS | SECRET_SEARCH_UNLOCK,
NULL,
@@ -117,6 +140,7 @@ static int keyring_get(struct credential *c)
SecretItem *item;
SecretValue *secret;
const char *s;
+ gchar **parts;
item = items->data;
secret = secret_item_get_secret(item);
@@ -130,8 +154,27 @@ static int keyring_get(struct credential *c)
s = secret_value_get_text(secret);
if (s) {
- g_free(c->password);
- c->password = g_strdup(s);
+ /*
+ * Passwords and other attributes encoded in following format:
+ * hunter2
+ * password_expiry_utc=1684189401
+ * oauth_refresh_token=xyzzy
+ */
+ parts = g_strsplit(s, "\n", 0);
+ if (g_strv_length(parts) >= 1) {
+ g_free(c->password);
+ c->password = g_strdup(parts[0]);
+ }
+ for (int i = 1; i < g_strv_length(parts); i++) {
+ if (g_str_has_prefix(parts[i], "password_expiry_utc=")) {
+ g_free(c->password_expiry_utc);
+ c->password_expiry_utc = g_strdup(&parts[i][20]);
+ } else if (g_str_has_prefix(parts[i], "oauth_refresh_token=")) {
+ g_free(c->oauth_refresh_token);
+ c->oauth_refresh_token = g_strdup(&parts[i][20]);
+ }
+ }
+ g_strfreev(parts);
}
g_hash_table_unref(attributes);
@@ -148,6 +191,7 @@ static int keyring_store(struct credential *c)
char *label = NULL;
GHashTable *attributes = NULL;
GError *error = NULL;
+ GString *secret = NULL;
/*
* Sanity check that what we are storing is actually sensible.
@@ -162,13 +206,23 @@ static int keyring_store(struct credential *c)
label = make_label(c);
attributes = make_attr_list(c);
- secret_password_storev_sync(SECRET_SCHEMA_COMPAT_NETWORK,
+ secret = g_string_new(c->password);
+ if (c->password_expiry_utc) {
+ g_string_append_printf(secret, "\npassword_expiry_utc=%s",
+ c->password_expiry_utc);
+ }
+ if (c->oauth_refresh_token) {
+ g_string_append_printf(secret, "\noauth_refresh_token=%s",
+ c->oauth_refresh_token);
+ }
+ secret_password_storev_sync(&schema,
attributes,
NULL,
label,
- c->password,
+ secret->str,
NULL,
&error);
+ g_string_free(secret, TRUE);
g_free(label);
g_hash_table_unref(attributes);
@@ -185,6 +239,7 @@ static int keyring_erase(struct credential *c)
{
GHashTable *attributes = NULL;
GError *error = NULL;
+ struct credential existing = CREDENTIAL_INIT;
/*
* Sanity check that we actually have something to match
@@ -197,8 +252,22 @@ static int keyring_erase(struct credential *c)
if (!c->protocol && !c->host && !c->path && !c->username)
return EXIT_FAILURE;
+ if (c->password) {
+ existing.host = g_strdup(c->host);
+ existing.path = g_strdup(c->path);
+ existing.port = c->port;
+ existing.protocol = g_strdup(c->protocol);
+ existing.username = g_strdup(c->username);
+ keyring_get(&existing);
+ if (existing.password && strcmp(c->password, existing.password)) {
+ credential_clear(&existing);
+ return EXIT_SUCCESS;
+ }
+ credential_clear(&existing);
+ }
+
attributes = make_attr_list(c);
- secret_password_clearv_sync(SECRET_SCHEMA_COMPAT_NETWORK,
+ secret_password_clearv_sync(&schema,
attributes,
NULL,
&error);
@@ -238,6 +307,8 @@ static void credential_clear(struct credential *c)
g_free(c->path);
g_free(c->username);
g_free(c->password);
+ g_free(c->password_expiry_utc);
+ g_free(c->oauth_refresh_token);
credential_init(c);
}
@@ -284,11 +355,19 @@ static int credential_read(struct credential *c)
} else if (!strcmp(key, "username")) {
g_free(c->username);
c->username = g_strdup(value);
+ } else if (!strcmp(key, "password_expiry_utc")) {
+ g_free(c->password_expiry_utc);
+ c->password_expiry_utc = g_strdup(value);
} else if (!strcmp(key, "password")) {
g_free(c->password);
c->password = g_strdup(value);
while (*value)
*value++ = '\0';
+ } else if (!strcmp(key, "oauth_refresh_token")) {
+ g_free(c->oauth_refresh_token);
+ c->oauth_refresh_token = g_strdup(value);
+ while (*value)
+ *value++ = '\0';
}
/*
* Ignore other lines; we don't know what they mean, but
@@ -314,6 +393,10 @@ static void credential_write(const struct credential *c)
/* only write username/password, if set */
credential_write_item(stdout, "username", c->username);
credential_write_item(stdout, "password", c->password);
+ credential_write_item(stdout, "password_expiry_utc",
+ c->password_expiry_utc);
+ credential_write_item(stdout, "oauth_refresh_token",
+ c->oauth_refresh_token);
}
static void usage(const char *name)
diff --git a/contrib/credential/wincred/git-credential-wincred.c b/contrib/credential/wincred/git-credential-wincred.c
index 96f10613ae..4cd56c42e2 100644
--- a/contrib/credential/wincred/git-credential-wincred.c
+++ b/contrib/credential/wincred/git-credential-wincred.c
@@ -109,7 +109,18 @@ static int match_part_last(LPCWSTR *ptarget, LPCWSTR want, LPCWSTR delim)
return match_part_with_last(ptarget, want, delim, 1);
}
-static int match_cred(const CREDENTIALW *cred)
+static int match_cred_password(const CREDENTIALW *cred) {
+ int ret;
+ WCHAR *cred_password = xmalloc(cred->CredentialBlobSize);
+ wcsncpy_s(cred_password, cred->CredentialBlobSize,
+ (LPCWSTR)cred->CredentialBlob,
+ cred->CredentialBlobSize / sizeof(WCHAR));
+ ret = !wcscmp(cred_password, password);
+ free(cred_password);
+ return ret;
+}
+
+static int match_cred(const CREDENTIALW *cred, int match_password)
{
LPCWSTR target = cred->TargetName;
if (wusername && wcscmp(wusername, cred->UserName ? cred->UserName : L""))
@@ -119,7 +130,8 @@ static int match_cred(const CREDENTIALW *cred)
match_part(&target, protocol, L"://") &&
match_part_last(&target, wusername, L"@") &&
match_part(&target, host, L"/") &&
- match_part(&target, path, L"");
+ match_part(&target, path, L"") &&
+ (!match_password || match_cred_password(cred));
}
static void get_credential(void)
@@ -134,7 +146,7 @@ static void get_credential(void)
/* search for the first credential that matches username */
for (i = 0; i < num_creds; ++i)
- if (match_cred(creds[i])) {
+ if (match_cred(creds[i], 0)) {
write_item("username", creds[i]->UserName,
creds[i]->UserName ? wcslen(creds[i]->UserName) : 0);
write_item("password",
@@ -196,7 +208,7 @@ static void erase_credential(void)
return;
for (i = 0; i < num_creds; ++i) {
- if (match_cred(creds[i]))
+ if (match_cred(creds[i], password != NULL))
CredDeleteW(creds[i]->TargetName, creds[i]->Type, 0);
}
diff --git a/contrib/git-jump/git-jump b/contrib/git-jump/git-jump
index 40c4b0d111..47e0c557e6 100755
--- a/contrib/git-jump/git-jump
+++ b/contrib/git-jump/git-jump
@@ -9,7 +9,7 @@ The <mode> parameter is one of:
diff: elements are diff hunks. Arguments are given to diff.
-merge: elements are merge conflicts. Arguments are ignored.
+merge: elements are merge conflicts. Arguments are given to ls-files -u.
grep: elements are grep hits. Arguments are given to git grep or, if
configured, to the command in `jump.grepCmd`.
diff --git a/contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh b/contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh
index 6187ec67fa..7139995a40 100755
--- a/contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh
+++ b/contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh
@@ -161,7 +161,7 @@ test_expect_success 'git push properly warns about insufficient permissions' '
git add foo.forbidden &&
git commit -m "add a file" &&
git push 2>actual &&
- test_i18ngrep "foo.forbidden is not a permitted file" actual
+ test_grep "foo.forbidden is not a permitted file" actual
)
'
diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 7db4c45676..3028029ac2 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -33,19 +33,19 @@ git subtree split --prefix=<prefix> [<commit>]
git subtree pull --prefix=<prefix> <repository> <ref>
git subtree push --prefix=<prefix> <repository> <refspec>
--
-h,help show the help
-q,quiet quiet
-d,debug show debug messages
+h,help! show the help
+q,quiet! quiet
+d,debug! show debug messages
P,prefix= the name of the subdir to split out
options for 'split' (also: 'push')
annotate= add a prefix to commit message of new commits
-b,branch= create a new branch from the split subtree
+b,branch!= create a new branch from the split subtree
ignore-joins ignore prior --rejoin commits
onto= try connecting new tree to an existing one
rejoin merge the new branch back into HEAD
options for 'add' and 'merge' (also: 'pull', 'split --rejoin', and 'push --rejoin')
squash merge subtree changes as a single commit
-m,message= use the given message as the commit message for the merge commit
+m,message!= use the given message as the commit message for the merge commit
"
indent=0
@@ -373,7 +373,8 @@ try_remove_previous () {
# Usage: process_subtree_split_trailer SPLIT_HASH MAIN_HASH [REPOSITORY]
process_subtree_split_trailer () {
- assert test $# = 2 -o $# = 3
+ assert test $# -ge 2
+ assert test $# -le 3
b="$1"
sq="$2"
repository=""
@@ -402,7 +403,8 @@ process_subtree_split_trailer () {
# Usage: find_latest_squash DIR [REPOSITORY]
find_latest_squash () {
- assert test $# = 1 -o $# = 2
+ assert test $# -ge 1
+ assert test $# -le 2
dir="$1"
repository=""
if test "$#" = 2
@@ -455,7 +457,8 @@ find_latest_squash () {
# Usage: find_existing_splits DIR REV [REPOSITORY]
find_existing_splits () {
- assert test $# = 2 -o $# = 3
+ assert test $# -ge 2
+ assert test $# -le 3
debug "Looking for prior splits..."
local indent=$(($indent + 1))
@@ -489,13 +492,13 @@ find_existing_splits () {
;;
END)
debug "Main is: '$main'"
- if test -z "$main" -a -n "$sub"
+ if test -z "$main" && test -n "$sub"
then
# squash commits refer to a subtree
debug " Squash: $sq from $sub"
cache_set "$sq" "$sub"
fi
- if test -n "$main" -a -n "$sub"
+ if test -n "$main" && test -n "$sub"
then
debug " Prior: $main -> $sub"
cache_set $main $sub
@@ -638,10 +641,16 @@ subtree_for_commit () {
while read mode type tree name
do
assert test "$name" = "$dir"
- assert test "$type" = "tree" -o "$type" = "commit"
- test "$type" = "commit" && continue # ignore submodules
- echo $tree
- break
+
+ case "$type" in
+ commit)
+ continue;; # ignore submodules
+ tree)
+ echo $tree
+ break;;
+ *)
+ die "fatal: tree entry is of type ${type}, expected tree or commit";;
+ esac
done || exit $?
}
@@ -916,7 +925,7 @@ cmd_split () {
if test $# -eq 0
then
rev=$(git rev-parse HEAD)
- elif test $# -eq 1 -o $# -eq 2
+ elif test $# -eq 1 || test $# -eq 2
then
rev=$(git rev-parse -q --verify "$1^{commit}") ||
die "fatal: '$1' does not refer to a commit"
@@ -1006,8 +1015,11 @@ cmd_split () {
# Usage: cmd_merge REV [REPOSITORY]
cmd_merge () {
- test $# -eq 1 -o $# -eq 2 ||
+ if test $# -lt 1 || test $# -gt 2
+ then
die "fatal: you must provide exactly one revision, and optionally a repository. Got: '$*'"
+ fi
+
rev=$(git rev-parse -q --verify "$1^{commit}") ||
die "fatal: '$1' does not refer to a commit"
repository=""
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 341c169eca..49a21dd7c9 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -71,7 +71,7 @@ test_expect_success 'shows short help text for -h' '
test_expect_code 129 git subtree -h >out 2>err &&
test_must_be_empty err &&
grep -e "^ *or: git subtree pull" out &&
- grep -e --annotate out
+ grep -F -e "--[no-]annotate" out
'
#