Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
git-mirror
/
git
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
0
Pull requests
0
Actions
Projects
0
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Security
Insights
Files
21ff2bd
Documentation
arm
compat
contrib
gitweb
mozilla-sha1
ppc
t
templates
xdiff
.gitignore
COPYING
GIT-VERSION-GEN
INSTALL
Makefile
README
alloc.c
archive-tar.c
archive-zip.c
archive.h
base85.c
blame.c
blob.c
blob.h
builtin-add.c
builtin-apply.c
builtin-archive.c
builtin-cat-file.c
builtin-check-ref-format.c
builtin-checkout-index.c
builtin-commit-tree.c
builtin-count-objects.c
builtin-diff-files.c
builtin-diff-index.c
builtin-diff-stages.c
builtin-diff-tree.c
builtin-diff.c
builtin-fmt-merge-msg.c
builtin-grep.c
builtin-init-db.c
builtin-log.c
builtin-ls-files.c
builtin-ls-tree.c
builtin-mailinfo.c
builtin-mailsplit.c
builtin-mv.c
builtin-name-rev.c
builtin-pack-objects.c
builtin-prune-packed.c
builtin-prune.c
builtin-push.c
builtin-read-tree.c
builtin-repo-config.c
builtin-rev-list.c
builtin-rev-parse.c
builtin-rm.c
builtin-runstatus.c
builtin-show-branch.c
builtin-stripspace.c
builtin-symbolic-ref.c
builtin-tar-tree.c
builtin-unpack-objects.c
builtin-update-index.c
builtin-update-ref.c
builtin-upload-archive.c
builtin-verify-pack.c
builtin-write-tree.c
builtin.h
cache-tree.c
cache-tree.h
cache.h
check-racy.c
color.c
color.h
combine-diff.c
commit.c
commit.h
config.c
config.mak.in
configure.ac
connect.c
convert-objects.c
copy.c
csum-file.c
csum-file.h
ctype.c
daemon.c
date.c
delta.h
describe.c
diff-delta.c
diff-lib.c
diff.c
diff.h
diffcore-break.c
diffcore-delta.c
diffcore-order.c
diffcore-pickaxe.c
diffcore-rename.c
diffcore.h
dir.c
dir.h
dump-cache-tree.c
entry.c
environment.c
exec_cmd.c
exec_cmd.h
fetch-clone.c
fetch-pack.c
fetch.c
fetch.h
fsck-objects.c
generate-cmdlist.sh
git-am.sh
git-annotate.perl
git-applymbox.sh
git-applypatch.sh
git-archimport.perl
git-bisect.sh
git-branch.sh
git-checkout.sh
git-cherry.sh
git-clean.sh
git-clone.sh
git-commit.sh
git-compat-util.h
git-cvsexportcommit.perl
git-cvsimport.perl
git-cvsserver.perl
git-fetch.sh
git-instaweb.sh
git-lost-found.sh
git-ls-remote.sh
git-merge-octopus.sh
git-merge-one-file.sh
git-merge-ours.sh
git-merge-recursive-old.py
git-merge-resolve.sh
git-merge-stupid.sh
git-merge.sh
git-p4import.py
git-parse-remote.sh
git-pull.sh
git-quiltimport.sh
git-rebase.sh
git-relink.perl
git-repack.sh
git-request-pull.sh
git-rerere.perl
git-reset.sh
git-resolve.sh
git-revert.sh
git-send-email.perl
git-sh-setup.sh
git-shortlog.perl
git-svn.perl
git-svnimport.perl
git-tag.sh
git-verify-tag.sh
git.c
git.spec.in
gitMergeCommon.py
gitk
grep.c
grep.h
hash-object.c
help.c
http-fetch.c
http-push.c
http.c
http.h
ident.c
imap-send.c
index-pack.c
interpolate.c
interpolate.h
list-objects.c
list-objects.h
local-fetch.c
lockfile.c
log-tree.c
log-tree.h
merge-base.c
merge-file.c
merge-index.c
merge-recursive.c
merge-tree.c
mktag.c
mktree.c
object-refs.c
object.c
object.h
pack-check.c
pack-redundant.c
pack.h
pager.c
patch-delta.c
patch-id.c
path-list.c
path-list.h
path.c
peek-remote.c
pkt-line.c
pkt-line.h
quote.c
quote.h
read-cache.c
receive-pack.c
refs.c
refs.h
revision.c
revision.h
rsh.c
rsh.h
run-command.c
run-command.h
send-pack.c
server-info.c
setup.c
sha1_file.c
sha1_name.c
shell.c
show-index.c
sideband.c
sideband.h
ssh-fetch.c
ssh-pull.c
ssh-push.c
ssh-upload.c
strbuf.c
strbuf.h
tag.c
tag.h
tar.h
test-date.c
test-delta.c
test-sha1.c
test-sha1.sh
trace.c
tree-diff.c
tree-walk.c
tree-walk.h
tree.c
tree.h
unpack-file.c
unpack-trees.c
unpack-trees.h
update-server-info.c
upload-pack.c
usage.c
var.c
write_or_die.c
wt-status.c
wt-status.h
xdiff-interface.c
xdiff-interface.h
Breadcrumbs
git
/
git-cvsexportcommit.perl
Blame
Blame
Latest commit
History
History
executable file
·
314 lines (277 loc) · 8.16 KB
Breadcrumbs
git
/
git-cvsexportcommit.perl
Top
File metadata and controls
Code
Blame
executable file
·
314 lines (277 loc) · 8.16 KB
Raw
#!/usr/bin/perl -w # Known limitations: # - cannot add or remove binary files # - does not propagate permissions # - tells "ready for commit" even when things could not be completed # (eg addition of a binary file) use strict; use Getopt::Std; use File::Temp qw(tempdir); use Data::Dumper; use File::Basename qw(basename dirname); unless ($ENV{GIT_DIR} && -r $ENV{GIT_DIR}){ die "GIT_DIR is not defined or is unreadable"; } our ($opt_h, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m ); getopts('hpvcfam:'); $opt_h && usage(); die "Need at least one commit identifier!" unless @ARGV; # setup a tempdir our ($tmpdir, $tmpdirname) = tempdir('git-cvsapplycommit-XXXXXX', TMPDIR => 1, CLEANUP => 1); # resolve target commit my $commit; $commit = pop @ARGV; $commit = safe_pipe_capture('git-rev-parse', '--verify', "$commit^0"); chomp $commit; if ($?) { die "The commit reference $commit did not resolve!"; } # resolve what parent we want my $parent; if (@ARGV) { $parent = pop @ARGV; $parent = safe_pipe_capture('git-rev-parse', '--verify', "$parent^0"); chomp $parent; if ($?) { die "The parent reference did not resolve!"; } } # find parents from the commit itself my @commit = safe_pipe_capture('git-cat-file', 'commit', $commit); my @parents; my $committer; my $author; my $stage = 'headers'; # headers, msg my $title; my $msg = ''; foreach my $line (@commit) { chomp $line; if ($stage eq 'headers' && $line eq '') { $stage = 'msg'; next; } if ($stage eq 'headers') { if ($line =~ m/^parent (\w{40})$/) { # found a parent push @parents, $1; } elsif ($line =~ m/^author (.+) \d+ \+\d+$/) { $author = $1; } elsif ($line =~ m/^committer (.+) \d+ \+\d+$/) { $committer = $1; } } else { $msg .= $line . "\n"; unless ($title) { $title = $line; } } } if ($parent) { my $found; # double check that it's a valid parent foreach my $p (@parents) { if ($p eq $parent) { $found = 1; last; }; # found it } die "Did not find $parent in the parents for this commit!" if !$found; } else { # we don't have a parent from the cmdline... if (@parents == 1) { # it's safe to get it from the commit $parent = $parents[0]; } else { # or perhaps not! die "This commit has more than one parent -- please name the parent you want to use explicitly"; } } $opt_v && print "Applying to CVS commit $commit from parent $parent\n"; # grab the commit message open(MSG, ">.msg") or die "Cannot open .msg for writing"; if ($opt_m) { print MSG $opt_m; } print MSG $msg; if ($opt_a) { print MSG "\n\nAuthor: $author\n"; if ($author ne $committer) { print MSG "Committer: $committer\n"; } } close MSG; my (@afiles, @dfiles, @mfiles, @dirs); my @files = safe_pipe_capture('git-diff-tree', '-r', $parent, $commit); #print @files; $? && die "Error in git-diff-tree"; foreach my $f (@files) { chomp $f; my @fields = split(m!\s+!, $f); if ($fields[4] eq 'A') { my $path = $fields[5]; push @afiles, $path; # add any needed parent directories $path = dirname $path; while (!-d $path and ! grep { $_ eq $path } @dirs) { unshift @dirs, $path; $path = dirname $path; } } if ($fields[4] eq 'M') { push @mfiles, $fields[5]; } if ($fields[4] eq 'D') { push @dfiles, $fields[5]; } } $opt_v && print "The commit affects:\n "; $opt_v && print join ("\n ", @afiles,@mfiles,@dfiles) . "\n\n"; undef @files; # don't need it anymore # check that the files are clean and up to date according to cvs my $dirty; foreach my $d (@dirs) { if (-e $d) { $dirty = 1; warn "$d exists and is not a directory!\n"; } } foreach my $f (@afiles) { # This should return only one value my @status = grep(m/^File/, safe_pipe_capture('cvs', '-q', 'status' ,$f)); if (@status > 1) { warn 'Strange! cvs status returned more than one line?'}; if (-d dirname $f and $status[0] !~ m/Status: Unknown$/ and $status[0] !~ m/^File: no file /) { $dirty = 1; warn "File $f is already known in your CVS checkout -- perhaps it has been added by another user. Or this may indicate that it exists on a different branch. If this is the case, use -f to force the merge.\n"; warn "Status was: $status[0]\n"; } } foreach my $f (@mfiles, @dfiles) { # TODO:we need to handle removed in cvs my @status = grep(m/^File/, safe_pipe_capture('cvs', '-q', 'status' ,$f)); if (@status > 1) { warn 'Strange! cvs status returned more than one line?'}; unless ($status[0] =~ m/Status: Up-to-date$/) { $dirty = 1; warn "File $f not up to date in your CVS checkout!\n"; } } if ($dirty) { if ($opt_f) { warn "The tree is not clean -- forced merge\n"; $dirty = 0; } else { die "Exiting: your CVS tree is not clean for this merge."; } } ### ### NOTE: if you are planning to die() past this point ### you MUST call cleanupcvs(@files) before die() ### print "Creating new directories\n"; foreach my $d (@dirs) { unless (mkdir $d) { warn "Could not mkdir $d: $!"; $dirty = 1; } `cvs add $d`; if ($?) { $dirty = 1; warn "Failed to cvs add directory $d -- you may need to do it manually"; } } print "'Patching' binary files\n"; my @bfiles = grep(m/^Binary/, safe_pipe_capture('git-diff-tree', '-p', $parent, $commit)); @bfiles = map { chomp } @bfiles; foreach my $f (@bfiles) { # check that the file in cvs matches the "old" file # extract the file to $tmpdir and compare with cmp my $tree = safe_pipe_capture('git-rev-parse', "$parent^{tree}"); chomp $tree; my $blob = `git-ls-tree $tree "$f" | cut -f 1 | cut -d ' ' -f 3`; chomp $blob; `git-cat-file blob $blob > $tmpdir/blob`; if (system('cmp', '-s', $f, "$tmpdir/blob")) { warn "Binary file $f in CVS does not match parent.\n"; $dirty = 1; next; } # replace with the new file `git-cat-file blob $blob > $f`; # TODO: something smart with file modes } if ($dirty) { cleanupcvs(@files); die "Exiting: Binary files in CVS do not match parent"; } ## apply non-binary changes my $fuzz = $opt_p ? 0 : 2; print "Patching non-binary files\n"; print `(git-diff-tree -p $parent -p $commit | patch -p1 -F $fuzz ) 2>&1`; my $dirtypatch = 0; if (($? >> 8) == 2) { cleanupcvs(@files); die "Exiting: Patch reported serious trouble -- you will have to apply this patch manually"; } elsif (($? >> 8) == 1) { # some hunks failed to apply $dirtypatch = 1; } foreach my $f (@afiles) { system('cvs', 'add', $f); if ($?) { $dirty = 1; warn "Failed to cvs add $f -- you may need to do it manually"; } } foreach my $f (@dfiles) { system('cvs', 'rm', '-f', $f); if ($?) { $dirty = 1; warn "Failed to cvs rm -f $f -- you may need to do it manually"; } } print "Commit to CVS\n"; print "Patch: $title\n"; my $commitfiles = join(' ', @afiles, @mfiles, @dfiles); my $cmd = "cvs commit -F .msg $commitfiles"; if ($dirtypatch) { print "NOTE: One or more hunks failed to apply cleanly.\n"; print "Resolve the conflicts and then commit using:\n"; print "\n $cmd\n\n"; exit(1); } if ($opt_c) { print "Autocommit\n $cmd\n"; print safe_pipe_capture('cvs', 'commit', '-F', '.msg', @afiles, @mfiles, @dfiles); if ($?) { cleanupcvs(@files); die "Exiting: The commit did not succeed"; } print "Committed successfully to CVS\n"; } else { print "Ready for you to commit, just run:\n\n $cmd\n"; } sub usage { print STDERR <<END; Usage: GIT_DIR=/path/to/.git ${\basename $0} [-h] [-p] [-v] [-c] [-f] [-m msgprefix] [ parent ] commit END exit(1); } # ensure cvs is clean before we die sub cleanupcvs { my @files = @_; foreach my $f (@files) { system('cvs', '-q', 'update', '-C', $f); if ($?) { warn "Warning! Failed to cleanup state of $f\n"; } } } # An alternative to `command` that allows input to be passed as an array # to work around shell problems with weird characters in arguments # if the exec returns non-zero we die sub safe_pipe_capture { my @output; if (my $pid = open my $child, '-|') { @output = (<$child>); close $child or die join(' ',@_).": $! $?"; } else { exec(@_) or die "$! $?"; # exec() can fail the executable can't be found } return wantarray ? @output : join('',@output); }
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
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
You can’t perform that action at this time.