[PATCH] Add git-edit-index.perl

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This script can be used to edit a file in the index without affecting
your working tree. It checkouts a copy of the file to a temporary file
and runs an editor on it. If the editor completes successfully with a
non-empty file then it updates the index with the new data.

This is useful to fine tune the results from git add -p. For example
sometimes your unrelated changes are too close together and
git-add--interactive will refuse to split them up. Using this script
you can add both the changes and later edit the index file to
temporarily remove one of the changes.

Signed-off-by: Neil Roberts <bpeeluk@xxxxxxxxxxx>
---
 .gitignore          |    1 +
 Makefile            |    1 +
 git-edit-index.perl |   98 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 100 insertions(+), 0 deletions(-)
 create mode 100755 git-edit-index.perl

diff --git a/.gitignore b/.gitignore
index d9adce5..251d90b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,6 +36,7 @@ git-diff-files
 git-diff-index
 git-diff-tree
 git-describe
+git-edit-index
 git-fast-export
 git-fast-import
 git-fetch
diff --git a/Makefile b/Makefile
index 5158197..77ee97f 100644
--- a/Makefile
+++ b/Makefile
@@ -275,6 +275,7 @@ SCRIPT_PERL += git-archimport.perl
 SCRIPT_PERL += git-cvsexportcommit.perl
 SCRIPT_PERL += git-cvsimport.perl
 SCRIPT_PERL += git-cvsserver.perl
+SCRIPT_PERL += git-edit-index.perl
 SCRIPT_PERL += git-relink.perl
 SCRIPT_PERL += git-send-email.perl
 SCRIPT_PERL += git-svn.perl
diff --git a/git-edit-index.perl b/git-edit-index.perl
new file mode 100755
index 0000000..a5d9886
--- /dev/null
+++ b/git-edit-index.perl
@@ -0,0 +1,98 @@
+#!/usr/bin/perl -w
+#
+# Copyright 2008 Neil Roberts <bpeeluk@xxxxxxxxxxx>
+#
+# GPL v2 (See COPYING)
+#
+# Opens an editor on a copy of a file in the index and updates it when
+# the editor is finished. This can be used to fine tune to results of
+# git add -p
+
+use strict;
+use warnings;
+use Git;
+
+sub usage {
+	print <<EOT;
+git edit-index <file>...
+EOT
+	exit(1);
+}
+
+sub delete_temp_files {
+        # Delete the temporary files created by checkout-index
+        # --temp. The output from checkout-index should be passed as
+        # arguments
+        foreach my $fnfull (@_) {
+                my ($tmp_fn, $fn) = split(/\t/, $fnfull);
+                unlink($tmp_fn);
+        }
+}
+
+sub check_file_size {
+        my ($fn) = @_;
+        my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
+            $atime, $mtime, $ctime, $blksize, $blocks) = stat($fn);
+
+        $size;
+}
+
+usage unless @ARGV;
+
+my $repo = Git->repository();
+
+my %file_modes;
+
+my $editor = $ENV{GIT_EDITOR}
+    || $repo->config("core.editor")
+    || $ENV{VISUAL}
+    || $ENV{EDITOR}
+    || "vi";
+
+# Create a temporary copy of each file in the index
+my @file_list = $repo->command(qw(checkout-index --temp --), @ARGV);
+
+# Get the current mode of each file
+foreach my $fnfull (@file_list) {
+        my ($tmp_fn, $fn) = split(/\t/, $fnfull);
+        my ($file_details) = $repo->command_oneline(qw(ls-files --stage --),
+                                                    $fn);
+        unless (defined($file_details) && $file_details =~ /\A([0-7]{6}) /)
+        {
+                delete_temp_files(@file_list);
+                die("$fn is not in the index");
+        }
+
+        $file_modes{$fn} = $1;
+}
+
+# Edit each file
+foreach my $fnfull (@file_list) {
+        my ($tmp_fn, $fn) = split(/\t/, $fnfull);
+
+        unless (system($editor, $tmp_fn) == 0
+                && check_file_size($tmp_fn)) {
+                # If the editor failed, the file has disappeared or it
+                # has zero size then give up
+                delete_temp_files(@file_list);
+                die("Editor failed or file has zero size");
+        }
+}
+
+# Add each file back to the index
+foreach my $fnfull (@file_list) {
+        my ($tmp_fn, $fn) = split(/\t/, $fnfull);
+
+        my $hash = $repo->command_oneline(qw(hash-object -w --), $tmp_fn);
+
+        unless (defined($hash) && $hash =~ /\A[0-9a-f]{40}\z/) {
+                delete_temp_files(@file_list);
+                die("Failed to add new file");
+        }
+
+        $repo->command(qw(update-index --cacheinfo),
+                       $file_modes{$fn}, $hash, $fn);
+}
+
+# Clean up the temporary files
+delete_temp_files(@file_list);
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux