summaryrefslogtreecommitdiff
path: root/doc/tips/DreamHost
ModeNameSize
-rw-r--r--discussion.mdwn1065logplain
="hl kwa">use open qw{:utf8 :std};
  • my $sha1_pattern = qr/[0-9a-fA-F]{40}/; # pattern to validate Git sha1sums
  • my $dummy_commit_msg = 'dummy commit'; # message to skip in recent changes
  • sub _safe_git (&@) { #{{{
  • # Start a child process safely without resorting /bin/sh.
  • # Return command output or success state (in scalar context).
  • my ($error_handler, @cmdline) = @_;
  • my $pid = open my $OUT, "-|";
  • error("Cannot fork: $!") if !defined $pid;
  • if (!$pid) {
  • # In child.
  • # Git commands want to be in wc.
  • chdir $config{srcdir}
  • or error("Cannot chdir to $config{srcdir}: $!");
  • exec @cmdline or error("Cannot exec '@cmdline': $!");
  • }
  • # In parent.
  • my @lines;
  • while (<$OUT>) {
  • chomp;
  • push @lines, $_;
  • }
  • close $OUT;
  • $error_handler->("'@cmdline' failed: $!") if $? && $error_handler;
  • return wantarray ? @lines : ($? == 0);
  • }
  • # Convenient wrappers.
  • sub run_or_die ($@) { _safe_git(\&error, @_) }
  • sub run_or_cry ($@) { _safe_git(sub { warn @_ }, @_) }
  • sub run_or_non ($@) { _safe_git(undef, @_) }
  • #}}}
  • sub _merge_past ($$$) { #{{{
  • # Unlike with Subversion, Git cannot make a 'svn merge -rN:M file'.
  • # Git merge commands work with the committed changes, except in the
  • # implicit case of '-m' of git checkout(1). So we should invent a
  • # kludge here. In principle, we need to create a throw-away branch
  • # in preparing for the merge itself. Since branches are cheap (and
  • # branching is fast), this shouldn't cost high.
  • #
  • # The main problem is the presence of _uncommitted_ local changes. One
  • # possible approach to get rid of this situation could be that we first
  • # make a temporary commit in the master branch and later restore the
  • # initial state (this is possible since Git has the ability to undo a
  • # commit, i.e. 'git reset --soft HEAD^'). The method can be summarized
  • # as follows:
  • #
  • # - create a diff of HEAD:current-sha1
  • # - dummy commit
  • # - create a dummy branch and switch to it
  • # - rewind to past (reset --hard to the current-sha1)
  • # - apply the diff and commit
  • # - switch to master and do the merge with the dummy branch
  • # - make a soft reset (undo the last commit of master)
  • #
  • # The above method has some drawbacks: (1) it needs a redundant commit
  • # just to get rid of local changes, (2) somewhat slow because of the
  • # required system forks. Until someone points a more straight method
  • # (which I would be grateful) I have implemented an alternative method.
  • # In this approach, we hide all the modified files from Git by renaming
  • # them (using the 'rename' builtin) and later restore those files in
  • # the throw-away branch (that is, we put the files themselves instead
  • # of applying a patch).