From: Junio C Hamano <junkio@cox.net>
To: Linus Torvalds <torvalds@osdl.org>
Cc: git@vger.kernel.org
Subject: Re: Merge with git-pasky II.
Date: Thu, 14 Apr 2005 04:14:13 -0700 [thread overview]
Message-ID: <7vvf6pr4oq.fsf@assigned-by-dhcp.cox.net> (raw)
In-Reply-To: <Pine.LNX.4.58.0504140201130.7211@ppc970.osdl.org> (Linus Torvalds's message of "Thu, 14 Apr 2005 02:10:22 -0700 (PDT)")
Here is a diff to update the git-merge.perl script I showed you
earlier today ;-). It contains the following updates against
your HEAD (bb95843a5a0f397270819462812735ee29796fb4).
* git-merge.perl command we talked about on the git list. I've
covered the changed-to-the-same case etc. I still haven't done
anything about file-vs-directory case yet.
It does warn when it needed to run merge to automerge and let
merge give a warning message about conflicts if any. In
modify/remove cases, modified in one but removed in the other
files are left in either $path~A~ or $path~B~ in the merge
temporary directory, and the script issues a warning at the
end.
* show-files and ls-tree updates to add -z flag to NUL terminate records;
this is needed for git-merge.perl to work.
* show-diff updates to add -r flag to squelch diffs for files not in
the working directory. This is mainly useful when verifying the
result of an automated merge.
* update-cache updates to add "--cacheinfo mode sha1" flag to register
a file that is not in the current working directory. Needed for
minimum-checkout merging by git-merge.perl.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
git-merge.perl | 247 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ls-tree.c | 9 +-
show-diff.c | 11 +-
show-files.c | 12 ++
update-cache.c | 25 +++++
5 files changed, 296 insertions(+), 8 deletions(-)
diff -x .git -Nru ,,1/git-merge.perl ,,2/git-merge.perl
--- ,,1/git-merge.perl 1969-12-31 16:00:00.000000000 -0800
+++ ,,2/git-merge.perl 2005-04-14 04:00:14.000000000 -0700
@@ -0,0 +1,247 @@
+#!/usr/bin/perl -w
+
+use Getopt::Long;
+
+my $full_checkout = 0;
+my $oneside_checkout = 0;
+GetOptions("full" => \$full_checkout,
+ "oneside" => \$oneside_checkout)
+ or die;
+
+if ($full_checkout) {
+ $oneside_checkout = 1;
+}
+
+sub read_rev_tree {
+ my (@head) = @_;
+ my ($fhi);
+ open $fhi, '-|', 'rev-tree', '--edges', @head
+ or die "$!: rev-tree --edges @head";
+ my %common;
+ while (<$fhi>) {
+ chomp;
+ (undef, undef, my @common) = split(/ /, $_);
+ for (@common) {
+ if (s/^([a-f0-f]{40}):3$/$1/) {
+ $common{$_}++;
+ }
+ }
+ }
+ close $fhi;
+
+ my @common = (map { $_->[1] }
+ sort { $b->[0] <=> $a->[0] }
+ map { [ $common{$_} => $_ ] }
+ keys %common);
+
+ return $common[0];
+}
+
+sub read_commit_tree {
+ my ($commit) = @_;
+ my ($fhi);
+ open $fhi, '-|', 'cat-file', 'commit', $commit
+ or die "$!: cat-file commit $commit";
+ my $tree = <$fhi>;
+ close $fhi;
+ $tree =~ s/^tree //;
+ return $tree;
+}
+
+# Reads diff-tree -r output and gives a hash that maps a path
+# to 3-tuple (old-mode new-mode new-sha).
+# When creating, old-mode is undef. When removing, new-* are undef.
+sub read_diff_tree {
+ my (@tree) = @_;
+ my ($fhi);
+ local ($_, $/);
+ $/ = "\0";
+ my %path;
+ open $fhi, '-|', 'diff-tree', '-r', @tree
+ or die "$!: diff-tree -r @tree";
+ while (<$fhi>) {
+ chomp;
+ if (/^\*([0-7]+)->([0-7]+)\tblob\t[0-9a-f]+->([0-9a-f]{40})\t(.*)$/s) {
+ $path{$4} = [$1, $2, $3];
+ }
+ elsif (/^\+([0-7]+)\tblob\t([0-9a-f]{40})\t(.*)$/s) {
+ $path{$3} = [undef, $1, $2];
+ }
+ elsif (/^\-([0-7]+)\tblob\t[0-9a-f]{40}\t(.*)$/s) {
+ $path{$2} = [$1, undef, undef];
+ }
+ else {
+ die "cannot parse diff-tree output: $_";
+ }
+ }
+ close $fhi;
+ return %path;
+}
+
+sub read_show_files {
+ my ($fhi);
+ local ($_, $/);
+ $/ = "\0";
+ open $fhi, '-|', 'show-files', '-z'
+ or die "$!: show-files -z";
+ my (@path) = map { chomp; $_ } <$fhi>;
+ close $fhi;
+ return @path;
+}
+
+sub checkout_file {
+ my ($path, $info) = @_;
+ my (@elt) = split(/\//, $path);
+ my $j = '';
+ my $tail = pop @elt;
+ my ($fhi, $fho);
+ for (@elt) {
+ mkdir "$j$_";
+ $j = "$j$_/";
+ }
+ open $fho, '>', "$path";
+ open $fhi, '-|', 'cat-file', 'blob', $info->[2]
+ or die "$!: cat-file blob $info->[2]";
+ while (<$fhi>) {
+ print $fho $_;
+ }
+ close $fhi;
+ close $fho;
+ chmod oct("0$info->[1]"), "$path";
+}
+
+sub record_file {
+ my ($path, $info) = @_;
+ system ('update-cache', '--add', '--cacheinfo',
+ $info->[1], $info->[2], $path);
+}
+
+sub merge_tree {
+ my ($path, $info0, $info1) = @_;
+ checkout_file(',,merge-0', $info0);
+ checkout_file(',,merge-1', $info1);
+ system 'checkout-cache', $path;
+ my ($fhi, $fho);
+ open $fhi, '-|', 'merge', '-p', ',,merge-0', $path, ',,merge-1';
+ open $fho, '>', "$path+";
+ local ($/);
+ while (<$fhi>) { print $fho $_; }
+ close $fhi;
+ close $fho;
+ unlink ',,merge-0', ',,merge-1';
+ rename "$path+", $path;
+ # There is no reason to prefer info0 over info1 but
+ # we need to pick one.
+ chmod oct("0$info0->[1]"), "$path";
+}
+
+# Find common ancestor of two trees.
+my $common = read_rev_tree(@ARGV);
+print "Common ancestor: $common\n";
+
+# Create a temporary directory and go there.
+system 'rm', '-rf', ',,merge-temp';
+for ((',,merge-temp', '.git')) { mkdir $_; chdir $_; }
+symlink "../../.git/objects", "objects";
+chdir '..';
+
+my $ancestor_tree = read_commit_tree($common);
+system 'read-tree', $ancestor_tree;
+
+my %tree0 = read_diff_tree($ancestor_tree, read_commit_tree($ARGV[0]));
+my %tree1 = read_diff_tree($ancestor_tree, read_commit_tree($ARGV[1]));
+
+my @ancestor_file = read_show_files();
+my %ancestor_file = map { $_ => 1 } @ancestor_file;
+
+for (@ancestor_file) {
+ if (! exists $tree0{$_} && ! exists $tree1{$_}) {
+ if ($full_checkout) {
+ system 'checkout-cache', $_;
+ }
+ print STDERR "O - $_\n";
+ }
+}
+
+for my $set ([\%tree0, \%tree1, 'A'], [\%tree1, \%tree0, 'B']) {
+ my ($treeA, $treeB, $side) = @$set;
+ while (my ($path, $info) = each %$treeA) {
+ # In this loop we do not deal with overlaps.
+ next if (exists $treeB->{$path});
+
+ if (! defined $info->[1]) {
+ # deleted in this tree only.
+ unlink $path;
+ system 'update-cache', '--remove', $path;
+ print STDERR "$side D $path\n";
+ }
+ else {
+ # modified or created in this tree only.
+ print STDERR "$side M $path\n";
+ if ($oneside_checkout) {
+ checkout_file($path, $info);
+ system 'update-cache', '--add', "$path";
+ } else {
+ record_file($path, $info);
+ }
+ }
+ }
+}
+
+my @warning = ();
+
+while (my ($path, $info0) = each %tree0) {
+ # We need to deal only with overlaps.
+ next if (!exists $tree1{$path});
+
+ my $info1 = $tree1{$path};
+ if (! defined $info0->[1]) {
+ # deleted in this tree.
+ if (! defined $info1->[1]) {
+ # deleted in both trees. Obvious.
+ print STDERR "*DD $path\n";
+ unlink $path;
+ system 'update-cache', '--remove', $path;
+ }
+ else {
+ # oops. tree0 wants to remove but tree1 wants to modify it.
+ print STDERR "*DM $path\n";
+ checkout_file("$path~B~", $info1);
+ push @warning, $path;
+ }
+ }
+ else {
+ # modified or created in tree0
+ if (! defined $info1->[1]) {
+ # oops. tree0 wants to modify but tree1 wants to remove it.
+ print STDERR "*MD $path\n";
+ checkout_file("$path~A~", $info0);
+ push @warning, $path;
+ }
+ else {
+ # modified both in tree0 and tree1
+ # are they modifying to the same contents?
+ if ($info0->[2] eq $info1->[2]) {
+ # just mode changes (or no changes)
+ # we prefer tree0 over tree1 for no particular reason.
+ print STDERR "*MM $path\n";
+ record_file($path, $info0);
+ }
+ else {
+ # modified in both. Needs merge.
+ print STDERR "MRG $path\n";
+ merge_tree($path, $info0, $info1);
+ }
+ }
+ }
+}
+
+if (@warning) {
+ print "\nThere are some files that were deleted in one branch and\n"
+ . "modified in another. Please examine them carefully:\n";
+ for (@warning) {
+ print "$_\n";
+ }
+}
+
+# system 'show-diff';
diff -x .git -Nru ,,1/ls-tree.c ,,2/ls-tree.c
--- ,,1/ls-tree.c 2005-04-14 03:47:18.000000000 -0700
+++ ,,2/ls-tree.c 2005-04-14 04:00:14.000000000 -0700
@@ -5,6 +5,8 @@
*/
#include "cache.h"
+int line_termination = '\n';
+
static int list(unsigned char *sha1)
{
void *buffer;
@@ -31,7 +33,8 @@
* It seems not worth it to read each file just to get this
* and the file size. -- pasky@ucw.cz */
type = S_ISDIR(mode) ? "tree" : "blob";
- printf("%03o\t%s\t%s\t%s\n", mode, type, sha1_to_hex(sha1), path);
+ printf("%03o\t%s\t%s\t%s%c", mode, type, sha1_to_hex(sha1),
+ path, line_termination);
}
return 0;
}
@@ -40,6 +43,10 @@
{
unsigned char sha1[20];
+ if (argc == 3 && !strcmp(argv[1], "-z")) {
+ line_termination = 0;
+ argc--; argv++;
+ }
if (argc != 2)
usage("ls-tree <key>");
if (get_sha1_hex(argv[1], sha1) < 0)
diff -x .git -Nru ,,1/show-diff.c ,,2/show-diff.c
--- ,,1/show-diff.c 2005-04-14 03:47:18.000000000 -0700
+++ ,,2/show-diff.c 2005-04-14 04:00:14.000000000 -0700
@@ -58,15 +58,20 @@
int main(int argc, char **argv)
{
int silent = 0;
+ int silent_on_nonexisting_files = 0;
int entries = read_cache();
int i;
while (argc-- > 1) {
if (!strcmp(argv[1], "-s")) {
- silent = 1;
+ silent_on_nonexisting_files = silent = 1;
continue;
}
- usage("show-diff [-s]");
+ if (!strcmp(argv[1], "-r")) {
+ silent_on_nonexisting_files = 1;
+ continue;
+ }
+ usage("show-diff [-s] [-r]");
}
if (entries < 0) {
@@ -83,7 +88,7 @@
if (stat(ce->name, &st) < 0) {
printf("%s: %s\n", ce->name, strerror(errno));
- if (errno == ENOENT && !silent)
+ if (errno == ENOENT && !silent_on_nonexisting_files)
show_diff_empty(ce);
continue;
}
diff -x .git -Nru ,,1/show-files.c ,,2/show-files.c
--- ,,1/show-files.c 2005-04-14 03:47:18.000000000 -0700
+++ ,,2/show-files.c 2005-04-14 04:00:14.000000000 -0700
@@ -14,6 +14,7 @@
static int show_cached = 0;
static int show_others = 0;
static int show_ignored = 0;
+static int line_terminator = '\n';
static const char **dir;
static int nr_dir;
@@ -105,12 +106,12 @@
}
if (show_others) {
for (i = 0; i < nr_dir; i++)
- printf("%s\n", dir[i]);
+ printf("%s%c", dir[i], line_terminator);
}
if (show_cached) {
for (i = 0; i < active_nr; i++) {
struct cache_entry *ce = active_cache[i];
- printf("%s\n", ce->name);
+ printf("%s%c", ce->name, line_terminator);
}
}
if (show_deleted) {
@@ -119,7 +120,7 @@
struct stat st;
if (!stat(ce->name, &st))
continue;
- printf("%s\n", ce->name);
+ printf("%s%c", ce->name, line_terminator);
}
}
if (show_ignored) {
@@ -134,6 +135,11 @@
for (i = 1; i < argc; i++) {
char *arg = argv[i];
+ if (!strcmp(arg, "-z")) {
+ line_terminator = 0;
+ continue;
+ }
+
if (!strcmp(arg, "--cached")) {
show_cached = 1;
continue;
diff -x .git -Nru ,,1/update-cache.c ,,2/update-cache.c
--- ,,1/update-cache.c 2005-04-14 03:47:18.000000000 -0700
+++ ,,2/update-cache.c 2005-04-14 04:00:14.000000000 -0700
@@ -250,6 +250,8 @@
{
int i, newfd, entries;
int allow_options = 1;
+ const char *sha1_force = NULL;
+ const char *mode_force = NULL;
newfd = open(".git/index.lock", O_RDWR | O_CREAT | O_EXCL, 0600);
if (newfd < 0)
@@ -282,14 +284,35 @@
refresh_cache();
continue;
}
+ if (!strcmp(path, "--cacheinfo")) {
+ mode_force = argv[++i];
+ sha1_force = argv[++i];
+ continue;
+ }
die("unknown option %s", path);
}
if (!verify_path(path)) {
fprintf(stderr, "Ignoring path %s\n", argv[i]);
continue;
}
- if (add_file_to_cache(path))
+ if (sha1_force && mode_force) {
+ struct cache_entry *ce;
+ int namelen = strlen(path);
+ int mode;
+ int size = cache_entry_size(namelen);
+ sscanf(mode_force, "%o", &mode);
+ ce = malloc(size);
+ memset(ce, 0, size);
+ memcpy(ce->name, path, namelen);
+ ce->namelen = namelen;
+ ce->st_mode = mode;
+ get_sha1_hex(sha1_force, ce->sha1);
+
+ add_cache_entry(ce, 1);
+ }
+ else if (add_file_to_cache(path))
die("Unable to add %s to database", path);
+ mode_force = sha1_force = NULL;
}
if (write_cache(newfd, active_cache, active_nr) ||
rename(".git/index.lock", ".git/index"))
next prev parent reply other threads:[~2005-04-14 11:11 UTC|newest]
Thread overview: 148+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-04-14 0:29 Merge with git-pasky II Petr Baudis
2005-04-13 21:25 ` Christopher Li
2005-04-14 0:45 ` Petr Baudis
2005-04-13 22:00 ` Christopher Li
2005-04-14 3:51 ` Linus Torvalds
2005-04-14 1:23 ` Christopher Li
2005-04-14 5:03 ` Paul Jackson
2005-04-14 2:16 ` Christopher Li
2005-04-14 6:16 ` Paul Jackson
2005-04-14 7:05 ` Junio C Hamano
2005-04-14 8:06 ` Linus Torvalds
2005-04-14 8:39 ` Junio C Hamano
2005-04-14 9:10 ` Linus Torvalds
2005-04-14 11:14 ` Junio C Hamano [this message]
2005-04-14 12:16 ` Petr Baudis
2005-04-14 18:12 ` Junio C Hamano
2005-04-14 18:36 ` Linus Torvalds
2005-04-14 19:59 ` Junio C Hamano
2005-04-14 20:20 ` Petr Baudis
2005-04-15 0:42 ` Linus Torvalds
2005-04-15 2:33 ` Barry Silverman
2005-04-15 10:02 ` David Woodhouse
2005-04-15 15:32 ` Linus Torvalds
2005-04-15 16:01 ` David Woodhouse
2005-04-15 16:31 ` C. Scott Ananian
2005-04-15 17:11 ` Linus Torvalds
2005-04-16 15:33 ` Johannes Schindelin
2005-04-17 13:14 ` David Woodhouse
2005-04-15 19:20 ` Paul Jackson
2005-04-16 1:44 ` Simon Fowler
2005-04-16 12:19 ` David Lang
2005-04-16 15:55 ` Simon Fowler
2005-04-16 16:03 ` Petr Baudis
2005-04-16 16:26 ` Simon Fowler
2005-04-16 16:26 ` Linus Torvalds
2005-04-16 23:02 ` David Lang
2005-04-17 14:52 ` Ingo Molnar
2005-04-17 15:08 ` Brad Roberts
2005-04-17 15:18 ` Ingo Molnar
2005-04-17 15:28 ` Ingo Molnar
2005-04-17 17:34 ` Linus Torvalds
2005-04-17 22:12 ` Herbert Xu
2005-04-17 22:35 ` Linus Torvalds
2005-04-17 23:29 ` Herbert Xu
2005-04-17 23:34 ` Petr Baudis
2005-04-17 23:53 ` Kenneth Johansson
2005-04-18 0:49 ` Herbert Xu
2005-04-18 0:55 ` Petr Baudis
2005-04-17 23:50 ` Linus Torvalds
2005-04-18 4:16 ` Sanjoy Mahajan
2005-04-18 7:42 ` Ingo Molnar
2005-04-16 20:29 ` Sanjoy Mahajan
2005-04-16 20:41 ` Linus Torvalds
2005-04-15 2:21 ` [Patch] ls-tree enhancements Junio C Hamano
2005-04-15 16:13 ` Petr Baudis
2005-04-15 18:25 ` Junio C Hamano
2005-04-15 9:14 ` Merge with git-pasky II David Woodhouse
2005-04-15 9:36 ` Ingo Molnar
2005-04-15 10:05 ` David Woodhouse
2005-04-15 14:53 ` Ingo Molnar
2005-04-15 15:09 ` David Woodhouse
2005-04-15 12:03 ` Johannes Schindelin
2005-04-15 10:22 ` Theodore Ts'o
2005-04-15 14:53 ` Linus Torvalds
2005-04-15 15:29 ` David Woodhouse
2005-04-15 15:51 ` Linus Torvalds
2005-04-15 15:54 ` Paul Jackson
2005-04-15 16:30 ` C. Scott Ananian
2005-04-15 18:29 ` Paul Jackson
2005-04-14 18:51 ` Christopher Li
2005-04-14 19:35 ` Petr Baudis
2005-04-14 20:01 ` Live Merging from remote repositories Barry Silverman
2005-04-14 23:22 ` Junio C Hamano
2005-04-15 1:07 ` Question about git process model Barry Silverman
2005-04-14 20:23 ` Re: Merge with git-pasky II Erik van Konijnenburg
2005-04-14 20:24 ` Petr Baudis
2005-04-14 23:12 ` Junio C Hamano
2005-04-14 20:24 ` Christopher Li
2005-04-14 23:31 ` Petr Baudis
2005-04-14 20:30 ` Christopher Li
2005-04-14 20:37 ` Christopher Li
2005-04-14 20:50 ` Christopher Li
2005-04-15 0:58 ` Junio C Hamano
2005-04-14 22:30 ` Christopher Li
2005-04-15 7:43 ` Junio C Hamano
2005-04-15 6:28 ` Christopher Li
2005-04-15 11:11 ` Junio C Hamano
[not found] ` <7vaco0i3t9.fsf_-_@assigned-by-dhcp.cox.net>
2005-04-15 18:44 ` write-tree is pasky-0.4 Linus Torvalds
2005-04-15 18:56 ` Petr Baudis
2005-04-15 20:13 ` Linus Torvalds
2005-04-15 22:36 ` Petr Baudis
2005-04-16 0:22 ` Linus Torvalds
2005-04-16 1:13 ` Daniel Barkalow
2005-04-16 2:18 ` Linus Torvalds
2005-04-16 2:49 ` Daniel Barkalow
2005-04-16 3:13 ` Linus Torvalds
2005-04-16 3:56 ` Daniel Barkalow
2005-04-16 6:59 ` Paul Jackson
2005-04-16 15:34 ` Re: Re: " Petr Baudis
2005-04-15 20:10 ` Junio C Hamano
2005-04-15 20:58 ` C. Scott Ananian
2005-04-15 21:22 ` Petr Baudis
2005-04-15 23:16 ` Junio C Hamano
2005-04-15 21:48 ` [PATCH 1/2] merge-trees script for Linus git Junio C Hamano
2005-04-15 21:54 ` [PATCH 2/2] " Junio C Hamano
2005-04-15 23:33 ` [PATCH 3/2] " Junio C Hamano
2005-04-16 1:02 ` Linus Torvalds
2005-04-16 4:10 ` Junio C Hamano
2005-04-16 5:02 ` Linus Torvalds
2005-04-16 6:26 ` Linus Torvalds
2005-04-16 8:12 ` Junio C Hamano
2005-04-16 9:27 ` [PATCH] Byteorder fix for read-tree, new -m semantics version Junio C Hamano
2005-04-16 10:35 ` [PATCH 1/2] Add --stage to show-files for new stage dircache Junio C Hamano
2005-04-16 10:42 ` [PATCH 2/2] " Junio C Hamano
2005-04-16 14:03 ` Issues with higher-order stages in dircache Junio C Hamano
2005-04-17 5:11 ` Junio C Hamano
2005-04-17 5:31 ` Linus Torvalds
2005-04-17 6:01 ` Junio C Hamano
2005-04-17 10:00 ` Summary of "read-tree -m O A B" mechanism Junio C Hamano
2005-04-16 15:28 ` [PATCH 3/2] merge-trees script for Linus git Linus Torvalds
2005-04-16 16:36 ` Linus Torvalds
2005-04-16 17:14 ` Junio C Hamano
2005-04-15 19:54 ` Re: Merge with git-pasky II Petr Baudis
2005-04-15 10:22 ` Junio C Hamano
2005-04-15 20:40 ` Petr Baudis
2005-04-15 22:41 ` Junio C Hamano
2005-04-15 19:57 ` Junio C Hamano
2005-04-15 20:45 ` Linus Torvalds
2005-04-14 0:30 ` Petr Baudis
2005-04-14 22:11 ` git merge Petr Baudis
[not found] <000d01c541ed$32241fd0$6400a8c0@gandalf>
2005-04-15 20:31 ` Merge with git-pasky II Linus Torvalds
2005-04-15 23:00 ` Barry Silverman
2005-04-16 0:32 ` Linus Torvalds
2005-04-26 18:55 Bram Cohen
2005-04-26 19:58 ` Linus Torvalds
2005-04-26 20:30 ` Tom Lord
2005-04-26 20:31 ` Bram Cohen
2005-04-26 20:39 ` Tom Lord
2005-04-26 20:58 ` Linus Torvalds
2005-04-26 21:25 ` Linus Torvalds
2005-04-26 21:28 ` Bram Cohen
2005-04-26 21:36 ` Fabian Franz
2005-04-26 22:30 ` Linus Torvalds
2005-04-26 22:25 ` Linus Torvalds
2005-04-28 0:42 ` Petr Baudis
2005-04-26 21:26 ` Diego Calleja
2005-04-26 20:31 ` Daniel Barkalow
2005-04-26 20:44 ` Tom Lord
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=7vvf6pr4oq.fsf@assigned-by-dhcp.cox.net \
--to=junkio@cox.net \
--cc=git@vger.kernel.org \
--cc=torvalds@osdl.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).