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
9953a00
Documentation
arm
compat
contrib
git-gui
gitweb
mozilla-sha1
perl
ppc
t
templates
xdiff
.gitignore
.mailmap
COPYING
GIT-VERSION-GEN
INSTALL
Makefile
README
RelNotes
alloc.c
archive-tar.c
archive-zip.c
archive.h
attr.c
attr.h
base85.c
blob.c
blob.h
builtin-add.c
builtin-annotate.c
builtin-apply.c
builtin-archive.c
builtin-blame.c
builtin-branch.c
builtin-bundle.c
builtin-cat-file.c
builtin-check-attr.c
builtin-check-ref-format.c
builtin-checkout-index.c
builtin-commit-tree.c
builtin-config.c
builtin-count-objects.c
builtin-describe.c
builtin-diff-files.c
builtin-diff-index.c
builtin-diff-tree.c
builtin-diff.c
builtin-fetch--tool.c
builtin-fmt-merge-msg.c
builtin-for-each-ref.c
builtin-fsck.c
builtin-gc.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-merge-base.c
builtin-merge-file.c
builtin-mv.c
builtin-name-rev.c
builtin-pack-objects.c
builtin-pack-refs.c
builtin-prune-packed.c
builtin-prune.c
builtin-push.c
builtin-read-tree.c
builtin-reflog.c
builtin-rerere.c
builtin-rev-list.c
builtin-rev-parse.c
builtin-revert.c
builtin-rm.c
builtin-runstatus.c
builtin-shortlog.c
builtin-show-branch.c
builtin-show-ref.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-builtins.sh
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
convert.c
copy.c
csum-file.c
csum-file.h
ctype.c
daemon.c
date.c
decorate.c
decorate.h
delta.h
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
fast-import.c
fetch-pack.c
fetch.c
fetch.h
generate-cmdlist.sh
git-add--interactive.perl
git-am.sh
git-applymbox.sh
git-applypatch.sh
git-archimport.perl
git-bisect.sh
git-checkout.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-resolve.sh
git-merge-stupid.sh
git-merge.sh
git-mergetool.sh
git-p4import.py
git-parse-remote.sh
git-pull.sh
git-quiltimport.sh
git-rebase.sh
git-relink.perl
git-remote.perl
git-repack.sh
git-request-pull.sh
git-reset.sh
git-send-email.perl
git-sh-setup.sh
git-svn.perl
git-svnimport.perl
git-tag.sh
git-verify-tag.sh
git.c
git.spec.in
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
mailmap.c
mailmap.h
match-trees.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-write.c
pack.h
pager.c
patch-delta.c
patch-id.c
patch-ids.c
patch-ids.h
path-list.c
path-list.h
path.c
peek-remote.c
pkt-line.c
pkt-line.h
progress.c
progress.h
quote.c
quote.h
reachable.c
reachable.h
read-cache.c
receive-pack.c
reflog-walk.c
reflog-walk.h
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
shallow.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
symlinks.c
tag.c
tag.h
tar.h
test-chmtime.c
test-date.c
test-delta.c
test-genrandom.c
test-match-trees.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
utf8.c
utf8.h
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
·
316 lines (278 loc) · 8.26 KB
Breadcrumbs
git
/
git-cvsexportcommit.perl
Top
File metadata and controls
Code
Blame
executable file
·
316 lines (278 loc) · 8.26 KB
Raw
#!/usr/bin/perl -w # Known limitations: # - does not propagate permissions # - error handling has not been extensively tested # 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_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m, $opt_d, $opt_u); getopts('uhPpvcfam:d:'); $opt_h && usage(); die "Need at least one commit identifier!" unless @ARGV; my @cvs; if ($opt_d) { @cvs = ('cvs', '-d', $opt_d); } else { @cvs = ('cvs'); } # 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 and !$opt_P; } 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; `git-diff-tree --binary -p $parent $commit >.cvsexportcommit.diff`;# || die "Cannot diff"; ## apply non-binary changes # In pedantic mode require all lines of context to match. In normal # mode, be compatible with diff/patch: assume 3 lines of context and # require at least one line match, i.e. ignore at most 2 lines of # context, like diff/patch do by default. my $context = $opt_p ? '' : '-C1'; print "Checking if patch will apply\n"; my @stat; open APPLY, "GIT_DIR= git-apply $context --binary --summary --numstat<.cvsexportcommit.diff|" || die "cannot patch"; @stat=<APPLY>; close APPLY || die "Cannot patch"; my (@bfiles,@files,@afiles,@dfiles); chomp @stat; foreach (@stat) { push (@bfiles,$1) if m/^-\t-\t(.*)$/; push (@files, $1) if m/^-\t-\t(.*)$/; push (@files, $1) if m/^\d+\t\d+\t(.*)$/; push (@afiles,$1) if m/^ create mode [0-7]+ (.*)$/; push (@dfiles,$1) if m/^ delete mode [0-7]+ (.*)$/; } map { s/^"(.*)"$/$1/g } @bfiles,@files; map { s/\\([0-7]{3})/sprintf('%c',oct $1)/eg } @bfiles,@files; # check that the files are clean and up to date according to cvs my $dirty; my @dirs; foreach my $p (@afiles) { my $path = dirname $p; while (!-d $path and ! grep { $_ eq $path } @dirs) { unshift @dirs, $path; $path = dirname $path; } } # ... check dirs, foreach my $d (@dirs) { if (-e $d) { $dirty = 1; warn "$d exists and is not a directory!\n"; } } # ... query status of all files that we have a directory for and parse output of 'cvs status' to %cvsstat. my @canstatusfiles; foreach my $f (@files) { my $path = dirname $f; next if (grep { $_ eq $path } @dirs); push @canstatusfiles, $f; } my %cvsstat; if (@canstatusfiles) { if ($opt_u) { my @updated = safe_pipe_capture(@cvs, 'update', @canstatusfiles); print @updated; } my @cvsoutput; @cvsoutput= safe_pipe_capture(@cvs, 'status', @canstatusfiles); my $matchcount = 0; foreach my $l (@cvsoutput) { chomp $l; if ( $l =~ /^File:/ and $l =~ /Status: (.*)$/ ) { $cvsstat{$canstatusfiles[$matchcount]} = $1; $matchcount++; } } } # ... validate new files, foreach my $f (@afiles) { if (defined ($cvsstat{$f}) and $cvsstat{$f} ne "Unknown") { $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: $cvsstat{$f}\n"; } } # ... validate known files. foreach my $f (@files) { next if grep { $_ eq $f } @afiles; # TODO:we need to handle removed in cvs unless (defined ($cvsstat{$f}) and $cvsstat{$f} eq "Up-to-date") { $dirty = 1; warn "File $f not up to date but has status '$cvsstat{$f}' 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."; } } print "Applying\n"; `GIT_DIR= git-apply $context --binary --summary --numstat --apply <.cvsexportcommit.diff` || die "cannot patch"; print "Patch applied successfully. Adding new files and directories to CVS\n"; my $dirtypatch = 0; foreach my $d (@dirs) { if (system(@cvs,'add',$d)) { $dirtypatch = 1; warn "Failed to cvs add directory $d -- you may need to do it manually"; } } foreach my $f (@afiles) { if (grep { $_ eq $f } @bfiles) { system(@cvs, 'add','-kb',$f); } else { system(@cvs, 'add', $f); } if ($?) { $dirtypatch = 1; warn "Failed to cvs add $f -- you may need to do it manually"; } } foreach my $f (@dfiles) { system(@cvs, 'rm', '-f', $f); if ($?) { $dirtypatch = 1; warn "Failed to cvs rm -f $f -- you may need to do it manually"; } } print "Commit to CVS\n"; print "Patch title (first comment line): $title\n"; my @commitfiles = map { unless (m/\s/) { '\''.$_.'\''; } else { $_; }; } (@files); my $cmd = join(' ', @cvs)." commit -F .msg @commitfiles"; if ($dirtypatch) { print "NOTE: One or more hunks failed to apply cleanly.\n"; print "You'll need to apply the patch in .cvsexportcommit.diff manually\n"; print "using a patch program. After applying the patch and resolving the\n"; print "problems you may commit using:"; print "\n $cmd\n\n"; exit(1); } if ($opt_c) { print "Autocommit\n $cmd\n"; print safe_pipe_capture(@cvs, 'commit', '-F', '.msg', @files); if ($?) { die "Exiting: The commit did not succeed"; } print "Committed successfully to CVS\n"; # clean up unlink(".msg"); } else { print "Ready for you to commit, just run:\n\n $cmd\n"; } # clean up unlink(".cvsexportcommit.diff"); 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); } # 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); } sub safe_pipe_capture_blob { my $output; if (my $pid = open my $child, '-|') { local $/; undef $/; $output = (<$child>); close $child or die join(' ',@_).": $! $?"; } else { exec(@_) or die "$! $?"; # exec() can fail the executable can't be found } return $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
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
315
316
You can’t perform that action at this time.