Repository: cargo-generate/cargo-generate
Pull request #572 (2022-04-01 08:22:59)

feat(git): Refactor of handling favorites, git and path (#547)
* Init of refactoring --git, --path and favorite
* Make all not ignored test pass
* Make pass all old test (1 new fail) with git2 lib
* Remove unused code
* Fix not loading ssh-identity from application configuration
* Relocate code. Increase readability
* Remove unused http crate
* Move parsing args and app_config to seperate module
* Allow distinguishing usage of git cli and libgit2 with env CARGO_GENERATE_GIT_WITH_CLI
* remove doubled code for abbreviation
* Test also GIT_WITH_CLI option
* restore warn when favorite was not found
* move url crate to dev-dependencies
* fix: better handle org/repo parsing
* ssh credentials are optional if `--identity` was not specified
* fix: set envirnoment variable in os independed way
* Improve tests. Minor fixes
* resolve concern
* remove optional shelling out to git
* revert to remove_dir_all crate
* fix clippy warning
* update git dependencies to resolve test problem: `cannot get submodules without a working tree`

Co-authored-by: Sven Assmann <sven.assmann.it@gmail.com>


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index ac5743b..2bb296d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -91,9 +91,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 
 [[package]]
 name = "backtrace"
-version = "0.3.64"
+version = "0.3.65"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e121dee8023ce33ab248d9ce1493df03c3b38a659b240096fcbd7048ff9c31f"
+checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61"
 dependencies = [
  "addr2line",
  "cc",
@@ -156,7 +156,7 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
 
 [[package]]
 name = "cargo-generate"
-version = "0.13.1"
+version = "0.14.0-alpha.1"
 dependencies = [
  "anyhow",
  "assert_cmd",
@@ -291,9 +291,9 @@ dependencies = [
 
 [[package]]
 name = "dialoguer"
-version = "0.10.0"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "349d6b4fabcd9e97e1df1ae15395ac7e49fb144946a0d453959dc2696273b9da"
+checksum = "d8c8ae48e400addc32a8710c8d62d55cb84249a7d58ac4cd959daecfbaddc545"
 dependencies = [
  "console",
  "tempfile",
@@ -484,9 +484,9 @@ dependencies = [
 
 [[package]]
 name = "git-hash"
-version = "0.9.3"
+version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "106e7c3a08b97285bf0bca7f109e67d286e7fbf34b222faf742443b021de2bb4"
+checksum = "e05d7e760613f4118cdccaf881fc9d1323c3ea596d156aac25a4eb44b428f11e"
 dependencies = [
  "hex",
  "quick-error",
@@ -494,9 +494,9 @@ dependencies = [
 
 [[package]]
 name = "git2"
-version = "0.14.2"
+version = "0.14.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3826a6e0e2215d7a41c2bfc7c9244123969273f3476b939a226aac0ab56e9e3c"
+checksum = "d0155506aab710a86160ddb504a480d2964d7ab5b9e62419be69e0032bc5931c"
 dependencies = [
  "bitflags",
  "libc",
@@ -602,12 +602,9 @@ dependencies = [
 
 [[package]]
 name = "indoc"
-version = "1.0.4"
+version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7906a9fababaeacb774f72410e497a1d18de916322e33797bb2cd29baa23c9e"
-dependencies = [
- "unindent",
-]
+checksum = "05a0bd019339e5d968b37855180087b7b9d512c5046fbd244cf8c95687927d6e"
 
 [[package]]
 name = "instant"
@@ -629,9 +626,9 @@ dependencies = [
 
 [[package]]
 name = "itoa"
-version = "1.0.1"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
+checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
 
 [[package]]
 name = "jobserver"
@@ -660,15 +657,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.122"
+version = "0.2.126"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259"
+checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
 
 [[package]]
 name = "libgit2-sys"
-version = "0.13.2+1.4.2"
+version = "0.13.4+1.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a42de9a51a5c12e00fc0e4ca6bc2ea43582fc6418488e8f615e905d886f258b"
+checksum = "d0fa6563431ede25f5cc7f6d803c6afbc1c5d3ad3d4925d12c882bf2b526f5d1"
 dependencies = [
  "cc",
  "libc",
@@ -694,9 +691,9 @@ dependencies = [
 
 [[package]]
 name = "libz-sys"
-version = "1.1.5"
+version = "1.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f35facd4a5673cb5a48822be2be1d4236c1c99cb4113cab7061ac720d5bf859"
+checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf"
 dependencies = [
  "cc",
  "libc",
@@ -763,9 +760,9 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.16"
+version = "0.4.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
+checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
 dependencies = [
  "cfg-if",
 ]
@@ -784,9 +781,9 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
 
 [[package]]
 name = "memchr"
-version = "2.4.1"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 
 [[package]]
 name = "memoffset"
@@ -805,12 +802,11 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.4.4"
+version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
+checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
 dependencies = [
  "adler",
- "autocfg",
 ]
 
 [[package]]
@@ -831,9 +827,9 @@ checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
 
 [[package]]
 name = "num-traits"
-version = "0.2.14"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
+checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
 dependencies = [
  "autocfg",
 ]
@@ -850,9 +846,9 @@ dependencies = [
 
 [[package]]
 name = "num_threads"
-version = "0.1.5"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aba1801fb138d8e85e11d0fc70baf4fe1cdfffda7c6cd34a854905df588e5ed0"
+checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
 dependencies = [
  "libc",
 ]
@@ -865,18 +861,18 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
 
 [[package]]
 name = "object"
-version = "0.27.1"
+version = "0.28.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
+checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "once_cell"
-version = "1.10.0"
+version = "1.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
+checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225"
 
 [[package]]
 name = "opaque-debug"
@@ -886,18 +882,30 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
 
 [[package]]
 name = "openssl"
-version = "0.10.38"
+version = "0.10.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95"
+checksum = "fb81a6430ac911acb25fe5ac8f1d2af1b4ea8a4fdfda0f1ee4292af2e2d8eb0e"
 dependencies = [
  "bitflags",
  "cfg-if",
  "foreign-types",
  "libc",
  "once_cell",
+ "openssl-macros",
  "openssl-sys",
 ]
 
+[[package]]
+name = "openssl-macros"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "openssl-probe"
 version = "0.1.5"
@@ -906,18 +914,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
 
 [[package]]
 name = "openssl-src"
-version = "111.18.0+1.1.1n"
+version = "111.20.0+1.1.1o"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7897a926e1e8d00219127dc020130eca4292e5ca666dd592480d72c3eca2ff6c"
+checksum = "92892c4f87d56e376e469ace79f1128fdaded07646ddf73aa0be4706ff712dec"
 dependencies = [
  "cc",
 ]
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.72"
+version = "0.9.73"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb"
+checksum = "9d5fd19fb3e0a8191c1e34935718976a3e70c112ab9a24af6d7cadccd9d90bc0"
 dependencies = [
  "autocfg",
  "cc",
@@ -1062,11 +1070,11 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.37"
+version = "1.0.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
+checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f"
 dependencies = [
- "unicode-xid",
+ "unicode-ident",
 ]
 
 [[package]]
@@ -1120,9 +1128,9 @@ dependencies = [
 
 [[package]]
 name = "rayon"
-version = "1.5.1"
+version = "1.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
+checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d"
 dependencies = [
  "autocfg",
  "crossbeam-deque",
@@ -1132,14 +1140,13 @@ dependencies = [
 
 [[package]]
 name = "rayon-core"
-version = "1.9.1"
+version = "1.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
+checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f"
 dependencies = [
  "crossbeam-channel",
  "crossbeam-deque",
  "crossbeam-utils",
- "lazy_static",
  "num_cpus",
 ]
 
@@ -1165,9 +1172,9 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.5.5"
+version = "1.5.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
+checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -1182,9 +1189,9 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
 
 [[package]]
 name = "regex-syntax"
-version = "0.6.25"
+version = "0.6.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
+checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
 
 [[package]]
 name = "remove_dir_all"
@@ -1210,9 +1217,9 @@ dependencies = [
 
 [[package]]
 name = "rhai"
-version = "1.6.1"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ef3d57e55ca044c53ced279d2d3ee9df229b247556b005a23713d5206a2ecfc"
+checksum = "9f06953bb8b9e4307cb7ccc0d9d018e2ddd25a30d32831f631ce4fe8f17671f7"
 dependencies = [
  "ahash",
  "bitflags",
@@ -1267,27 +1274,27 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 
 [[package]]
 name = "semver"
-version = "1.0.7"
+version = "1.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4"
+checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde"
-version = "1.0.136"
+version = "1.0.137"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
+checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.136"
+version = "1.0.137"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
+checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1361,13 +1368,13 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "1.0.91"
+version = "1.0.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
+checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942"
 dependencies = [
  "proc-macro2",
  "quote",
- "unicode-xid",
+ "unicode-ident",
 ]
 
 [[package]]
@@ -1423,18 +1430,18 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "1.0.30"
+version = "1.0.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
+checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.30"
+version = "1.0.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
+checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1470,9 +1477,9 @@ checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792"
 
 [[package]]
 name = "tinyvec"
-version = "1.5.1"
+version = "1.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2"
+checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
 dependencies = [
  "tinyvec_macros",
 ]
@@ -1506,9 +1513,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
 
 [[package]]
 name = "unicode-bidi"
-version = "0.3.7"
+version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
+checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
 
 [[package]]
 name = "unicode-bom"
@@ -1516,6 +1523,12 @@ version = "1.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "63ec69f541d875b783ca40184d655f2927c95f0bffd486faa83cd3ac3529ec32"
 
+[[package]]
+name = "unicode-ident"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"
+
 [[package]]
 name = "unicode-normalization"
 version = "0.1.19"
@@ -1539,15 +1552,9 @@ checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
 
 [[package]]
 name = "unicode-xid"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
-
-[[package]]
-name = "unindent"
-version = "0.1.8"
+version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "514672a55d7380da379785a4d70ca8386c8883ff7eaae877be4d2081cebe73d8"
+checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
 
 [[package]]
 name = "url"
@@ -1638,6 +1645,6 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "zeroize"
-version = "1.5.4"
+version = "1.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7eb5728b8afd3f280a869ce1d4c554ffaed35f45c231fc41bfbd0381bef50317"
+checksum = "94693807d016b2f2d2e14420eb3bfcca689311ff775dcf113d74ea624b7cdf07"
diff --git a/Cargo.toml b/Cargo.toml
index 643dab3..2a5ed88 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,10 +1,8 @@
 [package]
 name = "cargo-generate"
 description = "cargo, make me a project"
-version = "0.13.1"
-authors = [
-    "Ashley Williams <ashley666ashley@gmail.com>"
-]
+version = "0.14.0-alpha.1"
+authors = ["Ashley Williams <ashley666ashley@gmail.com>"]
 license = "MIT/Apache-2.0"
 repository = "https://github.com/cargo-generate/cargo-generate"
 edition = "2021"
@@ -23,7 +21,6 @@ heck = "0.4"
 walkdir = "2.3"
 remove_dir_all = "0.7"
 ignore = "0.4"
-url = "2.2"
 structopt = "0.3"
 anyhow = "1.0"
 toml = "0.5"
@@ -56,11 +53,17 @@ features = ["derive"]
 predicates = "2.1"
 assert_cmd = "2.0"
 indoc = "1.0"
+url = "2.2"
 
 [dev-dependencies.cargo-husky]
 version = "1"
 default-features = false
-features = ["prepush-hook", "run-cargo-test", "run-cargo-clippy", "run-cargo-fmt"]
+features = [
+  "prepush-hook",
+  "run-cargo-test",
+  "run-cargo-clippy",
+  "run-cargo-fmt",
+]
 
 [features]
 vendored-openssl = ['openssl/vendored']
diff --git a/src/app_config.rs b/src/app_config.rs
index db8cdee..94d79e6 100644
--- a/src/app_config.rs
+++ b/src/app_config.rs
@@ -18,6 +18,12 @@ pub struct AppConfig {
     pub values: Option<HashMap<String, toml::Value>>,
 }
 
+impl AppConfig {
+    pub fn get_favorite_cfg(&self, favorite_name: &str) -> Option<&FavoriteConfig> {
+        self.favorites.as_ref().and_then(|f| f.get(favorite_name))
+    }
+}
+
 #[derive(Deserialize, Default)]
 pub struct FavoriteConfig {
     pub description: Option<String>,
diff --git a/src/args.rs b/src/args.rs
index 575c6cc..fdc0487 100644
--- a/src/args.rs
+++ b/src/args.rs
@@ -155,7 +155,9 @@ impl Vcs {
     pub fn initialize(&self, project_dir: &Path, branch: String, force: bool) -> Result<()> {
         match self {
             Self::None => Ok(()),
-            Self::Git => git::init(project_dir, &branch, force).map(|_| ()),
+            Self::Git => git::init(project_dir, &branch, force)
+                .map(|_| ())
+                .map_err(anyhow::Error::from),
         }
     }
 
diff --git a/src/favorites.rs b/src/favorites.rs
index 7469a1a..ed2c044 100644
--- a/src/favorites.rs
+++ b/src/favorites.rs
@@ -1,10 +1,10 @@
-use std::collections::HashMap;
+//! Module dealing with <favorite> arg passed to cargo-generate
 
 use crate::{
     app_config::{AppConfig, FavoriteConfig},
-    emoji, warn, Args,
+    emoji, Args,
 };
-use anyhow::{anyhow, Result};
+use anyhow::Result;
 use console::style;
 
 pub fn list_favorites(app_config: &AppConfig, args: &Args) -> Result<()> {
@@ -47,66 +47,3 @@ pub fn list_favorites(app_config: &AppConfig, args: &Args) -> Result<()> {
 
     Ok(())
 }
-
-pub fn resolve_favorite_args_and_default_values(
-    app_config: &AppConfig,
-    args: &mut Args,
-) -> Result<Option<HashMap<String, toml::Value>>> {
-    if args.git.is_some() {
-        args.subfolder = args.favorite.take();
-        return Ok(app_config.values.clone());
-    }
-
-    if args.path.is_some() {
-        return Ok(app_config.values.clone());
-    }
-
-    let favorite_name = args
-        .favorite
-        .as_ref()
-        .ok_or_else(|| anyhow!("Please specify either --git option, or a predefined favorite"))?;
-
-    let (values, git, branch, subfolder, path) = app_config
-        .favorites
-        .as_ref()
-        .and_then(|f| f.get(favorite_name.as_str()))
-        .map_or_else(
-            || {
-                warn!(
-                    "Favorite {} not found in config, using it as a git repo url",
-                    style(&favorite_name).bold()
-                );
-                (
-                    None,
-                    Some(favorite_name.clone()),
-                    args.branch.as_ref().cloned(),
-                    args.subfolder.clone(),
-                    None,
-                )
-            },
-            |f| {
-                let values = match app_config.values.clone() {
-                    Some(mut values) => {
-                        values.extend(f.values.clone().unwrap_or_default());
-                        Some(values)
-                    }
-                    None => f.values.clone(),
-                };
-
-                (
-                    values,
-                    f.git.clone(),
-                    args.branch.as_ref().or(f.branch.as_ref()).cloned(),
-                    args.subfolder.as_ref().or(f.subfolder.as_ref()).cloned(),
-                    f.path.clone(),
-                )
-            },
-        );
-
-    args.git = git;
-    args.branch = branch;
-    args.subfolder = subfolder;
-    args.path = path;
-
-    Ok(values)
-}
diff --git a/src/git/creds.rs b/src/git/creds.rs
new file mode 100644
index 0000000..27c07be
--- /dev/null
+++ b/src/git/creds.rs
@@ -0,0 +1,43 @@
+use crate::git::utils::home;
+use crate::git::{identity_path::IdentityPath, utils::canonicalize_path};
+use crate::info;
+use anyhow::Result;
+use console::style;
+use git2::{Cred, RemoteCallbacks};
+use std::path::PathBuf;
+
+// Ok(None) is returned when identity was None and .ssh/id_rsa was not present
+pub fn git_ssh_credentials_callback<'a>(
+    identity: Option<PathBuf>,
+) -> Result<Option<RemoteCallbacks<'a>>> {
+    let private_key = if let Some(identity) = identity {
+        let identity = canonicalize_path(identity)?;
+        IdentityPath::try_from(identity)?
+    } else {
+        // if .ssh/id_rsa not exist its not error
+        let default_ssh_key = home()?.join(".ssh/id_rsa");
+        match IdentityPath::try_from(default_ssh_key) {
+            Ok(v) => v,
+            Err(_e) => return Ok(None),
+        }
+    };
+
+    info!(
+        "{} `{}` {}",
+        style("Using private key:").bold(),
+        style(format!("{}", &private_key)).bold().yellow(),
+        style("for git-ssh checkout").bold()
+    );
+    let mut cb = RemoteCallbacks::new();
+    cb.credentials(
+        move |_url, username_from_url: Option<&str>, _allowed_types| {
+            Cred::ssh_key(
+                username_from_url.unwrap_or("git"),
+                None,
+                private_key.as_ref(),
+                None,
+            )
+        },
+    );
+    Ok(Some(cb))
+}
diff --git a/src/git/gitconfig.rs b/src/git/gitconfig.rs
new file mode 100644
index 0000000..ca7e014
--- /dev/null
+++ b/src/git/gitconfig.rs
@@ -0,0 +1,64 @@
+use crate::git::utils::home;
+use anyhow::Context;
+use anyhow::Result;
+use git_config::file::GitConfig as GitConfigParser;
+use git_config::parser::Key;
+use std::path::{Path, PathBuf};
+
+pub fn find_gitconfig() -> Result<Option<PathBuf>> {
+    let gitconfig = home().map(|home| home.join(".gitconfig"))?;
+    if gitconfig.exists() {
+        return Ok(Some(gitconfig));
+    }
+
+    Ok(None)
+}
+
+/// trades urls, to replace a given repo remote url with the right on based
+/// on the `[url]` section in the `~/.gitconfig`
+pub fn resolve_instead_url(
+    remote: impl AsRef<str>,
+    gitconfig: impl AsRef<Path>,
+) -> Result<Option<String>> {
+    let gitconfig = gitconfig.as_ref();
+    let remote = remote.as_ref().to_string();
+    let config = GitConfigParser::open(gitconfig).context("Cannot read or parse .gitconfig")?;
+    Ok(config
+        .sections_by_name_with_header("url")
+        .iter()
+        .map(|(head, body)| {
+            let url = head.subsection_name.as_ref();
+            let instead_of = body
+                .value(&Key::from("insteadOf"))
+                .map(|x| std::str::from_utf8(&x[..]).unwrap().to_owned());
+            (instead_of, url)
+        })
+        .filter(|(old, new)| new.is_some() && old.is_some())
+        .find_map(|(old, new)| {
+            let old = old.unwrap();
+            let new = new.unwrap().to_string();
+            remote
+                .starts_with(old.as_str())
+                .then(|| remote.replace(old.as_str(), new.as_str()))
+        }))
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn should_resolve_instead_url() {
+        let sample_config = r#"
+[url "ssh://git@github.com:"]
+    insteadOf = https://github.com/
+"#;
+        let where_gitconfig_lives = tempfile::tempdir().unwrap();
+        let gitconfig = where_gitconfig_lives.path().join(".gitconfig");
+        std::fs::write(&gitconfig, sample_config).unwrap();
+
+        // SSH, aka git@github.com: or ssh://git@github.com/
+        let x = resolve_instead_url("https://github.com/foo/bar.git", &gitconfig).unwrap();
+        assert_eq!(x.unwrap().as_str(), "ssh://git@github.com:foo/bar.git")
+    }
+}
diff --git a/src/git/identity_path.rs b/src/git/identity_path.rs
index 7889509..c8ffc5b 100644
--- a/src/git/identity_path.rs
+++ b/src/git/identity_path.rs
@@ -1,21 +1,33 @@
-use crate::git::utils::{canonicalize_path, home};
+use crate::git::utils::home;
 use std::fmt::{Display, Formatter};
 
-use anyhow::{bail, Result};
+use anyhow::Result;
 use std::path::{Path, PathBuf};
+use thiserror::Error;
+
+//FIXME: this could be io::Error
+#[derive(Debug, Clone, Error)]
+pub enum IdentityPathErr {
+    #[error("identity file do not exist")]
+    FileNoExist,
+    #[error("path is not a file")]
+    NotFile,
+}
 
 pub struct IdentityPath(PathBuf);
 
 impl TryFrom<PathBuf> for IdentityPath {
-    type Error = anyhow::Error;
+    type Error = IdentityPathErr;
 
     fn try_from(path: PathBuf) -> Result<Self, Self::Error> {
-        let path_can = canonicalize_path(&path)?;
-
-        if path_can.exists() {
-            Ok(Self(path_can))
+        if path.exists() {
+            if path.is_file() {
+                Ok(Self(path))
+            } else {
+                Err(IdentityPathErr::NotFile)
+            }
         } else {
-            bail!("Invalid ssh identity path: {}", path.as_path().display())
+            Err(IdentityPathErr::FileNoExist)
         }
     }
 }
diff --git a/src/git/mod.rs b/src/git/mod.rs
index 1b292a5..0214db2 100644
--- a/src/git/mod.rs
+++ b/src/git/mod.rs
@@ -1,5 +1,164 @@
+//! Handle `--git` and related flags
+
+mod creds;
+mod gitconfig;
 mod identity_path;
-mod remote;
 mod utils;
 
-pub use utils::{create, init, remove_history, GitConfig};
+use anyhow::Result;
+use std::path::{Path, PathBuf};
+
+use git2::{build::RepoBuilder, FetchOptions, ProxyOptions, Repository, RepositoryInitOptions};
+pub use utils::clone_git_template_into_temp;
+
+// cargo-generate (as application) whant from git module:
+// 1. cloning remote
+// 2. initialize freshly generated template
+// 3. remove history from cloned template
+
+// Assumptions:
+// * `--git <url>` should only be parse in the same way as `git clone <url>` would
+// * submodules should be clone by default
+// * `.git` should be removed to make clear repository
+// * if `<url>` is the local path on system the clone should also be done the same way as `git clone` there is `--path`
+//    for different behavior
+
+// basicly we want to call:
+// git clone --recurse-submodules --depth 1 --branch <branch> <url> <tmp_dir>
+
+/// Default branch to use if not specified but required
+pub const DEFAULT_BRANCH: &str = "main";
+
+type Git2Result<T> = Result<T, git2::Error>;
+
+struct RepoCloneBuilder<'cb> {
+    builder: RepoBuilder<'cb>,
+    fetch_options: FetchOptions<'cb>,
+    identity: Option<PathBuf>,
+    url: String,
+}
+
+impl<'cb> RepoCloneBuilder<'cb> {
+    pub fn new(url: &str) -> Result<Self> {
+        let mut po = ProxyOptions::new();
+        po.auto();
+        let mut fo = FetchOptions::new();
+        fo.proxy_options(po);
+
+        let url = gitconfig::find_gitconfig()?.map_or_else(
+            || url.to_owned(),
+            |gitcfg| {
+                gitconfig::resolve_instead_url(url, gitcfg)
+                    .expect("correct configuration")
+                    .unwrap_or_else(|| url.to_owned())
+            },
+        );
+
+        Ok(Self {
+            builder: RepoBuilder::new(),
+            fetch_options: fo,
+            identity: None,
+            url,
+        })
+    }
+
+    pub fn new_with(url: &str, branch: Option<&str>, identity_path: Option<&Path>) -> Result<Self> {
+        let mut builer = Self::new(url)?;
+        if let Some(branch) = branch {
+            builer.set_branch(branch);
+        }
+
+        if let Some(identity_path) = identity_path {
+            builer.set_identity(identity_path);
+        }
+
+        Ok(builer)
+    }
+
+    pub fn set_identity(&mut self, identity_path: &Path) {
+        self.identity = Some(PathBuf::from(identity_path));
+    }
+
+    pub fn set_branch(&mut self, branch: &str) {
+        self.builder.branch(branch);
+    }
+
+    fn clone(mut self, dest_path: &Path) -> Result<Repository> {
+        if let Some(callbacks) = crate::git::creds::git_ssh_credentials_callback(self.identity)? {
+            self.fetch_options.remote_callbacks(callbacks);
+        }
+        self.builder.fetch_options(self.fetch_options);
+        self.builder
+            .clone(&self.url, dest_path)
+            .map_err(anyhow::Error::from)
+    }
+
+    pub fn clone_with_submodules(self, dest_path: &Path) -> Result<Repository> {
+        self.clone(dest_path).and_then(|repo| {
+            for mut sub in repo.submodules()? {
+                sub.update(true, None)?;
+            }
+
+            Ok(repo)
+        })
+    }
+}
+
+/// Init project_dir with fresh repository on branch
+///
+/// Arguments:
+/// - `force` - enforce a fresh git init
+pub fn init(project_dir: &Path, branch: &str, force: bool) -> Git2Result<Repository> {
+    fn just_init(project_dir: &Path, branch: &str) -> Git2Result<Repository> {
+        let mut opts = RepositoryInitOptions::new();
+        opts.bare(false);
+        opts.initial_head(branch);
+        Repository::init_opts(project_dir, &opts)
+    }
+
+    match Repository::discover(project_dir) {
+        Ok(repo) => {
+            if force {
+                Repository::open(project_dir).or_else(|_| just_init(project_dir, branch))
+            } else {
+                Ok(repo)
+            }
+        }
+        Err(_) => just_init(project_dir, branch),
+    }
+}
+
+use crate::warn;
+use remove_dir_all::remove_dir_all;
+use std::{io, ops::Sub, thread::sleep, time::Duration};
+
+/// remove context of repository by removing `.git` from filesystem
+pub fn remove_history(project_dir: &Path) -> io::Result<()> {
+    let git_dir = project_dir.join(".git");
+    if git_dir.exists() && git_dir.is_dir() {
+        let mut attempt = 0_u8;
+
+        loop {
+            attempt += 1;
+            if let Err(e) = remove_dir_all(&git_dir) {
+                if attempt == 5 {
+                    return Err(e);
+                }
+
+                if e.to_string().contains("The process cannot access the file because it is being used by another process.") {
+                    let wait_for = Duration::from_secs(2_u64.pow(attempt.sub(1).into()));
+                    warn!("Git history cleanup failed with a windows process blocking error. [Retry in {:?}]", wait_for);
+                    sleep(wait_for);
+                } else {
+                    return Err(e);
+                }
+            } else {
+                return Ok(());
+            }
+        }
+    } else {
+        //FIXME should we assume this is expected by caller?
+        // panic!("tmp panic");
+        Ok(())
+    }
+}
diff --git a/src/git/remote.rs b/src/git/remote.rs
deleted file mode 100644
index 61b24fe..0000000
--- a/src/git/remote.rs
+++ /dev/null
@@ -1,112 +0,0 @@
-use anyhow::Result;
-use console::style;
-use core::convert::{AsRef, TryFrom};
-use core::result::Result::Ok;
-use std::borrow::Cow;
-use std::path::PathBuf;
-
-use crate::git::utils::{canonicalize_path, determine_repo_kind, resolve_instead_url, RepoKind};
-use crate::info;
-
-/// url and gitconfig content
-pub struct GitUrlAndConfig<'a>(pub Cow<'a, str>, pub PathBuf);
-
-impl<'a> TryFrom<GitUrlAndConfig<'a>> for GitRemote<'a> {
-    type Error = anyhow::Error;
-
-    fn try_from(value: GitUrlAndConfig<'a>) -> Result<Self, Self::Error> {
-        let r = value.0.as_ref();
-        let url = if let Ok(Some(url)) = resolve_instead_url(r, &value.1) {
-            info!(
-                "Using gitconfig `{}` for {:?} -> {:?}",
-                style("insteadOf").bold(),
-                style(r).bold().yellow(),
-                style(&url).bold().yellow()
-            );
-            url
-        } else {
-            r.to_owned()
-        };
-
-        url.try_into()
-    }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct GitRemote<'a> {
-    url: Cow<'a, str>,
-    kind: RepoKind,
-}
-
-impl<'a> AsRef<str> for GitRemote<'a> {
-    fn as_ref(&self) -> &str {
-        self.url.as_ref()
-    }
-}
-
-impl<'a> TryFrom<Cow<'a, str>> for GitRemote<'a> {
-    type Error = anyhow::Error;
-
-    fn try_from(url: Cow<'a, str>) -> Result<Self, Self::Error> {
-        let url = url.as_ref();
-        let (remote, kind) = match determine_repo_kind(url) {
-            RepoKind::Invalid => anyhow::bail!("Invalid git remote '{}'", url),
-            RepoKind::LocalFolder => {
-                let full_path = canonicalize_path(&url)?;
-                if !full_path.exists() {
-                    anyhow::bail!("The given git remote {:?} does not exist.", url);
-                }
-                (full_path.display().to_string(), RepoKind::LocalFolder)
-            }
-            k => (url.to_string(), k),
-        };
-        Ok(Self {
-            url: Cow::from(remote),
-            kind,
-        })
-    }
-}
-
-impl<'a> TryFrom<String> for GitRemote<'a> {
-    type Error = anyhow::Error;
-
-    fn try_from(url: String) -> Result<Self, Self::Error> {
-        Cow::from(url).try_into()
-    }
-}
-
-impl<'a> TryFrom<&'a str> for GitRemote<'a> {
-    type Error = anyhow::Error;
-
-    fn try_from(url: &'a str) -> Result<Self, Self::Error> {
-        Cow::from(url).try_into()
-    }
-}
-
-impl<'a> AsRef<RepoKind> for GitRemote<'a> {
-    fn as_ref(&self) -> &RepoKind {
-        &self.kind
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn should_provide_a_remove() {
-        let sample_config = r#"
-[url "ssh://git@github.com:"]
-    insteadOf = https://github.com/
-"#;
-        let where_gitconfig_lives = tempfile::tempdir().unwrap();
-        let gitconfig = where_gitconfig_lives.path().join(".gitconfig");
-        std::fs::write(&gitconfig, sample_config).unwrap();
-
-        let remote = GitUrlAndConfig(Cow::from("https://github.com/sassman/t-rec-rs"), gitconfig);
-        let remote: GitRemote = remote.try_into().unwrap();
-        let remote: &str = remote.as_ref();
-
-        assert_eq!(remote, "ssh://git@github.com:sassman/t-rec-rs");
-    }
-}
diff --git a/src/git/utils.rs b/src/git/utils.rs
index 8d3a0f7..e2fc7de 100644
--- a/src/git/utils.rs
+++ b/src/git/utils.rs
@@ -1,109 +1,11 @@
-use crate::git::remote::{GitRemote, GitUrlAndConfig};
-use crate::warn;
-use crate::{copy_dir_all, info};
-
-use crate::git::identity_path::IdentityPath;
 use anyhow::Context;
 use anyhow::Result;
-use console::style;
-use git2::build::RepoBuilder;
-use git2::{Cred, FetchOptions, ProxyOptions, RemoteCallbacks, Repository, RepositoryInitOptions};
-use git2::{ErrorClass, ErrorCode};
-use git_config::file::GitConfig as GitConfigParser;
-use git_config::parser::Key;
-use remove_dir_all::remove_dir_all;
-use std::borrow::Cow;
-use std::ops::{Add, Sub};
 use std::path::{Path, PathBuf};
-use std::thread::sleep;
-use std::time::Duration;
-
-#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum RepoKind {
-    LocalFolder,
-    RemoteHttp,
-    RemoteHttps,
-    RemoteSsh,
-    RemoteGit,
-    Invalid,
-}
-
-/// Information to find a specific commit in a Git repository.
-#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum GitReference {
-    /// From a branch.
-    Branch(String),
-    /// The default branch of the repository, the reference named `HEAD`.
-    DefaultBranch,
-}
-
-pub struct GitConfig<'a> {
-    remote: GitRemote<'a>,
-    branch: GitReference,
-    identity: Option<PathBuf>,
-}
-
-impl<'a> GitConfig<'a> {
-    /// Creates a new `GitConfig` by parsing `git` as a URL or a local path.
-    pub fn new(
-        git: impl AsRef<str> + 'a,
-        branch: Option<String>,
-        identity: Option<PathBuf>,
-    ) -> Result<Self> {
-        let git = Cow::from(git.as_ref().to_string());
-        let gitconfig = find_gitconfig()?;
-        let remote = if let Some(gitconfig) = gitconfig {
-            GitRemote::try_from(GitUrlAndConfig(git, gitconfig))?
-        } else {
-            GitRemote::try_from(git)?
-        };
-
-        Ok(GitConfig {
-            remote,
-            identity,
-            branch: branch
-                .map(GitReference::Branch)
-                .unwrap_or(GitReference::DefaultBranch),
-        })
-    }
 
-    /// Creates a new `GitConfig`, first with `new` and then as a GitHub `owner/repo` remote, like
-    /// [hub].
-    ///
-    /// [hub]: https://github.com/github/hub
-    pub fn new_abbr(
-        git: impl AsRef<str>,
-        branch: Option<String>,
-        identity: Option<PathBuf>,
-    ) -> Result<Self> {
-        let full_remote = abbreviated_git_url_to_full_remote(&git);
-        Self::new(full_remote, branch.clone(), identity.clone()).or_else(|_| {
-            let full_remote = abbreviated_git_url_to_full_remote(format!("gh:{}", git.as_ref()));
-            Self::new(full_remote, branch, identity)
-        })
-    }
-}
+use git2::Repository;
+use tempfile::TempDir;
 
-pub fn abbreviated_git_url_to_full_remote(git: impl AsRef<str>) -> String {
-    let git = git.as_ref();
-    if git.len() >= 3 {
-        match &git[..3] {
-            "gl:" => format!("https://gitlab.com/{}.git", &git[3..]),
-            "bb:" => format!("https://bitbucket.org/{}.git", &git[3..]),
-            "gh:" => format!("https://github.com/{}.git", &git[3..]),
-            _ => git.to_owned(),
-        }
-    } else {
-        git.to_owned()
-    }
-}
-
-pub fn create(project_dir: &Path, args: GitConfig) -> Result<String> {
-    let branch = git_clone_all(project_dir, args)?;
-    remove_history(project_dir, None)?;
-
-    Ok(branch)
-}
+use super::{remove_history, RepoCloneBuilder};
 
 /// deals with `~/` and `$HOME/` prefixes
 pub fn canonicalize_path(p: impl AsRef<Path>) -> Result<PathBuf> {
@@ -119,6 +21,49 @@ pub fn canonicalize_path(p: impl AsRef<Path>) -> Result<PathBuf> {
     p.canonicalize().context("path does not exist")
 }
 
+/// home path wrapper
+pub fn home() -> Result<PathBuf> {
+    dirs::home_dir().context("$HOME was not set")
+}
+
+// clone git reposiotry into temp using libgit2
+pub fn clone_git_template_into_temp(
+    git: &str,
+    branch: Option<&str>,
+    identity: Option<&Path>,
+) -> anyhow::Result<(TempDir, String)> {
+    let git_clone_dir = tempfile::tempdir()?;
+
+    let builder = RepoCloneBuilder::new_with(git, branch, identity)?;
+
+    let repo = builder
+        .clone_with_submodules(git_clone_dir.path())
+        .context("Please check if the Git user / repository exists.")?;
+    let branch = get_branch_name_repo(&repo)?;
+
+    // change from git repository into normal folder.
+    remove_history(git_clone_dir.path())?;
+
+    Ok((git_clone_dir, branch))
+}
+
+/// thanks to @extrawurst for pointing this out
+/// <https://github.com/extrawurst/gitui/blob/master/asyncgit/src/sync/branch/mod.rs#L38>
+fn get_branch_name_repo(repo: &Repository) -> anyhow::Result<String> {
+    let iter = repo.branches(None)?;
+
+    for b in iter {
+        let b = b?;
+
+        if b.0.is_head() {
+            let name = b.0.name()?.unwrap_or("");
+            return Ok(name.into());
+        }
+    }
+
+    anyhow::bail!("A repo has no Head")
+}
+
 #[test]
 fn should_canonicalize() {
     #[cfg(target_os = "macos")]
@@ -148,371 +93,3 @@ fn should_canonicalize() {
         .unwrap()
         .starts_with("\\\\?\\"));
 }
-
-/// takes care of `~/` paths, defaults to `$HOME/.ssh/id_rsa` and resolves symlinks.
-fn get_private_key_path(identity: Option<PathBuf>) -> Result<IdentityPath> {
-    let private_key = identity.unwrap_or(home()?.join(".ssh/id_rsa"));
-    private_key.try_into()
-}
-
-fn git_ssh_credentials_callback<'a>(identity: Option<PathBuf>) -> Result<RemoteCallbacks<'a>> {
-    let private_key = get_private_key_path(identity)?;
-    info!(
-        "{} `{}` {}",
-        style("Using private key:").bold(),
-        style(format!("{}", &private_key)).bold().yellow(),
-        style("for git-ssh checkout").bold()
-    );
-    let mut cb = RemoteCallbacks::new();
-    cb.credentials(
-        move |_url, username_from_url: Option<&str>, _allowed_types| {
-            Cred::ssh_key(
-                username_from_url.unwrap_or("git"),
-                None,
-                private_key.as_ref(),
-                None,
-            )
-        },
-    );
-    Ok(cb)
-}
-
-/// home path wrapper
-pub fn home() -> Result<PathBuf> {
-    canonicalize_path(&dirs::home_dir().context("$HOME was not set")?)
-}
-
-/// thanks to @extrawurst for pointing this out
-/// <https://github.com/extrawurst/gitui/blob/master/asyncgit/src/sync/branch/mod.rs#L38>
-fn get_branch_name_repo(repo: &Repository) -> Result<String> {
-    let iter = repo.branches(None)?;
-
-    for b in iter {
-        let b = b?;
-
-        if b.0.is_head() {
-            let name = b.0.name()?.unwrap_or("");
-            return Ok(name.into());
-        }
-    }
-
-    anyhow::bail!("A repo has no Head")
-}
-
-fn init_all_submodules(repo: &Repository) -> Result<()> {
-    for mut sub in repo.submodules().unwrap() {
-        sub.update(true, None)?;
-    }
-
-    Ok(())
-}
-
-fn git_clone_all(project_dir: &Path, args: GitConfig) -> Result<String> {
-    let mut builder = RepoBuilder::new();
-    if let GitReference::Branch(branch_name) = &args.branch {
-        builder.branch(branch_name.as_str());
-    }
-
-    let mut fo = FetchOptions::new();
-    match args.remote.as_ref() {
-        RepoKind::LocalFolder => {}
-        RepoKind::RemoteHttp | RepoKind::RemoteHttps => {
-            let mut proxy = ProxyOptions::new();
-            proxy.auto();
-            fo.proxy_options(proxy);
-        }
-        RepoKind::RemoteSsh => {
-            let callbacks = git_ssh_credentials_callback(args.identity)?;
-            fo.remote_callbacks(callbacks);
-        }
-        RepoKind::RemoteGit => {
-            // todo: verify if that would just work as is
-        }
-        RepoKind::Invalid => {
-            unreachable!()
-        }
-    }
-    builder.fetch_options(fo);
-
-    match builder.clone(args.remote.as_ref(), project_dir) {
-        Ok(repo) => {
-            let branch = get_branch_name_repo(&repo)?;
-            init_all_submodules(&repo)?;
-            Ok(branch)
-        }
-        Err(e) => {
-            {
-                // super wired that the windows libgit2 does behave different for this case,
-                // both things actually mean the same!
-                #[cfg(windows)]
-                if e.class() == ErrorClass::Http
-                    && e.code() == ErrorCode::GenericError
-                    && e.message().contains("request failed with status code: 401")
-                {
-                    return Err(anyhow::Error::msg(
-                        "Please check if the Git user / repository exists.",
-                    ));
-                }
-                #[cfg(not(windows))]
-                if e.code() == ErrorCode::Auth && e.class() == ErrorClass::Http {
-                    return Err(anyhow::Error::msg(
-                        "Please check if the Git user / repository exists.",
-                    ));
-                }
-            }
-            if e.code() != ErrorCode::NotFound {
-                return Err(e.into());
-            }
-
-            let path: &str = args.remote.as_ref();
-            let path = Path::new(path);
-            if !path.exists() || !path.is_dir() {
-                return Err(e.into());
-            }
-
-            warn!("Template does not seem to be a git repository, using as a plain folder");
-            copy_dir_all(path, project_dir)?;
-            Ok("".to_string())
-        }
-    }
-}
-
-pub fn remove_history(project_dir: &Path, attempt: Option<u8>) -> Result<()> {
-    let git_dir = project_dir.join(".git");
-    if git_dir.exists() && git_dir.is_dir() {
-        if let Err(e) = remove_dir_all(git_dir) {
-            // see https://github.com/cargo-generate/cargo-generate/issues/375
-            if e.to_string().contains(
-                "The process cannot access the file because it is being used by another process.",
-            ) {
-                let attempt = attempt.unwrap_or(1);
-                if attempt == 5 {
-                    warn!("cargo-generate was not able to delete the git history after {} retries. Please delete the `.git` sub-folder manually", attempt);
-                    return Ok(());
-                }
-                let wait_for = Duration::from_secs(2_u64.pow(attempt.sub(1).into()));
-                warn!("Git history cleanup failed with a windows process blocking error. [Retry in {:?}]", wait_for);
-                sleep(wait_for);
-                remove_history(project_dir, Some(attempt.add(1)))?
-            }
-        }
-    }
-    Ok(())
-}
-
-pub fn init(project_dir: &Path, branch: &str, force: bool) -> Result<Repository> {
-    fn just_init(project_dir: &Path, branch: &str) -> Result<Repository> {
-        let mut opts = RepositoryInitOptions::new();
-        opts.bare(false);
-        opts.initial_head(branch);
-        Repository::init_opts(project_dir, &opts).context("Couldn't init new repository")
-    }
-
-    match Repository::discover(project_dir) {
-        Ok(repo) => {
-            if force {
-                Repository::open(project_dir).or_else(|_| just_init(project_dir, branch))
-            } else {
-                Ok(repo)
-            }
-        }
-        Err(_) => just_init(project_dir, branch),
-    }
-}
-
-/// determines what kind of repository we got
-pub fn determine_repo_kind(remote_url: &str) -> RepoKind {
-    if remote_url.starts_with("git@") || remote_url.starts_with("ssh://") {
-        RepoKind::RemoteSsh
-    } else if remote_url.starts_with("git://") {
-        RepoKind::RemoteGit
-    } else if remote_url.starts_with("http://") {
-        RepoKind::RemoteHttp
-    } else if remote_url.starts_with("https://") {
-        RepoKind::RemoteHttps
-    } else if Path::new(remote_url).exists() {
-        RepoKind::LocalFolder
-    } else {
-        RepoKind::Invalid
-    }
-}
-
-pub fn find_gitconfig() -> Result<Option<PathBuf>> {
-    let gitconfig = home().map(|home| home.join(".gitconfig"))?;
-    if gitconfig.exists() {
-        return Ok(Some(gitconfig));
-    }
-
-    Ok(None)
-}
-
-/// trades urls, to replace a given repo remote url with the right on based
-/// on the `[url]` section in the `~/.gitconfig`
-pub fn resolve_instead_url(
-    remote: impl AsRef<str>,
-    gitconfig: impl AsRef<Path>,
-) -> Result<Option<String>> {
-    let gitconfig = gitconfig.as_ref();
-    let remote = remote.as_ref().to_string();
-    let config = GitConfigParser::open(gitconfig).context("Cannot read or parse .gitconfig")?;
-    Ok(config
-        .sections_by_name_with_header("url")
-        .iter()
-        .map(|(head, body)| {
-            let url = head.subsection_name.as_ref();
-            let instead_of = body
-                .value(&Key::from("insteadOf"))
-                .map(|x| std::str::from_utf8(&x[..]).unwrap().to_owned());
-            (instead_of, url)
-        })
-        .filter(|(old, new)| new.is_some() && old.is_some())
-        .filter_map(|(old, new)| {
-            let old = old.unwrap();
-            let new = new.unwrap().to_string();
-            remote
-                .starts_with(old.as_str())
-                .then(|| remote.replace(old.as_str(), new.as_str()))
-        })
-        .next())
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use std::env::current_dir;
-    use url::Url;
-
-    const REPO_URL: &str = "https://github.com/cargo-generate/cargo-generate.git";
-    const REPO_URL_SSH: &str = "git@github.com:cargo-generate/cargo-generate.git";
-
-    #[test]
-    fn should_determine_repo_kind() {
-        for (u, k) in &[
-            (REPO_URL, RepoKind::RemoteHttps),
-            (
-                "http://github.com/cargo-generate/cargo-generate.git",
-                RepoKind::RemoteHttp,
-            ),
-            (REPO_URL_SSH, RepoKind::RemoteSsh),
-            ("./", RepoKind::LocalFolder),
-            ("ftp://foobar.bak", RepoKind::Invalid),
-        ] {
-            let kind = determine_repo_kind(u);
-            assert_eq!(&kind, k, "{} is not a {:?}", u, k);
-        }
-    }
-
-    #[test]
-    fn should_not_fail_for_ssh_remote_urls() {
-        let config = GitConfig::new(REPO_URL_SSH, None, None).unwrap();
-        let kind: &RepoKind = config.remote.as_ref();
-        assert_eq!(kind, &RepoKind::RemoteSsh);
-    }
-
-    #[test]
-    #[should_panic(expected = "Invalid git remote 'aslkdgjlaskjdglskj'")]
-    fn should_fail_for_non_existing_local_path() {
-        GitConfig::new("aslkdgjlaskjdglskj", None, None).unwrap();
-    }
-
-    #[test]
-    fn should_support_a_local_relative_path() {
-        let config = GitConfig::new("src", None, None).unwrap();
-        let remote: &str = config.remote.as_ref();
-        #[cfg(unix)]
-        assert!(
-            remote.ends_with("/src"),
-            "remote {} ends with /src",
-            &remote
-        );
-        #[cfg(windows)]
-        assert!(
-            remote.ends_with("\\src"),
-            "remote {} ends with \\src",
-            &remote
-        );
-
-        #[cfg(unix)]
-        assert!(remote.starts_with('/'), "remote {} starts with /", &remote);
-        #[cfg(windows)]
-        assert!(
-            remote.starts_with("\\\\?\\"),
-            "remote {} starts with \\\\?\\",
-            &remote
-        );
-    }
-
-    #[test]
-    fn should_support_a_local_absolute_path() {
-        // Absolute path.
-        // If this fails because you cloned this repository into a non-UTF-8 directory... all
-        // I can say is you probably had it comin'.
-        let config =
-            GitConfig::new(current_dir().unwrap().display().to_string(), None, None).unwrap();
-        let remote: &str = config.remote.as_ref();
-        #[cfg(unix)]
-        assert!(remote.starts_with('/'), "remote {} starts with /", &remote);
-        #[cfg(windows)]
-        assert!(
-            remote.starts_with("\\\\?\\"),
-            "remote {} starts with \\\\?\\ then the drive letter",
-            &remote
-        );
-    }
-
-    #[test]
-    fn should_test_happy_path() {
-        // Remote HTTPS URL.
-        let cfg = GitConfig::new(REPO_URL, Some("main".to_owned()), None).unwrap();
-        let url: &str = cfg.remote.as_ref();
-
-        assert_eq!(url, Url::parse(REPO_URL).unwrap().as_str());
-        assert_eq!(cfg.branch, GitReference::Branch("main".to_owned()));
-    }
-
-    #[test]
-    fn should_support_abbreviated_repository_short_urls_like() {
-        let config = GitConfig::new_abbr("cargo-generate/cargo-generate", None, None).unwrap();
-        let url: &str = config.remote.as_ref();
-        assert_eq!(url, Url::parse(REPO_URL).unwrap().as_str());
-    }
-
-    #[test]
-    fn should_support_abbreviated_repository_short_urls_like_for_github() {
-        let config = GitConfig::new_abbr("gh:cargo-generate/cargo-generate", None, None).unwrap();
-        let url: &str = config.remote.as_ref();
-        assert_eq!(url, Url::parse(REPO_URL).unwrap().as_str());
-    }
-
-    #[test]
-    fn should_support_bb_gl_gh_abbreviations() {
-        assert_eq!(
-            &abbreviated_git_url_to_full_remote("gh:foo/bar"),
-            "https://github.com/foo/bar.git"
-        );
-        assert_eq!(
-            &abbreviated_git_url_to_full_remote("bb:foo/bar"),
-            "https://bitbucket.org/foo/bar.git"
-        );
-        assert_eq!(
-            &abbreviated_git_url_to_full_remote("gl:foo/bar"),
-            "https://gitlab.com/foo/bar.git"
-        );
-        assert_eq!(&abbreviated_git_url_to_full_remote("foo/bar"), "foo/bar");
-    }
-
-    #[test]
-    fn should_resolve_instead_url() {
-        let sample_config = r#"
-[url "ssh://git@github.com:"]
-    insteadOf = https://github.com/
-"#;
-        let where_gitconfig_lives = tempfile::tempdir().unwrap();
-        let gitconfig = where_gitconfig_lives.path().join(".gitconfig");
-        std::fs::write(&gitconfig, sample_config).unwrap();
-
-        // SSH, aka git@github.com: or ssh://git@github.com/
-        let x = resolve_instead_url("https://github.com/foo/bar.git", &gitconfig).unwrap();
-        assert_eq!(x.unwrap().as_str(), "ssh://git@github.com:foo/bar.git")
-    }
-}
diff --git a/src/lib.rs b/src/lib.rs
index d8b0e6f..67dc3cf 100755
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -39,13 +39,15 @@ mod project_variables;
 mod template;
 mod template_filters;
 mod template_variables;
+mod user_parsed_input;
 
 pub use args::*;
 
 use anyhow::{anyhow, bail, Context, Result};
 use config::{locate_template_configs, Config, CONFIG_FILE_NAME};
 use console::style;
-use favorites::{list_favorites, resolve_favorite_args_and_default_values};
+use favorites::list_favorites;
+use git::DEFAULT_BRANCH;
 use hooks::{execute_post_hooks, execute_pre_hooks};
 use ignore_me::remove_dir_files;
 use interactive::prompt_for_variable;
@@ -59,15 +61,16 @@ use std::{
     path::{Path, PathBuf},
     rc::Rc,
 };
+use user_parsed_input::{TemplateLocation, UserParsedInput};
 
 use tempfile::TempDir;
 
+use crate::template_variables::load_env_and_args_template_values;
 use crate::{
     app_config::{app_config_path, AppConfig},
     project_variables::ConversionError,
     template_variables::{CrateType, ProjectName},
 };
-use crate::{git::GitConfig, template_variables::resolve_template_values};
 
 /// # Panics
 pub fn generate(mut args: Args) -> Result<()> {
@@ -88,17 +91,14 @@ pub fn generate(mut args: Args) -> Result<()> {
             .ssh_identity
             .as_ref()
             .cloned();
-        if let Some(id) = args.ssh_identity.as_ref() {
-            info!(
-                "Using ssh-identity from application config: {}",
-                style(id.as_path().display()).bold()
-            )
-        }
     }
 
-    let default_values = resolve_favorite_args_and_default_values(&app_config, &mut args)?;
+    let mut source_template = UserParsedInput::try_from_args_and_config(&app_config, &args);
+    source_template
+        .template_values_mut()
+        .extend(load_env_and_args_template_values(&args)?);
 
-    let (template_base_dir, template_folder, branch) = prepare_local_template(&args)?;
+    let (template_base_dir, template_folder, branch) = prepare_local_template(&source_template)?;
 
     let template_config = Config::from_path(
         &locate_template_file(CONFIG_FILE_NAME, &template_base_dir, &template_folder).ok(),
@@ -106,7 +106,6 @@ pub fn generate(mut args: Args) -> Result<()> {
     .unwrap_or_default();
 
     check_cargo_generate_version(&template_config)?;
-    let template_values = resolve_template_values(default_values, &args)?;
 
     let project_name = resolve_project_name(&args)?;
     let project_dir = resolve_project_dir(&project_name, &args)?;
@@ -121,7 +120,7 @@ pub fn generate(mut args: Args) -> Result<()> {
     expand_template(
         &project_name,
         &template_folder,
-        &template_values,
+        source_template.template_values(),
         template_config,
         &args,
     )?;
@@ -151,58 +150,34 @@ pub fn generate(mut args: Args) -> Result<()> {
     Ok(())
 }
 
-fn prepare_local_template(args: &Args) -> Result<(TempDir, PathBuf, String), anyhow::Error> {
-    let (template_base_dir, template_folder, branch) = match (&args.git, &args.path) {
-        (Some(_), None) => {
-            let (template_base_dir, branch) = clone_git_template_into_temp(args)?;
-            let template_folder = resolve_template_dir(&template_base_dir, args)?;
-            (template_base_dir, template_folder, branch)
-        }
-        (None, Some(_)) => {
-            let template_base_dir = copy_path_template_into_temp(args)?;
-            let branch = args.branch.clone().unwrap_or_else(|| String::from("main"));
-            let template_folder =
-                auto_locate_template_dir(template_base_dir.path(), prompt_for_variable)?;
-            (template_base_dir, template_folder, branch)
-        }
-        _ => bail!(
-            "{} {} {} {} {}",
-            emoji::ERROR,
-            style("Please specify either").bold(),
-            style("--git <repo>").bold().yellow(),
-            style("or").bold(),
-            style("--path <path>").bold().yellow(),
-        ),
-    };
+fn prepare_local_template(
+    source_template: &UserParsedInput,
+) -> Result<(TempDir, PathBuf, String), anyhow::Error> {
+    let (temp_dir, branch) = get_source_template_into_temp(source_template.location())?;
+    let template_folder = resolve_template_dir(&temp_dir, source_template.subfolder())?;
 
-    Ok((template_base_dir, template_folder, branch))
+    Ok((temp_dir, template_folder, branch))
 }
 
-fn check_cargo_generate_version(template_config: &Config) -> Result<(), anyhow::Error> {
-    if let Config {
-        template:
-            Some(config::TemplateConfig {
-                cargo_generate_version: Some(requirement),
-                ..
-            }),
-        ..
-    } = template_config
-    {
-        let version = semver::Version::parse(env!("CARGO_PKG_VERSION"))?;
-        if !requirement.matches(&version) {
-            bail!(
-                "{} {} {} {} {}",
-                emoji::ERROR,
-                style("Required cargo-generate version not met. Required:")
-                    .bold()
-                    .red(),
-                style(requirement).yellow(),
-                style(" was:").bold().red(),
-                style(version).yellow(),
-            );
+fn get_source_template_into_temp(
+    template_location: &TemplateLocation,
+) -> Result<(TempDir, String)> {
+    let temp_dir: TempDir;
+    let branch: String;
+    match template_location {
+        TemplateLocation::Git(git) => {
+            let (temp_dir2, branch2) =
+                git::clone_git_template_into_temp(git.url(), git.branch(), git.identity())?;
+            temp_dir = temp_dir2;
+            branch = branch2;
         }
-    }
-    Ok(())
+        TemplateLocation::Path(path) => {
+            temp_dir = copy_path_template_into_temp(path)?;
+            branch = String::from(DEFAULT_BRANCH); // FIXME is here any reason to set branch when path is used?
+        }
+    };
+
+    Ok((temp_dir, branch))
 }
 
 fn resolve_project_name(args: &Args) -> Result<ProjectName> {
@@ -220,49 +195,46 @@ fn resolve_project_name(args: &Args) -> Result<ProjectName> {
     }
 }
 
-fn resolve_template_dir(template_base_dir: &TempDir, args: &Args) -> Result<PathBuf> {
-    match &args.subfolder {
-        Some(subfolder) => {
-            let template_base_dir = fs::canonicalize(template_base_dir.path())?;
-            let template_dir =
-                fs::canonicalize(template_base_dir.join(subfolder)).with_context(|| {
-                    format!(
-                        "not able to find subfolder '{}' in repository {}",
-                        subfolder,
-                        args.git
-                            .as_ref()
-                            .map(|v| v.to_owned())
-                            .unwrap_or_else(|| args.path.as_ref().unwrap().display().to_string()),
-                    )
-                })?;
-
-            if !template_dir.starts_with(&template_base_dir) {
-                return Err(anyhow!(
-                    "{} {} {}",
-                    emoji::ERROR,
-                    style("Subfolder Error:").bold().red(),
-                    style("Invalid subfolder. Must be part of the template folder structure.")
-                        .bold()
-                        .red(),
-                ));
-            }
-            if !template_dir.is_dir() {
-                return Err(anyhow!(
-                    "{} {} {}",
-                    emoji::ERROR,
-                    style("Subfolder Error:").bold().red(),
-                    style("The specified subfolder must be a valid folder.")
-                        .bold()
-                        .red(),
-                ));
-            }
+fn resolve_template_dir(template_base_dir: &TempDir, subfolder: Option<&str>) -> Result<PathBuf> {
+    if let Some(subfolder) = subfolder {
+        let template_base_dir = fs::canonicalize(template_base_dir.path())?;
+        let template_dir =
+            fs::canonicalize(template_base_dir.join(subfolder)).with_context(|| {
+                format!(
+                    "not able to find subfolder '{}' in source template",
+                    subfolder
+                )
+            })?;
+
+        // make sure subfolder is not `../../subfolder`
+        if !template_dir.starts_with(&template_base_dir) {
+            return Err(anyhow!(
+                "{} {} {}",
+                emoji::ERROR,
+                style("Subfolder Error:").bold().red(),
+                style("Invalid subfolder. Must be part of the template folder structure.")
+                    .bold()
+                    .red(),
+            ));
+        }
 
-            Ok(auto_locate_template_dir(
-                &template_dir,
-                prompt_for_variable,
-            )?)
+        if !template_dir.is_dir() {
+            return Err(anyhow!(
+                "{} {} {}",
+                emoji::ERROR,
+                style("Subfolder Error:").bold().red(),
+                style("The specified subfolder must be a valid folder.")
+                    .bold()
+                    .red(),
+            ));
         }
-        None => auto_locate_template_dir(template_base_dir.path(), prompt_for_variable),
+
+        Ok(auto_locate_template_dir(
+            &template_dir,
+            prompt_for_variable,
+        )?)
+    } else {
+        auto_locate_template_dir(template_base_dir.path(), prompt_for_variable)
     }
 }
 
@@ -292,42 +264,14 @@ fn auto_locate_template_dir(
     }
 }
 
-fn copy_path_template_into_temp(args: &Args) -> Result<TempDir> {
+fn copy_path_template_into_temp(src_path: &Path) -> Result<TempDir> {
     let path_clone_dir = tempfile::tempdir()?;
-    copy_dir_all(
-        args.path
-            .as_ref()
-            .with_context(|| "Missing option git, path or a favorite")?,
-        path_clone_dir.path(),
-    )?;
-    git::remove_history(path_clone_dir.path(), None)?;
+    copy_dir_all(src_path, path_clone_dir.path())?;
+    git::remove_history(path_clone_dir.path())?;
 
     Ok(path_clone_dir)
 }
 
-fn clone_git_template_into_temp(args: &Args) -> Result<(TempDir, String)> {
-    let git_clone_dir = tempfile::tempdir()?;
-
-    let remote = args
-        .git
-        .clone()
-        .with_context(|| "Missing option git, path or a favorite")?;
-
-    let git_config =
-        GitConfig::new_abbr(remote, args.branch.to_owned(), args.ssh_identity.clone())?;
-
-    let branch = git::create(git_clone_dir.path(), git_config).map_err(|e| {
-        anyhow!(
-            "{} {} {}",
-            emoji::ERROR,
-            style("Git Error:").bold().red(),
-            style(e).bold().red(),
-        )
-    })?;
-
-    Ok((git_clone_dir, branch))
-}
-
 pub(crate) fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> Result<()> {
     fn check_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> Result<()> {
         if !dst.as_ref().exists() {
@@ -532,6 +476,7 @@ fn merge_conditionals(
 
     let mut conditionals = conditionals.unwrap();
     let mut engine = rhai::Engine::new();
+    #[allow(deprecated)]
     engine.on_var({
         let liqobj = liquid_object.clone();
         move |name, _, _| match liqobj.get(name) {
@@ -609,6 +554,33 @@ fn rename_warning(name: &ProjectName) {
     }
 }
 
+fn check_cargo_generate_version(template_config: &Config) -> Result<(), anyhow::Error> {
+    if let Config {
+        template:
+            Some(config::TemplateConfig {
+                cargo_generate_version: Some(requirement),
+                ..
+            }),
+        ..
+    } = template_config
+    {
+        let version = semver::Version::parse(env!("CARGO_PKG_VERSION"))?;
+        if !requirement.matches(&version) {
+            bail!(
+                "{} {} {} {} {}",
+                emoji::ERROR,
+                style("Required cargo-generate version not met. Required:")
+                    .bold()
+                    .red(),
+                style(requirement).yellow(),
+                style(" was:").bold().red(),
+                style(version).yellow(),
+            );
+        }
+    }
+    Ok(())
+}
+
 #[cfg(test)]
 mod tests {
     use crate::{auto_locate_template_dir, project_variables::VarInfo};
diff --git a/src/template_values.rs b/src/template_values.rs
new file mode 100644
index 0000000..bc14d46
--- /dev/null
+++ b/src/template_values.rs
@@ -0,0 +1,2 @@
+/// represents key value storage of defined values
+pub type TemplateValues = HashMap<String, toml::Value>;
diff --git a/src/template_variables/mod.rs b/src/template_variables/mod.rs
index 95b092f..3c2e5f1 100644
--- a/src/template_variables/mod.rs
+++ b/src/template_variables/mod.rs
@@ -17,42 +17,39 @@ pub use crate_type::CrateType;
 pub use os_arch::get_os_arch;
 pub use project_name::ProjectName;
 
-pub fn resolve_template_values(
-    favorite_values: Option<HashMap<String, toml::Value>>,
-    args: &Args,
-) -> Result<HashMap<String, Value>> {
-    let mut values = favorite_values.unwrap_or_default();
-
-    values.extend(
-        std::env::var("CARGO_GENERATE_TEMPLATE_VALUES_FILE")
-            .ok()
-            .map_or(Ok(Default::default()), |path| {
-                read_template_values_file(Path::new(&path))
-            })?,
-    );
+fn load_env_template_values() -> Result<HashMap<String, toml::Value>> {
+    //FIXME: use this variable to be in sync with args
+    let mut values = std::env::var("CARGO_GENERATE_TEMPLATE_VALUES_FILE")
+        .ok()
+        .map_or(Ok(Default::default()), |path| {
+            read_template_values_file(Path::new(&path))
+        })?;
 
     values.extend(std::env::vars().filter_map(|(key, value)| {
         key.strip_prefix("CARGO_GENERATE_VALUE_")
             .map(|key| (key.to_lowercase(), Value::from(value)))
     }));
 
-    values.extend(
-        args.template_values_file
-            .as_ref()
-            .map(Path::new)
-            .map_or(Ok(Default::default()), |path| {
-                read_template_values_file(path)
-            })?,
-    );
+    Ok(values)
+}
 
-    add_cli_defined_values(&mut values, &args.define)?;
+fn load_args_template_values(args: &Args) -> Result<HashMap<String, toml::Value>> {
+    let mut values = args
+        .template_values_file
+        .as_ref()
+        .map(Path::new)
+        .map_or(Ok(Default::default()), |path| {
+            read_template_values_file(path)
+        })?;
 
+    values.extend(read_template_values_from_definitions(&args.define)?);
     Ok(values)
 }
 
-#[derive(Deserialize, Debug, PartialEq)]
-struct TemplateValuesToml {
-    pub(crate) values: HashMap<String, toml::Value>,
+pub fn load_env_and_args_template_values(args: &Args) -> Result<HashMap<String, toml::Value>> {
+    let mut template_variables = load_env_template_values()?;
+    template_variables.extend(load_args_template_values(args)?);
+    Ok(template_variables)
 }
 
 fn read_template_values_file(path: &Path) -> Result<HashMap<String, Value>> {
@@ -69,109 +66,101 @@ fn read_template_values_file(path: &Path) -> Result<HashMap<String, Value>> {
     }
 }
 
-fn add_cli_defined_values<S: AsRef<str> + Display>(
-    template_values: &mut HashMap<String, Value>,
+fn read_template_values_from_definitions<S: AsRef<str> + Display>(
     definitions: &[S],
-) -> Result<()> {
+) -> Result<HashMap<String, toml::Value>> {
+    let mut values = HashMap::with_capacity(definitions.len());
     let key_value_regex = Regex::new(r"^([a-zA-Z]+[a-zA-Z0-9\-_]*)\s*=\s*(.+)$").unwrap();
 
-    definitions
-        .iter()
-        .try_fold(
-            template_values,
-            |template_values, definition| match key_value_regex.captures(definition.as_ref()) {
-                Some(cap) => {
-                    let key = cap.get(1).unwrap().as_str().to_string();
-                    let value = cap.get(2).unwrap().as_str().to_string();
-                    println!("{} => '{}'", key, value);
-                    template_values.insert(key, Value::from(value));
-                    Ok(template_values)
-                }
-                None => Err(anyhow::anyhow!(
-                    "{} {} {}",
-                    emoji::ERROR,
-                    style("Failed to parse value:").bold().red(),
-                    style(definition).bold().red(),
-                )),
-            },
-        )?;
-    Ok(())
+    definitions.iter().try_fold(
+        &mut values,
+        |template_values, definition| match key_value_regex.captures(definition.as_ref()) {
+            Some(cap) => {
+                let key = cap.get(1).unwrap().as_str().to_string();
+                let value = cap.get(2).unwrap().as_str().to_string();
+                println!("{} => '{}'", key, value);
+                template_values.insert(key, Value::from(value));
+                Ok(template_values)
+            }
+            None => Err(anyhow::anyhow!(
+                "{} {} {}",
+                emoji::ERROR,
+                style("Failed to parse value:").bold().red(),
+                style(definition).bold().red(),
+            )),
+        },
+    )?;
+    Ok(values)
+}
+
+#[derive(Deserialize, Debug, PartialEq)]
+struct TemplateValuesToml {
+    pub(crate) values: HashMap<String, toml::Value>,
 }
 
 #[cfg(test)]
 mod test {
-    use super::add_cli_defined_values;
-    use std::collections::HashMap;
+    use super::read_template_values_from_definitions;
 
     #[test]
     fn names_must_start_with_word_char() {
-        let mut template_values = HashMap::new();
         let definitions = vec!["0key=42"];
-        let result = add_cli_defined_values(&mut template_values, &definitions);
+        let result = read_template_values_from_definitions(&definitions);
         assert!(result.is_err());
 
         let definitions = vec!["$key=42"];
-        let result = add_cli_defined_values(&mut template_values, &definitions);
+        let result = read_template_values_from_definitions(&definitions);
         assert!(result.is_err());
 
         let definitions = vec!["-key=42"];
-        let result = add_cli_defined_values(&mut template_values, &definitions);
+        let result = read_template_values_from_definitions(&definitions);
         assert!(result.is_err());
 
         let definitions = vec!["_key=42"];
-        let result = add_cli_defined_values(&mut template_values, &definitions);
+        let result = read_template_values_from_definitions(&definitions);
         assert!(result.is_err());
     }
 
     #[test]
     fn names_may_contain_digits() {
-        let mut template_values = HashMap::new();
         let definitions = vec!["my0123456789key=42"];
-        let result = add_cli_defined_values(&mut template_values, &definitions);
-        assert!(result.is_ok());
+        let result = read_template_values_from_definitions(&definitions).unwrap();
 
-        let val = template_values["my0123456789key"].as_str().unwrap();
+        let val = result["my0123456789key"].as_str().unwrap();
         assert_eq!(val, "42");
     }
 
     #[test]
     fn names_may_contain_dash() {
-        let mut template_values = HashMap::new();
         let definitions = vec!["my-key=42"];
-        let result = add_cli_defined_values(&mut template_values, &definitions);
-        assert!(result.is_ok());
+        let result = read_template_values_from_definitions(&definitions).unwrap();
 
-        let val = template_values["my-key"].as_str().unwrap();
+        let val = result["my-key"].as_str().unwrap();
         assert_eq!(val, "42");
     }
 
     #[test]
     fn names_may_contain_underscore() {
-        let mut template_values = HashMap::new();
         let definitions = vec!["my_key=42"];
-        let result = add_cli_defined_values(&mut template_values, &definitions);
-        assert!(result.is_ok());
+        let result = read_template_values_from_definitions(&definitions).unwrap();
 
-        let val = template_values["my_key"].as_str().unwrap();
+        let val = result["my_key"].as_str().unwrap();
         assert_eq!(val, "42");
     }
 
     #[test]
     fn spaces_are_not_allowed_in_names() {
-        let mut template_values = HashMap::new();
         let definitions = vec!["my key=42"];
-        let result = add_cli_defined_values(&mut template_values, &definitions);
+        let result = read_template_values_from_definitions(&definitions);
         assert!(result.is_err());
     }
 
     #[test]
     fn spaces_around_assignment_is_ok() {
-        let mut template_values = HashMap::new();
         let definitions = vec!["key   =      42"];
-        let result = add_cli_defined_values(&mut template_values, &definitions);
-        assert!(result.is_ok());
+        let result = read_template_values_from_definitions(&definitions).unwrap();
 
-        let val = template_values["key"].as_str().unwrap();
+        let val = result["key"].as_str().unwrap();
         assert_eq!(val, "42");
     }
 }
diff --git a/src/user_parsed_input.rs b/src/user_parsed_input.rs
new file mode 100644
index 0000000..8c5df05
--- /dev/null
+++ b/src/user_parsed_input.rs
@@ -0,0 +1,293 @@
+//! Input from user but after prase
+
+use std::{
+    collections::HashMap,
+    path::{Path, PathBuf},
+};
+
+use console::style;
+use regex::Regex;
+
+use crate::{app_config::AppConfig, warn, Args};
+
+// Contains parsed information from user.
+pub struct UserParsedInput {
+    // from where clone or copy template?
+    template_location: TemplateLocation,
+    // if template_location contains many templates user already specified one
+    subfolder: Option<String>,
+    // all values that user defined through:
+    // 1. envirnoment variables
+    // 2. configuration file
+    // 3. cli arguments --define
+    template_values: HashMap<String, toml::Value>,
+    //TODO:
+    // 1. This structure should be used instead of args
+    // 2. This struct can contains internaly args and app_config to not confuse
+    //    other developer with parsing configuration and args by themself
+}
+
+impl UserParsedInput {
+    fn new(
+        template_location: impl Into<TemplateLocation>,
+        subfolder: Option<String>,
+        default_values: HashMap<String, toml::Value>,
+    ) -> Self {
+        Self {
+            template_location: template_location.into(),
+            subfolder,
+            template_values: default_values,
+        }
+    }
+
+    /// Try create `UserParsedInput` reading in order [`AppConfig`] and [`Args`]
+    ///
+    /// # Panics
+    /// This function assume that Args and AppConfig are verfied eariler and are logicly correct
+    /// For example if both `--git` and `--path` are set this function will panic
+    pub fn try_from_args_and_config(app_config: &AppConfig, args: &Args) -> Self {
+        // --git and --path can not be set at the same time
+        assert!(args.git.is_none() || args.path.is_none());
+        let mut default_values = app_config.values.clone().unwrap_or_default();
+        let ssh_identity = app_config
+            .defaults
+            .as_ref()
+            .and_then(|dcfg| dcfg.ssh_identity.clone())
+            .or_else(|| args.ssh_identity.clone());
+
+        // --git
+        if let Some(git_url) = &args.git {
+            assert!(args.subfolder.is_none());
+
+            let git_user_in = GitUserInput::new(
+                git_url,
+                args.branch.clone(),
+                ssh_identity,
+                args.force_git_init,
+            );
+            return Self::new(git_user_in, args.favorite.clone(), default_values);
+        }
+
+        // --path
+        if let Some(path) = &args.path {
+            assert!(args.subfolder.is_none());
+
+            return Self::new(path, args.favorite.clone(), default_values);
+        }
+
+        // check if favorite is favorite configuration
+        assert!(args.favorite.is_some());
+        let fav_name = args.favorite.as_ref().unwrap();
+
+        if let Some(fav_cfg) = app_config.get_favorite_cfg(fav_name) {
+            assert!(fav_cfg.git.is_none() || fav_cfg.path.is_none());
+
+            let temp_location = fav_cfg.git.as_ref().map_or_else(
+                || fav_cfg.path.as_ref().map(TemplateLocation::from).unwrap(),
+                |git_url| {
+                    let branch = args.branch.clone().or_else(|| fav_cfg.branch.clone());
+                    let git_user_input =
+                        GitUserInput::new(git_url, branch, ssh_identity, args.force_git_init);
+
+                    TemplateLocation::from(git_user_input)
+                },
+            );
+
+            if let Some(fav_default_values) = &fav_cfg.values {
+                default_values.extend(fav_default_values.clone());
+            }
+
+            return Self::new(
+                temp_location,
+                args.subfolder.clone().or_else(|| fav_cfg.subfolder.clone()),
+                default_values,
+            );
+        }
+
+        // there is no specified favorite in configuration
+        // this part try to guess what user wanted in order:
+
+        // 1. look for abbrevations like gh:, gl: etc.
+        let temp_location = abbreviated_git_url_to_full_remote(fav_name).map(|git_url| {
+            let git_user_in = GitUserInput::with_git_url_and_args(&git_url, args);
+            TemplateLocation::from(git_user_in)
+        });
+
+        // 2. check if template directory exist
+        let temp_location =
+            temp_location.or_else(|| local_path(fav_name).map(TemplateLocation::from));
+
+        // 3. check if the input is in form org/repo<> (map to github)
+        let temp_location = temp_location.or_else(|| {
+            abbreviated_github(fav_name).map(|git_url| {
+                let git_user_in = GitUserInput::with_git_url_and_args(&git_url, args);
+                TemplateLocation::from(git_user_in)
+            })
+        });
+
+        // 4. assume user wanted use --git
+        let temp_location = temp_location.unwrap_or_else(|| {
+            let git_user_in = GitUserInput::new(
+                fav_name,
+                args.branch.clone(),
+                ssh_identity,
+                args.force_git_init,
+            );
+            TemplateLocation::from(git_user_in)
+        });
+
+        // Print information what happend to user
+        let location_msg = match &temp_location {
+            TemplateLocation::Git(git_user_input) => {
+                format!("git repository: {}", style(git_user_input.url()).bold())
+            }
+            TemplateLocation::Path(path) => {
+                format!("local path: {}", style(path.display()).bold())
+            }
+        };
+        warn!(
+            "Favorite `{}` not found in config, using it as a {}",
+            style(&fav_name).bold(),
+            location_msg
+        );
+
+        Self::new(temp_location, args.subfolder.clone(), default_values)
+    }
+
+    pub const fn location(&self) -> &TemplateLocation {
+        &self.template_location
+    }
+
+    pub fn subfolder(&self) -> Option<&str> {
+        self.subfolder.as_deref()
+    }
+
+    pub const fn template_values(&self) -> &HashMap<String, toml::Value> {
+        &self.template_values
+    }
+
+    pub fn template_values_mut(&mut self) -> &mut HashMap<String, toml::Value> {
+        &mut self.template_values
+    }
+}
+
+// favorite can be in form with abbrevation what means that input is git repositoru
+pub fn abbreviated_git_url_to_full_remote(git: impl AsRef<str>) -> Option<String> {
+    let git = git.as_ref();
+    if git.len() >= 3 {
+        match &git[..3] {
+            "gl:" => Some(format!("https://gitlab.com/{}.git", &git[3..])),
+            "bb:" => Some(format!("https://bitbucket.org/{}.git", &git[3..])),
+            "gh:" => Some(format!("https://github.com/{}.git", &git[3..])),
+            _ => None,
+        }
+    } else {
+        None
+    }
+}
+
+// favorite can be in form of org/repo what should be parsed as github.com
+pub fn abbreviated_github(fav: &str) -> Option<String> {
+    let org_repo_regex = Regex::new(r"^[a-zA-Z0-9_]+/[a-zA-Z0-9_%-]+$").unwrap();
+    org_repo_regex
+        .is_match(fav)
+        .then(|| format!("https://github.com/{fav}.git"))
+}
+
+pub fn local_path(fav: &str) -> Option<PathBuf> {
+    let path = PathBuf::from(fav);
+    (path.exists() && path.is_dir()).then(|| path)
+}
+
+// Template should be cloned with git
+pub struct GitUserInput {
+    url: String,
+    branch: Option<String>,
+    identity: Option<PathBuf>,
+    _force_init: bool,
+}
+
+impl GitUserInput {
+    fn new(url: &str, branch: Option<String>, identity: Option<PathBuf>, force_init: bool) -> Self {
+        Self {
+            url: url.to_owned(),
+            branch,
+            identity,
+            _force_init: force_init,
+        }
+    }
+
+    // when git was used as abbreviation but other flags still could be passed
+    fn with_git_url_and_args(url: &str, args: &Args) -> Self {
+        Self::new(
+            url,
+            args.branch.clone(),
+            args.ssh_identity.clone(),
+            args.force_git_init,
+        )
+    }
+
+    pub fn url(&self) -> &str {
+        self.url.as_ref()
+    }
+
+    pub fn branch(&self) -> Option<&str> {
+        self.branch.as_deref()
+    }
+
+    pub fn identity(&self) -> Option<&Path> {
+        self.identity.as_deref()
+    }
+}
+
+// Distinguish between plain copy and clone
+pub enum TemplateLocation {
+    Git(GitUserInput),
+    Path(PathBuf),
+}
+
+impl From<GitUserInput> for TemplateLocation {
+    fn from(source: GitUserInput) -> Self {
+        Self::Git(source)
+    }
+}
+
+impl<T> From<T> for TemplateLocation
+where
+    T: AsRef<Path>,
+{
+    fn from(source: T) -> Self {
+        Self::Path(PathBuf::from(source.as_ref()))
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn should_support_bb_gl_gh_abbreviations() {
+        assert_eq!(
+            &abbreviated_git_url_to_full_remote("gh:foo/bar").unwrap(),
+            "https://github.com/foo/bar.git"
+        );
+        assert_eq!(
+            &abbreviated_git_url_to_full_remote("bb:foo/bar").unwrap(),
+            "https://bitbucket.org/foo/bar.git"
+        );
+        assert_eq!(
+            &abbreviated_git_url_to_full_remote("gl:foo/bar").unwrap(),
+            "https://gitlab.com/foo/bar.git"
+        );
+        assert!(&abbreviated_git_url_to_full_remote("foo/bar").is_none());
+    }
+
+    #[test]
+    fn should_appreviation_org_repo_to_github() {
+        assert_eq!(
+            &abbreviated_github("org/repo").unwrap(),
+            "https://github.com/org/repo.git"
+        );
+        assert!(&abbreviated_github("path/to/a/sth").is_none());
+    }
+}


Test patch:
diff --git a/tests/integration/basics.rs b/tests/integration/basics.rs
index 89c2bf7..bffe035 100644
--- a/tests/integration/basics.rs
+++ b/tests/integration/basics.rs
@@ -33,9 +33,14 @@ version = "0.1.0"
         .current_dir(&dir.path())
         .assert()
         .success()
-        .stdout(predicates::str::contains("Done!").from_utf8().and(
-            predicates::str::contains("Template does not seem to be a git repository").from_utf8(),
-        ));
+        .stdout(
+            predicates::str::contains("Done!")
+                .and(predicates::str::contains(format!(
+                    "Favorite `{}` not found in config, using it as a local path",
+                    template.path().display()
+                )))
+                .from_utf8(),
+        );
 
     let repo = git2::Repository::open(&dir.path().join("foobar-project")).unwrap();
     let references = repo.references().unwrap().count();
@@ -1382,86 +1387,7 @@ fn error_message_for_invalid_repo_or_user() {
         .assert()
         .failure()
         .stderr(
-            predicates::str::contains(
-                r#"Git Error: Please check if the Git user / repository exists."#,
-            )
-            .from_utf8(),
+            predicates::str::contains(r#"Error: Please check if the Git user / repository exists"#)
+                .from_utf8(),
         );
 }
-
-#[cfg(test)]
-#[cfg(unix)]
-mod ssh_remote {
-    use super::*;
-
-    #[test]
-    #[ignore]
-    // for now only locally working
-    fn it_should_support_a_public_repo() {
-        let dir = tmp_dir().build();
-
-        binary()
-            .arg("generate")
-            .arg("--git")
-            .arg("git@github.com:ashleygwilliams/wasm-pack-template.git")
-            .arg("--name")
-            .arg("foobar-project")
-            .current_dir(&dir.path())
-            .assert()
-            .success()
-            .stdout(predicates::str::contains("Done!").from_utf8());
-
-        let cargo_toml = dir.read("foobar-project/Cargo.toml");
-        assert!(cargo_toml.contains("foobar-project"));
-    }
-
-    #[test]
-    #[ignore]
-    // for now only locally working
-    fn it_should_support_a_private_repo() {
-        let dir = tmp_dir().build();
-
-        binary()
-            .arg("generate")
-            .arg("--git")
-            .arg("git@github.com:cargo-generate/wasm-pack-template.git")
-            .arg("--name")
-            .arg("foobar-project")
-            .current_dir(&dir.path())
-            .assert()
-            .success()
-            .stdout(predicates::str::contains("Done!").from_utf8());
-
-        let cargo_toml = dir.read("foobar-project/Cargo.toml");
-        assert!(cargo_toml.contains("foobar-project"));
-    }
-
-    #[test]
-    #[ignore]
-    // for now only locally working
-    fn it_should_support_a_custom_ssh_key() {
-        let dir = tmp_dir().build();
-
-        binary()
-            .arg("generate")
-            .arg("-i")
-            .arg("~/workspaces/rust/cargo-generate-org/.env/id_rsa_ci")
-            .arg("--git")
-            .arg("git@github.com:cargo-generate/wasm-pack-template.git")
-            .arg("--name")
-            .arg("foobar-project")
-            .current_dir(&dir.path())
-            .assert()
-            .success()
-            .stdout(
-                predicates::str::contains("Using private key:")
-                    .and(predicates::str::contains(
-                        "cargo-generate-org/.env/id_rsa_ci",
-                    ))
-                    .from_utf8(),
-            );
-
-        let cargo_toml = dir.read("foobar-project/Cargo.toml");
-        assert!(cargo_toml.contains("foobar-project"));
-    }
-}
diff --git a/tests/integration/config_file/defaults.rs b/tests/integration/config_file/defaults.rs
index a5f200b..282d6c8 100644
--- a/tests/integration/config_file/defaults.rs
+++ b/tests/integration/config_file/defaults.rs
@@ -9,7 +9,7 @@ use indoc::indoc;
 
 #[test]
 fn it_uses_ssh_identity_from_defaults_config() {
-    let working_dir = tmp_dir().file("fake_ssh", "fake stuff").build();
+    let working_dir = tmp_dir().file("fake_ssh_identity", "fake stuff").build();
     let fake_ssh_id = working_dir.path().join("fake_ssh_identity");
     let config_dir = tmp_dir()
         .file(
@@ -22,7 +22,7 @@ fn it_uses_ssh_identity_from_defaults_config() {
                 id = fake_ssh_id.display().to_string().escape_default()
             ),
         )
-        .file("fake_ssh_identity", "random foo")
+        .file("fake_ssh", "random foo") // FIXME: what is for?
         .build();
     let some_template = create_template("some-template");
 
@@ -39,7 +39,7 @@ fn it_uses_ssh_identity_from_defaults_config() {
         .success()
         .stdout(
             predicates::str::contains("Done!").from_utf8().and(
-                predicates::str::contains("Using ssh-identity from application config: ")
+                predicates::str::contains("Using private key: ")
                     .from_utf8()
                     .and(predicates::str::contains("fake_ssh_identity").from_utf8()),
             ),
diff --git a/tests/integration/config_file/favorites.rs b/tests/integration/config_file/favorites.rs
index 015a5b5..d3c8e8e 100644
--- a/tests/integration/config_file/favorites.rs
+++ b/tests/integration/config_file/favorites.rs
@@ -170,7 +170,10 @@ fn favorites_default_to_git_if_not_defined() {
         .current_dir(&working_dir.path())
         .assert()
         .failure()
-        .stderr(predicates::str::contains(r#"status code: 404"#).from_utf8());
+        .stderr(
+            predicates::str::contains(r#"Please check if the Git user / repository exists"#)
+                .from_utf8(),
+        );
 }
 
 #[test]
diff --git a/tests/integration/main.rs b/tests/integration/main.rs
index a90d112..7f5cb86 100644
--- a/tests/integration/main.rs
+++ b/tests/integration/main.rs
@@ -7,3 +7,4 @@ mod filenames;
 mod git;
 mod hooks;
 mod library;
+mod online;
diff --git a/tests/integration/online.rs b/tests/integration/online.rs
new file mode 100644
index 0000000..856c078
--- /dev/null
+++ b/tests/integration/online.rs
@@ -0,0 +1,155 @@
+//! Thest that use real connection and working third part service.
+//!
+//! The test are ignored by default
+//! You can run them with:
+//! ```
+//! cargo test -- --include-ignored
+//! ````
+
+use predicates::prelude::*;
+
+use crate::helpers::project::binary;
+use crate::helpers::project_builder::tmp_dir;
+
+use assert_cmd::prelude::*;
+
+#[test]
+#[ignore]
+fn git_flag_can_be_skipped_and_cargo_will_use_correct_implementation() {
+    // with --git
+    let dir = tmp_dir().build();
+    binary()
+        .arg("generate")
+        .arg("--name")
+        .arg("my-proj")
+        .arg("--init")
+        .arg("git://github.com/ashleygwilliams/wasm-pack-template")
+        .current_dir(&dir.path())
+        .assert()
+        .success()
+        .stdout(predicates::str::contains("Done!").from_utf8());
+}
+
+#[test]
+#[ignore]
+fn plain_git_repo_works() {
+    let possible_urls = vec![
+        "git://github.com/ashleygwilliams/wasm-pack-template",
+        "git://github.com/ashleygwilliams/wasm-pack-template.git",
+        "https://github.com/ashleygwilliams/wasm-pack-template.git",
+        "https://github.com/ashleygwilliams/wasm-pack-template",
+        "http://github.com/ashleygwilliams/wasm-pack-template.git",
+        "http://github.com/ashleygwilliams/wasm-pack-template",
+    ];
+
+    // with --git
+    for remote in possible_urls {
+        let dir = tmp_dir().build();
+        binary()
+            .arg("generate")
+            .arg("--git")
+            .arg(remote)
+            .arg("--name")
+            .arg("my-proj")
+            .arg("--init")
+            .current_dir(&dir.path())
+            .assert()
+            .success()
+            .stdout(predicates::str::contains("Done!").from_utf8());
+    }
+}
+
+#[test]
+#[ignore]
+fn abbreviation_for_github_works() {
+    let dir = tmp_dir().build();
+    binary()
+        .arg("generate")
+        .arg("--name")
+        .arg("my-proj")
+        .arg("ashleygwilliams/wasm-pack-template")
+        .current_dir(&dir.path())
+        .assert()
+        .success()
+        .stdout(predicates::str::contains("Done!").and(
+            predicates::str::contains(
+                "Favorite `ashleygwilliams/wasm-pack-template` not found in config, using it as a git repository: https://github.com/ashleygwilliams/wasm-pack-template.git"
+            )).from_utf8());
+}
+
+#[cfg(test)]
+#[cfg(unix)]
+mod ssh_remote {
+    use super::*;
+
+    #[test]
+    #[ignore]
+    // for now only locally working
+    fn it_should_support_a_public_repo() {
+        let dir = tmp_dir().build();
+
+        binary()
+            .arg("generate")
+            .arg("--git")
+            .arg("git@github.com:ashleygwilliams/wasm-pack-template.git")
+            .arg("--name")
+            .arg("foobar-project")
+            .current_dir(&dir.path())
+            .assert()
+            .success()
+            .stdout(predicates::str::contains("Done!").from_utf8());
+
+        let cargo_toml = dir.read("foobar-project/Cargo.toml");
+        assert!(cargo_toml.contains("foobar-project"));
+    }
+
+    #[test]
+    #[ignore]
+    // for now only locally working
+    fn it_should_support_a_private_repo() {
+        let dir = tmp_dir().build();
+
+        binary()
+            .arg("generate")
+            .arg("--git")
+            .arg("git@github.com:cargo-generate/wasm-pack-template.git")
+            .arg("--name")
+            .arg("foobar-project")
+            .current_dir(&dir.path())
+            .assert()
+            .success()
+            .stdout(predicates::str::contains("Done!").from_utf8());
+
+        let cargo_toml = dir.read("foobar-project/Cargo.toml");
+        assert!(cargo_toml.contains("foobar-project"));
+    }
+
+    #[test]
+    #[ignore]
+    // for now only locally working
+    fn it_should_support_a_custom_ssh_key() {
+        let dir = tmp_dir().build();
+
+        binary()
+            .arg("generate")
+            .arg("-i")
+            .arg("~/workspaces/rust/cargo-generate-org/.env/id_rsa_ci")
+            .arg("--git")
+            .arg("git@github.com:cargo-generate/wasm-pack-template.git")
+            .arg("--name")
+            .arg("foobar-project")
+            .current_dir(&dir.path())
+            .assert()
+            .success()
+            .stdout(
+                predicates::str::contains("Using private key:")
+                    .and(predicates::str::contains(
+                        "cargo-generate-org/.env/id_rsa_ci",
+                    ))
+                    .from_utf8(),
+            );
+
+        let cargo_toml = dir.read("foobar-project/Cargo.toml");
+        assert!(cargo_toml.contains("foobar-project"));
+    }
+}