nitfol();
}'
-We have already talked about the "--stdin" form of git-diff-tree
+We have already talked about the "\--stdin" form of git-diff-tree
command that reads the list of commits and compares each commit
with its parents. The git-whatchanged command internally runs
the equivalent of the above command, and can be used like this:
files:
- git-diff-index compares contents of a "tree" object and the
- working directory (when '--cached' flag is not used) or a
- "tree" object and the index file (when '--cached' flag is
+ working directory (when '\--cached' flag is not used) or a
+ "tree" object and the index file (when '\--cached' flag is
used);
- git-diff-files compares contents of the index file and the
number after "-M" or "-C" option (e.g. "-M8" to tell it to use
8/10 = 80%).
-Note. When the "-C" option is used with --find-copies-harder
+Note. When the "-C" option is used with `\--find-copies-harder`
option, git-diff-\* commands feed unmodified filepairs to
diffcore mechanism as well as modified ones. This lets the copy
detector consider unmodified files as copy source candidates at
-the expense of making it slower. Without --find-copies-harder,
+the expense of making it slower. Without `\--find-copies-harder`,
git-diff-\* commands can detect copies only if the file that was
copied happened to have been modified in the same changeset.
This transformation is used to find filepairs that represent
changes that touch a specified string, and is controlled by the
--S option and the --pickaxe-all option to the git-diff-*
+-S option and the `\--pickaxe-all` option to the git-diff-*
commands.
When diffcore-pickaxe is in use, it checks if there are
string appeared in this changeset". It also checks for the
opposite case that loses the specified string.
-When --pickaxe-all is not in effect, diffcore-pickaxe leaves
+When `\--pickaxe-all` is not in effect, diffcore-pickaxe leaves
only such filepairs that touches the specified string in its
-output. When --pickaxe-all is used, diffcore-pickaxe leaves all
+output. When `\--pickaxe-all` is used, diffcore-pickaxe leaves all
filepairs intact if there is such a filepair, or makes the
output empty otherwise. The latter behaviour is designed to
make reviewing of the changes in the context of the whole
NAME
----
-git-archimport - Import an arch repository into git
+git-archimport - Import an Arch repository into GIT
SYNOPSIS
--------
-`git-archimport` [--option...] <args>
+`git-archimport` [ -h ] [ -v ] [ -T ] [ -t tempdir ]
+ <archive/branch> [ <archive/branch> ]
DESCRIPTION
-----------
-The script expects you to provide the key roots where it can start the
-import from an 'initial import' or 'tag' type of Arch commit. It will
-then follow all the branching and tagging within the provided roots.
+Imports a project from one or more Arch repositories. It will follow branches
+and repositories within the namespaces defined by the <archive/branch>
+parameters suppplied. If it cannot find the remote branch a merge comes from
+it will just import it as a regular commit. If it can find it, it will mark it
+as a merge whenever possible (see discussion below).
-It will die if it sees branches that have different roots.
+The script expects you to provide the key roots where it can start the import
+from an 'initial import' or 'tag' type of Arch commit. It will follow and import
+new branches within the provided roots.
+It expects to be dealing with one project only. If it sees
+branches that have different roots, it will refuse to run. In that case, edit your
+<archive/branch> parameters to define clearly the scope of the import.
+
+`git-archimport` uses `tla` extensively in the background to access the Arch repository.
+Make sure you have a recent version of `tla` available in the path. `tla` must
+know about the repositories you pass to `git-archimport`.
+
+For the initial import `git-archimport` expects to find itself in an empty
+directory. To follow the development of a project that uses Arch, rerun
+`git-archimport` with the same parameters as the initial import to perform incremental imports.
+
+MERGES
+------
+Patch merge data from Arch is used to mark merges in GIT as well. GIT
+does not care much about tracking patches, and only considers a merge when a
+branch incorporates all the commits since the point they forked. The end result
+is that GIT will have a good idea of how far branches have diverged. So the
+import process does lose some patch-trading metadata.
+
+Fortunately, when you try and merge branches imported from Arch,
+GIT will find a good merge base, and it has a good chance of identifying
+patches that have been traded out-of-sequence between the branches.
OPTIONS
-------
---option::
- Some option not yet documented.
-<args>...::
- Some argument not yet documented.
+-h::
+ Display usage.
+
+-v::
+ Verbose output.
+
+-T::
+ Many tags. Will create a tag for every commit, reflecting the commit
+ name in the Arch repository.
+
+-t <tmpdir>::
+ Override the default tempdir.
+
+
+<archive/branch>::
+ Archive/branch identifier in a format that `tla log` understands.
Author
Documentation
--------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
+Documentation by Junio C Hamano, Martin Langhoff and the git-list <git@vger.kernel.org>.
GIT
---
----------
This hook is invoked by `git-commit`, and can be bypassed
-with `--no-verify` option. It takes no parameter, and is
+with `\--no-verify` option. It takes no parameter, and is
invoked before obtaining the proposed commit log message and
making a commit. Exiting with non-zero status from this script
causes the `git-commit` to abort.
----------
This hook is invoked by `git-commit`, and can be bypassed
-with `--no-verify` option. It takes a single parameter, the
+with `\--no-verify` option. It takes a single parameter, the
name of the file that holds the proposed commit log message.
Exiting with non-zero status causes the `git-commit` to
abort.
(which is correct, so never mind), and you can write a small merge
message about your adventures in git-merge-land.
-After you're done, start up `gitk --all` to see graphically what the
+After you're done, start up `gitk \--all` to see graphically what the
history looks like. Notice that `mybranch` still exists, and you can
switch to it, and continue to work with it if you want to. The
`mybranch` branch will not contain the merge, but next time you merge it
the tree of your branch to that of the `master` branch. This is
often called 'fast forward' merge.
-You can run `gitk --all` again to see how the commit ancestry
+You can run `gitk \--all` again to see how the commit ancestry
looks like, or run `show-branch`, which tells you this.
------------------------------------------------
static struct child {
pid_t pid;
- socklen_t addrlen;
+ int addrlen;
struct sockaddr_storage address;
} live_child[MAX_CHILDREN];
-static void add_child(int idx, pid_t pid, struct sockaddr *addr, socklen_t addrlen)
+static void add_child(int idx, pid_t pid, struct sockaddr *addr, int addrlen)
{
live_child[idx].pid = pid;
live_child[idx].addrlen = addrlen;
}
}
-static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
+static void handle(int incoming, struct sockaddr *addr, int addrlen)
{
pid_t pid = fork();
if (FD_ISSET(sockfd, &fds)) {
struct sockaddr_storage ss;
- socklen_t sslen = sizeof(ss);
+ int sslen = sizeof(ss);
int incoming = accept(sockfd, (struct sockaddr *)&ss, &sslen);
if (incoming < 0) {
switch (errno) {
if (*cp++ != ' ')
break;
status = *cp++;
- if (!strchr("MCRNDU", status))
+ if (!strchr("AMCRDU", status))
break;
two_paths = score = 0;
if (status == DIFF_STATUS_RENAMED ||
# The basic idea is to walk the output of tla abrowse,
# fetch the changesets and apply them.
#
+
=head1 Invocation
- git-archimport -i <archive>/<branch> [<archive>/<branch>]
- [ <archive>/<branch> ]
+ git-archimport [ -h ] [ -v ] [ -T ] [ -t tempdir ] <archive>/<branch> [ <archive>/<branch> ]
- The script expects you to provide the key roots where it can start the
- import from an 'initial import' or 'tag' type of Arch commit. It will
- then follow all the branching and tagging within the provided roots.
+Imports a project from one or more Arch repositories. It will follow branches
+and repositories within the namespaces defined by the <archive/branch>
+parameters suppplied. If it cannot find the remote branch a merge comes from
+it will just import it as a regular commit. If it can find it, it will mark it
+as a merge whenever possible.
- It will die if it sees branches that have different roots.
+See man (1) git-archimport for more details.
-=head2 TODO
+=head1 TODO
- - keep track of merged patches, and mark a git merge when it happens
- - smarter rules to parse the archive history "up" and "down"
- - be able to continue an import where we left off
+ - create tag objects instead of ref tags
- audit shell-escaping of filenames
+ - hide our private tags somewhere smarter
+ - find a way to make "cat *patches | patch" safe even when patchfiles are missing newlines
=head1 Devel tricks
use warnings;
use Getopt::Std;
use File::Spec;
-use File::Temp qw(tempfile);
+use File::Temp qw(tempfile tempdir);
use File::Path qw(mkpath);
use File::Basename qw(basename dirname);
use String::ShellQuote;
$SIG{'PIPE'}="IGNORE";
$ENV{'TZ'}="UTC";
+my $git_dir = $ENV{"GIT_DIR"} || ".git";
+$ENV{"GIT_DIR"} = $git_dir;
+
our($opt_h,$opt_v, $opt_T,
$opt_C,$opt_t);
sub usage() {
print STDERR <<END;
Usage: ${\basename $0} # fetch/update GIT from Arch
- [ -h ] [ -v ] [ -T ]
- [ -C GIT_repository ] [ -t tempdir ]
+ [ -h ] [ -v ] [ -T ] [ -t tempdir ]
repository/arch-branch [ repository/arch-branch] ...
END
exit(1);
}
-getopts("ThviC:t:") or usage();
+getopts("Thvt:") or usage();
usage if $opt_h;
@ARGV >= 1 or usage();
my @arch_roots = @ARGV;
-my $tmp = $opt_t;
-$tmp ||= '/tmp';
-$tmp .= '/git-archimport/';
-
-my $git_tree = $opt_C;
-$git_tree ||= ".";
-
+my ($tmpdir, $tmpdirname) = tempdir('git-archimport-XXXXXX', TMPDIR => 1, CLEANUP => 1);
+my $tmp = $opt_t || 1;
+$tmp = tempdir('git-archimport-XXXXXX', TMPDIR => 1, CLEANUP => 1);
+$opt_v && print "+ Using $tmp as temporary directory\n";
my @psets = (); # the collection
my %psets = (); # the collection, by name
## and put an initial import
## or a full tag
my $import = 0;
-unless (-d '.git') { # initial import
+unless (-d $git_dir) { # initial import
if ($psets[0]{type} eq 'i' || $psets[0]{type} eq 't') {
print "Starting import from $psets[0]{id}\n";
`git-init-db`;
}
} else { # progressing an import
# load the rptags
- opendir(DIR, ".git/archimport/tags")
+ opendir(DIR, "$git_dir/archimport/tags")
|| die "can't opendir: $!";
while (my $file = readdir(DIR)) {
# skip non-interesting-files
- next unless -f ".git/archimport/tags/$file";
+ next unless -f "$git_dir/archimport/tags/$file";
next if $file =~ m/--base-0$/; # don't care for base-0
my $sha = ptag($file);
chomp $sha;
}
unless ($import) { # skip for import
- if ( -e ".git/refs/heads/$ps->{branch}") {
+ if ( -e "$git_dir/refs/heads/$ps->{branch}") {
# we know about this branch
`git checkout $ps->{branch}`;
} else {
# imports don't give us good info
# on added files. Shame on them
if ($ps->{type} eq 'i' || $ps->{type} eq 't') {
- `find . -type f -print0 | grep -zv '^./.git' | xargs -0 -l100 git-update-index --add`;
+ `find . -type f -print0 | grep -zv '^./$git_dir' | xargs -0 -l100 git-update-index --add`;
`git-ls-files --deleted -z | xargs --no-run-if-empty -0 -l100 git-update-index --remove`;
}
# Who's your daddy?
#
my @par;
- if ( -e ".git/refs/heads/$ps->{branch}") {
- if (open HEAD, "<.git/refs/heads/$ps->{branch}") {
+ if ( -e "$git_dir/refs/heads/$ps->{branch}") {
+ if (open HEAD, "<$git_dir/refs/heads/$ps->{branch}") {
my $p = <HEAD>;
close HEAD;
chomp $p;
#
# Update the branch
#
- open HEAD, ">.git/refs/heads/$ps->{branch}";
+ open HEAD, ">$git_dir/refs/heads/$ps->{branch}";
print HEAD $commitid;
close HEAD;
- unlink ('.git/HEAD');
- symlink("refs/heads/$ps->{branch}",".git/HEAD");
+ unlink ("$git_dir/HEAD");
+ symlink("refs/heads/$ps->{branch}","$git_dir/HEAD");
# tag accordingly
ptag($ps->{id}, $commitid); # private tag
`tla get -s --no-pristine -A $ps->{repo} $ps->{id} $tmp/import`;
die "Cannot get import: $!" if $?;
- `rsync -v --archive --delete --exclude '.git' --exclude '.arch-ids' --exclude '{arch}' $tmp/import/* ./`;
+ `rsync -v --archive --delete --exclude '$git_dir' --exclude '.arch-ids' --exclude '{arch}' $tmp/import/* ./`;
die "Cannot rsync import:$!" if $?;
`rm -fr $tmp/import`;
}
# bring in new files
- `rsync --archive --exclude '.git' --exclude '.arch-ids' --exclude '{arch}' $tmp/changeset/new-files-archive/* ./`;
+ `rsync --archive --exclude '$git_dir' --exclude '.arch-ids' --exclude '{arch}' $tmp/changeset/new-files-archive/* ./`;
# deleted files are hinted from the commitlog processing
$tag = shell_quote($tag);
if ($commit) {
- open(C,">.git/refs/tags/$tag")
+ open(C,">$git_dir/refs/tags/$tag")
or die "Cannot create tag $tag: $!\n";
print C "$commit\n"
or die "Cannot write tag $tag: $!\n";
or die "Cannot write tag $tag: $!\n";
print " * Created tag ' $tag' on '$commit'\n" if $opt_v;
} else { # read
- open(C,"<.git/refs/tags/$tag")
+ open(C,"<$git_dir/refs/tags/$tag")
or die "Cannot read tag $tag: $!\n";
$commit = <C>;
chomp $commit;
$tag =~ s|/|--|g;
$tag = shell_quote($tag);
- unless (-d '.git/archimport/tags') {
- mkpath('.git/archimport/tags');
+ unless (-d "$git_dir/archimport/tags") {
+ mkpath("$git_dir/archimport/tags");
}
if ($commit) { # write
- open(C,">.git/archimport/tags/$tag")
+ open(C,">$git_dir/archimport/tags/$tag")
or die "Cannot create tag $tag: $!\n";
print C "$commit\n"
or die "Cannot write tag $tag: $!\n";
unless $tag =~ m/--base-0$/;
} else { # read
# if the tag isn't there, return 0
- unless ( -s ".git/archimport/tags/$tag") {
+ unless ( -s "$git_dir/archimport/tags/$tag") {
return 0;
}
- open(C,"<.git/archimport/tags/$tag")
+ open(C,"<$git_dir/archimport/tags/$tag")
or die "Cannot read tag $tag: $!\n";
$commit = <C>;
chomp $commit;
SHA1_Update(context, write_buffer, left);
}
+ /* Flush first if not enough space for SHA1 signature */
+ if (left + 20 > WRITE_BUFFER_SIZE) {
+ if (write(fd, write_buffer, left) != left)
+ return -1;
+ left = 0;
+ }
+
/* Append the SHA1 signature at the end */
SHA1_Final(write_buffer + left, context);
left += 20;