Skip to content

Commit ee19f0c

Browse files
authored
Merge pull request #926 from devlights:add-git-archive-example
Update
2 parents b115eec + ba81eca commit ee19f0c

File tree

4 files changed

+251
-0
lines changed

4 files changed

+251
-0
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
gitar
2+
*.zip
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# これは何?
2+
3+
git + ar(chive) = gitar
4+
5+
gitのコミット差分から変更があったファイルのみを抽出してアーカイブするツールです。
6+
7+
コマンドラインで利用するツールとなります。
8+
9+
gitを使っての実務作業をしていると、毎日たくさんのメンバーがPUSHを行います。
10+
11+
その都度、リポジトリには更新が反映されるのですが、ファイルが多くなってくると
12+
13+
「どのファイルが更新されたのか?」を判断するのが面倒になります。
14+
15+
実は、gitコマンドを以下のように発行すると指定したコミット間の変更ファイル一式を取得することが出来ます。
16+
17+
```sh
18+
$ git archive --prefix=archive/ main $(git diff --name-only HEAD~1 HEAD) -o archive.zip
19+
```
20+
21+
上記のコマンドを実行すると、直近のコミットで変更されたファイルがzipファイルで取得できます。
22+
23+
でも、毎回こんなコマンドを実行するの面倒くさいってことで作ったツールです。
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# https://taskfile.dev
2+
3+
version: '3'
4+
5+
vars:
6+
APP_NAME: gitar
7+
8+
tasks:
9+
default:
10+
cmds:
11+
- task: clean
12+
- task: build
13+
- task: run
14+
clean:
15+
cmds:
16+
- rm -f ./{{.APP_NAME}}
17+
build:
18+
cmds:
19+
- go build -o {{.APP_NAME}} .
20+
run:
21+
cmds:
22+
- ./{{.APP_NAME}}
23+
- unzip -l archive.zip
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
package main
2+
3+
import (
4+
"archive/zip"
5+
"bytes"
6+
"flag"
7+
"fmt"
8+
"io"
9+
"log"
10+
"os"
11+
"os/exec"
12+
"strings"
13+
)
14+
15+
const (
16+
DefaultCommitFrom = "HEAD~1"
17+
DefaultCommitTo = "HEAD"
18+
DefaultRepoPath = "."
19+
DefaultArchivePrefix = "archive"
20+
DefaultArchiveFilePath = "./archive.zip"
21+
)
22+
23+
type (
24+
Gitcmd string
25+
)
26+
27+
func NewGitcmd() Gitcmd {
28+
return Gitcmd("git")
29+
}
30+
31+
func (me Gitcmd) Exec(args ...string) ([]byte, error) {
32+
var (
33+
cmd = exec.Command(string(me), args...)
34+
out []byte
35+
err error
36+
)
37+
out, err = cmd.CombinedOutput()
38+
if err != nil {
39+
return nil, err
40+
}
41+
42+
return bytes.TrimSuffix(out, []byte("\n")), nil
43+
}
44+
45+
func (me Gitcmd) ExecString(args ...string) (string, error) {
46+
var (
47+
out []byte
48+
err error
49+
)
50+
out, err = me.Exec(args...)
51+
if err != nil {
52+
return "", err
53+
}
54+
55+
return string(out), nil
56+
}
57+
58+
type (
59+
Args struct {
60+
CommitFrom string
61+
CommitTo string
62+
RepoPath string
63+
ArchivePrefix string
64+
ArchiveFilePath string
65+
Verbose bool
66+
}
67+
)
68+
69+
func (me *Args) restore() {
70+
if me.CommitFrom == "" {
71+
me.CommitFrom = DefaultCommitFrom
72+
}
73+
if me.CommitTo == "" {
74+
me.CommitTo = DefaultCommitTo
75+
}
76+
if me.RepoPath == "" {
77+
me.RepoPath = DefaultRepoPath
78+
}
79+
if me.ArchivePrefix == "" {
80+
me.ArchivePrefix = DefaultArchivePrefix
81+
}
82+
if me.ArchiveFilePath == "" {
83+
me.ArchiveFilePath = DefaultArchiveFilePath
84+
}
85+
}
86+
87+
var (
88+
args Args
89+
)
90+
91+
func init() {
92+
flag.StringVar(&args.CommitFrom, "from", DefaultCommitFrom, "起点となるコミットハッシュ")
93+
flag.StringVar(&args.CommitTo, "to", DefaultCommitTo, "終点となるコミットハッシュ")
94+
flag.StringVar(&args.RepoPath, "repo", DefaultRepoPath, "リポジトリパス")
95+
flag.StringVar(&args.ArchivePrefix, "prefix", DefaultArchivePrefix, "アーカイブ内のプレフィックスディレクトリ")
96+
flag.StringVar(&args.ArchiveFilePath, "archive", DefaultArchiveFilePath, "アーカイブファイル")
97+
flag.BoolVar(&args.Verbose, "v", false, "詳細表示")
98+
}
99+
100+
func main() {
101+
log.SetFlags(0)
102+
flag.Parse()
103+
104+
(&args).restore()
105+
106+
if err := run(); err != nil {
107+
log.Fatal(err)
108+
}
109+
}
110+
111+
func run() error {
112+
var (
113+
git = NewGitcmd()
114+
err error
115+
)
116+
117+
// リポジトリの場所に移動
118+
err = os.Chdir(args.RepoPath)
119+
if err != nil {
120+
return err
121+
}
122+
123+
// 最新のコミットハッシュを取得
124+
var (
125+
from string
126+
to string
127+
)
128+
from, err = git.ExecString("rev-parse", args.CommitFrom)
129+
if err != nil {
130+
return err
131+
}
132+
to, err = git.ExecString("rev-parse", args.CommitTo)
133+
if err != nil {
134+
return err
135+
}
136+
137+
if args.Verbose {
138+
log.Printf("起点コミットハッシュ: %s(%s)", args.CommitFrom, from)
139+
log.Printf("終点コミットハッシュ: %s(%s)", args.CommitTo, to)
140+
}
141+
142+
// 変更されたファイルの一覧を取得
143+
var (
144+
diff string
145+
files []string
146+
)
147+
diff, err = git.ExecString("diff", "--name-only", from, to)
148+
if err != nil {
149+
return err
150+
}
151+
files = strings.Split(diff, "\n")
152+
if len(files) == 0 {
153+
return nil
154+
}
155+
156+
// ZIPファイルを作成
157+
var (
158+
zipFile *os.File
159+
writer *zip.Writer
160+
)
161+
zipFile, err = os.Create(args.ArchiveFilePath)
162+
if err != nil {
163+
return err
164+
}
165+
defer zipFile.Close()
166+
167+
writer = zip.NewWriter(zipFile)
168+
defer writer.Close()
169+
170+
for _, file := range files {
171+
if file == "" {
172+
continue
173+
}
174+
175+
// ファイルの内容を取得し、ZIPファイルにエントリ書き込み
176+
var (
177+
contents []byte
178+
entry io.Writer
179+
)
180+
contents, err = git.Exec("show", fmt.Sprintf("%s:%s", to, file))
181+
if err != nil {
182+
return err
183+
}
184+
185+
entry, err = writer.Create(fmt.Sprintf("%s/%s", args.ArchivePrefix, file))
186+
if err != nil {
187+
return err
188+
}
189+
190+
if _, err = entry.Write(contents); err != nil {
191+
return err
192+
}
193+
194+
if args.Verbose {
195+
log.Printf("ファイル追加: %s", file)
196+
}
197+
}
198+
if err = writer.Close(); err != nil {
199+
return err
200+
}
201+
202+
return nil
203+
}

0 commit comments

Comments
 (0)