From 61346636d132419234f8dc9a2041b3e8877165a6 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Sun, 9 Sep 2012 17:38:31 +0100 Subject: Move luacov out to a submodule --- .gitmodules | 3 + extras/luacov | 1 + extras/luacov/Makefile | 26 ----- extras/luacov/README.md | 79 ------------- extras/luacov/doc/doc.css | 223 ------------------------------------ extras/luacov/doc/index.html | 200 -------------------------------- extras/luacov/doc/license.html | 113 ------------------ extras/luacov/doc/luacov.png | Bin 8420 -> 0 bytes extras/luacov/luacov-0.2-1.rockspec | 28 ----- extras/luacov/src/bin/luacov | 142 ----------------------- extras/luacov/src/luacov.lua | 95 --------------- extras/luacov/src/luacov/stats.lua | 73 ------------ extras/luacov/src/luacov/tick.lua | 7 -- 13 files changed, 4 insertions(+), 986 deletions(-) create mode 100644 .gitmodules create mode 160000 extras/luacov delete mode 100644 extras/luacov/Makefile delete mode 100644 extras/luacov/README.md delete mode 100644 extras/luacov/doc/doc.css delete mode 100644 extras/luacov/doc/index.html delete mode 100644 extras/luacov/doc/license.html delete mode 100644 extras/luacov/doc/luacov.png delete mode 100644 extras/luacov/luacov-0.2-1.rockspec delete mode 100755 extras/luacov/src/bin/luacov delete mode 100644 extras/luacov/src/luacov.lua delete mode 100644 extras/luacov/src/luacov/stats.lua delete mode 100644 extras/luacov/src/luacov/tick.lua diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..8f93b7c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "extras/luacov"] + path = extras/luacov + url = git://git.gitano.org.uk/luacov.git diff --git a/extras/luacov b/extras/luacov new file mode 160000 index 0000000..fe10d23 --- /dev/null +++ b/extras/luacov @@ -0,0 +1 @@ +Subproject commit fe10d23a7c6eb6fbe37c3fba1afc10817629a60a diff --git a/extras/luacov/Makefile b/extras/luacov/Makefile deleted file mode 100644 index 1518bbf..0000000 --- a/extras/luacov/Makefile +++ /dev/null @@ -1,26 +0,0 @@ - -PACKAGE=luacov -VERSION=0.3 -PREFIX=/usr/local -BINDIR=$(PREFIX)/bin -LUADIR=$(PREFIX)/share/lua/5.1/ - -install: - mkdir -p $(BINDIR) - cp src/bin/luacov $(BINDIR) - mkdir -p $(LUADIR) - cp src/luacov.lua $(LUADIR) - mkdir -p $(LUADIR)/luacov - cp src/luacov/stats.lua $(LUADIR)/luacov - cp src/luacov/tick.lua $(LUADIR)/luacov - -dist: - rm -f dist.files - rm -rf $(PACKAGE)-$(VERSION) - rm -f $(PACKAGE)-$(VERSION).tar.gz - find * | grep -v CVS > dist.files - mkdir -p $(PACKAGE)-$(VERSION) - cpio -p $(PACKAGE)-$(VERSION) < dist.files - tar czvf $(PACKAGE)-$(VERSION).tar.gz $(PACKAGE)-$(VERSION) - rm -f dist.files - rm -rf $(PACKAGE)-$(VERSION) diff --git a/extras/luacov/README.md b/extras/luacov/README.md deleted file mode 100644 index efc31c5..0000000 --- a/extras/luacov/README.md +++ /dev/null @@ -1,79 +0,0 @@ -## Overview - -LuaCov is a simple coverage analyzer for [Lua](http://www.lua.org) -scripts. When a Lua script is run with the `luacov` module loaded, it -generates a stats file with the number of executions of each line of the -script and its loaded modules. The `luacov` command-line script then -processes this file generating a report file which allows one to visualize -which code paths were not traversed, which is useful for verifying the -effectiveness of a test suite. - -LuaCov is free software and, like Lua, is released under the -[MIT License](http://www.lua.org/license.html). - -## Download and Installation - -LuaCov can be downloaded from its -[LuaForge page](http://luaforge.net/projects/luacov/files). - -It can also be installed using Luarocks: - - luarocks install luacov - -LuaCov is written in pure Lua and has no external dependencies. - -## Instructions - -Using LuaCov consists of two steps: running your script to collect -coverage data, and then running `luacov` on the collected data to -generate a report. - -To collect coverage data, your script needs to load the `luacov` -Lua module. This can be done from the command-line, without modifying -your script, like this: - - lua -lluacov test.lua - -Alternatively, you can add `require("luacov")` to the first line -of your script. - -Once the script is run, a file called `lcov.stats.out` is generated. -If the file already exists, statistics are _added_ to it. This is useful, -for example, for making a series of runs with different input parameters in -a test suite. To start the accounting from scratch, just delete the stats file. - -To generate a report, just run the `luacov` command-line script. -It expects to find a file named `lcov.stats.out` in the current -directory, and outputs a file named `lcov.report.out`. - -This is an example output of the report file: - - ============================================================ - ../test.lua - ============================================================ - - -- Which branch will run? - 1 if 10 > 100 then - 0 print("I don't think this line will execute.") - 0 else - 1 print("Hello, LuaCov!") - 1 end - -Note that to generate this report, `luacov` reads the source files. -Therefore, it expects to find them in the same location they were when -the `luacov` module ran (the stats file stores the filenames, but -not the sources themselves). - -LuaCov saves its stats upon normal program termination. If your program -is a daemon -- in other words, if it does not terminate normally -- you -can use the `luacov.tick` module, which periodically saves the -stats file. For example, to run (on Unix systems) LuaCov on -[Xavante](http://www.keplerproject.org/xavante), -just modify the first line of `xavante_start.lua` so it reads: - - #!/usr/bin/env lua -lluacov.tick - -## Credits - -LuaCov was designed and implemented by Hisham Muhammad as a tool for -testing [Luarocks](http://luarocks.luaforge.net). diff --git a/extras/luacov/doc/doc.css b/extras/luacov/doc/doc.css deleted file mode 100644 index 3770e4e..0000000 --- a/extras/luacov/doc/doc.css +++ /dev/null @@ -1,223 +0,0 @@ -body { - margin-left: 1em; - margin-right: 1em; - font-family: arial, helvetica, geneva, sans-serif; - background-color:#ffffff; margin:0px; -} - -code { - font-family: "Andale Mono", monospace; -} - -tt { - font-family: "Andale Mono", monospace; -} - -body, td, th { font-size: 11pt; } - -h1, h2, h3, h4 { margin-left: 0em; } - -textarea, pre, tt { font-size:10pt; } -body, td, th { color:#000000; } -small { font-size:0.85em; } -h1 { font-size:1.5em; } -h2 { font-size:1.25em; } -h3 { font-size:1.15em; } -h4 { font-size:1.06em; } - -a:link { font-weight:bold; color: #004080; text-decoration: none; } -a:visited { font-weight:bold; color: #006699; text-decoration: none; } -a:link:hover { text-decoration:underline; } -hr { color:#cccccc } -img { border-width: 0px; } - - -h3 { padding-top: 1em; } - -p { margin-left: 1em; } - -p.name { - font-family: "Andale Mono", monospace; - padding-top: 1em; - margin-left: 0em; -} - -blockquote { margin-left: 3em; } - -.example { - background-color: rgb(245, 245, 245); - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-style: solid; - border-right-style: solid; - border-bottom-style: solid; - border-left-style: solid; - border-top-color: silver; - border-right-color: silver; - border-bottom-color: silver; - border-left-color: silver; - padding: 1em; - margin-left: 1em; - margin-right: 1em; - font-family: "Andale Mono", monospace; - font-size: smaller; -} - - -hr { - margin-left: 0em; - background: #00007f; - border: 0px; - height: 1px; -} - -ul { list-style-type: disc; } - -table.index { border: 1px #00007f; } -table.index td { text-align: left; vertical-align: top; } -table.index ul { padding-top: 0em; margin-top: 0em; } - -table { - border: 1px solid black; - border-collapse: collapse; - margin-left: auto; - margin-right: auto; -} -th { - border: 1px solid black; - padding: 0.5em; -} -td { - border: 1px solid black; - padding: 0.5em; -} -div.header, div.footer { margin-left: 0em; } - -#container -{ - margin-left: 1em; - margin-right: 1em; - background-color: #f0f0f0; -} - -#product -{ - text-align: center; - border-bottom: 1px solid #cccccc; - background-color: #ffffff; -} - -#product big { - font-size: 2em; -} - -#product_logo -{ -} - -#product_name -{ -} - -#product_description -{ -} - -#main -{ - background-color: #f0f0f0; - border-left: 2px solid #cccccc; -} - -#navigation -{ - float: left; - width: 12em; - margin: 0; - vertical-align: top; - background-color: #f0f0f0; - overflow:visible; -} - -#navigation h1 { - background-color:#e7e7e7; - font-size:1.1em; - color:#000000; - text-align:left; - margin:0px; - padding:0.2em; - border-top:1px solid #dddddd; - border-bottom:1px solid #dddddd; -} - -#navigation ul -{ - font-size:1em; - list-style-type: none; - padding: 0; - margin: 1px; -} - -#navigation li -{ - text-indent: -1em; - margin: 0em 0em 0em 0.5em; - display: block; - padding: 3px 0px 0px 12px; -} - -#navigation li li a -{ - padding: 0px 3px 0px -1em; -} - -#content -{ - margin-left: 12em; - padding: 1em; - border-left: 2px solid #cccccc; - border-right: 2px solid #cccccc; - background-color: #ffffff; -} - -#about -{ - clear: both; - margin: 0; - padding: 5px; - border-top: 2px solid #cccccc; - background-color: #ffffff; -} - -@media print { - body { - font: 10pt "Times New Roman", "TimeNR", Times, serif; - } - a { font-weight:bold; color: #004080; text-decoration: underline; } - - #main { background-color: #ffffff; border-left: 0px; } - #container { margin-left: 2%; margin-right: 2%; background-color: #ffffff; } - - #content { margin-left: 0px; padding: 1em; border-left: 0px; border-right: 0px; background-color: #ffffff; } - - #navigation { display: none; - } - - #product_logo - { - display: none; - } - - #about img - { - display: none; - } - - .example { - font-family: "Andale Mono", monospace; - font-size: 8pt; - page-break-inside: avoid; - } -} diff --git a/extras/luacov/doc/index.html b/extras/luacov/doc/index.html deleted file mode 100644 index ed451a2..0000000 --- a/extras/luacov/doc/index.html +++ /dev/null @@ -1,200 +0,0 @@ - - - - LuaCov - Coverage analysis for Lua scripts - - - - - - - -
- -
- -
LuaCov
-
Coverage analysis for Lua scripts
-
- -
- - - -
- -

Overview

- -

-LuaCov is a simple coverage analyzer for Lua -scripts. When a Lua script is run with the luacov module loaded, it -generates a stats file with the number of executions of each line of the -script and its loaded modules. The luacov command-line script then -processes this file generating a report file which allows one to visualize -which code paths were not traversed, which is useful for verifying the -effectiveness of a test suite. -

- -

-LuaCov is free software and uses the same license as Lua. -

- -

Download

- -

-LuaCov can be downloaded from its -LuaForge page. -

- -

-LuaCov is written in pure Lua and has no external dependencies. -

- -

Instructions

- -

-Using LuaCov consists of two steps: running your script to collect -coverage data, and then running luacov on the collected data to -generate a report. -

- -

-To collect coverage data, your script needs to load the luacov -Lua module. This can be done from the command-line, without modifying -your script, like this: -

- -
-lua -lluacov test.lua -
- -

-(Alternatively, you can add require("luacov") to the first line -of your script.) -

- -

-Once the script is run, a file called lcov.stats.out is generated. -If the file already exists, statistics are added to it. This is useful, -for example, for making a series of runs with different input parameters in -a test suite. To start the accounting from scratch, just delete the stats file. -

- -

-To generate a report, just run the luacov command-line script. -It expects to find a file named lcov.stats.out in the current -directory, and outputs a file named lcov.report.out. -

- -

This is an example output of the report file:

- -
-============================================================
-../test.lua
-============================================================
-
-        -- Which branch will run?
-1       if 10 > 100 then
-0          print("I don't think this line will execute.")
-0       else
-1          print("Hello, LuaCov!")
-1       end
-
- -

-Note that to generate this report, luacov reads the source files. -Therefore, it expects to find them in the same location they were when -the luacov module ran (the stats file stores the filenames, but -not the sources themselves). -

- -

-LuaCov saves its stats upon normal program termination. If your program -is a daemon -- in other words, if it does not terminate normally -- you -can use the luacov.tick module, which periodically saves the -stats file. For example, to run (on Unix systems) LuaCov on -Xavante, -just modify the first line of xavante_start.lua so it reads: -

- -
-#!/usr/bin/env lua -lluacov.tick -
- -

History

- -
-
0.1 [July 16, 2007]
-
-
    -
  • Initial release.
  • -
-
-
- -

Credits

- -

-LuaCov was designed and implemented by Hisham Muhammad as a tool for -testing LuaRocks. -

- -

Contact

- -

-For more information please -contact us. Comments are welcome! -

- -
- -
- -
-

- Valid XHTML 1.0!

-
- -
- - - diff --git a/extras/luacov/doc/license.html b/extras/luacov/doc/license.html deleted file mode 100644 index afbb9f6..0000000 --- a/extras/luacov/doc/license.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - LuaCov - Coverage analysis for Lua scripts - - - - - - -
- -
- -
LuaCov
-
Coverage analysis for Lua scripts
-
- -
- - - -
- -

License

- -

-LuaCov is free software: it can be used for both academic and commercial purposes -at absolutely no cost. There are no royalties or GNU-like "copyleft" restrictions. -LuaCov qualifies as Open Source software. -Its licenses are compatible with GPL. -LuaCov is not in the public domain. The legal details are below. -

- -

-The spirit of the license is that you are free to use LuaCov for any purpose -at no cost without having to ask us. The only requirement is that if you do use -LuaCov, then you should give us credit by including the appropriate copyright notice -somewhere in your product or its documentation. -

- -

-LuaCov is designed and implemented by Hisham Muhammad. -The implementation is not derived from licensed software. -

- -
- -

Copyright (c) 2007 Hisham Muhammad.

- -

-Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -

- -

-The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -

- -

-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -

- -
- -
- -
-

- Valid XHTML 1.0!

-
- -
- - - diff --git a/extras/luacov/doc/luacov.png b/extras/luacov/doc/luacov.png deleted file mode 100644 index 1cf37b7..0000000 Binary files a/extras/luacov/doc/luacov.png and /dev/null differ diff --git a/extras/luacov/luacov-0.2-1.rockspec b/extras/luacov/luacov-0.2-1.rockspec deleted file mode 100644 index 37eff94..0000000 --- a/extras/luacov/luacov-0.2-1.rockspec +++ /dev/null @@ -1,28 +0,0 @@ -package = "LuaCov" -version = "0.2-1" -source = { - url = "http://luaforge.net/frs/download.php/4053/luacov-0.2.tar.gz" -} -description = { - summary = "Coverage analysis tool for Lua scripts", - detailed = [[ - LuaCov is a simple coverage analysis tool for Lua scripts. - When a Lua script is run with the luacov module, it - generates a stats file. The luacov command-line script then - processes this file generating a report indicating which code - paths were not traversed, which is useful for verifying the - effectiveness of a test suite. - ]], - license = "MIT/X11", - homepage = "http://luacov.luaforge.net/" -} -dependencies = { - "lua >= 5.0", -} -build = { - type = "make", - variables = { - LUADIR = "$(LUADIR)", - BINDIR = "$(BINDIR)" - } -} diff --git a/extras/luacov/src/bin/luacov b/extras/luacov/src/bin/luacov deleted file mode 100755 index 6a24bc6..0000000 --- a/extras/luacov/src/bin/luacov +++ /dev/null @@ -1,142 +0,0 @@ -#!/usr/bin/env lua - -local luacov = require("luacov.stats") - -local data, most_hits = luacov.load() - -if not data then - print("Could not load stats file "..luacov.statsfile..".") - print("Run your Lua program with -lluacov and then rerun luacov.") - os.exit(1) -end - -local report = io.open("luacov.report.out", "w") - --- only report on files specified on the command line -local patterns = {} -local exclude_patterns = {} -local exclude_next = false -for i = 1, #arg do - if arg[i] == "-X" then - exclude_next = true - else - if exclude_next then - exclude_patterns[#exclude_patterns+1] = arg[i] - exclude_next = false - else - patterns[#patterns+1] = arg[i] - end - end -end - -local names = {} -for filename, _ in pairs(data) do - if not patterns[1] then - table.insert(names, filename) - else - local path = filename:gsub("/", "."):gsub("%.lua$", "") - local include = false - for _, p in ipairs(patterns) do - if path:match(p) then - include = true - break - end - end - if include then - for _, p in ipairs(exclude_patterns) do - if path:match(p) then - include = false - break - end - end - end - if include then - table.insert(names, filename) - end - end -end - -table.sort(names) - -local most_hits_length = ("%d"):format(most_hits):len() -local empty_format = (" "):rep(most_hits_length+1) -local false_negative_format = ("!%% %dd"):format(most_hits_length) -local zero_format = ("*"):rep(most_hits_length).."0" -local count_format = ("%% %dd"):format(most_hits_length+1) - -local exclusions = -{ - { false, "^#!" }, -- Unix hash-bang magic line - { true, "" }, -- Empty line - { true, "}" }, -- Just a close-brace - { true, "end,?" }, -- Single "end" - { true, "else" }, -- Single "else" - { true, "repeat" }, -- Single "repeat" - { true, "do" }, -- Single "do" - { true, "local%s+[%w_,%s]+" }, -- "local var1, ..., varN" - { true, "local%s+[%w_,%s]+%s*=" }, -- "local var1, ..., varN =" - { true, "local%s+function%s*%([%w_,%.%s]*%)" }, -- "local function(arg1, ..., argN)" - { true, "local%s+function%s+[%w_]*%s*%([%w_,%.%s]*%)" }, -- "local function f (arg1, ..., argN)" -} - -local function excluded(line) - for _, e in ipairs(exclusions) do - if e[1] then - if line:match("^%s*"..e[2].."%s*$") or line:match("^%s*"..e[2].."%s*%-%-") then return true end - else - if line:match(e[2]) then return true end - end - end - return false -end - -for _, filename in ipairs(names) do - local filedata = data[filename] - local file = io.open(filename, "r") - if file then - report:write("\n") - report:write("==============================================================================\n") - report:write(filename, "\n") - report:write("==============================================================================\n") - local line_nr = 1 - block_comment, equals = false, "" - while true do - local line = file:read("*l") - if not line then break end - local true_line = line - - local new_block_comment = false - if not block_comment then - local l, equals = line:match("^(.*)%-%-%[(=*)%[") - if l then - line = l - new_block_comment = true - end - else - local l = line:match("%]"..equals.."%](.*)$") - if l then - line = l - block_comment = false - end - end - - local hits = filedata[line_nr] or 0 - if block_comment or excluded(line) then - if hits > 0 then - report:write(false_negative_format:format(hits)) - else - report:write(empty_format) - end - else - if hits == 0 then - report:write(zero_format) - else - report:write(count_format:format(hits)) - end - end - report:write("\t", true_line, "\n") - if new_block_comment then block_comment = true end - line_nr = line_nr + 1 - end - end -end diff --git a/extras/luacov/src/luacov.lua b/extras/luacov/src/luacov.lua deleted file mode 100644 index a44333a..0000000 --- a/extras/luacov/src/luacov.lua +++ /dev/null @@ -1,95 +0,0 @@ - -local M = {} - -local stats = require("luacov.stats") -local data = stats.load() -local statsfile = stats.start() -M.statsfile = statsfile - -local tick = package.loaded["luacov.tick"] -local ctr = 0 -local luacovlock = os.tmpname() - -local booting = true -local skip = {} -M.skip = skip - -local function on_line(_, line_nr) - if tick then - ctr = ctr + 1 - if ctr == 100 then - ctr = 0 - stats.save(data, statsfile) - end - end - - -- get name of processed file; ignore Lua code loaded from raw strings - local name = debug.getinfo(2, "S").source - if not name:match("^@") then - return - end - name = name:sub(2) - - -- skip 'luacov.lua' in coverage report - if booting then - skip[name] = true - booting = false - end - - if skip[name] then - return - end - - local file = data[name] - if not file then - file = {max=0} - data[name] = file - end - if line_nr > file.max then - file.max = line_nr - end - file[line_nr] = (file[line_nr] or 0) + 1 -end - -local function on_exit() - os.remove(luacovlock) - stats.save(data, statsfile) - stats.stop(statsfile) -end - -local function init() - if not tick then - M.on_exit_trick = io.open(luacovlock, "w") - debug.setmetatable(M.on_exit_trick, { __gc = on_exit } ) - end - - debug.sethook(on_line, "l") - - local rawcoroutinecreate = coroutine.create - coroutine.create = function(...) - local co = rawcoroutinecreate(...) - debug.sethook(co, on_line, "l") - return co - end - coroutine.wrap = function(...) - local co = rawcoroutinecreate(...) - debug.sethook(co, on_line, "l") - return function() - local r = { coroutine.resume(co) } - if not r[1] then - error(r[2]) - end - return unpack(r, 2) - end - end - - local rawexit = os.exit - os.exit = function(...) - on_exit() - rawexit(...) - end -end - -init() - -return M diff --git a/extras/luacov/src/luacov/stats.lua b/extras/luacov/src/luacov/stats.lua deleted file mode 100644 index 5390c75..0000000 --- a/extras/luacov/src/luacov/stats.lua +++ /dev/null @@ -1,73 +0,0 @@ - -local M = {} - -local statsfile = "luacov.stats.out" -local stats - -function M.load() - local data, most_hits = {}, 0 - stats = io.open(statsfile, "r") - if not stats then - return data - end - while true do - local nlines = stats:read("*n") - if not nlines then - break - end - local skip = stats:read(1) - if skip ~= ":" then - break - end - local filename = stats:read("*l") - if not filename then - break - end - data[filename] = { - max=nlines - } - for i = 1, nlines do - local hits = stats:read("*n") - if not hits then - break - end - local skip = stats:read(1) - if skip ~= " " then - break - end - if hits > 0 then - data[filename][i] = hits - most_hits = math.max(most_hits, hits) - end - end - end - stats:close() - return data, most_hits -end - -function M.start() - return io.open(statsfile, "w") -end - -function M.stop(stats) - stats:close() -end - -function M.save(data, stats) - stats:seek("set") - for filename, filedata in pairs(data) do - local max = filedata.max - stats:write(max, ":", filename, "\n") - for i = 1, max do - local hits = filedata[i] - if not hits then - hits = 0 - end - stats:write(hits, " ") - end - stats:write("\n") - end - stats:flush() -end - -return M diff --git a/extras/luacov/src/luacov/tick.lua b/extras/luacov/src/luacov/tick.lua deleted file mode 100644 index 624cae3..0000000 --- a/extras/luacov/src/luacov/tick.lua +++ /dev/null @@ -1,7 +0,0 @@ - ---- Load luacov using this if you want it to periodically --- save the stats file. This is useful if your script is --- a daemon (ie, does not properly terminate.) -module("luacov.tick", package.seeall) - -require("luacov") -- cgit v1.2.1