-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
/
Copy pathgit.jl
108 lines (92 loc) · 3.64 KB
/
git.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
module Git
#
# some utility functions for working with git repos
#
import Base: shell_escape
function dir(d)
g = joinpath(d,".git")
isdir(g) && return g
c = `git rev-parse --git-dir`
isempty(d) || (c = `sh -c "cd $(shell_escape(d)) && $(shell_escape(c))"`)
normpath(d,Base.readchomp(c))
end
function git(d)
isempty(d) && return `git`
work_tree = abspath(d)
git_dir = joinpath(work_tree, dir(work_tree))
normpath(work_tree, ".") == normpath(git_dir, ".") ? # is it a bare repo?
`git --git-dir=$work_tree` : `git --work-tree=$work_tree --git-dir=$git_dir`
end
cmd(args::Cmd; dir="") = `$(git(dir)) $args`
run(args::Cmd; dir="", out=STDOUT) = Base.run(cmd(args,dir=dir) |> out)
readall(args::Cmd; dir="") = Base.readall(cmd(args,dir=dir))
readchomp(args::Cmd; dir="") = Base.readchomp(cmd(args,dir=dir))
function success(args::Cmd; dir="")
g = git(dir)
Base.readchomp(`$g rev-parse --is-bare-repository`) == "false" &&
Base.run(`$g update-index -q --really-refresh`)
Base.success(`$g $args`)
end
modules(args::Cmd; dir="") = readchomp(`config -f .gitmodules $args`, dir=dir)
different(verA::String, verB::String, path::String; dir="") =
!success(`diff-tree --quiet $verA $verB -- $path`, dir=dir)
dirty(; dir="") = !success(`diff-index --quiet HEAD`, dir=dir)
staged(; dir="") = !success(`diff-index --quiet --cached HEAD`, dir=dir)
unstaged(; dir="") = !success(`diff-files --quiet`, dir=dir)
dirty(paths; dir="") = !success(`diff-index --quiet HEAD -- $paths`, dir=dir)
staged(paths; dir="") = !success(`diff-index --quiet --cached HEAD -- $paths`, dir=dir)
unstaged(paths; dir="") = !success(`diff-files --quiet -- $paths`, dir=dir)
iscommit(name; dir="") = success(`cat-file commit $name`, dir=dir)
attached(; dir="") = success(`symbolic-ref -q HEAD`, dir=dir)
branch(; dir="") = readchomp(`rev-parse --symbolic-full-name --abbrev-ref HEAD`, dir=dir)
head(; dir="") = readchomp(`rev-parse HEAD`, dir=dir)
immutable State
head::ASCIIString
index::ASCIIString
work::ASCIIString
end
function snapshot(; dir="")
head = readchomp(`rev-parse HEAD`, dir=dir)
index = readchomp(`write-tree`, dir=dir)
work = try
run(`add --all`, dir=dir)
run(`add .`, dir=dir)
readchomp(`write-tree`, dir=dir)
finally
run(`read-tree $index`, dir=dir) # restore index
end
State(head, index, work)
end
function restore(s::State; dir="")
run(`reset -q --`, dir=dir) # unstage everything
run(`read-tree $(s.work)`, dir=dir) # move work tree to index
run(`checkout-index -fa`, dir=dir) # check the index out to work
run(`clean -qdf`, dir=dir) # remove everything else
run(`read-tree $(s.index)`, dir=dir) # restore index
run(`reset -q --soft $(s.head)`, dir=dir) # restore head
end
function transact(f::Function; dir="")
state = snapshot(dir=dir)
try f() catch
restore(state, dir=dir)
rethrow()
end
end
function is_ancestor_of(a::String, b::String; dir="")
A = readchomp(`rev-parse $a`, dir=dir)
readchomp(`merge-base $A $b`, dir=dir) == A
end
const GITHUB_REGEX =
r"^(?:git@|git://|https://(?:[\w\.\+\-]+@)?)github.com[:/](.*?)(?:\.git)?$"i
function set_remote_url(url::String; remote::String="origin", dir="")
run(`config remote.$remote.url $url`, dir=dir)
m = match(GITHUB_REGEX,url)
m == nothing && return
push = "[email protected]:$(m.captures[1]).git"
push != url && run(`config remote.$remote.pushurl $push`, dir=dir)
end
function normalize_url(url::String)
m = match(GITHUB_REGEX,url)
m == nothing ? url : "git://github.com/$(m.captures[1]).git"
end
end # module