summaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rw-r--r--contrib/emacs/git.el197
-rwxr-xr-xcontrib/examples/git-reset.sh106
-rwxr-xr-xcontrib/fast-import/git-import.perl64
-rwxr-xr-xcontrib/fast-import/git-import.sh38
-rwxr-xr-xcontrib/fast-import/git-p4342
5 files changed, 563 insertions, 184 deletions
diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el
index 280557ecd4..2d77fd47ec 100644
--- a/contrib/emacs/git.el
+++ b/contrib/emacs/git.el
@@ -97,6 +97,21 @@ if there is already one that displays the same directory."
:group 'git
:type 'string)
+(defcustom git-show-uptodate nil
+ "Whether to display up-to-date files."
+ :group 'git
+ :type 'boolean)
+
+(defcustom git-show-ignored nil
+ "Whether to display ignored files."
+ :group 'git
+ :type 'boolean)
+
+(defcustom git-show-unknown t
+ "Whether to display unknown files."
+ :group 'git
+ :type 'boolean)
+
(defface git-status-face
'((((class color) (background light)) (:foreground "purple"))
@@ -479,6 +494,27 @@ and returns the process output as a string."
(setf (git-fileinfo->orig-name info) nil)
(setf (git-fileinfo->needs-refresh info) t))))
+(defun git-set-filenames-state (status files state)
+ "Set the state of a list of named files."
+ (when files
+ (setq files (sort files #'string-lessp))
+ (let ((file (pop files))
+ (node (ewoc-nth status 0)))
+ (while (and file node)
+ (let ((info (ewoc-data node)))
+ (cond ((string-lessp (git-fileinfo->name info) file)
+ (setq node (ewoc-next status node)))
+ ((string-equal (git-fileinfo->name info) file)
+ (unless (eq (git-fileinfo->state info) state)
+ (setf (git-fileinfo->state info) state)
+ (setf (git-fileinfo->rename-state info) nil)
+ (setf (git-fileinfo->orig-name info) nil)
+ (setf (git-fileinfo->needs-refresh info) t))
+ (setq file (pop files)))
+ (t (setq file (pop files)))))))
+ (unless state ;; delete files whose state has been set to nil
+ (ewoc-filter status (lambda (info) (git-fileinfo->state info))))))
+
(defun git-state-code (code)
"Convert from a string to a added/deleted/modified state."
(case (string-to-char code)
@@ -532,19 +568,36 @@ and returns the process output as a string."
" " (git-escape-file-name (git-fileinfo->name info))
(git-rename-as-string info))))
-(defun git-insert-fileinfo (status info &optional refresh)
- "Insert INFO in the status buffer, optionally refreshing an existing one."
- (let ((node (and refresh
- (git-find-status-file status (git-fileinfo->name info)))))
- (setf (git-fileinfo->needs-refresh info) t)
- (when node ;preserve the marked flag
- (setf (git-fileinfo->marked info) (git-fileinfo->marked (ewoc-data node))))
- (if node (setf (ewoc-data node) info) (ewoc-enter-last status info))))
+(defun git-insert-info-list (status infolist)
+ "Insert a list of file infos in the status buffer, replacing existing ones if any."
+ (setq infolist (sort infolist
+ (lambda (info1 info2)
+ (string-lessp (git-fileinfo->name info1)
+ (git-fileinfo->name info2)))))
+ (let ((info (pop infolist))
+ (node (ewoc-nth status 0)))
+ (while info
+ (setf (git-fileinfo->needs-refresh info) t)
+ (cond ((not node)
+ (ewoc-enter-last status info)
+ (setq info (pop infolist)))
+ ((string-lessp (git-fileinfo->name (ewoc-data node))
+ (git-fileinfo->name info))
+ (setq node (ewoc-next status node)))
+ ((string-equal (git-fileinfo->name (ewoc-data node))
+ (git-fileinfo->name info))
+ ;; preserve the marked flag
+ (setf (git-fileinfo->marked info) (git-fileinfo->marked (ewoc-data node)))
+ (setf (ewoc-data node) info)
+ (setq info (pop infolist)))
+ (t
+ (ewoc-enter-before status node info)
+ (setq info (pop infolist)))))))
(defun git-run-diff-index (status files)
"Run git-diff-index on FILES and parse the results into STATUS.
Return the list of files that haven't been handled."
- (let ((refresh files))
+ (let (infolist)
(with-temp-buffer
(apply #'git-run-command t nil "diff-index" "-z" "-M" "HEAD" "--" files)
(goto-char (point-min))
@@ -558,13 +611,14 @@ Return the list of files that haven't been handled."
(new-name (match-string 8)))
(if new-name ; copy or rename
(if (eq ?C (string-to-char state))
- (git-insert-fileinfo status (git-create-fileinfo 'added new-name old-perm new-perm 'copy name) refresh)
- (git-insert-fileinfo status (git-create-fileinfo 'deleted name 0 0 'rename new-name) refresh)
- (git-insert-fileinfo status (git-create-fileinfo 'added new-name old-perm new-perm 'rename name)) refresh)
- (git-insert-fileinfo status (git-create-fileinfo (git-state-code state) name old-perm new-perm) refresh))
+ (push (git-create-fileinfo 'added new-name old-perm new-perm 'copy name) infolist)
+ (push (git-create-fileinfo 'deleted name 0 0 'rename new-name) infolist)
+ (push (git-create-fileinfo 'added new-name old-perm new-perm 'rename name) infolist))
+ (push (git-create-fileinfo (git-state-code state) name old-perm new-perm) infolist))
(setq files (delete name files))
- (when new-name (setq files (delete new-name files)))))))
- files)
+ (when new-name (setq files (delete new-name files))))))
+ (git-insert-info-list status infolist)
+ files))
(defun git-find-status-file (status file)
"Find a given file in the status ewoc and return its node."
@@ -576,16 +630,16 @@ Return the list of files that haven't been handled."
(defun git-run-ls-files (status files default-state &rest options)
"Run git-ls-files on FILES and parse the results into STATUS.
Return the list of files that haven't been handled."
- (let ((refresh files))
+ (let (infolist)
(with-temp-buffer
- (apply #'git-run-command t nil "ls-files" "-z" "-t" (append options (list "--") files))
+ (apply #'git-run-command t nil "ls-files" "-z" (append options (list "--") files))
(goto-char (point-min))
- (while (re-search-forward "\\([HMRCK?]\\) \\([^\0]*\\)\0" nil t 1)
- (let ((state (match-string 1))
- (name (match-string 2)))
- (git-insert-fileinfo status (git-create-fileinfo (or (git-state-code state) default-state) name) refresh)
- (setq files (delete name files))))))
- files)
+ (while (re-search-forward "\\([^\0]*\\)\0" nil t 1)
+ (let ((name (match-string 1)))
+ (push (git-create-fileinfo default-state name) infolist)
+ (setq files (delete name files)))))
+ (git-insert-info-list status infolist)
+ files))
(defun git-run-ls-unmerged (status files)
"Run git-ls-files -u on FILES and parse the results into STATUS."
@@ -594,9 +648,8 @@ Return the list of files that haven't been handled."
(goto-char (point-min))
(let (unmerged-files)
(while (re-search-forward "[0-7]\\{6\\} [0-9a-f]\\{40\\} [123]\t\\([^\0]+\\)\0" nil t)
- (let ((node (git-find-status-file status (match-string 1))))
- (when node (push (ewoc-data node) unmerged-files))))
- (git-set-files-state unmerged-files 'unmerged))))
+ (push (match-string 1) unmerged-files))
+ (git-set-filenames-state status unmerged-files 'unmerged))))
(defun git-get-exclude-files ()
"Get the list of exclude files to pass to git-ls-files."
@@ -608,34 +661,30 @@ Return the list of files that haven't been handled."
(push config files))
files))
+(defun git-run-ls-files-with-excludes (status files default-state &rest options)
+ "Run git-ls-files on FILES with appropriate --exclude-from options."
+ (let ((exclude-files (git-get-exclude-files)))
+ (apply #'git-run-ls-files status files default-state
+ (concat "--exclude-per-directory=" git-per-dir-ignore-file)
+ (append options (mapcar (lambda (f) (concat "--exclude-from=" f)) exclude-files)))))
+
(defun git-update-status-files (files &optional default-state)
"Update the status of FILES from the index."
(unless git-status (error "Not in git-status buffer."))
- (let* ((status git-status)
- (remaining-files
+ (unless files
+ (when git-show-uptodate (git-run-ls-files git-status nil 'uptodate "-c")))
+ (let* ((remaining-files
(if (git-empty-db-p) ; we need some special handling for an empty db
- (git-run-ls-files status files 'added "-c")
- (git-run-diff-index status files))))
- (git-run-ls-unmerged status files)
- (when (or (not files) remaining-files)
- (let ((exclude-files (git-get-exclude-files)))
- (setq remaining-files (apply #'git-run-ls-files status remaining-files 'unknown "-o"
- (concat "--exclude-per-directory=" git-per-dir-ignore-file)
- (mapcar (lambda (f) (concat "--exclude-from=" f)) exclude-files)))))
- ; mark remaining files with the default state (or remove them if nil)
- (when remaining-files
- (if default-state
- (ewoc-map (lambda (info)
- (when (member (git-fileinfo->name info) remaining-files)
- (git-set-files-state (list info) default-state))
- nil)
- status)
- (ewoc-filter status
- (lambda (info files)
- (not (member (git-fileinfo->name info) files)))
- remaining-files)))
+ (git-run-ls-files git-status files 'added "-c")
+ (git-run-diff-index git-status files))))
+ (git-run-ls-unmerged git-status files)
+ (when (or remaining-files (and git-show-unknown (not files)))
+ (setq remaining-files (git-run-ls-files-with-excludes git-status remaining-files 'unknown "-o")))
+ (when (or remaining-files (and git-show-ignored (not files)))
+ (setq remaining-files (git-run-ls-files-with-excludes git-status remaining-files 'ignored "-o" "-i")))
+ (git-set-filenames-state git-status remaining-files default-state)
(git-refresh-files)
- (git-refresh-ewoc-hf status)))
+ (git-refresh-ewoc-hf git-status)))
(defun git-marked-files ()
"Return a list of all marked files, or if none a list containing just the file at cursor position."
@@ -853,7 +902,7 @@ Return the list of files that haven't been handled."
(defun git-add-file ()
"Add marked file(s) to the index cache."
(interactive)
- (let ((files (git-get-filenames (git-marked-files-state 'unknown))))
+ (let ((files (git-get-filenames (git-marked-files-state 'unknown 'ignored))))
(unless files
(push (file-relative-name (read-file-name "File to add: " nil nil t)) files))
(apply #'git-run-command nil nil "update-index" "--add" "--" files)
@@ -871,7 +920,7 @@ Return the list of files that haven't been handled."
(defun git-remove-file ()
"Remove the marked file(s)."
(interactive)
- (let ((files (git-get-filenames (git-marked-files-state 'added 'modified 'unknown 'uptodate))))
+ (let ((files (git-get-filenames (git-marked-files-state 'added 'modified 'unknown 'uptodate 'ignored))))
(unless files
(push (file-relative-name (read-file-name "File to remove: " nil nil t)) files))
(if (yes-or-no-p
@@ -916,11 +965,41 @@ Return the list of files that haven't been handled."
(interactive)
(ewoc-filter git-status
(lambda (info)
- (not (or (eq (git-fileinfo->state info) 'ignored)
- (eq (git-fileinfo->state info) 'uptodate)))))
+ (case (git-fileinfo->state info)
+ ('ignored git-show-ignored)
+ ('uptodate git-show-uptodate)
+ ('unknown git-show-unknown)
+ (t t))))
(unless (ewoc-nth git-status 0) ; refresh header if list is empty
(git-refresh-ewoc-hf git-status)))
+(defun git-toggle-show-uptodate ()
+ "Toogle the option for showing up-to-date files."
+ (interactive)
+ (if (setq git-show-uptodate (not git-show-uptodate))
+ (git-refresh-status)
+ (git-remove-handled)))
+
+(defun git-toggle-show-ignored ()
+ "Toogle the option for showing ignored files."
+ (interactive)
+ (if (setq git-show-ignored (not git-show-ignored))
+ (progn
+ (git-run-ls-files-with-excludes git-status nil 'ignored "-o" "-i")
+ (git-refresh-files)
+ (git-refresh-ewoc-hf git-status))
+ (git-remove-handled)))
+
+(defun git-toggle-show-unknown ()
+ "Toogle the option for showing unknown files."
+ (interactive)
+ (if (setq git-show-unknown (not git-show-unknown))
+ (progn
+ (git-run-ls-files-with-excludes git-status nil 'unknown "-o")
+ (git-refresh-files)
+ (git-refresh-ewoc-hf git-status))
+ (git-remove-handled)))
+
(defun git-setup-diff-buffer (buffer)
"Setup a buffer for displaying a diff."
(let ((dir default-directory))
@@ -1146,7 +1225,8 @@ Return the list of files that haven't been handled."
(unless git-status-mode-map
(let ((map (make-keymap))
- (diff-map (make-sparse-keymap)))
+ (diff-map (make-sparse-keymap))
+ (toggle-map (make-sparse-keymap)))
(suppress-keymap map)
(define-key map "?" 'git-help)
(define-key map "h" 'git-help)
@@ -1170,6 +1250,7 @@ Return the list of files that haven't been handled."
(define-key map "q" 'git-status-quit)
(define-key map "r" 'git-remove-file)
(define-key map "R" 'git-resolve-file)
+ (define-key map "t" toggle-map)
(define-key map "T" 'git-toggle-all-marks)
(define-key map "u" 'git-unmark-file)
(define-key map "U" 'git-revert-file)
@@ -1186,6 +1267,11 @@ Return the list of files that haven't been handled."
(define-key diff-map "h" 'git-diff-file-merge-head)
(define-key diff-map "m" 'git-diff-file-mine)
(define-key diff-map "o" 'git-diff-file-other)
+ ; the toggle submap
+ (define-key toggle-map "u" 'git-toggle-show-uptodate)
+ (define-key toggle-map "i" 'git-toggle-show-ignored)
+ (define-key toggle-map "k" 'git-toggle-show-unknown)
+ (define-key toggle-map "m" 'git-toggle-all-marks)
(setq git-status-mode-map map)))
;; git mode should only run in the *git status* buffer
@@ -1207,6 +1293,9 @@ Commands:
(let ((status (ewoc-create 'git-fileinfo-prettyprint "" "")))
(set (make-local-variable 'git-status) status))
(set (make-local-variable 'list-buffers-directory) default-directory)
+ (make-local-variable 'git-show-uptodate)
+ (make-local-variable 'git-show-ignored)
+ (make-local-variable 'git-show-unknown)
(run-hooks 'git-status-mode-hook)))
(defun git-find-status-buffer (dir)
diff --git a/contrib/examples/git-reset.sh b/contrib/examples/git-reset.sh
new file mode 100755
index 0000000000..bafeb52cd1
--- /dev/null
+++ b/contrib/examples/git-reset.sh
@@ -0,0 +1,106 @@
+#!/bin/sh
+#
+# Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano
+#
+USAGE='[--mixed | --soft | --hard] [<commit-ish>] [ [--] <paths>...]'
+SUBDIRECTORY_OK=Yes
+. git-sh-setup
+set_reflog_action "reset $*"
+require_work_tree
+
+update= reset_type=--mixed
+unset rev
+
+while test $# != 0
+do
+ case "$1" in
+ --mixed | --soft | --hard)
+ reset_type="$1"
+ ;;
+ --)
+ break
+ ;;
+ -*)
+ usage
+ ;;
+ *)
+ rev=$(git rev-parse --verify "$1") || exit
+ shift
+ break
+ ;;
+ esac
+ shift
+done
+
+: ${rev=HEAD}
+rev=$(git rev-parse --verify $rev^0) || exit
+
+# Skip -- in "git reset HEAD -- foo" and "git reset -- foo".
+case "$1" in --) shift ;; esac
+
+# git reset --mixed tree [--] paths... can be used to
+# load chosen paths from the tree into the index without
+# affecting the working tree nor HEAD.
+if test $# != 0
+then
+ test "$reset_type" = "--mixed" ||
+ die "Cannot do partial $reset_type reset."
+
+ git diff-index --cached $rev -- "$@" |
+ sed -e 's/^:\([0-7][0-7]*\) [0-7][0-7]* \([0-9a-f][0-9a-f]*\) [0-9a-f][0-9a-f]* [A-Z] \(.*\)$/\1 \2 \3/' |
+ git update-index --add --remove --index-info || exit
+ git update-index --refresh
+ exit
+fi
+
+cd_to_toplevel
+
+if test "$reset_type" = "--hard"
+then
+ update=-u
+fi
+
+# Soft reset does not touch the index file nor the working tree
+# at all, but requires them in a good order. Other resets reset
+# the index file to the tree object we are switching to.
+if test "$reset_type" = "--soft"
+then
+ if test -f "$GIT_DIR/MERGE_HEAD" ||
+ test "" != "$(git ls-files --unmerged)"
+ then
+ die "Cannot do a soft reset in the middle of a merge."
+ fi
+else
+ git read-tree -v --reset $update "$rev" || exit
+fi
+
+# Any resets update HEAD to the head being switched to.
+if orig=$(git rev-parse --verify HEAD 2>/dev/null)
+then
+ echo "$orig" >"$GIT_DIR/ORIG_HEAD"
+else
+ rm -f "$GIT_DIR/ORIG_HEAD"
+fi
+git update-ref -m "$GIT_REFLOG_ACTION" HEAD "$rev"
+update_ref_status=$?
+
+case "$reset_type" in
+--hard )
+ test $update_ref_status = 0 && {
+ printf "HEAD is now at "
+ GIT_PAGER= git log --max-count=1 --pretty=oneline \
+ --abbrev-commit HEAD
+ }
+ ;;
+--soft )
+ ;; # Nothing else to do
+--mixed )
+ # Report what has not been updated.
+ git update-index --refresh
+ ;;
+esac
+
+rm -f "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/rr-cache/MERGE_RR" \
+ "$GIT_DIR/SQUASH_MSG" "$GIT_DIR/MERGE_MSG"
+
+exit $update_ref_status
diff --git a/contrib/fast-import/git-import.perl b/contrib/fast-import/git-import.perl
new file mode 100755
index 0000000000..f9fef6db28
--- /dev/null
+++ b/contrib/fast-import/git-import.perl
@@ -0,0 +1,64 @@
+#!/usr/bin/perl
+#
+# Performs an initial import of a directory. This is the equivalent
+# of doing 'git init; git add .; git commit'. It's a little slower,
+# but is meant to be a simple fast-import example.
+
+use strict;
+use File::Find;
+
+my $USAGE = 'Usage: git-import branch import-message';
+my $branch = shift or die "$USAGE\n";
+my $message = shift or die "$USAGE\n";
+
+chomp(my $username = `git config user.name`);
+chomp(my $email = `git config user.email`);
+die 'You need to set user name and email'
+ unless $username && $email;
+
+system('git init');
+open(my $fi, '|-', qw(git fast-import --date-format=now))
+ or die "unable to spawn fast-import: $!";
+
+print $fi <<EOF;
+commit refs/heads/$branch
+committer $username <$email> now
+data <<MSGEOF
+$message
+MSGEOF
+
+EOF
+
+find(
+ sub {
+ if($File::Find::name eq './.git') {
+ $File::Find::prune = 1;
+ return;
+ }
+ return unless -f $_;
+
+ my $fn = $File::Find::name;
+ $fn =~ s#^.\/##;
+
+ open(my $in, '<', $_)
+ or die "unable to open $fn: $!";
+ my @st = stat($in)
+ or die "unable to stat $fn: $!";
+ my $len = $st[7];
+
+ print $fi "M 644 inline $fn\n";
+ print $fi "data $len\n";
+ while($len > 0) {
+ my $r = read($in, my $buf, $len < 4096 ? $len : 4096);
+ defined($r) or die "read error from $fn: $!";
+ $r > 0 or die "premature EOF from $fn: $!";
+ print $fi $buf;
+ $len -= $r;
+ }
+ print $fi "\n";
+
+ }, '.'
+);
+
+close($fi);
+exit $?;
diff --git a/contrib/fast-import/git-import.sh b/contrib/fast-import/git-import.sh
new file mode 100755
index 0000000000..0ca7718d05
--- /dev/null
+++ b/contrib/fast-import/git-import.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+#
+# Performs an initial import of a directory. This is the equivalent
+# of doing 'git init; git add .; git commit'. It's a lot slower,
+# but is meant to be a simple fast-import example.
+
+if [ -z "$1" -o -z "$2" ]; then
+ echo "Usage: git-import branch import-message"
+ exit 1
+fi
+
+USERNAME="$(git config user.name)"
+EMAIL="$(git config user.email)"
+
+if [ -z "$USERNAME" -o -z "$EMAIL" ]; then
+ echo "You need to set user name and email"
+ exit 1
+fi
+
+git init
+
+(
+ cat <<EOF
+commit refs/heads/$1
+committer $USERNAME <$EMAIL> now
+data <<MSGEOF
+$2
+MSGEOF
+
+EOF
+ find * -type f|while read i;do
+ echo "M 100644 inline $i"
+ echo data $(stat -c '%s' "$i")
+ cat "$i"
+ echo
+ done
+ echo
+) | git fast-import --date-format=now
diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
index 65c57ac4d8..557649a14a 100755
--- a/contrib/fast-import/git-p4
+++ b/contrib/fast-import/git-p4
@@ -289,6 +289,19 @@ def createOrUpdateBranchesFromOrigin(localRefPrefix = "refs/remotes/p4/", silent
def originP4BranchesExist():
return gitBranchExists("origin") or gitBranchExists("origin/p4") or gitBranchExists("origin/p4/master")
+def p4ChangesForPaths(depotPaths, changeRange):
+ assert depotPaths
+ output = read_pipe_lines("p4 changes " + ' '.join (["%s...%s" % (p, changeRange)
+ for p in depotPaths]))
+
+ changes = []
+ for line in output:
+ changeNum = line.split(" ")[1]
+ changes.append(int(changeNum))
+
+ changes.sort()
+ return changes
+
class Command:
def __init__(self):
self.usage = "usage: %prog [options]"
@@ -672,9 +685,8 @@ class P4Submit(Command):
f.close();
os.chdir(self.clientPath)
- response = raw_input("Do you want to sync %s with p4 sync? [y]es/[n]o " % self.clientPath)
- if response == "y" or response == "yes":
- system("p4 sync ...")
+ print "Syncronizing p4 checkout..."
+ system("p4 sync ...")
if self.reset:
self.firstTime = True
@@ -713,10 +725,14 @@ class P4Submit(Command):
else:
print "All changes applied!"
os.chdir(self.oldWorkingDirectory)
- response = raw_input("Do you want to sync from Perforce now using git-p4 rebase? [y]es/[n]o ")
+
+ sync = P4Sync()
+ sync.run([])
+
+ response = raw_input("Do you want to rebase current HEAD from Perforce now using git-p4 rebase? [y]es/[n]o ")
if response == "y" or response == "yes":
rebase = P4Rebase()
- rebase.run([])
+ rebase.rebase()
os.remove(self.configFile)
return True
@@ -1110,6 +1126,186 @@ class P4Sync(Command):
self.keepRepoPath = (d.has_key('options')
and ('keepRepoPath' in d['options']))
+ def gitRefForBranch(self, branch):
+ if branch == "main":
+ return self.refPrefix + "master"
+
+ if len(branch) <= 0:
+ return branch
+
+ return self.refPrefix + self.projectName + branch
+
+ def gitCommitByP4Change(self, ref, change):
+ if self.verbose:
+ print "looking in ref " + ref + " for change %s using bisect..." % change
+
+ earliestCommit = ""
+ latestCommit = parseRevision(ref)
+
+ while True:
+ if self.verbose:
+ print "trying: earliest %s latest %s" % (earliestCommit, latestCommit)
+ next = read_pipe("git rev-list --bisect %s %s" % (latestCommit, earliestCommit)).strip()
+ if len(next) == 0:
+ if self.verbose:
+ print "argh"
+ return ""
+ log = extractLogMessageFromGitCommit(next)
+ settings = extractSettingsGitLog(log)
+ currentChange = int(settings['change'])
+ if self.verbose:
+ print "current change %s" % currentChange
+
+ if currentChange == change:
+ if self.verbose:
+ print "found %s" % next
+ return next
+
+ if currentChange < change:
+ earliestCommit = "^%s" % next
+ else:
+ latestCommit = "%s" % next
+
+ return ""
+
+ def importNewBranch(self, branch, maxChange):
+ # make fast-import flush all changes to disk and update the refs using the checkpoint
+ # command so that we can try to find the branch parent in the git history
+ self.gitStream.write("checkpoint\n\n");
+ self.gitStream.flush();
+ branchPrefix = self.depotPaths[0] + branch + "/"
+ range = "@1,%s" % maxChange
+ #print "prefix" + branchPrefix
+ changes = p4ChangesForPaths([branchPrefix], range)
+ if len(changes) <= 0:
+ return False
+ firstChange = changes[0]
+ #print "first change in branch: %s" % firstChange
+ sourceBranch = self.knownBranches[branch]
+ sourceDepotPath = self.depotPaths[0] + sourceBranch
+ sourceRef = self.gitRefForBranch(sourceBranch)
+ #print "source " + sourceBranch
+
+ branchParentChange = int(p4Cmd("changes -m 1 %s...@1,%s" % (sourceDepotPath, firstChange))["change"])
+ #print "branch parent: %s" % branchParentChange
+ gitParent = self.gitCommitByP4Change(sourceRef, branchParentChange)
+ if len(gitParent) > 0:
+ self.initialParents[self.gitRefForBranch(branch)] = gitParent
+ #print "parent git commit: %s" % gitParent
+
+ self.importChanges(changes)
+ return True
+
+ def importChanges(self, changes):
+ cnt = 1
+ for change in changes:
+ description = p4Cmd("describe %s" % change)
+ self.updateOptionDict(description)
+
+ if not self.silent:
+ sys.stdout.write("\rImporting revision %s (%s%%)" % (change, cnt * 100 / len(changes)))
+ sys.stdout.flush()
+ cnt = cnt + 1
+
+ try:
+ if self.detectBranches:
+ branches = self.splitFilesIntoBranches(description)
+ for branch in branches.keys():
+ ## HACK --hwn
+ branchPrefix = self.depotPaths[0] + branch + "/"
+
+ parent = ""
+
+ filesForCommit = branches[branch]
+
+ if self.verbose:
+ print "branch is %s" % branch
+
+ self.updatedBranches.add(branch)
+
+ if branch not in self.createdBranches:
+ self.createdBranches.add(branch)
+ parent = self.knownBranches[branch]
+ if parent == branch:
+ parent = ""
+ else:
+ fullBranch = self.projectName + branch
+ if fullBranch not in self.p4BranchesInGit:
+ if not self.silent:
+ print("\n Importing new branch %s" % fullBranch);
+ if self.importNewBranch(branch, change - 1):
+ parent = ""
+ self.p4BranchesInGit.append(fullBranch)
+ if not self.silent:
+ print("\n Resuming with change %s" % change);
+
+ if self.verbose:
+ print "parent determined through known branches: %s" % parent
+
+ branch = self.gitRefForBranch(branch)
+ parent = self.gitRefForBranch(parent)
+
+ if self.verbose:
+ print "looking for initial parent for %s; current parent is %s" % (branch, parent)
+
+ if len(parent) == 0 and branch in self.initialParents:
+ parent = self.initialParents[branch]
+ del self.initialParents[branch]
+
+ self.commit(description, filesForCommit, branch, [branchPrefix], parent)
+ else:
+ files = self.extractFilesFromCommit(description)
+ self.commit(description, files, self.branch, self.depotPaths,
+ self.initialParent)
+ self.initialParent = ""
+ except IOError:
+ print self.gitError.read()
+ sys.exit(1)
+
+ def importHeadRevision(self, revision):
+ print "Doing initial import of %s from revision %s into %s" % (' '.join(self.depotPaths), revision, self.branch)
+
+ details = { "user" : "git perforce import user", "time" : int(time.time()) }
+ details["desc"] = ("Initial import of %s from the state at revision %s"
+ % (' '.join(self.depotPaths), revision))
+ details["change"] = revision
+ newestRevision = 0
+
+ fileCnt = 0
+ for info in p4CmdList("files "
+ + ' '.join(["%s...%s"
+ % (p, revision)
+ for p in self.depotPaths])):
+
+ if info['code'] == 'error':
+ sys.stderr.write("p4 returned an error: %s\n"
+ % info['data'])
+ sys.exit(1)
+
+
+ change = int(info["change"])
+ if change > newestRevision:
+ newestRevision = change
+
+ if info["action"] == "delete":
+ # don't increase the file cnt, otherwise details["depotFile123"] will have gaps!
+ #fileCnt = fileCnt + 1
+ continue
+
+ for prop in ["depotFile", "rev", "action", "type" ]:
+ details["%s%s" % (prop, fileCnt)] = info[prop]
+
+ fileCnt = fileCnt + 1
+
+ details["change"] = newestRevision
+ self.updateOptionDict(details)
+ try:
+ self.commit(details, self.extractFilesFromCommit(details), self.branch, self.depotPaths)
+ except IOError:
+ print "IO error with git fast-import. Is your git version recent enough?"
+ print self.gitError.read()
+
+
def run(self, args):
self.depotPaths = []
self.changeRange = ""
@@ -1207,7 +1403,7 @@ class P4Sync(Command):
self.depotPaths = sorted(args)
- self.revision = ""
+ revision = ""
self.users = {}
newPaths = []
@@ -1218,15 +1414,15 @@ class P4Sync(Command):
if self.changeRange == "@all":
self.changeRange = ""
elif ',' not in self.changeRange:
- self.revision = self.changeRange
+ revision = self.changeRange
self.changeRange = ""
p = p[:atIdx]
elif p.find("#") != -1:
hashIdx = p.index("#")
- self.revision = p[hashIdx:]
+ revision = p[hashIdx:]
p = p[:hashIdx]
elif self.previousDepotPaths == []:
- self.revision = "#head"
+ revision = "#head"
p = re.sub ("\.\.\.$", "", p)
if not p.endswith("/"):
@@ -1267,49 +1463,8 @@ class P4Sync(Command):
self.gitStream = importProcess.stdin
self.gitError = importProcess.stderr
- if self.revision:
- print "Doing initial import of %s from revision %s into %s" % (' '.join(self.depotPaths), self.revision, self.branch)
-
- details = { "user" : "git perforce import user", "time" : int(time.time()) }
- details["desc"] = ("Initial import of %s from the state at revision %s"
- % (' '.join(self.depotPaths), self.revision))
- details["change"] = self.revision
- newestRevision = 0
-
- fileCnt = 0
- for info in p4CmdList("files "
- + ' '.join(["%s...%s"
- % (p, self.revision)
- for p in self.depotPaths])):
-
- if info['code'] == 'error':
- sys.stderr.write("p4 returned an error: %s\n"
- % info['data'])
- sys.exit(1)
-
-
- change = int(info["change"])
- if change > newestRevision:
- newestRevision = change
-
- if info["action"] == "delete":
- # don't increase the file cnt, otherwise details["depotFile123"] will have gaps!
- #fileCnt = fileCnt + 1
- continue
-
- for prop in ["depotFile", "rev", "action", "type" ]:
- details["%s%s" % (prop, fileCnt)] = info[prop]
-
- fileCnt = fileCnt + 1
-
- details["change"] = newestRevision
- self.updateOptionDict(details)
- try:
- self.commit(details, self.extractFilesFromCommit(details), self.branch, self.depotPaths)
- except IOError:
- print "IO error with git fast-import. Is your git version recent enough?"
- print self.gitError.read()
-
+ if revision:
+ self.importHeadRevision(revision)
else:
changes = []
@@ -1327,15 +1482,7 @@ class P4Sync(Command):
if self.verbose:
print "Getting p4 changes for %s...%s" % (', '.join(self.depotPaths),
self.changeRange)
- assert self.depotPaths
- output = read_pipe_lines("p4 changes " + ' '.join (["%s...%s" % (p, self.changeRange)
- for p in self.depotPaths]))
-
- for line in output:
- changeNum = line.split(" ")[1]
- changes.append(int(changeNum))
-
- changes.sort()
+ changes = p4ChangesForPaths(self.depotPaths, self.changeRange)
if len(self.maxChanges) > 0:
changes = changes[:min(int(self.maxChanges), len(changes))]
@@ -1350,74 +1497,7 @@ class P4Sync(Command):
self.updatedBranches = set()
- cnt = 1
- for change in changes:
- description = p4Cmd("describe %s" % change)
- self.updateOptionDict(description)
-
- if not self.silent:
- sys.stdout.write("\rImporting revision %s (%s%%)" % (change, cnt * 100 / len(changes)))
- sys.stdout.flush()
- cnt = cnt + 1
-
- try:
- if self.detectBranches:
- branches = self.splitFilesIntoBranches(description)
- for branch in branches.keys():
- ## HACK --hwn
- branchPrefix = self.depotPaths[0] + branch + "/"
-
- parent = ""
-
- filesForCommit = branches[branch]
-
- if self.verbose:
- print "branch is %s" % branch
-
- self.updatedBranches.add(branch)
-
- if branch not in self.createdBranches:
- self.createdBranches.add(branch)
- parent = self.knownBranches[branch]
- if parent == branch:
- parent = ""
- elif self.verbose:
- print "parent determined through known branches: %s" % parent
-
- # main branch? use master
- if branch == "main":
- branch = "master"
- else:
-
- ## FIXME
- branch = self.projectName + branch
-
- if parent == "main":
- parent = "master"
- elif len(parent) > 0:
- ## FIXME
- parent = self.projectName + parent
-
- branch = self.refPrefix + branch
- if len(parent) > 0:
- parent = self.refPrefix + parent
-
- if self.verbose:
- print "looking for initial parent for %s; current parent is %s" % (branch, parent)
-
- if len(parent) == 0 and branch in self.initialParents:
- parent = self.initialParents[branch]
- del self.initialParents[branch]
-
- self.commit(description, filesForCommit, branch, [branchPrefix], parent)
- else:
- files = self.extractFilesFromCommit(description)
- self.commit(description, files, self.branch, self.depotPaths,
- self.initialParent)
- self.initialParent = ""
- except IOError:
- print self.gitError.read()
- sys.exit(1)
+ self.importChanges(changes)
if not self.silent:
print ""
@@ -1427,7 +1507,6 @@ class P4Sync(Command):
sys.stdout.write("%s " % b)
sys.stdout.write("\n")
-
self.gitStream.close()
if importProcess.wait() != 0:
die("fast-import failed: %s" % self.gitError.read())
@@ -1448,6 +1527,9 @@ class P4Rebase(Command):
sync = P4Sync()
sync.run([])
+ return self.rebase()
+
+ def rebase(self):
[upstream, settings] = findUpstreamBranchPoint()
if len(upstream) == 0:
die("Cannot find upstream branchpoint for rebase")