threads / discuss / 35561

git-mv-submodule

Subject: git-mv-submodule

## tl;dr

3 messages between Dec 21, 2013 and Dec 21, 2013.

replies: 2people: 2as markdown or json

fREW Schmidt· Dec 21, 2013, 09:48 UTC · lore
Hello all,

I was on a plane, moving around some of the many (30ish) submodules in my dotfiles and got really annoyed at how much work it is (move the dir, remove old from git, add new to git, fix .gitmodules, fix .git/config, fix all the parts of the submodule config) so I wrote a perl script to work for the most common case.

As far as I know it should work for anyone not doing Something Weird, ie manually fiddling with their submodules. The main case it does not support that I'd like to in the future is submodules containing submodules, and also at some point I'd like to wrap git mv to invoke this script on demand automatically.

Note that this script requires perl 5.10.1, released in 2009. If you are stuck with something inferior to that you can comment out the version at the top and the autodie usage and it should work further back, but won't be quite as robust.

Enjoy!
-- 
fREW Schmidt
http://blog.afoolishmanifesto.com


#!/usr/bin/env perl

use 5.10.1;
use strict;
use warnings;

use autodie;
use File::Basename 'dirname';
use File::Path 'make_path';

die "you must pass both a from and a to" unless @ARGV == 2;

my ($from, $to) = @ARGV;

die "you have changes in your working copy!"
   unless is_clean();

# move the real dir
make_path(dirname($to));
safe_system('mv', $from, $to);

# move the git dir (not really that important)
make_path(dirname(".git/modules/$to"));
safe_system('mv', ".git/modules/$from", ".git/modules/$to");

# update .gitmodules and .git/config book keeping
spew($_, slurp($_) =~ s/\Q$from\E/$to/gr)
   for qw( .gitmodules .git/config );

my $dir_count = scalar split qr(/), $to =~ s(/$)()r;

my $derp = ('../' x (2 + $dir_count)) . $to;

# update .git/modules/$to/config book keeping
spew(
   ".git/modules/$to/config",
   slurp(".git/modules/$to/config") =~ s/worktree.*/worktree = $derp/gr
);

# update $to book keeping
spew(
   "$to/.git",
   'gitdir: ' . ('../' x $dir_count) . ".git/modules/$to"
);

safe_system(qw( git add -A ), $from, $to, '.gitmodules' );

sub safe_system {
   system(@_);

   die "@_ exited poorly :("
      if $? >> 8;
}

sub safe_capture {
   my $ret = qx(@_);

   die "@_ exited poorly :("
      if $? >> 8;

   return $ret;
}

sub slurp {
   open my $fh, '<', $_[0];
   local $/ = undef;
   scalar <$fh>
}

sub spew {
   open my $fh, '>', $_[0];
   print {$fh} $_[1]
}

sub is_clean { !safe_capture(qw(git status --porcelain)) }
Jens Lehmann· Dec 21, 2013, 16:08 UTC · re: fREW Schmidt · lore

Re: git-mv-submodule

Am 21.12.2013 10:48, schrieb fREW Schmidt:
Show 13 quoted lines
> Hello all,
> 
> I was on a plane, moving around some of the many (30ish) submodules in
> my dotfiles and got really annoyed at how much work it is (move the
> dir, remove old from git, add new to git, fix .gitmodules, fix
> .git/config, fix all the parts of the submodule config) so I wrote a
> perl script to work for the most common case.
> 
> As far as I know it should work for anyone not doing Something Weird,
> ie manually fiddling with their submodules.  The main case it does not
> support that I'd like to in the future is submodules containing
> submodules, and also at some point I'd like to wrap git mv to invoke
> this script on demand automatically.

Thanks for sharing! Form a cursory look over your perl script it looks like it does what stock "git mv" will do since 1.8.5 (except for changing the name of the submodule, which I would not advise to do when only moving the submodule location in the work tree).

fREW Schmidt· Dec 21, 2013, 16:23 UTC · re: Jens Lehmann · lore

Re: git-mv-submodule

On Sat, Dec 21, 2013 at 05:08:59PM +0100, Jens Lehmann wrote:
Show 5 quoted lines
> Am 21.12.2013 10:48, schrieb fREW Schmidt:
> Thanks for sharing! Form a cursory look over your perl script it
> looks like it does what stock "git mv" will do since 1.8.5 (except
> for changing the name of the submodule, which I would not advise
> to do when only moving the submodule location in the work tree).

See, I thought I read that in the changelog; unfortunately I don'g thing it does the final set of book-keeping (changing the .git file if you changed the depth of the submodule in the mv and changing the path of the worktree in the actual git repo in .git/modules)

I'd love to be wrong on that as this script is clearly not perfect. I think my second little script in my previous email re git submodule bugs shows the issue. I'll include it here for simplicity though:

 mkdir -p test/a test/b
 cd test/a
 git init
 touch a.txt
 git add a.txt
 git ci -m 'initial commit'
 cd ../b
 git init
 mkdir c
 touch c/c.txt
 git submodule add ../a c/a
 git ci -m 'initial commit'
 git mv c d
 git status
-- 
fREW Schmidt
http://blog.afoolishmanifesto.com

← back to recent threads