├── tests ├── test_repo │ ├── a.txt │ ├── c.txt │ ├── Test2 │ │ ├── a2.txt │ │ └── Test21 │ │ │ └── a21.txt │ ├── b.txt │ ├── root.txt │ ├── dotgit │ │ ├── HEAD │ │ ├── ORIG_HEAD │ │ ├── refs │ │ │ └── heads │ │ │ │ ├── master │ │ │ │ ├── modify_test1 │ │ │ │ └── old_working │ │ ├── COMMIT_EDITMSG │ │ ├── description │ │ ├── index │ │ ├── objects │ │ │ ├── 14 │ │ │ │ └── b24c2aaf5914483753d94dfad3e2a7d058b489 │ │ │ ├── 17 │ │ │ │ └── 9df84dd18230231286f0f99992f9bc33ba1203 │ │ │ ├── 19 │ │ │ │ ├── 6d57c3cc77419f0e7bc7b3406869099e6fe58a │ │ │ │ └── 71f5bd758c338db3c6ffe45b33d92818e2acd3 │ │ │ ├── 21 │ │ │ │ └── e0b01aa86508dfa231b4f6e0b723694aadf745 │ │ │ ├── 26 │ │ │ │ └── 022942e540014755e42e47b651e092771018e4 │ │ │ ├── 29 │ │ │ │ └── 0863b4267807d87bbbe8007138b50cd4030e5f │ │ │ ├── 31 │ │ │ │ └── 58f63ca79c1ec871b23d100f033fc9a33f1f28 │ │ │ ├── 34 │ │ │ │ └── 10062ba67c5ed59b854387a8bc0ec012479368 │ │ │ ├── 38 │ │ │ │ ├── 5ba04ed583c36c1efe2f60a7ac18f26020a50d │ │ │ │ └── e1b9eec0c60bc4a72459e29a2ac8de3ddea2f6 │ │ │ ├── 41 │ │ │ │ └── 8c908a629c7b9ccdf3d00a08f6a6f493d647b3 │ │ │ ├── 42 │ │ │ │ ├── 2bd029d96d126d163649706cfbbd430d70d0d4 │ │ │ │ └── 6d1ca78737216766852029b5b7a57a2deea391 │ │ │ ├── 43 │ │ │ │ └── 320b7c8b0e731588bae20bcf1043b5d4b61c2a │ │ │ ├── 47 │ │ │ │ └── 7950bef5024dd42c41ef3ad8fc79b88aa3a6eb │ │ │ ├── 48 │ │ │ │ ├── 0d105f04a8e3b34245941ed0953a3016044240 │ │ │ │ └── 5f1defe8d7fb3e0e4d5877ba0decd88946562a │ │ │ ├── 50 │ │ │ │ └── 6ff9b38c403a70106084c764913977d0774db0 │ │ │ ├── 56 │ │ │ │ └── dd8e44f5bf4881725e168fa80096b75b976af1 │ │ │ ├── 63 │ │ │ │ └── d8dbd40c23542e740659a7168a0ce3138ea748 │ │ │ ├── 69 │ │ │ │ ├── 0d05a98e20094354173f6f4254eb2786c0df70 │ │ │ │ └── 3e5c70c8e92072a0acfa150613b7aa93f32798 │ │ │ ├── 74 │ │ │ │ └── 9a42d1e74b3673de917fc06e7f73a3431492a5 │ │ │ ├── 76 │ │ │ │ └── 7af1f698de8e0e66b6e0fdfe2f47b25cd96b7c │ │ │ ├── 92 │ │ │ │ └── 90b36a3562b837f5b282d1b1ad2888031cc1f7 │ │ │ ├── 94 │ │ │ │ └── d85da1bbd0308ccf01c6f2a34e0bc54eff3f1e │ │ │ ├── 97 │ │ │ │ └── 00c2e19d868f2f9dc01d27b16fce956a2ce2f1 │ │ │ ├── 04 │ │ │ │ └── 78844cc504377ba1a8c63a31f9f122a4404121 │ │ │ ├── 09 │ │ │ │ └── 80048071f43857df0364170fdbc39f1f395ec4 │ │ │ ├── 1a │ │ │ │ └── 602d9bd07ce5272ddaa64e21da12dbca2b8c9f │ │ │ ├── 1f │ │ │ │ └── 33bf72bbf7add5173bf1391e5ce5daf8b135f3 │ │ │ ├── 2b │ │ │ │ └── 0774a9f5de3a08dbd37b7d32575f7e66df67a7 │ │ │ ├── 2c │ │ │ │ └── f48b308ea8072014a4669b80384de6f30321fd │ │ │ ├── 2d │ │ │ │ └── e0c5a85df29340d376f572fc2d3c642f10ed82 │ │ │ ├── 2e │ │ │ │ └── 65efe2a145dda7ee51d1741299f848e5bf752e │ │ │ ├── 2f │ │ │ │ └── 5a2b09524c495aeaa4dff717b933b429a8934a │ │ │ ├── 3a │ │ │ │ └── ea0bdc3f032029933fecb45d9bfb444ccd89d1 │ │ │ ├── 3e │ │ │ │ └── 0eb98d9ec081a2c4227b3cd81202dd6a9f54c0 │ │ │ ├── 4d │ │ │ │ └── 05617cdf5435dd1b8646b85e9cccfb2a951c64 │ │ │ ├── 4e │ │ │ │ └── 2fd0b481a785eb99cab80ec1c582e1caf6cb44 │ │ │ ├── 6c │ │ │ │ └── 40a5a37965826f782119b342983572cc9944d5 │ │ │ ├── 7d │ │ │ │ ├── 1e7924b8f67eb30c415fb7d31e54e1a02d01dc │ │ │ │ └── 29c2b64271bb04a657fd8d25c50ec132fa7439 │ │ │ ├── 7e │ │ │ │ └── 2f966bc3b65b0c0df08c1c4399b727110f6a92 │ │ │ ├── 8d │ │ │ │ └── b0fc47fe826cf31d60040d706710ad64a8c929 │ │ │ ├── 9a │ │ │ │ └── 088b3b22550bfff0321f75b86ae7b00024946a │ │ │ ├── a6 │ │ │ │ └── b263066682e967cd20d3ddf2b25ae22b9311c8 │ │ │ ├── a8 │ │ │ │ └── 29e89b8fa98936127ae2462a82b003970b27b8 │ │ │ ├── ac │ │ │ │ └── fce16d5980ced47c36ec7a96e8b1cd3642d07e │ │ │ ├── b1 │ │ │ │ └── 86bf4588de98e03117f63306ea9f411c3ef7d2 │ │ │ ├── b7 │ │ │ │ └── 768615afdc728b456890d99c25d49c5d7294f4 │ │ │ ├── bc │ │ │ │ ├── 132db6396bcbccfec95025501a3db9c18e23c4 │ │ │ │ └── 6428df3ae260096489d7f6e3f2ac7acfe12691 │ │ │ ├── bf │ │ │ │ └── d68eeadd047c29fe08c6d4e571311b11c5a14a │ │ │ ├── c3 │ │ │ │ ├── ceb255dd65f47518754c0c59c80e14e78f9a8c │ │ │ │ └── fda6360e828ecc1041399d1b0853adfc870a86 │ │ │ ├── c4 │ │ │ │ ├── 6443f05a5e209b3fb9294580aaea11aabae78f │ │ │ │ └── a04869acb07d3b4f6e7f0d1de93f9ecb6d3a66 │ │ │ ├── cf │ │ │ │ └── 5a034c699378abfa883adeb9dbe3cfb1a6038f │ │ │ ├── d2 │ │ │ │ └── 10edd735ff26542ebfe5f3a3739f5a04ffc82e │ │ │ ├── d6 │ │ │ │ └── 06037cb232bfda7788a8322492312d55b2ae9d │ │ │ ├── da │ │ │ │ └── 106659a28c6a982fb5f3f50caa66588511368c │ │ │ ├── dc │ │ │ │ └── ab93401a4c531ca43ff6ebc07429b752887737 │ │ │ ├── dd │ │ │ │ └── ef224c6a52e2cfb5675574788b8d0f0c5fc05a │ │ │ ├── e1 │ │ │ │ └── 3a631a2b34cc0d0f568fadf3d8da17ba1cbcbe │ │ │ ├── e5 │ │ │ │ ├── 87d5cc0e78bf258266ecaf7427ac9e15885e8c │ │ │ │ └── c02bb4665eec1be05e842bef17b926ccdccae1 │ │ │ ├── e8 │ │ │ │ └── b4bb3031310ddaba57dfdb3f3aa32cf718795b │ │ │ ├── ea │ │ │ │ └── ea168a3ba5c7ca91d60bc243789773f52fda6d │ │ │ ├── eb │ │ │ │ └── e1ee79286137b4195afe189a5773ab23dcfb4f │ │ │ └── f5 │ │ │ │ └── 82b54731702927a3cbadfc048573e5c3fa0dea │ │ ├── config.backup │ │ ├── config │ │ ├── hooks │ │ │ ├── post-update.sample │ │ │ ├── pre-applypatch.sample │ │ │ ├── applypatch-msg.sample │ │ │ ├── commit-msg.sample │ │ │ ├── prepare-commit-msg.sample │ │ │ ├── pre-push.sample │ │ │ ├── pre-commit.sample │ │ │ ├── update.sample │ │ │ └── pre-rebase.sample │ │ ├── info │ │ │ └── exclude │ │ └── logs │ │ │ ├── refs │ │ │ └── heads │ │ │ │ ├── old_working │ │ │ │ ├── modify_test1 │ │ │ │ └── master │ │ │ └── HEAD │ ├── Test1 │ │ ├── a1.txt │ │ ├── b1.txt │ │ └── c1.txt │ └── Binary │ │ └── test.bin ├── KeepPatternFile1.txt ├── RemovePatternFile1.txt ├── GitRocketFilter.Tests.csproj ├── TestInvalidOptions.cs ├── TestTreeFilteringScripts.cs ├── TestCommitFiltering.cs ├── TestRepoBase.cs └── TestTreeFiltering.cs ├── img └── rocket.png ├── .gitmodules ├── changelog.md ├── License.txt ├── src ├── RocketException.cs ├── GitRocketFilter.csproj ├── RocketScriptBase.cs ├── SimpleCommit.cs ├── SimpleEntry.cs ├── Program.cs └── RocketFilterApp.cs ├── GitRocketFilter.sln ├── .gitignore └── readme.md /tests/test_repo/a.txt: -------------------------------------------------------------------------------- 1 | a -------------------------------------------------------------------------------- /tests/test_repo/c.txt: -------------------------------------------------------------------------------- 1 | c -------------------------------------------------------------------------------- /tests/test_repo/Test2/a2.txt: -------------------------------------------------------------------------------- 1 | test2 -------------------------------------------------------------------------------- /tests/test_repo/b.txt: -------------------------------------------------------------------------------- 1 | b pending -------------------------------------------------------------------------------- /tests/test_repo/root.txt: -------------------------------------------------------------------------------- 1 | akordak root -------------------------------------------------------------------------------- /tests/test_repo/Test2/Test21/a21.txt: -------------------------------------------------------------------------------- 1 | test21 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/HEAD: -------------------------------------------------------------------------------- 1 | ref: refs/heads/master 2 | -------------------------------------------------------------------------------- /tests/test_repo/Test1/a1.txt: -------------------------------------------------------------------------------- 1 | akordak test modify1 modify2 2 | test3 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/ORIG_HEAD: -------------------------------------------------------------------------------- 1 | ebe1ee79286137b4195afe189a5773ab23dcfb4f 2 | -------------------------------------------------------------------------------- /tests/test_repo/Test1/b1.txt: -------------------------------------------------------------------------------- 1 | empty b1 modify line1 2 | empty b1 newline 3 | test3 -------------------------------------------------------------------------------- /tests/test_repo/Test1/c1.txt: -------------------------------------------------------------------------------- 1 | akordak test2 modify line 2 2 | new test2 3 | test3 -------------------------------------------------------------------------------- /img/rocket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/img/rocket.png -------------------------------------------------------------------------------- /tests/test_repo/dotgit/refs/heads/master: -------------------------------------------------------------------------------- 1 | 690d05a98e20094354173f6f4254eb2786c0df70 2 | -------------------------------------------------------------------------------- /tests/test_repo/dotgit/COMMIT_EDITMSG: -------------------------------------------------------------------------------- 1 | Last commit 2 | 3 | Mutli-line comment 4 | Test 5 | -------------------------------------------------------------------------------- /tests/test_repo/dotgit/refs/heads/modify_test1: -------------------------------------------------------------------------------- 1 | da106659a28c6a982fb5f3f50caa66588511368c 2 | -------------------------------------------------------------------------------- /tests/test_repo/dotgit/refs/heads/old_working: -------------------------------------------------------------------------------- 1 | 21e0b01aa86508dfa231b4f6e0b723694aadf745 2 | -------------------------------------------------------------------------------- /tests/test_repo/dotgit/description: -------------------------------------------------------------------------------- 1 | Unnamed repository; edit this file 'description' to name the repository. 2 | -------------------------------------------------------------------------------- /tests/test_repo/dotgit/index: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/index -------------------------------------------------------------------------------- /tests/test_repo/Binary/test.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/Binary/test.bin -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ext/libgit2sharp"] 2 | path = ext/libgit2sharp 3 | url = https://github.com/xoofx/libgit2sharp.git 4 | branch = git-rocket-filter 5 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.0.1 4 | - Remove Console.WriteLine "Used assembly" in non verbose log 5 | 6 | ## 1.0.0 7 | - Add git-rocket-filter as a global dotnet tool 8 | -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/04/78844cc504377ba1a8c63a31f9f122a4404121: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/04/78844cc504377ba1a8c63a31f9f122a4404121 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/09/80048071f43857df0364170fdbc39f1f395ec4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/09/80048071f43857df0364170fdbc39f1f395ec4 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/14/b24c2aaf5914483753d94dfad3e2a7d058b489: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/14/b24c2aaf5914483753d94dfad3e2a7d058b489 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/17/9df84dd18230231286f0f99992f9bc33ba1203: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/17/9df84dd18230231286f0f99992f9bc33ba1203 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/19/6d57c3cc77419f0e7bc7b3406869099e6fe58a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/19/6d57c3cc77419f0e7bc7b3406869099e6fe58a -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/19/71f5bd758c338db3c6ffe45b33d92818e2acd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/19/71f5bd758c338db3c6ffe45b33d92818e2acd3 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/1a/602d9bd07ce5272ddaa64e21da12dbca2b8c9f: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/1a/602d9bd07ce5272ddaa64e21da12dbca2b8c9f -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/1f/33bf72bbf7add5173bf1391e5ce5daf8b135f3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/1f/33bf72bbf7add5173bf1391e5ce5daf8b135f3 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/21/e0b01aa86508dfa231b4f6e0b723694aadf745: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/21/e0b01aa86508dfa231b4f6e0b723694aadf745 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/26/022942e540014755e42e47b651e092771018e4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/26/022942e540014755e42e47b651e092771018e4 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/29/0863b4267807d87bbbe8007138b50cd4030e5f: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/29/0863b4267807d87bbbe8007138b50cd4030e5f -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/2b/0774a9f5de3a08dbd37b7d32575f7e66df67a7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/2b/0774a9f5de3a08dbd37b7d32575f7e66df67a7 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/2c/f48b308ea8072014a4669b80384de6f30321fd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/2c/f48b308ea8072014a4669b80384de6f30321fd -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/2d/e0c5a85df29340d376f572fc2d3c642f10ed82: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/2d/e0c5a85df29340d376f572fc2d3c642f10ed82 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/2e/65efe2a145dda7ee51d1741299f848e5bf752e: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/2e/65efe2a145dda7ee51d1741299f848e5bf752e -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/2f/5a2b09524c495aeaa4dff717b933b429a8934a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/2f/5a2b09524c495aeaa4dff717b933b429a8934a -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/31/58f63ca79c1ec871b23d100f033fc9a33f1f28: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/31/58f63ca79c1ec871b23d100f033fc9a33f1f28 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/34/10062ba67c5ed59b854387a8bc0ec012479368: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/34/10062ba67c5ed59b854387a8bc0ec012479368 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/38/5ba04ed583c36c1efe2f60a7ac18f26020a50d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/38/5ba04ed583c36c1efe2f60a7ac18f26020a50d -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/38/e1b9eec0c60bc4a72459e29a2ac8de3ddea2f6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/38/e1b9eec0c60bc4a72459e29a2ac8de3ddea2f6 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/3a/ea0bdc3f032029933fecb45d9bfb444ccd89d1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/3a/ea0bdc3f032029933fecb45d9bfb444ccd89d1 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/3e/0eb98d9ec081a2c4227b3cd81202dd6a9f54c0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/3e/0eb98d9ec081a2c4227b3cd81202dd6a9f54c0 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/41/8c908a629c7b9ccdf3d00a08f6a6f493d647b3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/41/8c908a629c7b9ccdf3d00a08f6a6f493d647b3 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/42/2bd029d96d126d163649706cfbbd430d70d0d4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/42/2bd029d96d126d163649706cfbbd430d70d0d4 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/42/6d1ca78737216766852029b5b7a57a2deea391: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/42/6d1ca78737216766852029b5b7a57a2deea391 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/43/320b7c8b0e731588bae20bcf1043b5d4b61c2a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/43/320b7c8b0e731588bae20bcf1043b5d4b61c2a -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/47/7950bef5024dd42c41ef3ad8fc79b88aa3a6eb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/47/7950bef5024dd42c41ef3ad8fc79b88aa3a6eb -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/48/0d105f04a8e3b34245941ed0953a3016044240: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/48/0d105f04a8e3b34245941ed0953a3016044240 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/48/5f1defe8d7fb3e0e4d5877ba0decd88946562a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/48/5f1defe8d7fb3e0e4d5877ba0decd88946562a -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/4d/05617cdf5435dd1b8646b85e9cccfb2a951c64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/4d/05617cdf5435dd1b8646b85e9cccfb2a951c64 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/4e/2fd0b481a785eb99cab80ec1c582e1caf6cb44: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/4e/2fd0b481a785eb99cab80ec1c582e1caf6cb44 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/50/6ff9b38c403a70106084c764913977d0774db0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/50/6ff9b38c403a70106084c764913977d0774db0 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/56/dd8e44f5bf4881725e168fa80096b75b976af1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/56/dd8e44f5bf4881725e168fa80096b75b976af1 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/63/d8dbd40c23542e740659a7168a0ce3138ea748: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/63/d8dbd40c23542e740659a7168a0ce3138ea748 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/69/0d05a98e20094354173f6f4254eb2786c0df70: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/69/0d05a98e20094354173f6f4254eb2786c0df70 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/69/3e5c70c8e92072a0acfa150613b7aa93f32798: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/69/3e5c70c8e92072a0acfa150613b7aa93f32798 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/6c/40a5a37965826f782119b342983572cc9944d5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/6c/40a5a37965826f782119b342983572cc9944d5 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/74/9a42d1e74b3673de917fc06e7f73a3431492a5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/74/9a42d1e74b3673de917fc06e7f73a3431492a5 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/76/7af1f698de8e0e66b6e0fdfe2f47b25cd96b7c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/76/7af1f698de8e0e66b6e0fdfe2f47b25cd96b7c -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/7d/1e7924b8f67eb30c415fb7d31e54e1a02d01dc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/7d/1e7924b8f67eb30c415fb7d31e54e1a02d01dc -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/7d/29c2b64271bb04a657fd8d25c50ec132fa7439: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/7d/29c2b64271bb04a657fd8d25c50ec132fa7439 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/7e/2f966bc3b65b0c0df08c1c4399b727110f6a92: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/7e/2f966bc3b65b0c0df08c1c4399b727110f6a92 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/8d/b0fc47fe826cf31d60040d706710ad64a8c929: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/8d/b0fc47fe826cf31d60040d706710ad64a8c929 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/92/90b36a3562b837f5b282d1b1ad2888031cc1f7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/92/90b36a3562b837f5b282d1b1ad2888031cc1f7 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/94/d85da1bbd0308ccf01c6f2a34e0bc54eff3f1e: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/94/d85da1bbd0308ccf01c6f2a34e0bc54eff3f1e -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/97/00c2e19d868f2f9dc01d27b16fce956a2ce2f1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/97/00c2e19d868f2f9dc01d27b16fce956a2ce2f1 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/9a/088b3b22550bfff0321f75b86ae7b00024946a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/9a/088b3b22550bfff0321f75b86ae7b00024946a -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/a6/b263066682e967cd20d3ddf2b25ae22b9311c8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/a6/b263066682e967cd20d3ddf2b25ae22b9311c8 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/a8/29e89b8fa98936127ae2462a82b003970b27b8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/a8/29e89b8fa98936127ae2462a82b003970b27b8 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/ac/fce16d5980ced47c36ec7a96e8b1cd3642d07e: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/ac/fce16d5980ced47c36ec7a96e8b1cd3642d07e -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/b1/86bf4588de98e03117f63306ea9f411c3ef7d2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/b1/86bf4588de98e03117f63306ea9f411c3ef7d2 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/b7/768615afdc728b456890d99c25d49c5d7294f4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/b7/768615afdc728b456890d99c25d49c5d7294f4 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/bc/132db6396bcbccfec95025501a3db9c18e23c4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/bc/132db6396bcbccfec95025501a3db9c18e23c4 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/bc/6428df3ae260096489d7f6e3f2ac7acfe12691: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/bc/6428df3ae260096489d7f6e3f2ac7acfe12691 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/bf/d68eeadd047c29fe08c6d4e571311b11c5a14a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/bf/d68eeadd047c29fe08c6d4e571311b11c5a14a -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/c3/ceb255dd65f47518754c0c59c80e14e78f9a8c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/c3/ceb255dd65f47518754c0c59c80e14e78f9a8c -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/c3/fda6360e828ecc1041399d1b0853adfc870a86: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/c3/fda6360e828ecc1041399d1b0853adfc870a86 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/c4/6443f05a5e209b3fb9294580aaea11aabae78f: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/c4/6443f05a5e209b3fb9294580aaea11aabae78f -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/c4/a04869acb07d3b4f6e7f0d1de93f9ecb6d3a66: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/c4/a04869acb07d3b4f6e7f0d1de93f9ecb6d3a66 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/cf/5a034c699378abfa883adeb9dbe3cfb1a6038f: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/cf/5a034c699378abfa883adeb9dbe3cfb1a6038f -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/d2/10edd735ff26542ebfe5f3a3739f5a04ffc82e: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/d2/10edd735ff26542ebfe5f3a3739f5a04ffc82e -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/d6/06037cb232bfda7788a8322492312d55b2ae9d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/d6/06037cb232bfda7788a8322492312d55b2ae9d -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/da/106659a28c6a982fb5f3f50caa66588511368c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/da/106659a28c6a982fb5f3f50caa66588511368c -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/dc/ab93401a4c531ca43ff6ebc07429b752887737: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/dc/ab93401a4c531ca43ff6ebc07429b752887737 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/dd/ef224c6a52e2cfb5675574788b8d0f0c5fc05a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/dd/ef224c6a52e2cfb5675574788b8d0f0c5fc05a -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/e1/3a631a2b34cc0d0f568fadf3d8da17ba1cbcbe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/e1/3a631a2b34cc0d0f568fadf3d8da17ba1cbcbe -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/e5/87d5cc0e78bf258266ecaf7427ac9e15885e8c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/e5/87d5cc0e78bf258266ecaf7427ac9e15885e8c -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/e5/c02bb4665eec1be05e842bef17b926ccdccae1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/e5/c02bb4665eec1be05e842bef17b926ccdccae1 -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/e8/b4bb3031310ddaba57dfdb3f3aa32cf718795b: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/e8/b4bb3031310ddaba57dfdb3f3aa32cf718795b -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/ea/ea168a3ba5c7ca91d60bc243789773f52fda6d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/ea/ea168a3ba5c7ca91d60bc243789773f52fda6d -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/eb/e1ee79286137b4195afe189a5773ab23dcfb4f: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/eb/e1ee79286137b4195afe189a5773ab23dcfb4f -------------------------------------------------------------------------------- /tests/test_repo/dotgit/objects/f5/82b54731702927a3cbadfc048573e5c3fa0dea: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xoofx/git-rocket-filter/HEAD/tests/test_repo/dotgit/objects/f5/82b54731702927a3cbadfc048573e5c3fa0dea -------------------------------------------------------------------------------- /tests/KeepPatternFile1.txt: -------------------------------------------------------------------------------- 1 | # This is a keep pattern file 2 | # It is using the same syntax as .gitignore (with additional syntax to attach a script per pattern) 3 | 4 | # Keeps this directory 5 | /Test1 6 | -------------------------------------------------------------------------------- /tests/test_repo/dotgit/config.backup: -------------------------------------------------------------------------------- 1 | [core] 2 | repositoryformatversion = 0 3 | filemode = false 4 | bare = false 5 | logallrefupdates = true 6 | symlinks = false 7 | ignorecase = true 8 | hideDotFiles = dotGitOnly 9 | -------------------------------------------------------------------------------- /tests/RemovePatternFile1.txt: -------------------------------------------------------------------------------- 1 | # This is a remove pattern file 2 | # It is using the same syntax as .gitignore (with additional syntax to attach a script per pattern) 3 | 4 | # Keeps all files 5 | * 6 | # Except 7 | !a[12].txt 8 | -------------------------------------------------------------------------------- /tests/test_repo/dotgit/config: -------------------------------------------------------------------------------- 1 | [core] 2 | repositoryformatversion = 0 3 | filemode = false 4 | bare = false 5 | logallrefupdates = true 6 | symlinks = false 7 | ignorecase = true 8 | hideDotFiles = dotGitOnly 9 | autocrlf = Input 10 | -------------------------------------------------------------------------------- /tests/test_repo/dotgit/hooks/post-update.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to prepare a packed repository for use over 4 | # dumb transports. 5 | # 6 | # To enable this hook, rename this file to "post-update". 7 | 8 | exec git update-server-info 9 | -------------------------------------------------------------------------------- /tests/test_repo/dotgit/info/exclude: -------------------------------------------------------------------------------- 1 | # git ls-files --others --exclude-from=.git/info/exclude 2 | # Lines that start with '#' are comments. 3 | # For a project mostly in C, the following would be a good set of 4 | # exclude patterns (uncomment them if you want to use them): 5 | # *.[oa] 6 | # *~ 7 | -------------------------------------------------------------------------------- /tests/test_repo/dotgit/logs/refs/heads/old_working: -------------------------------------------------------------------------------- 1 | 0000000000000000000000000000000000000000 2f5a2b09524c495aeaa4dff717b933b429a8934a Alexandre Mutel 1439293184 +0900 branch: Created from 2f5a2b09524c495aeaa4dff717b933b429a8934a 2 | 2f5a2b09524c495aeaa4dff717b933b429a8934a 21e0b01aa86508dfa231b4f6e0b723694aadf745 Alexandre Mutel 1439293207 +0900 commit: Modify a.txt 3 | -------------------------------------------------------------------------------- /tests/test_repo/dotgit/hooks/pre-applypatch.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to verify what is about to be committed 4 | # by applypatch from an e-mail message. 5 | # 6 | # The hook should exit with non-zero status after issuing an 7 | # appropriate message if it wants to stop the commit. 8 | # 9 | # To enable this hook, rename this file to "pre-applypatch". 10 | 11 | . git-sh-setup 12 | test -x "$GIT_DIR/hooks/pre-commit" && 13 | exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} 14 | : 15 | -------------------------------------------------------------------------------- /tests/test_repo/dotgit/hooks/applypatch-msg.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to check the commit log message taken by 4 | # applypatch from an e-mail message. 5 | # 6 | # The hook should exit with non-zero status after issuing an 7 | # appropriate message if it wants to stop the commit. The hook is 8 | # allowed to edit the commit message file. 9 | # 10 | # To enable this hook, rename this file to "applypatch-msg". 11 | 12 | . git-sh-setup 13 | test -x "$GIT_DIR/hooks/commit-msg" && 14 | exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} 15 | : 16 | -------------------------------------------------------------------------------- /tests/test_repo/dotgit/logs/refs/heads/modify_test1: -------------------------------------------------------------------------------- 1 | 0000000000000000000000000000000000000000 749a42d1e74b3673de917fc06e7f73a3431492a5 Alexandre Mutel 1439292441 +0900 branch: Created from 749a42d1e74b3673de917fc06e7f73a3431492a5 2 | 749a42d1e74b3673de917fc06e7f73a3431492a5 1971f5bd758c338db3c6ffe45b33d92818e2acd3 Alexandre Mutel 1439292495 +0900 commit: Modify Test1/*.txt 3 | 1971f5bd758c338db3c6ffe45b33d92818e2acd3 38e1b9eec0c60bc4a72459e29a2ac8de3ddea2f6 Alexandre Mutel 1439292555 +0900 commit: Modify Test1/a1.txt 4 | 38e1b9eec0c60bc4a72459e29a2ac8de3ddea2f6 418c908a629c7b9ccdf3d00a08f6a6f493d647b3 Alexandre Mutel 1439292561 +0900 commit: Modify Test1/b1.txt 5 | 418c908a629c7b9ccdf3d00a08f6a6f493d647b3 da106659a28c6a982fb5f3f50caa66588511368c Alexandre Mutel 1439292565 +0900 commit: Modify Test1/c1.txt 6 | -------------------------------------------------------------------------------- /tests/test_repo/dotgit/hooks/commit-msg.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to check the commit log message. 4 | # Called by "git commit" with one argument, the name of the file 5 | # that has the commit message. The hook should exit with non-zero 6 | # status after issuing an appropriate message if it wants to stop the 7 | # commit. The hook is allowed to edit the commit message file. 8 | # 9 | # To enable this hook, rename this file to "commit-msg". 10 | 11 | # Uncomment the below to add a Signed-off-by line to the message. 12 | # Doing this in a hook is a bad idea in general, but the prepare-commit-msg 13 | # hook is more suited to it. 14 | # 15 | # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') 16 | # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" 17 | 18 | # This example catches duplicate Signed-off-by lines. 19 | 20 | test "" = "$(grep '^Signed-off-by: ' "$1" | 21 | sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { 22 | echo >&2 Duplicate Signed-off-by lines. 23 | exit 1 24 | } 25 | -------------------------------------------------------------------------------- /tests/GitRocketFilter.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netcoreapp2.1 4 | false 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | PreserveNewest 13 | 14 | 15 | PreserveNewest 16 | 17 | 18 | 19 | 20 | 21 | 22 | all 23 | runtime; build; native; contentfiles; analyzers 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Alexandre Mutel 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /tests/test_repo/dotgit/hooks/prepare-commit-msg.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to prepare the commit log message. 4 | # Called by "git commit" with the name of the file that has the 5 | # commit message, followed by the description of the commit 6 | # message's source. The hook's purpose is to edit the commit 7 | # message file. If the hook fails with a non-zero status, 8 | # the commit is aborted. 9 | # 10 | # To enable this hook, rename this file to "prepare-commit-msg". 11 | 12 | # This hook includes three examples. The first comments out the 13 | # "Conflicts:" part of a merge commit. 14 | # 15 | # The second includes the output of "git diff --name-status -r" 16 | # into the message, just before the "git status" output. It is 17 | # commented because it doesn't cope with --amend or with squashed 18 | # commits. 19 | # 20 | # The third example adds a Signed-off-by line to the message, that can 21 | # still be edited. This is rarely a good idea. 22 | 23 | case "$2,$3" in 24 | merge,) 25 | /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; 26 | 27 | # ,|template,) 28 | # /usr/bin/perl -i.bak -pe ' 29 | # print "\n" . `git diff --cached --name-status -r` 30 | # if /^#/ && $first++ == 0' "$1" ;; 31 | 32 | *) ;; 33 | esac 34 | 35 | # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') 36 | # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" 37 | -------------------------------------------------------------------------------- /src/RocketException.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Alexandre Mutel. All rights reserved. 2 | // Licensed under the BSD license. See LICENSE file in the project root for full license information. 3 | using System; 4 | 5 | namespace GitRocketFilter 6 | { 7 | /// 8 | /// An exception used to display errors (compilation, invalid parameters...etc). 9 | /// 10 | public class RocketException : Exception 11 | { 12 | /// 13 | /// Initializes a new instance of the class with a specified error message. 14 | /// 15 | /// The message that describes the error. 16 | public RocketException(string message) : base(message) 17 | { 18 | } 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | /// The format message. 24 | /// The arguments. 25 | public RocketException(string formatMessage, params object[] args) 26 | : base(string.Format(formatMessage, args)) 27 | { 28 | } 29 | 30 | /// 31 | /// Gets or sets the additional text. 32 | /// 33 | /// The additional text. 34 | public string AdditionalText { get; set; } 35 | } 36 | } -------------------------------------------------------------------------------- /src/GitRocketFilter.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | GitRocketFilter 5 | git-rocket-filter 6 | netcoreapp2.1 7 | 8 | 9 | true 10 | git-rocket-filter 11 | git-rocket-filter 12 | 1.0.1 13 | git;git-filter-branch 14 | https://github.com/xoofx/GitRocketFilter/blob/master/changelog.md 15 | https://raw.githubusercontent.com/xoofx/GitRocketFilter/master/img/rocket.png 16 | https://github.com/xoofx/GitRocketFilter 17 | BSD-2-Clause 18 | git-rocket-filter is a more powerful and faster version of git-filter-branch using C# Roslyn scripting to rewrite/filter commits. 19 | Alexandre Mutel 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /tests/test_repo/dotgit/hooks/pre-push.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # An example hook script to verify what is about to be pushed. Called by "git 4 | # push" after it has checked the remote status, but before anything has been 5 | # pushed. If this script exits with a non-zero status nothing will be pushed. 6 | # 7 | # This hook is called with the following parameters: 8 | # 9 | # $1 -- Name of the remote to which the push is being done 10 | # $2 -- URL to which the push is being done 11 | # 12 | # If pushing without using a named remote those arguments will be equal. 13 | # 14 | # Information about the commits which are being pushed is supplied as lines to 15 | # the standard input in the form: 16 | # 17 | # 18 | # 19 | # This sample shows how to prevent push of commits where the log message starts 20 | # with "WIP" (work in progress). 21 | 22 | remote="$1" 23 | url="$2" 24 | 25 | z40=0000000000000000000000000000000000000000 26 | 27 | IFS=' ' 28 | while read local_ref local_sha remote_ref remote_sha 29 | do 30 | if [ "$local_sha" = $z40 ] 31 | then 32 | # Handle delete 33 | : 34 | else 35 | if [ "$remote_sha" = $z40 ] 36 | then 37 | # New branch, examine all commits 38 | range="$local_sha" 39 | else 40 | # Update to existing branch, examine new commits 41 | range="$remote_sha..$local_sha" 42 | fi 43 | 44 | # Check for WIP commit 45 | commit=`git rev-list -n 1 --grep '^WIP' "$range"` 46 | if [ -n "$commit" ] 47 | then 48 | echo "Found WIP commit in $local_ref, not pushing" 49 | exit 1 50 | fi 51 | fi 52 | done 53 | 54 | exit 0 55 | -------------------------------------------------------------------------------- /tests/test_repo/dotgit/hooks/pre-commit.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to verify what is about to be committed. 4 | # Called by "git commit" with no arguments. The hook should 5 | # exit with non-zero status after issuing an appropriate message if 6 | # it wants to stop the commit. 7 | # 8 | # To enable this hook, rename this file to "pre-commit". 9 | 10 | if git rev-parse --verify HEAD >/dev/null 2>&1 11 | then 12 | against=HEAD 13 | else 14 | # Initial commit: diff against an empty tree object 15 | against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 16 | fi 17 | 18 | # If you want to allow non-ASCII filenames set this variable to true. 19 | allownonascii=$(git config --bool hooks.allownonascii) 20 | 21 | # Redirect output to stderr. 22 | exec 1>&2 23 | 24 | # Cross platform projects tend to avoid non-ASCII filenames; prevent 25 | # them from being added to the repository. We exploit the fact that the 26 | # printable range starts at the space character and ends with tilde. 27 | if [ "$allownonascii" != "true" ] && 28 | # Note that the use of brackets around a tr range is ok here, (it's 29 | # even required, for portability to Solaris 10's /usr/bin/tr), since 30 | # the square bracket bytes happen to fall in the designated range. 31 | test $(git diff --cached --name-only --diff-filter=A -z $against | 32 | LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 33 | then 34 | cat <<\EOF 35 | Error: Attempt to add a non-ASCII file name. 36 | 37 | This can cause problems if you want to work with people on other platforms. 38 | 39 | To be portable it is advisable to rename the file. 40 | 41 | If you know what you are doing you can disable this check using: 42 | 43 | git config hooks.allownonascii true 44 | EOF 45 | exit 1 46 | fi 47 | 48 | # If there are whitespace errors, print the offending file names and fail. 49 | exec git diff-index --check --cached $against -- 50 | -------------------------------------------------------------------------------- /tests/test_repo/dotgit/logs/refs/heads/master: -------------------------------------------------------------------------------- 1 | 0000000000000000000000000000000000000000 385ba04ed583c36c1efe2f60a7ac18f26020a50d Alexandre Mutel 1439292359 +0900 commit (initial): Add a.txt 2 | 385ba04ed583c36c1efe2f60a7ac18f26020a50d 3aea0bdc3f032029933fecb45d9bfb444ccd89d1 Alexandre Mutel 1439292366 +0900 commit: Add b.txt 3 | 3aea0bdc3f032029933fecb45d9bfb444ccd89d1 acfce16d5980ced47c36ec7a96e8b1cd3642d07e Alexandre Mutel 1439292377 +0900 commit: Add c.txt and root.txt 4 | acfce16d5980ced47c36ec7a96e8b1cd3642d07e a6b263066682e967cd20d3ddf2b25ae22b9311c8 Alexandre Mutel 1439292394 +0900 commit: Add Test1 with a1/b1/b2.txt 5 | a6b263066682e967cd20d3ddf2b25ae22b9311c8 2f5a2b09524c495aeaa4dff717b933b429a8934a Alexandre Mutel 1439292406 +0900 commit: Add Test2/a2.txt 6 | 2f5a2b09524c495aeaa4dff717b933b429a8934a 749a42d1e74b3673de917fc06e7f73a3431492a5 Alexandre Mutel 1439292417 +0900 commit: Add Test2/Test21/a21.txt 7 | 749a42d1e74b3673de917fc06e7f73a3431492a5 b7768615afdc728b456890d99c25d49c5d7294f4 Alexandre Mutel 1439292636 +0900 commit: Modify Test1/a1.txt and b1.txt 8 | b7768615afdc728b456890d99c25d49c5d7294f4 ebe1ee79286137b4195afe189a5773ab23dcfb4f Alexandre Mutel 1439292642 +0900 commit: Modify c1.txt 9 | ebe1ee79286137b4195afe189a5773ab23dcfb4f eaea168a3ba5c7ca91d60bc243789773f52fda6d Alexandre Mutel 1439293043 +0900 commit (merge): Merge branch 'modify_test1' 10 | eaea168a3ba5c7ca91d60bc243789773f52fda6d 7e2f966bc3b65b0c0df08c1c4399b727110f6a92 Alexandre Mutel 1439293137 +0900 commit: Add Binary/test.bin 11 | 7e2f966bc3b65b0c0df08c1c4399b727110f6a92 e5c02bb4665eec1be05e842bef17b926ccdccae1 Alexandre Mutel 1439293257 +0900 commit: Last commit 12 | e5c02bb4665eec1be05e842bef17b926ccdccae1 690d05a98e20094354173f6f4254eb2786c0df70 Alexandre Mutel 1439301164 +0900 commit (amend): Last commit 13 | -------------------------------------------------------------------------------- /src/RocketScriptBase.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Alexandre Mutel. All rights reserved. 2 | // Licensed under the BSD license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using LibGit2Sharp; 6 | 7 | namespace GitRocketFilter 8 | { 9 | /// 10 | /// Base class for a script. 11 | /// 12 | public abstract class RocketScriptBase 13 | { 14 | private readonly RocketFilterApp rocketFilterApp; 15 | 16 | /// 17 | /// Gets or sets the tag object (user). 18 | /// 19 | /// The tag object. 20 | protected object Tag { get; set; } 21 | 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// The rocket filter application. 26 | protected RocketScriptBase(RocketFilterApp rocketFilterApp) 27 | { 28 | if (rocketFilterApp == null) throw new ArgumentNullException("rocketFilterApp"); 29 | this.rocketFilterApp = rocketFilterApp; 30 | } 31 | 32 | /// 33 | /// Maps the specified commit to an already mapped commit. 34 | /// 35 | /// The commit. 36 | /// The new commit that has been mapped. 37 | /// commit 38 | public SimpleCommit Map(SimpleCommit commit) 39 | { 40 | if (commit == null) throw new ArgumentNullException("commit"); 41 | return rocketFilterApp.GetMapCommit(commit); 42 | } 43 | 44 | /// 45 | /// Transforms a object to a . 46 | /// 47 | /// The commit. 48 | /// A simple commit instance. 49 | /// commit 50 | public SimpleCommit Simple(Commit commit) 51 | { 52 | if (commit == null) throw new ArgumentNullException("commit"); 53 | return rocketFilterApp.GetSimpleCommit(commit); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /GitRocketFilter.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.329 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GitRocketFilter", "src\GitRocketFilter.csproj", "{16AD42F7-1C6D-4E3B-BA7A-3C81EFC2CC2A}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GitRocketFilter.Tests", "tests\GitRocketFilter.Tests.csproj", "{C054F10F-98DD-4C34-900B-F180C668EECE}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{C0CEA0BE-7453-4363-A040-81B87E40EECE}" 11 | ProjectSection(SolutionItems) = preProject 12 | changelog.md = changelog.md 13 | readme.md = readme.md 14 | EndProjectSection 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibGit2Sharp", "ext\libgit2sharp\LibGit2Sharp\LibGit2Sharp.csproj", "{02DD6031-D0BC-4008-890F-0F1B5A90269B}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Release|Any CPU = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {16AD42F7-1C6D-4E3B-BA7A-3C81EFC2CC2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {16AD42F7-1C6D-4E3B-BA7A-3C81EFC2CC2A}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {16AD42F7-1C6D-4E3B-BA7A-3C81EFC2CC2A}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {16AD42F7-1C6D-4E3B-BA7A-3C81EFC2CC2A}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {C054F10F-98DD-4C34-900B-F180C668EECE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {C054F10F-98DD-4C34-900B-F180C668EECE}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {C054F10F-98DD-4C34-900B-F180C668EECE}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {C054F10F-98DD-4C34-900B-F180C668EECE}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {02DD6031-D0BC-4008-890F-0F1B5A90269B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {02DD6031-D0BC-4008-890F-0F1B5A90269B}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {02DD6031-D0BC-4008-890F-0F1B5A90269B}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {02DD6031-D0BC-4008-890F-0F1B5A90269B}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {1F0788BB-03CC-44F4-BD3B-942A94BA9520} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /tests/TestInvalidOptions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Alexandre Mutel. All rights reserved. 2 | // Licensed under the BSD license. See LICENSE file in the project root for full license information. 3 | 4 | using Xunit; 5 | using Xunit.Abstractions; 6 | 7 | namespace GitRocketFilter.Tests 8 | { 9 | /// 10 | /// Tests various invalid options. 11 | /// 12 | public class TestInvalidOptions : TestRepoBase 13 | { 14 | public TestInvalidOptions(ITestOutputHelper outputHelper) 15 | : base(outputHelper) 16 | { 17 | } 18 | 19 | /// 20 | /// Forget the --branch option 21 | /// 22 | [Fact] 23 | public void ForgetBranch() 24 | { 25 | var test = InitializeTest(); 26 | 27 | var result = Program.Main("--keep", "/Test1", 28 | "--repo-dir", test.Path, 29 | @"HEAD"); 30 | 31 | Assert.NotEqual(0, result); 32 | 33 | Assert.Contains("Branch name is required and cannot be null", test.Output); 34 | 35 | // Cleanup the test only if we succeed 36 | test.Dispose(); 37 | } 38 | 39 | /// 40 | /// Branch already exist but no --force option 41 | /// 42 | [Fact] 43 | public void ForgetBranchForce() 44 | { 45 | var test = InitializeTest(); 46 | 47 | // Add an existing branch reference 48 | test.Repo.Refs.Add(NewBranchRef, test.Repo.Refs.Head); 49 | 50 | var result = Program.Main("--keep", "/Test1", 51 | "--repo-dir", test.Path, 52 | "--branch", NewBranch, 53 | @"HEAD"); 54 | 55 | Assert.NotEqual(0, result); 56 | 57 | Assert.Contains(string.Format("The branch [{0}] already exist. Cannot overwrite without force option", NewBranch), test.Output); 58 | 59 | // Cleanup the test only if we succeed 60 | test.Dispose(); 61 | } 62 | 63 | /// 64 | /// Branch already but with pass --force option 65 | /// 66 | [Fact] 67 | public void BranchForce() 68 | { 69 | var test = InitializeTest(); 70 | 71 | // Add an existing branch reference 72 | test.Repo.Refs.Add(NewBranchRef, test.Repo.Refs.Head); 73 | 74 | var result = Program.Main("--keep", "test.bin", 75 | "--repo-dir", test.Path, 76 | "--force", 77 | "--branch", NewBranch, 78 | @"HEAD"); 79 | 80 | Assert.Equal(0, result); 81 | 82 | var repo = test.Repo; 83 | var headNewMaster = AssertBranchRef(repo); 84 | 85 | var newCommits = GetCommits(repo, headNewMaster); 86 | 87 | Assert.Equal(1, newCommits.Count); 88 | 89 | Assert.NotNull(newCommits[0].Tree["Binary/test.bin"]); 90 | 91 | // Cleanup the test only if we succeed 92 | test.Dispose(); 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /tests/test_repo/dotgit/logs/HEAD: -------------------------------------------------------------------------------- 1 | 0000000000000000000000000000000000000000 385ba04ed583c36c1efe2f60a7ac18f26020a50d Alexandre Mutel 1439292359 +0900 commit (initial): Add a.txt 2 | 385ba04ed583c36c1efe2f60a7ac18f26020a50d 3aea0bdc3f032029933fecb45d9bfb444ccd89d1 Alexandre Mutel 1439292366 +0900 commit: Add b.txt 3 | 3aea0bdc3f032029933fecb45d9bfb444ccd89d1 acfce16d5980ced47c36ec7a96e8b1cd3642d07e Alexandre Mutel 1439292377 +0900 commit: Add c.txt and root.txt 4 | acfce16d5980ced47c36ec7a96e8b1cd3642d07e a6b263066682e967cd20d3ddf2b25ae22b9311c8 Alexandre Mutel 1439292394 +0900 commit: Add Test1 with a1/b1/b2.txt 5 | a6b263066682e967cd20d3ddf2b25ae22b9311c8 2f5a2b09524c495aeaa4dff717b933b429a8934a Alexandre Mutel 1439292406 +0900 commit: Add Test2/a2.txt 6 | 2f5a2b09524c495aeaa4dff717b933b429a8934a 749a42d1e74b3673de917fc06e7f73a3431492a5 Alexandre Mutel 1439292417 +0900 commit: Add Test2/Test21/a21.txt 7 | 749a42d1e74b3673de917fc06e7f73a3431492a5 749a42d1e74b3673de917fc06e7f73a3431492a5 Alexandre Mutel 1439292441 +0900 checkout: moving from master to modify_test1 8 | 749a42d1e74b3673de917fc06e7f73a3431492a5 1971f5bd758c338db3c6ffe45b33d92818e2acd3 Alexandre Mutel 1439292495 +0900 commit: Modify Test1/*.txt 9 | 1971f5bd758c338db3c6ffe45b33d92818e2acd3 38e1b9eec0c60bc4a72459e29a2ac8de3ddea2f6 Alexandre Mutel 1439292555 +0900 commit: Modify Test1/a1.txt 10 | 38e1b9eec0c60bc4a72459e29a2ac8de3ddea2f6 418c908a629c7b9ccdf3d00a08f6a6f493d647b3 Alexandre Mutel 1439292561 +0900 commit: Modify Test1/b1.txt 11 | 418c908a629c7b9ccdf3d00a08f6a6f493d647b3 da106659a28c6a982fb5f3f50caa66588511368c Alexandre Mutel 1439292565 +0900 commit: Modify Test1/c1.txt 12 | da106659a28c6a982fb5f3f50caa66588511368c 749a42d1e74b3673de917fc06e7f73a3431492a5 Alexandre Mutel 1439292579 +0900 checkout: moving from modify_test1 to master 13 | 749a42d1e74b3673de917fc06e7f73a3431492a5 b7768615afdc728b456890d99c25d49c5d7294f4 Alexandre Mutel 1439292636 +0900 commit: Modify Test1/a1.txt and b1.txt 14 | b7768615afdc728b456890d99c25d49c5d7294f4 ebe1ee79286137b4195afe189a5773ab23dcfb4f Alexandre Mutel 1439292642 +0900 commit: Modify c1.txt 15 | ebe1ee79286137b4195afe189a5773ab23dcfb4f eaea168a3ba5c7ca91d60bc243789773f52fda6d Alexandre Mutel 1439293043 +0900 commit (merge): Merge branch 'modify_test1' 16 | eaea168a3ba5c7ca91d60bc243789773f52fda6d 7e2f966bc3b65b0c0df08c1c4399b727110f6a92 Alexandre Mutel 1439293137 +0900 commit: Add Binary/test.bin 17 | 7e2f966bc3b65b0c0df08c1c4399b727110f6a92 2f5a2b09524c495aeaa4dff717b933b429a8934a Alexandre Mutel 1439293184 +0900 checkout: moving from master to old_working 18 | 2f5a2b09524c495aeaa4dff717b933b429a8934a 21e0b01aa86508dfa231b4f6e0b723694aadf745 Alexandre Mutel 1439293207 +0900 commit: Modify a.txt 19 | 21e0b01aa86508dfa231b4f6e0b723694aadf745 7e2f966bc3b65b0c0df08c1c4399b727110f6a92 Alexandre Mutel 1439293213 +0900 checkout: moving from old_working to master 20 | 7e2f966bc3b65b0c0df08c1c4399b727110f6a92 e5c02bb4665eec1be05e842bef17b926ccdccae1 Alexandre Mutel 1439293257 +0900 commit: Last commit 21 | e5c02bb4665eec1be05e842bef17b926ccdccae1 690d05a98e20094354173f6f4254eb2786c0df70 Alexandre Mutel 1439301164 +0900 commit (amend): Last commit 22 | -------------------------------------------------------------------------------- /tests/test_repo/dotgit/hooks/update.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to blocks unannotated tags from entering. 4 | # Called by "git receive-pack" with arguments: refname sha1-old sha1-new 5 | # 6 | # To enable this hook, rename this file to "update". 7 | # 8 | # Config 9 | # ------ 10 | # hooks.allowunannotated 11 | # This boolean sets whether unannotated tags will be allowed into the 12 | # repository. By default they won't be. 13 | # hooks.allowdeletetag 14 | # This boolean sets whether deleting tags will be allowed in the 15 | # repository. By default they won't be. 16 | # hooks.allowmodifytag 17 | # This boolean sets whether a tag may be modified after creation. By default 18 | # it won't be. 19 | # hooks.allowdeletebranch 20 | # This boolean sets whether deleting branches will be allowed in the 21 | # repository. By default they won't be. 22 | # hooks.denycreatebranch 23 | # This boolean sets whether remotely creating branches will be denied 24 | # in the repository. By default this is allowed. 25 | # 26 | 27 | # --- Command line 28 | refname="$1" 29 | oldrev="$2" 30 | newrev="$3" 31 | 32 | # --- Safety check 33 | if [ -z "$GIT_DIR" ]; then 34 | echo "Don't run this script from the command line." >&2 35 | echo " (if you want, you could supply GIT_DIR then run" >&2 36 | echo " $0 )" >&2 37 | exit 1 38 | fi 39 | 40 | if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then 41 | echo "usage: $0 " >&2 42 | exit 1 43 | fi 44 | 45 | # --- Config 46 | allowunannotated=$(git config --bool hooks.allowunannotated) 47 | allowdeletebranch=$(git config --bool hooks.allowdeletebranch) 48 | denycreatebranch=$(git config --bool hooks.denycreatebranch) 49 | allowdeletetag=$(git config --bool hooks.allowdeletetag) 50 | allowmodifytag=$(git config --bool hooks.allowmodifytag) 51 | 52 | # check for no description 53 | projectdesc=$(sed -e '1q' "$GIT_DIR/description") 54 | case "$projectdesc" in 55 | "Unnamed repository"* | "") 56 | echo "*** Project description file hasn't been set" >&2 57 | exit 1 58 | ;; 59 | esac 60 | 61 | # --- Check types 62 | # if $newrev is 0000...0000, it's a commit to delete a ref. 63 | zero="0000000000000000000000000000000000000000" 64 | if [ "$newrev" = "$zero" ]; then 65 | newrev_type=delete 66 | else 67 | newrev_type=$(git cat-file -t $newrev) 68 | fi 69 | 70 | case "$refname","$newrev_type" in 71 | refs/tags/*,commit) 72 | # un-annotated tag 73 | short_refname=${refname##refs/tags/} 74 | if [ "$allowunannotated" != "true" ]; then 75 | echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 76 | echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 77 | exit 1 78 | fi 79 | ;; 80 | refs/tags/*,delete) 81 | # delete tag 82 | if [ "$allowdeletetag" != "true" ]; then 83 | echo "*** Deleting a tag is not allowed in this repository" >&2 84 | exit 1 85 | fi 86 | ;; 87 | refs/tags/*,tag) 88 | # annotated tag 89 | if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 90 | then 91 | echo "*** Tag '$refname' already exists." >&2 92 | echo "*** Modifying a tag is not allowed in this repository." >&2 93 | exit 1 94 | fi 95 | ;; 96 | refs/heads/*,commit) 97 | # branch 98 | if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then 99 | echo "*** Creating a branch is not allowed in this repository" >&2 100 | exit 1 101 | fi 102 | ;; 103 | refs/heads/*,delete) 104 | # delete branch 105 | if [ "$allowdeletebranch" != "true" ]; then 106 | echo "*** Deleting a branch is not allowed in this repository" >&2 107 | exit 1 108 | fi 109 | ;; 110 | refs/remotes/*,commit) 111 | # tracking branch 112 | ;; 113 | refs/remotes/*,delete) 114 | # delete tracking branch 115 | if [ "$allowdeletebranch" != "true" ]; then 116 | echo "*** Deleting a tracking branch is not allowed in this repository" >&2 117 | exit 1 118 | fi 119 | ;; 120 | *) 121 | # Anything else (is there anything else?) 122 | echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 123 | exit 1 124 | ;; 125 | esac 126 | 127 | # --- Finished 128 | exit 0 129 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opensdf 80 | *.sdf 81 | *.cachefile 82 | 83 | # Visual Studio profiler 84 | *.psess 85 | *.vsp 86 | *.vspx 87 | 88 | # TFS 2012 Local Workspace 89 | $tf/ 90 | 91 | # Guidance Automation Toolkit 92 | *.gpState 93 | 94 | # ReSharper is a .NET coding add-in 95 | _ReSharper*/ 96 | *.[Rr]e[Ss]harper 97 | *.DotSettings.user 98 | 99 | # JustCode is a .NET coding add-in 100 | .JustCode 101 | 102 | # TeamCity is a build add-in 103 | _TeamCity* 104 | 105 | # DotCover is a Code Coverage Tool 106 | *.dotCover 107 | 108 | # NCrunch 109 | _NCrunch_* 110 | .*crunch*.local.xml 111 | nCrunchTemp_* 112 | 113 | # MightyMoose 114 | *.mm.* 115 | AutoTest.Net/ 116 | 117 | # Web workbench (sass) 118 | .sass-cache/ 119 | 120 | # Installshield output folder 121 | [Ee]xpress/ 122 | 123 | # DocProject is a documentation generator add-in 124 | DocProject/buildhelp/ 125 | DocProject/Help/*.HxT 126 | DocProject/Help/*.HxC 127 | DocProject/Help/*.hhc 128 | DocProject/Help/*.hhk 129 | DocProject/Help/*.hhp 130 | DocProject/Help/Html2 131 | DocProject/Help/html 132 | 133 | # Click-Once directory 134 | publish/ 135 | 136 | # Publish Web Output 137 | *.[Pp]ublish.xml 138 | *.azurePubxml 139 | # TODO: Comment the next line if you want to checkin your web deploy settings 140 | # but database connection strings (with potential passwords) will be unencrypted 141 | *.pubxml 142 | *.publishproj 143 | 144 | # NuGet Packages 145 | *.nupkg 146 | # The packages folder can be ignored because of Package Restore 147 | **/packages/* 148 | # except build/, which is used as an MSBuild target. 149 | !**/packages/build/ 150 | # Uncomment if necessary however generally it will be regenerated when needed 151 | #!**/packages/repositories.config 152 | 153 | # Windows Azure Build Output 154 | csx/ 155 | *.build.csdef 156 | 157 | # Windows Store app package directory 158 | AppPackages/ 159 | 160 | # Visual Studio cache files 161 | # files ending in .cache can be ignored 162 | *.[Cc]ache 163 | # but keep track of directories ending in .cache 164 | !*.[Cc]ache/ 165 | 166 | # Others 167 | ClientBin/ 168 | [Ss]tyle[Cc]op.* 169 | ~$* 170 | *~ 171 | *.dbmdl 172 | *.dbproj.schemaview 173 | *.pfx 174 | *.publishsettings 175 | node_modules/ 176 | orleans.codegen.cs 177 | 178 | # RIA/Silverlight projects 179 | Generated_Code/ 180 | 181 | # Backup & report files from converting an old project file 182 | # to a newer Visual Studio version. Backup files are not needed, 183 | # because we have git ;-) 184 | _UpgradeReport_Files/ 185 | Backup*/ 186 | UpgradeLog*.XML 187 | UpgradeLog*.htm 188 | 189 | # SQL Server files 190 | *.mdf 191 | *.ldf 192 | 193 | # Business Intelligence projects 194 | *.rdl.data 195 | *.bim.layout 196 | *.bim_*.settings 197 | 198 | # Microsoft Fakes 199 | FakesAssemblies/ 200 | 201 | # Node.js Tools for Visual Studio 202 | .ntvs_analysis.dat 203 | 204 | # Visual Studio 6 build log 205 | *.plg 206 | 207 | # Visual Studio 6 workspace options file 208 | *.opt 209 | 210 | # Visual Studio LightSwitch build output 211 | **/*.HTMLClient/GeneratedArtifacts 212 | **/*.DesktopClient/GeneratedArtifacts 213 | **/*.DesktopClient/ModelManifest.xml 214 | **/*.Server/GeneratedArtifacts 215 | **/*.Server/ModelManifest.xml 216 | _Pvt_Extensions 217 | -------------------------------------------------------------------------------- /tests/test_repo/dotgit/hooks/pre-rebase.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2006, 2008 Junio C Hamano 4 | # 5 | # The "pre-rebase" hook is run just before "git rebase" starts doing 6 | # its job, and can prevent the command from running by exiting with 7 | # non-zero status. 8 | # 9 | # The hook is called with the following parameters: 10 | # 11 | # $1 -- the upstream the series was forked from. 12 | # $2 -- the branch being rebased (or empty when rebasing the current branch). 13 | # 14 | # This sample shows how to prevent topic branches that are already 15 | # merged to 'next' branch from getting rebased, because allowing it 16 | # would result in rebasing already published history. 17 | 18 | publish=next 19 | basebranch="$1" 20 | if test "$#" = 2 21 | then 22 | topic="refs/heads/$2" 23 | else 24 | topic=`git symbolic-ref HEAD` || 25 | exit 0 ;# we do not interrupt rebasing detached HEAD 26 | fi 27 | 28 | case "$topic" in 29 | refs/heads/??/*) 30 | ;; 31 | *) 32 | exit 0 ;# we do not interrupt others. 33 | ;; 34 | esac 35 | 36 | # Now we are dealing with a topic branch being rebased 37 | # on top of master. Is it OK to rebase it? 38 | 39 | # Does the topic really exist? 40 | git show-ref -q "$topic" || { 41 | echo >&2 "No such branch $topic" 42 | exit 1 43 | } 44 | 45 | # Is topic fully merged to master? 46 | not_in_master=`git rev-list --pretty=oneline ^master "$topic"` 47 | if test -z "$not_in_master" 48 | then 49 | echo >&2 "$topic is fully merged to master; better remove it." 50 | exit 1 ;# we could allow it, but there is no point. 51 | fi 52 | 53 | # Is topic ever merged to next? If so you should not be rebasing it. 54 | only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` 55 | only_next_2=`git rev-list ^master ${publish} | sort` 56 | if test "$only_next_1" = "$only_next_2" 57 | then 58 | not_in_topic=`git rev-list "^$topic" master` 59 | if test -z "$not_in_topic" 60 | then 61 | echo >&2 "$topic is already up-to-date with master" 62 | exit 1 ;# we could allow it, but there is no point. 63 | else 64 | exit 0 65 | fi 66 | else 67 | not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` 68 | /usr/bin/perl -e ' 69 | my $topic = $ARGV[0]; 70 | my $msg = "* $topic has commits already merged to public branch:\n"; 71 | my (%not_in_next) = map { 72 | /^([0-9a-f]+) /; 73 | ($1 => 1); 74 | } split(/\n/, $ARGV[1]); 75 | for my $elem (map { 76 | /^([0-9a-f]+) (.*)$/; 77 | [$1 => $2]; 78 | } split(/\n/, $ARGV[2])) { 79 | if (!exists $not_in_next{$elem->[0]}) { 80 | if ($msg) { 81 | print STDERR $msg; 82 | undef $msg; 83 | } 84 | print STDERR " $elem->[1]\n"; 85 | } 86 | } 87 | ' "$topic" "$not_in_next" "$not_in_master" 88 | exit 1 89 | fi 90 | 91 | exit 0 92 | 93 | ################################################################ 94 | 95 | This sample hook safeguards topic branches that have been 96 | published from being rewound. 97 | 98 | The workflow assumed here is: 99 | 100 | * Once a topic branch forks from "master", "master" is never 101 | merged into it again (either directly or indirectly). 102 | 103 | * Once a topic branch is fully cooked and merged into "master", 104 | it is deleted. If you need to build on top of it to correct 105 | earlier mistakes, a new topic branch is created by forking at 106 | the tip of the "master". This is not strictly necessary, but 107 | it makes it easier to keep your history simple. 108 | 109 | * Whenever you need to test or publish your changes to topic 110 | branches, merge them into "next" branch. 111 | 112 | The script, being an example, hardcodes the publish branch name 113 | to be "next", but it is trivial to make it configurable via 114 | $GIT_DIR/config mechanism. 115 | 116 | With this workflow, you would want to know: 117 | 118 | (1) ... if a topic branch has ever been merged to "next". Young 119 | topic branches can have stupid mistakes you would rather 120 | clean up before publishing, and things that have not been 121 | merged into other branches can be easily rebased without 122 | affecting other people. But once it is published, you would 123 | not want to rewind it. 124 | 125 | (2) ... if a topic branch has been fully merged to "master". 126 | Then you can delete it. More importantly, you should not 127 | build on top of it -- other people may already want to 128 | change things related to the topic as patches against your 129 | "master", so if you need further changes, it is better to 130 | fork the topic (perhaps with the same name) afresh from the 131 | tip of "master". 132 | 133 | Let's look at this example: 134 | 135 | o---o---o---o---o---o---o---o---o---o "next" 136 | / / / / 137 | / a---a---b A / / 138 | / / / / 139 | / / c---c---c---c B / 140 | / / / \ / 141 | / / / b---b C \ / 142 | / / / / \ / 143 | ---o---o---o---o---o---o---o---o---o---o---o "master" 144 | 145 | 146 | A, B and C are topic branches. 147 | 148 | * A has one fix since it was merged up to "next". 149 | 150 | * B has finished. It has been fully merged up to "master" and "next", 151 | and is ready to be deleted. 152 | 153 | * C has not merged to "next" at all. 154 | 155 | We would want to allow C to be rebased, refuse A, and encourage 156 | B to be deleted. 157 | 158 | To compute (1): 159 | 160 | git rev-list ^master ^topic next 161 | git rev-list ^master next 162 | 163 | if these match, topic has not merged in next at all. 164 | 165 | To compute (2): 166 | 167 | git rev-list master..topic 168 | 169 | if this is empty, it is fully merged to "master". 170 | -------------------------------------------------------------------------------- /tests/TestTreeFilteringScripts.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Alexandre Mutel. All rights reserved. 2 | // Licensed under the BSD license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Linq; 5 | using LibGit2Sharp; 6 | using Xunit; 7 | using Xunit.Abstractions; 8 | 9 | namespace GitRocketFilter.Tests 10 | { 11 | /// 12 | /// Tests for tree-filtering with scripts: --keep, --keep-script, --remove, --remove-script options. 13 | /// 14 | public class TestTreeFilteringScripts : TestRepoBase 15 | { 16 | public TestTreeFilteringScripts(ITestOutputHelper outputHelper) : base(outputHelper) 17 | { 18 | } 19 | 20 | /// 21 | /// Keeps only non binary files less than 10 bytes 22 | /// 23 | [Fact] 24 | public void KeepOnlyNonBinaryFilesLessThan10Bytes() 25 | { 26 | var test = InitializeTest(); 27 | 28 | Assert.Equal(0, Program.Main("--keep", "* => entry.Discard = entry.IsBinary || entry.Size > 10; ", 29 | "--repo-dir", test.Path, 30 | "--branch", NewBranch, 31 | @"HEAD")); 32 | 33 | CheckKeepOnlyNonBinaryFilesLessThan10Bytes(test); 34 | 35 | // Cleanup the test only if we succeed 36 | test.Dispose(); 37 | } 38 | 39 | /// 40 | /// Keeps only non binary files less than 10 bytes (using multiline script 41 | /// 42 | [Fact] 43 | public void KeepOnlyNonBinaryFilesLessThan10BytesWithMultiLine() 44 | { 45 | var test = InitializeTest(); 46 | 47 | Assert.Equal(0, Program.Main("--keep", @"* {% 48 | entry.Discard = entry.IsBinary || entry.Size > 10; 49 | %}", 50 | "--repo-dir", test.Path, 51 | "--branch", NewBranch, 52 | @"HEAD")); 53 | 54 | CheckKeepOnlyNonBinaryFilesLessThan10Bytes(test); 55 | 56 | // Cleanup the test only if we succeed 57 | test.Dispose(); 58 | } 59 | 60 | /// 61 | /// Make sure that order is satisfied when using scripts (so first pattern is matched and stops). 62 | /// 63 | [Fact] 64 | public void PatternsScriptsOrder() 65 | { 66 | var test = InitializeTest(); 67 | 68 | Assert.Equal(0, Program.Main("--keep", "a.txt => entry.Discard = false;", 69 | "--keep", "* => entry.Discard = true;", 70 | "--repo-dir", test.Path, 71 | "--branch", NewBranch, 72 | @"HEAD")); 73 | 74 | var repo = test.Repo; 75 | var headNewMaster = AssertBranchRef(repo); 76 | 77 | var newCommits = GetCommits(repo, headNewMaster); 78 | 79 | Assert.Equal(1, newCommits.Count); 80 | 81 | var commit = newCommits[0]; 82 | { 83 | Assert.Equal(1, commit.Tree.Count); 84 | Assert.NotNull(commit.Tree["a.txt"]); 85 | } 86 | 87 | // Cleanup the test only if we succeed 88 | test.Dispose(); 89 | } 90 | 91 | /// 92 | /// Forget the closing multiline script %} 93 | /// 94 | [Fact] 95 | public void InvalidMultiLineScript() 96 | { 97 | var test = InitializeTest(); 98 | 99 | var result = Program.Main("--keep", @"* {% 100 | entry.Discard = entry.IsBinary || entry.Size > 10; 101 | ", 102 | "--repo-dir", test.Path, 103 | "--branch", NewBranch, 104 | @"HEAD"); 105 | 106 | Assert.NotEqual(0, result); 107 | 108 | Assert.Contains("Expecting the end %} of multiline script", test.Output); 109 | 110 | // Cleanup the test only if we succeed 111 | test.Dispose(); 112 | } 113 | 114 | /// 115 | /// Deletes all binary files bigger than 10 bytes 116 | /// 117 | [Fact] 118 | public void RemoveBinaryFilesBiggerThan10Bytes() 119 | { 120 | var test = InitializeTest(); 121 | 122 | Assert.Equal(0, Program.Main("--remove", "* => entry.Discard = entry.IsBinary && entry.Size > 10; ", 123 | "--repo-dir", test.Path, 124 | "--branch", NewBranch, 125 | @"HEAD")); 126 | 127 | var repo = test.Repo; 128 | var headNewMaster = AssertBranchRef(repo); 129 | 130 | var originalCommits = GetCommits(repo); 131 | var newCommits = GetCommits(repo, headNewMaster); 132 | 133 | // We have only a binary file in one commit, so we should have one commit less 134 | Assert.Equal(originalCommits.Count -1, newCommits.Count); 135 | 136 | foreach (var commit in newCommits) 137 | { 138 | var entries = GetEntries(commit.Tree).ToList(); 139 | 140 | foreach (var entry in entries) 141 | { 142 | var blob = (Blob)entry.Target; 143 | Assert.False(blob.IsBinary); 144 | } 145 | } 146 | 147 | // Cleanup the test only if we succeed 148 | test.Dispose(); 149 | } 150 | 151 | private static void CheckKeepOnlyNonBinaryFilesLessThan10Bytes(DisposeTempRepo test) 152 | { 153 | var repo = test.Repo; 154 | var headNewMaster = AssertBranchRef(repo); 155 | 156 | var newCommits = GetCommits(repo, headNewMaster); 157 | 158 | Assert.True(newCommits.Count > 0); 159 | 160 | foreach (var commit in newCommits) 161 | { 162 | var entries = GetEntries(commit.Tree).ToList(); 163 | 164 | foreach (var entry in entries) 165 | { 166 | var blob = (Blob) entry.Target; 167 | Assert.False(blob.IsBinary); 168 | Assert.True(blob.Size <= 10); 169 | } 170 | } 171 | } 172 | } 173 | } -------------------------------------------------------------------------------- /src/SimpleCommit.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Alexandre Mutel. All rights reserved. 2 | // Licensed under the BSD license. See LICENSE file in the project root for full license information. 3 | using System; 4 | using System.Collections.Generic; 5 | using LibGit2Sharp; 6 | 7 | namespace GitRocketFilter 8 | { 9 | /// 10 | /// Represents a git commit for scripting, with flattened properties with lower case name. 11 | /// 12 | public sealed class SimpleCommit 13 | { 14 | private readonly RocketFilterApp rocket; 15 | private readonly Commit commit; 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// The rocket. 21 | /// The commit. 22 | /// commit 23 | internal SimpleCommit(RocketFilterApp rocket, Commit commit) 24 | { 25 | if (commit == null) throw new ArgumentNullException("commit"); 26 | this.rocket = rocket; 27 | this.commit = commit; 28 | 29 | // Update all properties 30 | Reset(); 31 | } 32 | 33 | /// 34 | /// Gets the identifier. 35 | /// 36 | /// The identifier. 37 | public ObjectId Id 38 | { 39 | get { return commit.Id; } 40 | } 41 | 42 | /// 43 | /// Gets the sha identifier. 44 | /// 45 | /// The sha. 46 | public string Sha 47 | { 48 | get { return commit.Sha; } 49 | } 50 | 51 | /// 52 | /// Gets the encoding of the message. 53 | /// 54 | /// The encoding of the message. 55 | public string Encoding 56 | { 57 | get { return commit.Encoding; } 58 | } 59 | 60 | /// 61 | /// Gets or sets the author name. 62 | /// 63 | /// The author name. 64 | public string AuthorName { get; set; } 65 | 66 | /// 67 | /// Gets or sets the email. 68 | /// 69 | /// The email. 70 | public string AuthorEmail { get; set; } 71 | 72 | /// 73 | /// Gets or sets the date. 74 | /// 75 | /// The date. 76 | public DateTimeOffset AuthorDate { get; set; } 77 | 78 | /// 79 | /// Gets or sets the committer name. 80 | /// 81 | /// The author name. 82 | public string CommitterName { get; set; } 83 | 84 | /// 85 | /// Gets or sets the committer email. 86 | /// 87 | /// The email. 88 | public string CommitterEmail { get; set; } 89 | 90 | /// 91 | /// Gets or sets the committer date. 92 | /// 93 | /// The date. 94 | public DateTimeOffset CommitterDate { get; set; } 95 | 96 | /// 97 | /// Gets or sets the commit message. 98 | /// 99 | /// The message. 100 | public string Message { get; set; } 101 | 102 | /// 103 | /// Gets or sets the commit short message. 104 | /// 105 | /// The commit short message. 106 | public string MessageShort 107 | { 108 | get { return commit.MessageShort; } 109 | } 110 | 111 | /// 112 | /// Gets or sets the tree object. 113 | /// 114 | /// The tree. 115 | public Tree Tree { get; set; } 116 | 117 | /// 118 | /// Gets the parent commits. 119 | /// 120 | /// The parent commits. 121 | public IEnumerable Parents 122 | { 123 | get 124 | { 125 | foreach (var parentCommit in commit.Parents) 126 | { 127 | yield return rocket.GetSimpleCommit(parentCommit); 128 | } 129 | } 130 | } 131 | 132 | /// 133 | /// Gets or sets a value indicating whether this should be discarded. Default is false. 134 | /// 135 | /// true if this commit should be discarded; otherwise, false. 136 | public bool Discard { get; set; } 137 | 138 | /// 139 | /// Gets or sets a tag object. 140 | /// 141 | /// A tag object. 142 | public object Tag { get; set; } 143 | 144 | /// 145 | /// Gets the LibGit2 commit object. 146 | /// 147 | /// The LibGit2 commit object. 148 | public Commit GitCommit 149 | { 150 | get { return commit; } 151 | } 152 | 153 | /// 154 | /// Resets this values to the original commit. 155 | /// 156 | public void Reset() 157 | { 158 | AuthorName = commit.Author.Name; 159 | AuthorEmail = commit.Author.Email; 160 | AuthorDate = commit.Author.When; 161 | 162 | CommitterName = commit.Committer.Name; 163 | CommitterEmail = commit.Committer.Email; 164 | CommitterDate = commit.Committer.When; 165 | 166 | Message = commit.Message; 167 | 168 | Tree = commit.Tree; 169 | } 170 | 171 | public override string ToString() 172 | { 173 | return string.Format("id: {0}, name: {1}, email: {2}, date: {3}, messageShort: {4}", Id, AuthorName, AuthorEmail, AuthorDate, MessageShort); 174 | } 175 | 176 | /// 177 | /// Performs an implicit conversion from to . 178 | /// 179 | /// The commit. 180 | /// The result of the conversion. 181 | public static implicit operator Commit(SimpleCommit commit) 182 | { 183 | return commit != null ? commit.GitCommit : null; 184 | } 185 | } 186 | } -------------------------------------------------------------------------------- /tests/TestCommitFiltering.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Alexandre Mutel. All rights reserved. 2 | // Licensed under the BSD license. See LICENSE file in the project root for full license information. 3 | using System.Linq; 4 | using Xunit; 5 | using Xunit.Abstractions; 6 | 7 | namespace GitRocketFilter.Tests 8 | { 9 | /// 10 | /// Tests for commit filtering: --commit-filter option 11 | /// 12 | public class TestCommitFiltering : TestRepoBase 13 | { 14 | /// 15 | /// Initializes a new instance of the class. 16 | /// 17 | /// The output helper. 18 | public TestCommitFiltering(ITestOutputHelper outputHelper) : base(outputHelper) 19 | { 20 | } 21 | 22 | /// 23 | /// Appends the message "This is a test" to all commits. 24 | /// 25 | [Fact] 26 | public void ModifyCommitMessageAll() 27 | { 28 | var test = InitializeTest(); 29 | 30 | // Test directly the main program as we want to test also command line parameters 31 | Assert.Equal(0, Program.Main("--commit-filter", 32 | @"commit.Message += ""This is a test"";", 33 | "--repo-dir", test.Path, 34 | "--branch", NewBranch, 35 | @"HEAD")); 36 | 37 | var repo = test.Repo; 38 | var headNewMaster = AssertBranchRef(repo); 39 | 40 | var originalCommits = GetCommits(repo); 41 | var newCommits = GetCommits(repo, headNewMaster); 42 | 43 | // Make sure that we have the same number of commits 44 | Assert.Equal(originalCommits.Count, newCommits.Count); 45 | 46 | for (int i = 0; i < newCommits.Count; i++) 47 | { 48 | var originalCommit = originalCommits[i]; 49 | var commit = newCommits[i]; 50 | 51 | // All commits should have same tree id 52 | Assert.Equal(originalCommit.Tree.Id, commit.Tree.Id); 53 | 54 | // Check the new message 55 | Assert.EndsWith("This is a test", commit.Message); 56 | Assert.StartsWith(originalCommit.Message, commit.Message); 57 | } 58 | 59 | // Cleanup the test only if we succeed 60 | test.Dispose(); 61 | } 62 | 63 | /// 64 | /// Appends the message "This is a test" to the previous 4 commits. 65 | /// 66 | [Fact] 67 | public void ModifyCommitMessageLast4() 68 | { 69 | var test = InitializeTest(); 70 | 71 | // Test directly the main program as we want to test also command line parameters 72 | Assert.Equal(0, Program.Main("--commit-filter", 73 | @"commit.Message += ""This is a test"";", 74 | "--repo-dir", test.Path, 75 | "--branch", NewBranch, 76 | @"HEAD~4..HEAD")); 77 | 78 | var repo = test.Repo; 79 | var headNewMaster = AssertBranchRef(repo); 80 | 81 | var originalCommits = GetCommits(repo); 82 | var originalCommitsRange = GetCommitsFromRange(repo, @"HEAD~4..HEAD").Select(commit => commit.Id).ToList(); 83 | var newCommits = GetCommits(repo, headNewMaster); 84 | 85 | // Make sure that we have the same number of commits 86 | Assert.Equal(originalCommits.Count, newCommits.Count); 87 | 88 | for (int i = 0; i < newCommits.Count; i++) 89 | { 90 | var originalCommit = originalCommits[i]; 91 | var commit = newCommits[i]; 92 | 93 | if (originalCommitsRange.Contains(originalCommit.Id)) 94 | { 95 | // All commits should have same tree id 96 | Assert.Equal(originalCommit.Tree.Id, commit.Tree.Id); 97 | 98 | // Check the new message 99 | Assert.EndsWith("This is a test", commit.Message); 100 | Assert.StartsWith(originalCommit.Message, commit.Message); 101 | } 102 | else 103 | { 104 | // All commits should have same tree id 105 | Assert.Equal(originalCommit.Id, commit.Id); 106 | } 107 | } 108 | 109 | // Cleanup the test only if we succeed 110 | test.Dispose(); 111 | } 112 | 113 | /// 114 | /// Appends the message "This is a test" to the previous commit and detach it from its parent. 115 | /// 116 | [Fact] 117 | public void ModifyCommitMessageLast2WithDetach() 118 | { 119 | var test = InitializeTest(); 120 | 121 | // Test directly the main program as we want to test also command line parameters 122 | Assert.Equal(0, Program.Main("--commit-filter", 123 | @"commit.Message += ""This is a test"";", 124 | "--repo-dir", test.Path, 125 | "--branch", NewBranch, 126 | "--detach", 127 | @"HEAD~2..HEAD")); 128 | 129 | var repo = test.Repo; 130 | var headNewMaster = AssertBranchRef(repo); 131 | 132 | var originalCommits = GetCommitsFromRange(repo, @"HEAD~2..HEAD"); 133 | var newCommits = GetCommits(repo, headNewMaster); 134 | 135 | // Make sure that we have the same number of commits 136 | Assert.Equal(originalCommits.Count, newCommits.Count); 137 | 138 | for (int i = 0; i < newCommits.Count; i++) 139 | { 140 | var originalCommit = originalCommits[i]; 141 | var commit = newCommits[i]; 142 | 143 | // All commits should have same tree id 144 | Assert.Equal(originalCommit.Tree.Id, commit.Tree.Id); 145 | 146 | // Check the new message 147 | Assert.EndsWith("This is a test", commit.Message); 148 | Assert.StartsWith(originalCommit.Message, commit.Message); 149 | 150 | // The second commit is detached 151 | if (i == 1) 152 | { 153 | Assert.Equal(0, commit.Parents.Count()); 154 | } 155 | } 156 | 157 | // Cleanup the test only if we succeed 158 | test.Dispose(); 159 | } 160 | 161 | 162 | /// 163 | /// Discard all commits that don't contain the 'test.bin' text in their message. Rewrite author and committer of the commit left. 164 | /// 165 | [Fact] 166 | public void DiscardAllCommitMessageExceptOne() 167 | { 168 | var test = InitializeTest(); 169 | 170 | // Test directly the main program as we want to test also command line parameters 171 | Assert.Equal(0, Program.Main("--commit-filter", 172 | @"commit.Discard = !commit.Message.Contains(""test.bin""); if (!commit.Discard) { commit.AuthorName=""NewAuthor""; commit.AuthorEmail = ""test@gmail.com""; commit.CommitterName =""NewCommitter""; commit.CommitterEmail = ""test2@gmail.com""; }", 173 | "--repo-dir", test.Path, 174 | "--branch", NewBranch 175 | )); 176 | 177 | var repo = test.Repo; 178 | var headNewMaster = AssertBranchRef(repo); 179 | 180 | var newCommits = GetCommits(repo, headNewMaster); 181 | 182 | // We should have only 1 commit 183 | Assert.Equal(1, newCommits.Count); 184 | 185 | var commitLeft = newCommits[0]; 186 | Assert.Contains("test.bin", commitLeft.Message); 187 | 188 | // Check new field 189 | Assert.Equal("NewAuthor", commitLeft.Author.Name); 190 | Assert.Equal("test@gmail.com", commitLeft.Author.Email); 191 | Assert.Equal("NewCommitter", commitLeft.Committer.Name); 192 | Assert.Equal("test2@gmail.com", commitLeft.Committer.Email); 193 | 194 | // Cleanup the test only if we succeed 195 | test.Dispose(); 196 | } 197 | } 198 | } -------------------------------------------------------------------------------- /tests/TestRepoBase.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Alexandre Mutel. All rights reserved. 2 | // Licensed under the BSD license. See LICENSE file in the project root for full license information. 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Text; 8 | using LibGit2Sharp; 9 | using Xunit; 10 | using Xunit.Abstractions; 11 | 12 | namespace GitRocketFilter.Tests 13 | { 14 | public abstract class TestRepoBase 15 | { 16 | protected const string NewBranch = "new_master"; 17 | protected const string NewBranchRef = "refs/heads/new_master"; 18 | private readonly ITestOutputHelper outputHelper; 19 | 20 | protected TestRepoBase(ITestOutputHelper outputHelper) 21 | { 22 | this.outputHelper = outputHelper; 23 | } 24 | 25 | protected DisposeTempRepo InitializeTest([System.Runtime.CompilerServices.CallerMemberName] string memberName = "") 26 | { 27 | var path = AppDomain.CurrentDomain.BaseDirectory; 28 | var repoName = GetType().Name + "_" + memberName; 29 | var repoPath = Path.Combine(path, repoName); 30 | if (Directory.Exists(repoPath)) 31 | { 32 | RemoveDirectory(repoPath); 33 | } 34 | Directory.CreateDirectory(repoPath); 35 | var repoSourcePath = Path.Combine(path, @"..\..\..\test_repo\"); 36 | DirectoryCopy(repoSourcePath, repoPath, true); 37 | Directory.Move(Path.Combine(repoName, "dotgit"), Path.Combine(repoName, ".git")); 38 | 39 | var tempRepo = new DisposeTempRepo(repoPath); 40 | Program.RedirectOutput = new TextWriterRedirect(outputHelper, tempRepo.OutputBuilder); 41 | return tempRepo; 42 | } 43 | 44 | protected static string AssertBranchRef(Repository repo) 45 | { 46 | Assert.NotNull(repo.Refs[NewBranchRef]); 47 | return repo.Refs[NewBranchRef].TargetIdentifier; 48 | } 49 | 50 | protected static List GetCommits(Repository repo, string since = null) 51 | { 52 | var filter = new CommitFilter() {SortBy = CommitSortStrategies.Topological}; 53 | if (since != null) 54 | { 55 | filter.IncludeReachableFrom = since; 56 | } 57 | return 58 | repo.Commits.QueryBy(filter) 59 | .ToList(); 60 | } 61 | 62 | protected static List GetCommitsFromRange(Repository repo, string range) 63 | { 64 | return 65 | repo.Commits.QueryBy(new CommitFilter() {Range = range, SortBy = CommitSortStrategies.Topological}) 66 | .ToList(); 67 | } 68 | 69 | // http://stackoverflow.com/a/648055/1356325 70 | private static void RemoveDirectory(string directoryPath) 71 | { 72 | if (directoryPath == null) throw new ArgumentNullException("directoryPath"); 73 | RemoveDirectory(new DirectoryInfo(directoryPath)); 74 | } 75 | 76 | private static void RemoveDirectory(FileSystemInfo fileSystemInfo) 77 | { 78 | var directoryInfo = fileSystemInfo as DirectoryInfo; 79 | if (directoryInfo != null) 80 | { 81 | foreach (var childInfo in directoryInfo.GetFileSystemInfos()) 82 | { 83 | RemoveDirectory(childInfo); 84 | } 85 | } 86 | 87 | fileSystemInfo.Attributes = FileAttributes.Normal; 88 | fileSystemInfo.Delete(); 89 | } 90 | 91 | // https://msdn.microsoft.com/en-us/library/bb762914%28v=vs.110%29.aspx 92 | private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs) 93 | { 94 | // Get the subdirectories for the specified directory. 95 | DirectoryInfo dir = new DirectoryInfo(sourceDirName); 96 | DirectoryInfo[] dirs = dir.GetDirectories(); 97 | 98 | if (!dir.Exists) 99 | { 100 | throw new DirectoryNotFoundException( 101 | "Source directory does not exist or could not be found: " 102 | + sourceDirName); 103 | } 104 | 105 | // If the destination directory doesn't exist, create it. 106 | if (!Directory.Exists(destDirName)) 107 | { 108 | Directory.CreateDirectory(destDirName); 109 | } 110 | 111 | // Get the files in the directory and copy them to the new location. 112 | FileInfo[] files = dir.GetFiles(); 113 | foreach (FileInfo file in files) 114 | { 115 | string temppath = Path.Combine(destDirName, file.Name); 116 | file.CopyTo(temppath, false); 117 | } 118 | 119 | // If copying subdirectories, copy them and their contents to new location. 120 | if (copySubDirs) 121 | { 122 | foreach (DirectoryInfo subdir in dirs) 123 | { 124 | string temppath = Path.Combine(destDirName, subdir.Name); 125 | DirectoryCopy(subdir.FullName, temppath, copySubDirs); 126 | } 127 | } 128 | } 129 | 130 | protected static IEnumerable GetEntries(Tree tree) 131 | { 132 | foreach (var entry in tree) 133 | { 134 | if (entry.TargetType == TreeEntryTargetType.Tree) 135 | { 136 | var subTree = (Tree)entry.Target; 137 | foreach (var subEntry in GetEntries(subTree)) 138 | { 139 | yield return subEntry; 140 | } 141 | } 142 | else if (entry.TargetType == TreeEntryTargetType.Blob) 143 | { 144 | yield return entry; 145 | } 146 | } 147 | } 148 | 149 | protected struct DisposeTempRepo : IDisposable 150 | { 151 | private string text; 152 | 153 | public DisposeTempRepo(string path) 154 | { 155 | Path = path; 156 | Repo = new Repository(path); 157 | text = null; 158 | OutputBuilder = new StringBuilder(); 159 | } 160 | 161 | public readonly string Path; 162 | 163 | public readonly Repository Repo; 164 | 165 | public String Output 166 | { 167 | get { return text ?? (text = OutputBuilder.ToString()); } 168 | } 169 | 170 | internal readonly StringBuilder OutputBuilder; 171 | 172 | public void Dispose() 173 | { 174 | Repo.Dispose(); 175 | RemoveDirectory(Path); 176 | } 177 | } 178 | 179 | private class TextWriterRedirect : TextWriter 180 | { 181 | private readonly ITestOutputHelper outputHelper; 182 | private readonly StringBuilder globalLogger; 183 | private readonly StringBuilder buffer; 184 | 185 | public TextWriterRedirect(ITestOutputHelper outputHelper, StringBuilder globalLogger) 186 | { 187 | this.outputHelper = outputHelper; 188 | this.globalLogger = globalLogger; 189 | buffer = new StringBuilder(1024); 190 | } 191 | 192 | public override Encoding Encoding 193 | { 194 | get { return Encoding.UTF8; } 195 | } 196 | 197 | public override void Write(char value) 198 | { 199 | if (value == '\n') 200 | { 201 | var text = buffer.ToString(); 202 | outputHelper.WriteLine(text); 203 | globalLogger.AppendLine(text); 204 | buffer.Clear(); 205 | } 206 | else 207 | { 208 | buffer.Append(value); 209 | } 210 | } 211 | 212 | protected override void Dispose(bool disposing) 213 | { 214 | if (buffer.Length > 0) 215 | { 216 | var text = buffer.ToString(); 217 | outputHelper.WriteLine(text); 218 | globalLogger.AppendLine(text); 219 | buffer.Clear(); 220 | } 221 | base.Dispose(disposing); 222 | } 223 | } 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /tests/TestTreeFiltering.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Alexandre Mutel. All rights reserved. 2 | // Licensed under the BSD license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Linq; 5 | using LibGit2Sharp; 6 | using Xunit; 7 | using Xunit.Abstractions; 8 | 9 | namespace GitRocketFilter.Tests 10 | { 11 | /// 12 | /// Tests for tree-filtering: --keep, --keep-script, --remove, --remove-script options. 13 | /// 14 | public class TestTreeFiltering : TestRepoBase 15 | { 16 | public TestTreeFiltering(ITestOutputHelper outputHelper) : base(outputHelper) 17 | { 18 | } 19 | 20 | /// 21 | /// Keeps only /Test1 directory 22 | /// 23 | [Fact] 24 | public void KeepOnlyOneDirectory() 25 | { 26 | var test = InitializeTest(); 27 | 28 | Program.Main("--keep", 29 | @"/Test1", 30 | "--repo-dir", test.Path, 31 | "--branch", NewBranch, 32 | @"HEAD"); 33 | 34 | var repo = test.Repo; 35 | var headNewMaster = AssertBranchRef(repo); 36 | 37 | var newCommits = GetCommits(repo, headNewMaster); 38 | 39 | Assert.True(newCommits.Count > 0); 40 | 41 | for (int i = 0; i < newCommits.Count; i++) 42 | { 43 | var commit = newCommits[i]; 44 | Assert.Equal(1, commit.Tree.Count); 45 | 46 | var entry = commit.Tree["Test1"]; 47 | Assert.NotNull(entry); 48 | Assert.Equal(TreeEntryTargetType.Tree, entry.TargetType); 49 | 50 | var tree = (Tree) entry.Target; 51 | Assert.Equal(3, tree.Count); 52 | } 53 | 54 | // Cleanup the test only if we succeed 55 | test.Dispose(); 56 | } 57 | 58 | /// 59 | /// Keeps /Test1 directory and a.txt file 60 | /// 61 | [Fact] 62 | public void KeepOnlyOneDirectoryAndFile() 63 | { 64 | var test = InitializeTest(); 65 | 66 | Program.Main("--keep", "/Test1", 67 | "--keep", "a.txt", 68 | "--repo-dir", test.Path, 69 | "--branch", NewBranch, 70 | @"HEAD"); 71 | 72 | CheckKeepOnlyOneDirectoryAndFile(test); 73 | 74 | // Cleanup the test only if we succeed 75 | test.Dispose(); 76 | } 77 | 78 | /// 79 | /// Keeps /Test1 directory and a.txt file (version using --keep-script) 80 | /// 81 | [Fact] 82 | public void KeepAndKeepFromFile() 83 | { 84 | var test = InitializeTest(); 85 | 86 | Program.Main("--keep-script", "KeepPatternFile1.txt", 87 | "--keep", "a.txt", 88 | "--repo-dir", test.Path, 89 | "--branch", NewBranch, 90 | @"HEAD"); 91 | 92 | CheckKeepOnlyOneDirectoryAndFile(test); 93 | 94 | // Cleanup the test only if we succeed 95 | test.Dispose(); 96 | } 97 | 98 | private void CheckKeepOnlyOneDirectoryAndFile(DisposeTempRepo test) 99 | { 100 | var repo = test.Repo; 101 | var headNewMaster = AssertBranchRef(repo); 102 | 103 | var newCommits = GetCommits(repo, headNewMaster); 104 | 105 | Assert.True(newCommits.Count > 0); 106 | 107 | bool haveCommit2 = false; 108 | 109 | for (int i = 0; i < newCommits.Count; i++) 110 | { 111 | var commit = newCommits[i]; 112 | Assert.True(commit.Tree.Count == 1 || commit.Tree.Count == 2); 113 | 114 | Assert.NotNull(commit.Tree["a.txt"]); 115 | 116 | // /Test1 was added after a.txt 117 | if (commit.Tree.Count == 2) 118 | { 119 | haveCommit2 = true; 120 | var entry = commit.Tree["Test1"]; 121 | Assert.NotNull(entry); 122 | Assert.Equal(TreeEntryTargetType.Tree, entry.TargetType); 123 | 124 | var tree = (Tree)entry.Target; 125 | Assert.Equal(3, tree.Count); 126 | } 127 | } 128 | 129 | Assert.True(haveCommit2, "Missing commits for /Test1 folder"); 130 | } 131 | 132 | /// 133 | /// Removes all *.txt files 134 | /// 135 | [Fact] 136 | public void RemoveFilesWithTxtExtension() 137 | { 138 | var test = InitializeTest(); 139 | 140 | Program.Main("--remove", "*.txt", 141 | "--repo-dir", test.Path, 142 | "--branch", NewBranch, 143 | @"HEAD"); 144 | 145 | var repo = test.Repo; 146 | var headNewMaster = AssertBranchRef(repo); 147 | 148 | var newCommits = GetCommits(repo, headNewMaster); 149 | 150 | Assert.Equal(1, newCommits.Count); 151 | 152 | Assert.Equal(1, newCommits[0].Tree.Count); 153 | 154 | Assert.NotNull(newCommits[0].Tree["Binary/test.bin"]); 155 | 156 | // Cleanup the test only if we succeed 157 | test.Dispose(); 158 | } 159 | 160 | /// 161 | /// Keeps directory /Test[12], remove all files except a[12].txt 162 | /// 163 | [Fact] 164 | public void KeepTwoDirectoriesAndRemoveExcept() 165 | { 166 | var test = InitializeTest(); 167 | 168 | Program.Main("--keep", "/Test[12]", 169 | "--remove", "*", // removes all files 170 | "--remove", "!a[12].txt", // except a[12].txt 171 | "--repo-dir", test.Path, 172 | "--branch", NewBranch, 173 | @"HEAD"); 174 | 175 | CheckKeepTwoDirectoriesAndRemoveExcept(test); 176 | 177 | // Cleanup the test only if we succeed 178 | test.Dispose(); 179 | } 180 | 181 | /// 182 | /// Keeps directory /Test[12], remove all files except a[12].txt using --remove-script 183 | /// 184 | [Fact] 185 | public void KeepTwoDirectoriesAndRemoveFromFileExcept() 186 | { 187 | var test = InitializeTest(); 188 | 189 | Program.Main("--keep", "/Test[12]", 190 | "--remove-script", "RemovePatternFile1.txt", 191 | "--repo-dir", test.Path, 192 | "--branch", NewBranch, 193 | @"HEAD"); 194 | 195 | CheckKeepTwoDirectoriesAndRemoveExcept(test); 196 | 197 | // Cleanup the test only if we succeed 198 | test.Dispose(); 199 | } 200 | 201 | private static void CheckKeepTwoDirectoriesAndRemoveExcept(DisposeTempRepo test) 202 | { 203 | var repo = test.Repo; 204 | var headNewMaster = AssertBranchRef(repo); 205 | 206 | var newCommits = GetCommits(repo, headNewMaster); 207 | 208 | Assert.True(newCommits.Count > 0); 209 | 210 | for (int i = 0; i < newCommits.Count; i++) 211 | { 212 | var commit = newCommits[i]; 213 | 214 | var entries = GetEntries(commit.Tree).ToList(); 215 | 216 | // Check that we keps only a1/a2 217 | foreach (var entry in entries) 218 | { 219 | Assert.True(entry.Name == "a1.txt" || entry.Name == "a2.txt"); 220 | Assert.True(entry.Path.StartsWith("Test1") || entry.Path.StartsWith("Test2")); 221 | } 222 | } 223 | } 224 | 225 | [Fact] 226 | public void PreserveEmptyMergeCommit() 227 | { 228 | var test = InitializeTest(); 229 | 230 | Program.Main("--remove", "Test1", 231 | "--repo-dir", test.Path, 232 | "--branch", NewBranch, 233 | "--preserve-merge-commits"); 234 | 235 | var repo = test.Repo; 236 | var headNewMaster = AssertBranchRef(repo); 237 | 238 | var newCommits = GetCommits(repo, headNewMaster); 239 | 240 | // The merge commit should have survived 241 | var mergeCommit = newCommits.SingleOrDefault(c => c.Message.StartsWith("Merge branch 'modify_test1'")); 242 | Assert.NotNull(mergeCommit); 243 | Assert.Equal(2, mergeCommit.Parents.Count()); 244 | 245 | // Cleanup the test only if we succeed 246 | test.Dispose(); 247 | } 248 | } 249 | } -------------------------------------------------------------------------------- /src/SimpleEntry.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Alexandre Mutel. All rights reserved. 2 | // Licensed under the BSD license. See LICENSE file in the project root for full license information. 3 | using System; 4 | using System.IO; 5 | using System.Text; 6 | using LibGit2Sharp; 7 | 8 | namespace GitRocketFilter 9 | { 10 | /// 11 | /// Represents a git blob or link in a tree. 12 | /// 13 | public struct SimpleEntry 14 | { 15 | private readonly Repository repo; 16 | private readonly TreeEntry entry; 17 | private readonly GitObject target; 18 | private readonly GitLink link; 19 | private readonly Blob blob; 20 | 21 | internal EntryValue NewEntryValue; 22 | 23 | /// 24 | /// Initializes a new instance of the struct. 25 | /// 26 | /// The repo. 27 | /// The tree entry. 28 | /// 29 | /// repo 30 | /// or 31 | /// entry 32 | /// 33 | internal SimpleEntry(Repository repo, TreeEntry entry) 34 | : this() 35 | { 36 | if (repo == null) throw new ArgumentNullException("repo"); 37 | if (entry == null) throw new ArgumentNullException("entry"); 38 | this.repo = repo; 39 | this.entry = entry; 40 | target = entry.Target; 41 | this.blob = entry.Target as Blob; 42 | this.link = entry.Target as GitLink; 43 | } 44 | 45 | /// 46 | /// Gets the identifier object the blob or link object. 47 | /// 48 | /// The identifier. 49 | public ObjectId Id 50 | { 51 | get { return target.Id; } 52 | } 53 | 54 | /// 55 | /// Gets the text representation of . 56 | /// 57 | /// The sha. 58 | public string Sha 59 | { 60 | get { return target.Sha; } 61 | } 62 | 63 | /// 64 | /// Gets the name of this entry. 65 | /// 66 | /// The name. 67 | public string Name 68 | { 69 | get { return entry.Name; } 70 | } 71 | 72 | /// 73 | /// Gets the path of this entry. 74 | /// 75 | /// The path. 76 | public string Path 77 | { 78 | get { return entry.Path; } 79 | } 80 | 81 | /// 82 | /// Gets a value indicating whether this instance is a blob. 83 | /// 84 | /// true if this instance is a blob; otherwise, false. 85 | public bool IsBlob 86 | { 87 | get { return blob != null; } 88 | } 89 | 90 | /// 91 | /// Gets a value indicating whether this instance is binary blob. 92 | /// 93 | /// true if this instance is binary blob; otherwise, false. 94 | public bool IsBinary 95 | { 96 | get { return blob != null && blob.IsBinary; } 97 | } 98 | 99 | /// 100 | /// Gets a value indicating whether this instance is a git link. 101 | /// 102 | /// true if this instance is a git link; otherwise, false. 103 | public bool IsLink 104 | { 105 | get { return link != null; } 106 | } 107 | 108 | /// 109 | /// Gets the attributes of this entry. 110 | /// 111 | /// The attributes. 112 | public Mode Attributes 113 | { 114 | get { return entry.Mode; } 115 | } 116 | 117 | /// 118 | /// Gets the size of the blob or 0 if it is not a blob. 119 | /// 120 | /// The size. 121 | public long Size 122 | { 123 | get { return blob != null ? blob.Size : 0; } 124 | } 125 | 126 | /// 127 | /// Gets or sets a value indicating whether this should be discarded. Default is false. 128 | /// 129 | /// true if this commit should be discarded; otherwise, false. 130 | public bool Discard { get; set; } 131 | 132 | /// 133 | /// Gets or sets a tag object. 134 | /// 135 | /// A tag object. 136 | public object Tag { get; set; } 137 | 138 | /// 139 | /// Gets the content of the blob as a byte array. 140 | /// 141 | /// The content of the blob as a byte array or null if no blob. 142 | public byte[] GetBlobAsBytes() 143 | { 144 | if (blob == null) 145 | { 146 | return null; 147 | } 148 | 149 | var stream = blob.GetContentStream(); 150 | var memoryStream = new MemoryStream(); 151 | stream.CopyTo(memoryStream); 152 | memoryStream.Position = 0; 153 | return memoryStream.ToArray(); 154 | } 155 | 156 | /// 157 | /// Gets the content of the blob as a stream. 158 | /// 159 | /// The content of the blob as a stream or null if no blob. 160 | public Stream GetBlobAsStream() 161 | { 162 | if (blob != null) 163 | { 164 | return blob.GetContentStream(); 165 | } 166 | return null; 167 | } 168 | 169 | /// 170 | /// Gets the content of the blob as a text. 171 | /// 172 | /// The content of the blob as a text or null if no blob. 173 | public string GetBlobAsText() 174 | { 175 | if (blob != null) 176 | { 177 | return blob.GetContentText(); 178 | } 179 | return null; 180 | } 181 | 182 | /// 183 | /// Replace the content of this entry by a stream. 184 | /// 185 | /// The content stream. 186 | /// The mode. 187 | /// content 188 | public void SetBlob(Stream content, Mode mode = Mode.NonExecutableFile) 189 | { 190 | if (content == null) throw new ArgumentNullException("content"); 191 | var newBlob = repo.ObjectDatabase.CreateBlob(content); 192 | SetBlob(newBlob, mode); 193 | } 194 | 195 | /// 196 | /// Replace the content of this entry by a byte array. 197 | /// 198 | /// The content byte array. 199 | /// The mode. 200 | /// content 201 | public void SetBlob(byte[] content, Mode mode = Mode.NonExecutableFile) 202 | { 203 | if (content == null) throw new ArgumentNullException("content"); 204 | var newBlob = repo.ObjectDatabase.CreateBlob(new MemoryStream(content)); 205 | SetBlob(newBlob, mode); 206 | } 207 | 208 | /// 209 | /// Replace the content of this entry by a string. 210 | /// 211 | /// The content string. 212 | /// The mode. 213 | /// content 214 | public void SetBlob(string content, Mode mode = Mode.NonExecutableFile) 215 | { 216 | SetBlob(content, Encoding.UTF8, mode); 217 | } 218 | 219 | /// 220 | /// Replace the content of this entry by a string with a particular encoding. 221 | /// 222 | /// The content string. 223 | /// The encoding mode for the string. 224 | /// The mode. 225 | /// content 226 | public void SetBlob(string content, Encoding encoding, Mode mode = Mode.NonExecutableFile) 227 | { 228 | if (content == null) throw new ArgumentNullException("content"); 229 | var newBlob = repo.ObjectDatabase.CreateBlob(new MemoryStream(encoding.GetBytes(content))); 230 | SetBlob(newBlob, mode); 231 | } 232 | 233 | /// 234 | /// Replace the content of this entry by a blob. 235 | /// 236 | /// The content blob. 237 | /// The mode. 238 | /// content 239 | public void SetBlob(Blob newBlob, Mode mode = Mode.NonExecutableFile) 240 | { 241 | if (newBlob == null) throw new ArgumentNullException("newBlob"); 242 | NewEntryValue = new EntryValue(newBlob, mode); 243 | } 244 | 245 | /// 246 | /// Performs an implicit conversion from to . 247 | /// 248 | /// The entry. 249 | /// The result of the conversion. 250 | public static implicit operator TreeEntry(SimpleEntry entry) 251 | { 252 | return entry.entry; 253 | } 254 | 255 | public override string ToString() 256 | { 257 | return string.Format("Entry: {0} => {1}", Path, Id); 258 | } 259 | 260 | internal struct EntryValue 261 | { 262 | public EntryValue(Blob blob, Mode mode) 263 | { 264 | Blob = blob; 265 | Mode = mode; 266 | } 267 | 268 | public readonly Blob Blob; 269 | 270 | public readonly Mode Mode; 271 | } 272 | } 273 | } -------------------------------------------------------------------------------- /src/Program.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Alexandre Mutel. All rights reserved. 2 | // Licensed under the BSD license. See LICENSE file in the project root for full license information. 3 | using System; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using LibGit2Sharp; 8 | using Mono.Options; 9 | 10 | namespace GitRocketFilter 11 | { 12 | /// 13 | /// Main entry point for git-rocket-filter 14 | /// 15 | public class Program 16 | { 17 | [ThreadStatic] 18 | public static TextWriter RedirectOutput; 19 | 20 | public static int Main(params string[] args) 21 | { 22 | var rocket = new RocketFilterApp(); 23 | 24 | if (RedirectOutput == null) 25 | { 26 | RedirectOutput = Console.Out; 27 | } 28 | rocket.OutputWriter = RedirectOutput; 29 | 30 | var exeName = Path.GetFileNameWithoutExtension(typeof(Program).Assembly.Location); 31 | bool showHelp = false; 32 | var keeps = new StringBuilder(); 33 | var removes = new StringBuilder(); 34 | 35 | string repositoryPath = Environment.CurrentDirectory; 36 | 37 | 38 | var _ = string.Empty; 39 | var options = new OptionSet 40 | { 41 | "Copyright (C) 2015 Alexandre Mutel. All Rights Reserved", 42 | "git-rocket-filter - Version: " 43 | + 44 | String.Format( 45 | "{0}.{1}.{2}", 46 | typeof (Program).Assembly.GetName().Version.Major, 47 | typeof (Program).Assembly.GetName().Version.Minor, 48 | typeof (Program).Assembly.GetName().Version.Build) + string.Empty, 49 | _, 50 | string.Format("Usage: {0} --branch [options]+ [revspec]", exeName), 51 | _, 52 | "A single [revspec] is currently supported (either HEAD, commit-id, or a from..to). Default is HEAD ", 53 | _, 54 | "## Options", 55 | _, 56 | {"b|branch=", "All filtering will be created into the new branch specified by the {}.", v=> rocket.BranchName = v}, 57 | _, 58 | {"force", "If a branch is specified and a branch with the same name already exists, it will be overwritten.", (bool v) => rocket.BranchOverwrite = v}, 59 | _, 60 | {"h|help", "Show this message and exit", (bool v) => showHelp = v}, 61 | {"v|verbose", "Show more verbose progress logs", (bool v) => rocket.Verbose = v}, 62 | {"d|repo-dir=", "By default git-rocket-filter is running in the current directory expected to be a git repository. You can change this repository by passing a new repository path with this option", v => repositoryPath = v }, 63 | {"disable-threads", "By default git-rocket-filter is running on multiple threads. This option allow to disable this feature.", (bool v) => rocket.DisableTasks = v }, 64 | {"preserve-merge-commits", "By default git-rocket-filter removes merge commits that don't contain any changes compared to one of the parents. This option ensures that such 'empty' merge commits are preserved.", (bool v) => rocket.PreserveMergeCommits = v }, 65 | _, 66 | "## Options for commit filtering", 67 | _, 68 | {"c|commit-filter=", "Perform a rewrite of each commit by passing an {}. If the is true, the commit is kept, otherwise it is skipped. See Examples.", v => rocket.CommitFilter = v}, 69 | {"commit-filter-script=", "Perform a rewrite of each commit by passing a file {