summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2006-02-12 05:03:40 -0800
committerJunio C Hamano <junkio@cox.net>2006-02-12 05:03:40 -0800
commitcfac3f3fa7267c8c06372875f3b05311f0fe4346 (patch)
tree13cae59e4b5047b575eb87859b986eababa5cfbc
parentbff606b8e9b897caeb66c4addfd16c04ebea0b8b (diff)
parent5b766ea9014b4121cb72f424633b6bf9a97308a0 (diff)
downloadgit-cfac3f3fa7267c8c06372875f3b05311f0fe4346.tar.gz
Merge branch 'master'
* master: Add howto about separating topics. Merge branch 'pb/repo' Add support for explicit type specifiers when calling git-repo-config Merge branch 'jc/fixdiff' diff-tree: do not default to -c Avoid using "git-var -l" until it gets fixed. t5500: adjust to change in pack-object reporting behaviour. Only call git-rerere if $GIT_DIR/rr-cache exists. Use a relative path for SVN importing fetch-clone progress: finishing touches. Fix fetch-clone in the presense of signals Make "git clone" pack-fetching download statistics better Make "git clone" less of a deathly quiet experience
-rw-r--r--Documentation/git-repo-config.txt18
-rw-r--r--Documentation/howto/separating-topic-branches.txt91
-rw-r--r--cache.h2
-rw-r--r--clone-pack.c10
-rw-r--r--diff-tree.c4
-rw-r--r--fetch-clone.c77
-rw-r--r--fetch-pack.c2
-rwxr-xr-xgit-am.sh5
-rwxr-xr-xgit-commit.sh5
-rwxr-xr-xgit-merge.sh5
-rwxr-xr-xgit-pull.sh8
-rwxr-xr-xgit-sh-setup.sh6
-rwxr-xr-xgit-svnimport.perl2
-rwxr-xr-xgit-whatchanged.sh2
-rw-r--r--pack-objects.c43
-rw-r--r--repo-config.c27
-rwxr-xr-xt/t5500-fetch-pack.sh2
17 files changed, 277 insertions, 32 deletions
diff --git a/Documentation/git-repo-config.txt b/Documentation/git-repo-config.txt
index 306946412f..33fcde452a 100644
--- a/Documentation/git-repo-config.txt
+++ b/Documentation/git-repo-config.txt
@@ -8,12 +8,12 @@ git-repo-config - Get and set options in .git/config.
SYNOPSIS
--------
-'git-repo-config' name [value [value_regex]]
-'git-repo-config' --replace-all name [value [value_regex]]
-'git-repo-config' --get name [value_regex]
-'git-repo-config' --get-all name [value_regex]
-'git-repo-config' --unset name [value_regex]
-'git-repo-config' --unset-all name [value_regex]
+'git-repo-config' [type] name [value [value_regex]]
+'git-repo-config' [type] --replace-all name [value [value_regex]]
+'git-repo-config' [type] --get name [value_regex]
+'git-repo-config' [type] --get-all name [value_regex]
+'git-repo-config' [type] --unset name [value_regex]
+'git-repo-config' [type] --unset-all name [value_regex]
DESCRIPTION
-----------
@@ -26,6 +26,12 @@ should provide a POSIX regex for the value. If you want to handle the lines
*not* matching the regex, just prepend a single exclamation mark in front
(see EXAMPLES).
+The type specifier can be either '--int' or '--bool', which will make
+'git-repo-config' ensure that the variable(s) are of the given type and
+convert the value to the canonical form (simple decimal number for int,
+a "true" or "false" string for bool). If no type specifier is passed,
+no checks or transformations are performed on the value.
+
This command will fail if
. .git/config is invalid,
diff --git a/Documentation/howto/separating-topic-branches.txt b/Documentation/howto/separating-topic-branches.txt
new file mode 100644
index 0000000000..090e2c9b01
--- /dev/null
+++ b/Documentation/howto/separating-topic-branches.txt
@@ -0,0 +1,91 @@
+From: Junio C Hamano <junkio@cox.net>
+Subject: Separating topic branches
+Abstract: In this article, JC describes how to separate topic branches.
+
+This text was originally a footnote to a discussion about the
+behaviour of the git diff commands.
+
+Often I find myself doing that [running diff against something other
+than HEAD] while rewriting messy development history. For example, I
+start doing some work without knowing exactly where it leads, and end
+up with a history like this:
+
+ "master"
+ o---o
+ \ "topic"
+ o---o---o---o---o---o
+
+At this point, "topic" contains something I know I want, but it
+contains two concepts that turned out to be completely independent.
+And often, one topic component is larger than the other. It may
+contain more than two topics.
+
+In order to rewrite this mess to be more manageable, I would first do
+"diff master..topic", to extract the changes into a single patch, start
+picking pieces from it to get logically self-contained units, and
+start building on top of "master":
+
+ $ git diff master..topic >P.diff
+ $ git checkout -b topicA master
+ ... pick and apply pieces from P.diff to build
+ ... commits on topicA branch.
+
+ o---o---o
+ / "topicA"
+ o---o"master"
+ \ "topic"
+ o---o---o---o---o---o
+
+Before doing each commit on "topicA" HEAD, I run "diff HEAD"
+before update-index the affected paths, or "diff --cached HEAD"
+after. Also I would run "diff --cached master" to make sure
+that the changes are only the ones related to "topicA". Usually
+I do this for smaller topics first.
+
+After that, I'd do the remainder of the original "topic", but
+for that, I do not start from the patchfile I extracted by
+comparing "master" and "topic" I used initially. Still on
+"topicA", I extract "diff topic", and use it to rebuild the
+other topic:
+
+ $ git diff -R topic >P.diff ;# --cached also would work fine
+ $ git checkout -b topicB master
+ ... pick and apply pieces from P.diff to build
+ ... commits on topicB branch.
+
+ "topicB"
+ o---o---o---o---o
+ /
+ /o---o---o
+ |/ "topicA"
+ o---o"master"
+ \ "topic"
+ o---o---o---o---o---o
+
+After I am done, I'd try a pretend-merge between "topicA" and
+"topicB" in order to make sure I have not missed anything:
+
+ $ git pull . topicA ;# merge it into current "topicB"
+ $ git diff topic
+ "topicB"
+ o---o---o---o---o---* (pretend merge)
+ / /
+ /o---o---o----------'
+ |/ "topicA"
+ o---o"master"
+ \ "topic"
+ o---o---o---o---o---o
+
+The last diff better not to show anything other than cleanups
+for crufts. Then I can finally clean things up:
+
+ $ git branch -D topic
+ $ git reset --hard HEAD^ ;# nuke pretend merge
+
+ "topicB"
+ o---o---o---o---o
+ /
+ /o---o---o
+ |/ "topicA"
+ o---o"master"
+
diff --git a/cache.h b/cache.h
index cd58fada15..d7f5bdef07 100644
--- a/cache.h
+++ b/cache.h
@@ -350,6 +350,6 @@ extern int copy_fd(int ifd, int ofd);
/* Finish off pack transfer receiving end */
extern int receive_unpack_pack(int fd[2], const char *me, int quiet);
-extern int receive_keep_pack(int fd[2], const char *me);
+extern int receive_keep_pack(int fd[2], const char *me, int quiet);
#endif /* CACHE_H */
diff --git a/clone-pack.c b/clone-pack.c
index f634431be1..a4370f595f 100644
--- a/clone-pack.c
+++ b/clone-pack.c
@@ -6,6 +6,8 @@ static const char clone_pack_usage[] =
"git-clone-pack [--exec=<git-upload-pack>] [<host>:]<directory> [<heads>]*";
static const char *exec = "git-upload-pack";
+static int quiet = 0;
+
static void clone_handshake(int fd[2], struct ref *ref)
{
unsigned char sha1[20];
@@ -123,7 +125,9 @@ static int clone_pack(int fd[2], int nr_match, char **match)
}
clone_handshake(fd, refs);
- status = receive_keep_pack(fd, "git-clone-pack");
+ status = receive_keep_pack(fd, "git-clone-pack", quiet);
+ if (!quiet)
+ fprintf(stderr, "\n");
if (!status) {
if (nr_match == 0)
@@ -154,8 +158,10 @@ int main(int argc, char **argv)
char *arg = argv[i];
if (*arg == '-') {
- if (!strcmp("-q", arg))
+ if (!strcmp("-q", arg)) {
+ quiet = 1;
continue;
+ }
if (!strncmp("--exec=", arg, 7)) {
exec = arg + 7;
continue;
diff --git a/diff-tree.c b/diff-tree.c
index b170b03fd3..f55a35a9d5 100644
--- a/diff-tree.c
+++ b/diff-tree.c
@@ -6,7 +6,7 @@ static int show_root_diff = 0;
static int no_commit_id = 0;
static int verbose_header = 0;
static int ignore_merges = 1;
-static int combine_merges = 1;
+static int combine_merges = 0;
static int dense_combined_merges = 0;
static int read_stdin = 0;
static int always_show_header = 0;
@@ -248,7 +248,7 @@ int main(int argc, const char **argv)
continue;
}
if (!strcmp(arg, "-m")) {
- combine_merges = ignore_merges = 0;
+ ignore_merges = 0;
continue;
}
if (!strcmp(arg, "-c")) {
diff --git a/fetch-clone.c b/fetch-clone.c
index 859f400941..da1b3ffbaa 100644
--- a/fetch-clone.c
+++ b/fetch-clone.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "exec_cmd.h"
#include <sys/wait.h>
+#include <sys/time.h>
static int finish_pack(const char *pack_tmp_name, const char *me)
{
@@ -129,10 +130,35 @@ int receive_unpack_pack(int fd[2], const char *me, int quiet)
die("git-unpack-objects died of unnatural causes %d", status);
}
-int receive_keep_pack(int fd[2], const char *me)
+/*
+ * We average out the download speed over this many "events", where
+ * an event is a minimum of about half a second. That way, we get
+ * a reasonably stable number.
+ */
+#define NR_AVERAGE (4)
+
+/*
+ * A "binary msec" is a power-of-two-msec, aka 1/1024th of a second.
+ * Keeing the time in that format means that "bytes / msecs" means
+ * is the same as kB/s (modulo rounding).
+ *
+ * 1000512 is a magic number (usecs in a second, rounded up by half
+ * of 1024, to make "rounding" come out right ;)
+ */
+#define usec_to_binarymsec(x) ((int)(x) / (1000512 >> 10))
+
+int receive_keep_pack(int fd[2], const char *me, int quiet)
{
char tmpfile[PATH_MAX];
int ofd, ifd;
+ unsigned long total;
+ static struct timeval prev_tv;
+ struct average {
+ unsigned long bytes;
+ unsigned long time;
+ } download[NR_AVERAGE] = { {0, 0}, };
+ unsigned long avg_bytes, avg_time;
+ int idx = 0;
ifd = fd[0];
snprintf(tmpfile, sizeof(tmpfile),
@@ -141,6 +167,10 @@ int receive_keep_pack(int fd[2], const char *me)
if (ofd < 0)
return error("unable to create temporary file %s", tmpfile);
+ gettimeofday(&prev_tv, NULL);
+ total = 0;
+ avg_bytes = 0;
+ avg_time = 0;
while (1) {
char buf[8192];
ssize_t sz, wsz, pos;
@@ -148,10 +178,13 @@ int receive_keep_pack(int fd[2], const char *me)
if (sz == 0)
break;
if (sz < 0) {
- error("error reading pack (%s)", strerror(errno));
- close(ofd);
- unlink(tmpfile);
- return -1;
+ if (errno != EINTR && errno != EAGAIN) {
+ error("error reading pack (%s)", strerror(errno));
+ close(ofd);
+ unlink(tmpfile);
+ return -1;
+ }
+ sz = 0;
}
pos = 0;
while (pos < sz) {
@@ -165,6 +198,40 @@ int receive_keep_pack(int fd[2], const char *me)
}
pos += wsz;
}
+ total += sz;
+ if (!quiet) {
+ static unsigned long last;
+ struct timeval tv;
+ unsigned long diff = total - last;
+ /* not really "msecs", but a power-of-two millisec (1/1024th of a sec) */
+ unsigned long msecs;
+
+ gettimeofday(&tv, NULL);
+ msecs = tv.tv_sec - prev_tv.tv_sec;
+ msecs <<= 10;
+ msecs += usec_to_binarymsec(tv.tv_usec - prev_tv.tv_usec);
+
+ if (msecs > 500) {
+ prev_tv = tv;
+ last = total;
+
+ /* Update averages ..*/
+ avg_bytes += diff;
+ avg_time += msecs;
+ avg_bytes -= download[idx].bytes;
+ avg_time -= download[idx].time;
+ download[idx].bytes = diff;
+ download[idx].time = msecs;
+ idx++;
+ if (idx >= NR_AVERAGE)
+ idx = 0;
+
+ fprintf(stderr, "%4lu.%03luMB (%lu kB/s) \r",
+ total >> 20,
+ 1000*((total >> 10) & 1023)>>10,
+ avg_bytes / avg_time );
+ }
+ }
}
close(ofd);
return finish_pack(tmpfile, me);
diff --git a/fetch-pack.c b/fetch-pack.c
index 27f5d2a5ff..aa6f42ae1b 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -378,7 +378,7 @@ static int fetch_pack(int fd[2], int nr_match, char **match)
fprintf(stderr, "warning: no common commits\n");
if (keep_pack)
- status = receive_keep_pack(fd, "git-fetch-pack");
+ status = receive_keep_pack(fd, "git-fetch-pack", quiet);
else
status = receive_unpack_pack(fd, "git-fetch-pack", quiet);
diff --git a/git-am.sh b/git-am.sh
index ee6886f300..98b9215f70 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -88,7 +88,10 @@ fall_back_3way () {
# saying that we reverted all those changes.
git-merge-resolve $orig_tree -- HEAD $his_tree || {
- git-rerere
+ if test -d "$GIT_DIR/rr-cache"
+ then
+ git-rerere
+ fi
echo Failed to merge in the changes.
exit 1
}
diff --git a/git-commit.sh b/git-commit.sh
index 073ec81e14..59551d99f9 100755
--- a/git-commit.sh
+++ b/git-commit.sh
@@ -638,7 +638,10 @@ else
fi
ret="$?"
rm -f "$GIT_DIR/COMMIT_MSG" "$GIT_DIR/COMMIT_EDITMSG"
-git-rerere
+if test -d "$GIT_DIR/rr-cache"
+then
+ git-rerere
+fi
if test -x "$GIT_DIR"/hooks/post-commit && test "$ret" = 0
then
diff --git a/git-merge.sh b/git-merge.sh
index dc17baf6e0..74f07610fa 100755
--- a/git-merge.sh
+++ b/git-merge.sh
@@ -309,6 +309,9 @@ Conflicts:
sed -e 's/^[^ ]* / /' |
uniq
} >>"$GIT_DIR/MERGE_MSG"
- git rerere
+ if test -d "$GIT_DIR/rr-cache"
+ then
+ git-rerere
+ fi
die "Automatic merge failed; fix up by hand"
fi
diff --git a/git-pull.sh b/git-pull.sh
index 0991d5f14c..6caf1aad47 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -70,21 +70,21 @@ case "$merge_head" in
exit 0
;;
?*' '?*)
- var=`git-var -l | sed -ne 's/^pull\.octopus=/-s /p'`
+ var=`git repo-config --get pull.octopus`
if test '' = "$var"
then
strategy_default_args='-s octopus'
else
- strategy_default_args=$var
+ strategy_default_args="-s $var"
fi
;;
*)
- var=`git-var -l | sed -ne 's/^pull\.twohead=/-s /p'`
+ var=`git repo-config --get pull.twohead`
if test '' = "$var"
then
strategy_default_args='-s recursive'
else
- strategy_default_args=$var
+ strategy_default_args="-s $var"
fi
;;
esac
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 1e638e493d..157c7e4d6c 100755
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -41,7 +41,11 @@ then
: ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}
# Make sure we are in a valid repository of a vintage we understand.
- GIT_DIR="$GIT_DIR" git-var GIT_AUTHOR_IDENT >/dev/null || exit
+ GIT_DIR="$GIT_DIR" git repo-config --get core.nosuch >/dev/null
+ if test $? == 128
+ then
+ exit
+ fi
else
GIT_DIR=$(git-rev-parse --git-dir) || exit
fi
diff --git a/git-svnimport.perl b/git-svnimport.perl
index b6799d81ee..f17d5a27c8 100755
--- a/git-svnimport.perl
+++ b/git-svnimport.perl
@@ -318,7 +318,7 @@ sub get_file($$$) {
die $res->status_line." at $url\n";
}
} else {
- $name = $svn->file("/$svnpath",$rev);
+ $name = $svn->file("$svnpath",$rev);
return undef unless defined $name;
}
diff --git a/git-whatchanged.sh b/git-whatchanged.sh
index 574fc3558e..1fb9feb348 100755
--- a/git-whatchanged.sh
+++ b/git-whatchanged.sh
@@ -10,7 +10,7 @@ case "$0" in
count=
test -z "$diff_tree_flags" &&
diff_tree_flags=$(git-repo-config --get whatchanged.difftree)
- diff_tree_default_flags='-M --abbrev' ;;
+ diff_tree_default_flags='-c -M --abbrev' ;;
*show)
count=-n1
test -z "$diff_tree_flags" &&
diff --git a/pack-objects.c b/pack-objects.c
index c3f25317bb..2135e9a92e 100644
--- a/pack-objects.c
+++ b/pack-objects.c
@@ -3,6 +3,7 @@
#include "delta.h"
#include "pack.h"
#include "csum-file.h"
+#include <sys/time.h>
static const char pack_usage[] = "git-pack-objects [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} < object-list";
@@ -26,6 +27,7 @@ static struct object_entry *objects = NULL;
static int nr_objects = 0, nr_alloc = 0;
static const char *base_name;
static unsigned char pack_file_sha1[20];
+static int progress = 0;
static void *delta_against(void *buf, unsigned long size, struct object_entry *entry)
{
@@ -362,10 +364,13 @@ static void find_deltas(struct object_entry **list, int window, int depth)
int i, idx;
unsigned int array_size = window * sizeof(struct unpacked);
struct unpacked *array = xmalloc(array_size);
+ int eye_candy;
memset(array, 0, array_size);
i = nr_objects;
idx = 0;
+ eye_candy = i - (nr_objects / 20);
+
while (--i >= 0) {
struct object_entry *entry = list[i];
struct unpacked *n = array + idx;
@@ -373,6 +378,10 @@ static void find_deltas(struct object_entry **list, int window, int depth)
char type[10];
int j;
+ if (progress && i <= eye_candy) {
+ eye_candy -= nr_objects / 20;
+ fputc('.', stderr);
+ }
free(n->data);
n->entry = entry;
n->data = read_sha1_file(entry->sha1, type, &size);
@@ -404,11 +413,13 @@ static void prepare_pack(int window, int depth)
{
get_object_details();
- fprintf(stderr, "Packing %d objects\n", nr_objects);
-
+ if (progress)
+ fprintf(stderr, "Packing %d objects", nr_objects);
sorted_by_type = create_sorted_list(type_size_sort);
if (window && depth)
find_deltas(sorted_by_type, window+1, depth);
+ if (progress)
+ fputc('\n', stderr);
write_pack_file();
}
@@ -472,6 +483,10 @@ int main(int argc, char **argv)
int window = 10, depth = 10, pack_to_stdout = 0;
struct object_entry **list;
int i;
+ struct timeval prev_tv;
+ int eye_candy = 0;
+ int eye_candy_incr = 500;
+
setup_git_directory();
@@ -519,12 +534,34 @@ int main(int argc, char **argv)
if (pack_to_stdout != !base_name)
usage(pack_usage);
+ progress = isatty(2);
+
prepare_packed_git();
+ if (progress) {
+ fprintf(stderr, "Generating pack...\n");
+ gettimeofday(&prev_tv, NULL);
+ }
while (fgets(line, sizeof(line), stdin) != NULL) {
unsigned int hash;
char *p;
unsigned char sha1[20];
+ if (progress && (eye_candy <= nr_objects)) {
+ fprintf(stderr, "Counting objects...%d\r", nr_objects);
+ if (eye_candy && (50 <= eye_candy_incr)) {
+ struct timeval tv;
+ int time_diff;
+ gettimeofday(&tv, NULL);
+ time_diff = (tv.tv_sec - prev_tv.tv_sec);
+ time_diff <<= 10;
+ time_diff += (tv.tv_usec - prev_tv.tv_usec);
+ if ((1 << 9) < time_diff)
+ eye_candy_incr += 50;
+ else if (50 < eye_candy_incr)
+ eye_candy_incr -= 50;
+ }
+ eye_candy += eye_candy_incr;
+ }
if (get_sha1_hex(line, sha1))
die("expected sha1, got garbage:\n %s", line);
hash = 0;
@@ -537,6 +574,8 @@ int main(int argc, char **argv)
}
add_object_entry(sha1, hash);
}
+ if (progress)
+ fprintf(stderr, "Done counting %d objects.\n", nr_objects);
if (non_empty && !nr_objects)
return 0;
diff --git a/repo-config.c b/repo-config.c
index c31e441a3d..9cf65193f9 100644
--- a/repo-config.c
+++ b/repo-config.c
@@ -2,7 +2,7 @@
#include <regex.h>
static const char git_config_set_usage[] =
-"git-repo-config [--get | --get-all | --replace-all | --unset | --unset-all] name [value [value_regex]]";
+"git-repo-config [ --bool | --int ] [--get | --get-all | --replace-all | --unset | --unset-all] name [value [value_regex]]";
static char* key = NULL;
static char* value = NULL;
@@ -10,6 +10,7 @@ static regex_t* regexp = NULL;
static int do_all = 0;
static int do_not_match = 0;
static int seen = 0;
+static enum { T_RAW, T_INT, T_BOOL } type = T_RAW;
static int show_config(const char* key_, const char* value_)
{
@@ -25,7 +26,17 @@ static int show_config(const char* key_, const char* value_)
fprintf(stderr, "More than one value: %s\n", value);
free(value);
}
- value = strdup(value_);
+
+ if (type == T_INT) {
+ value = malloc(256);
+ sprintf(value, "%d", git_config_int(key_, value_));
+ } else if (type == T_BOOL) {
+ value = malloc(256);
+ sprintf(value, "%s", git_config_bool(key_, value_)
+ ? "true" : "false");
+ } else {
+ value = strdup(value_ ? value_ : "");
+ }
seen++;
}
return 0;
@@ -73,6 +84,18 @@ static int get_value(const char* key_, const char* regex_)
int main(int argc, const char **argv)
{
setup_git_directory();
+
+ while (1 < argc) {
+ if (!strcmp(argv[1], "--int"))
+ type = T_INT;
+ else if (!strcmp(argv[1], "--bool"))
+ type = T_BOOL;
+ else
+ break;
+ argc--;
+ argv++;
+ }
+
switch (argc) {
case 2:
return get_value(argv[1], NULL);
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 0781bd287e..e15e14fc32 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -76,7 +76,7 @@ function pull_to_client () {
git-symbolic-ref HEAD refs/heads/${heads:0:1}
test_expect_success "fsck" 'git-fsck-objects --full > fsck.txt 2>&1'
test_expect_object_count "after $number pull" $count
- pack_count=$(grep Packing log.txt|tr -dc "0-9")
+ pack_count=$(grep Unpacking log.txt|tr -dc "0-9")
test -z "$pack_count" && pack_count=0
if [ -z "$no_strict_count_check" ]; then
test_expect_success "minimal count" "test $count = $pack_count"