* Re: [PATCH] Many new features for cg-diff and cg-log
From: Petr Baudis @ 2005-06-08 20:40 UTC (permalink / raw)
To: Dan Holmsand; +Cc: git
In-Reply-To: <42A754D5.10705@gmail.com>
Dear diary, on Wed, Jun 08, 2005 at 10:28:05PM CEST, I got a letter
where Dan Holmsand <holmsand@gmail.com> told me that...
> Petr Baudis wrote:
> >FYI, I plan to release 0.11.2 this evening. I'll try to go through some
> >more queued patches before and update cg-log to fully use git-rev-list.
>
> In that case, you might want to have a look at this patch. I've been
> tinkering with cg-log and cg-diff for some time, and just about got
> ready to send you a patch.
>
> Sorry about the monster patch, but I wanted to get it to you quickly...
Well, it can always go to 0.11.3 or something. I probably wouldn't take
it to the tree just before release anyway even if you sent it split up,
since due to the size of the changes, it's bound to have some hidden
bugs. ;-)
> [PATCH] Many new features for cg-diff and cg-log
Ok, this is really too big. Could you please split it up some? Also,
I've been hacking on cg-log too (and will make it use git-diff-tree -v
yet this evening), so you'll need to update it to apply to the latest
version.
I like what's inside (at least from the description), though! (Well,
mostly. But I'll comment on specific patches. No major objections.)
> - Selection of ranges by date or maximum number of commits to show.
Ad date, isn't that already supported now? The -r arguments can be a
date. Ad maximum number of commits, what'd be its use?
--
Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor
^ permalink raw reply
* Handling merge conflicts a bit more gracefully..
From: Linus Torvalds @ 2005-06-08 20:55 UTC (permalink / raw)
To: Git Mailing List; +Cc: Junio C Hamano, Jeff Garzik
Ok, Jeff reported that whenever there is a merge conflict, he ends up
really punting on it and doing it all with diffs, which clearly meant that
I had to fix up my silly things for this. Which I think I've done now.
What happens now in the case of a merge conflict is:
- the merge is obviously not committed
- we do all the successful merges, and update the index file for them
- for the files that conflict, we force the index to contain the old
version of the file (ie we remove the merge from the index), and we
write the (failed) output of the merge into the working directory, and
we complain loudly:
Auto-merging xyzzy.
merge: warning: conflicts during merge
ERROR: Merge conflict in xyzzy.
fatal: merge program failed
Automatic merge failed, fix up by hand
at which point a normal "git-diff-files -p xyzzy" will show the incomplete
merge results (as relative to the original BRANCH you started with), and
in fact you can also do "git-diff-cache -p MERGE_HEAD xyzzy" to see the
same thing (but relative to the branch you tried to merge).
You then fix up the merge failure by hand (exactly the way you'd do with
CVS), and you do a "git-update-cache xyzzy" when you're happy with the end
result. Then a simple "git commit" should do the right thing.
If you decide that the merge is too hard to undo, you'd do:
git-read-tree -u -m HEAD
rm .git/MERGE_HEAD
and use git-checkout-cache judiciously to remove any edits the merge did.
This is definitely not perfect, but it's a hell of a lot more usable than
it used to be, and not really worse than what CVS people are used to (and
usually a lot better, since git will obviously get the origin of a
three-way merge right, unlike CVS).
Comments? It would be good to have people test this and maybe even write a
few automated tests that it all works as expected..
Linus
^ permalink raw reply
* [PATCH] Tidy up some rev-list-related stuff
From: Petr Baudis @ 2005-06-08 20:59 UTC (permalink / raw)
To: torvalds; +Cc: Jon Seymour, git
This patch tidies up the git-rev-list documentation and epoch.c, which
are in severe clash with the unwritten coding style now, and quite
unreadable.
The patch mostly wraps lines before or on the 80th column, removes
plenty of superfluous empty lines and changes comments from // to /* */.
Signed-off-by: Petr Baudis <pasky@ucw.cz>
---
Jon, since this is your stuff, could you ack the patch, please?
Thanks.
I'm sorry to send patches like this, but I think the files are really
ugly as of now, and not very readable. This should be a definite
improvement in this regard, I hope.
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -17,30 +17,45 @@ Lists commit objects in reverse chronolo
given commit, taking ancestry relationship into account. This is
useful to produce human-readable log output.
-If *--merge-order* is specified, the commit history is decomposed into a unique sequence of minimal, non-linear
-epochs and maximal, linear epochs. Non-linear epochs are then linearised by sorting them into merge order, which
+If *--merge-order* is specified, the commit history is decomposed into a
+unique sequence of minimal, non-linear epochs and maximal, linear epochs.
+Non-linear epochs are then linearised by sorting them into merge order, which
is described below.
-Maximal, linear epochs correspond to periods of sequential development. Minimal, non-linear epochs
-correspond to periods of divergent development followed by a converging merge. The theory of epochs is described
-in more detail at link:http://blackcubes.dyndns.org/epoch/[http://blackcubes.dyndns.org/epoch/].
-
-The merge order for a non-linear epoch is defined as a linearisation for which the following invariants are true:
-
- 1. if a commit P is reachable from commit N, commit P sorts after commit N in the linearised list.
- 2. if Pi and Pj are any two parents of a merge M (with i < j), then any commit N, such that N is reachable from Pj
- but not reachable from Pi, sorts before all commits reachable from Pi.
-
-Invariant 1 states that later commits appear before earlier commits they are derived from.
-
-Invariant 2 states that commits unique to "later" parents in a merge, appear before all commits from "earlier" parents of
-a merge.
-
-If *--show-breaks* is specified, each item of the list is output with a 2-character prefix consisting of one of:
- (|), (^), (=) followed by a space.
-Commits marked with (=) represent the boundaries of minimal, non-linear epochs and correspond either to the start of a period of divergent development or to the end of such a period.
-Commits marked with (|) are direct parents of commits immediately preceding the marked commit in the list.
-Commits marked with (^) are not parents of the immediately preceding commit. These "breaks" represent necessary discontinuities implied by trying to represent an arbtirary DAG in a linear form.
+Maximal, linear epochs correspond to periods of sequential development.
+Minimal, non-linear epochs correspond to periods of divergent development
+followed by a converging merge. The theory of epochs is described in more
+detail at
+link:http://blackcubes.dyndns.org/epoch/[http://blackcubes.dyndns.org/epoch/].
+
+The merge order for a non-linear epoch is defined as a linearisation for which
+the following invariants are true:
+
+ 1. if a commit P is reachable from commit N, commit P sorts after commit N
+ in the linearised list.
+ 2. if Pi and Pj are any two parents of a merge M (with i < j), then any
+ commit N, such that N is reachable from Pj but not reachable from Pi,
+ sorts before all commits reachable from Pi.
+
+Invariant 1 states that later commits appear before earlier commits they are
+derived from.
+
+Invariant 2 states that commits unique to "later" parents in a merge, appear
+before all commits from "earlier" parents of a merge.
+
+If *--show-breaks* is specified, each item of the list is output with a
+2-character prefix consisting of one of: (|), (^), (=) followed by a space.
+
+Commits marked with (=) represent the boundaries of minimal, non-linear epochs
+and correspond either to the start of a period of divergent development or to
+the end of such a period.
+
+Commits marked with (|) are direct parents of commits immediately preceding
+the marked commit in the list.
+
+Commits marked with (^) are not parents of the immediately preceding commit.
+These "breaks" represent necessary discontinuities implied by trying to
+represent an arbtirary DAG in a linear form.
*--show-breaks* is only valid if *--merge-order* is also specified.
diff --git a/epoch.c b/epoch.c
--- a/epoch.c
+++ b/epoch.c
@@ -8,9 +8,10 @@
*
*/
#include <stdlib.h>
-#include <openssl/bn.h> // provides arbitrary precision integers
- // required to accurately represent fractional
- //mass
+
+/* Provides arbitrary precision integers required to accurately represent
+ * fractional mass: */
+#include <openssl/bn.h>
#include "cache.h"
#include "commit.h"
@@ -125,7 +126,6 @@ static struct fraction *add(struct fract
static int compare(struct fraction *left, struct fraction *right)
{
BIGNUM a, b;
-
int result;
BN_init(&a);
@@ -159,7 +159,8 @@ static struct mass_counter *new_mass_cou
copy(&mass_counter->seen, get_zero());
if (commit->object.util) {
- die("multiple attempts to initialize mass counter for %s\n", sha1_to_hex(commit->object.sha1));
+ die("multiple attempts to initialize mass counter for %s",
+ sha1_to_hex(commit->object.sha1));
}
commit->object.util = mass_counter;
@@ -174,64 +175,59 @@ static void free_mass_counter(struct mas
free(counter);
}
-//
-// Finds the base commit of a list of commits.
-//
-// One property of the commit being searched for is that every commit reachable
-// from the base commit is reachable from the commits in the starting list only
-// via paths that include the base commit.
-//
-// This algorithm uses a conservation of mass approach to find the base commit.
-//
-// We start by injecting one unit of mass into the graph at each
-// of the commits in the starting list. Injecting mass into a commit
-// is achieved by adding to its pending mass counter and, if it is not already
-// enqueued, enqueuing the commit in a list of pending commits, in latest
-// commit date first order.
-//
-// The algorithm then preceeds to visit each commit in the pending queue.
-// Upon each visit, the pending mass is added to the mass already seen for that
-// commit and then divided into N equal portions, where N is the number of
-// parents of the commit being visited. The divided portions are then injected
-// into each of the parents.
-//
-// The algorithm continues until we discover a commit which has seen all the
-// mass originally injected or until we run out of things to do.
-//
-// If we find a commit that has seen all the original mass, we have found
-// the common base of all the commits in the starting list.
-//
-// The algorithm does _not_ depend on accurate timestamps for correct operation.
-// However, reasonably sane (e.g. non-random) timestamps are required in order
-// to prevent an exponential performance characteristic. The occasional
-// timestamp inaccuracy will not dramatically affect performance but may
-// result in more nodes being processed than strictly necessary.
-//
-// This procedure sets *boundary to the address of the base commit. It returns
-// non-zero if, and only if, there was a problem parsing one of the
-// commits discovered during the traversal.
-//
+/*
+ * Finds the base commit of a list of commits.
+ *
+ * One property of the commit being searched for is that every commit reachable
+ * from the base commit is reachable from the commits in the starting list only
+ * via paths that include the base commit.
+ *
+ * This algorithm uses a conservation of mass approach to find the base commit.
+ *
+ * We start by injecting one unit of mass into the graph at each
+ * of the commits in the starting list. Injecting mass into a commit
+ * is achieved by adding to its pending mass counter and, if it is not already
+ * enqueued, enqueuing the commit in a list of pending commits, in latest
+ * commit date first order.
+ *
+ * The algorithm then preceeds to visit each commit in the pending queue.
+ * Upon each visit, the pending mass is added to the mass already seen for that
+ * commit and then divided into N equal portions, where N is the number of
+ * parents of the commit being visited. The divided portions are then injected
+ * into each of the parents.
+ *
+ * The algorithm continues until we discover a commit which has seen all the
+ * mass originally injected or until we run out of things to do.
+ *
+ * If we find a commit that has seen all the original mass, we have found
+ * the common base of all the commits in the starting list.
+ *
+ * The algorithm does _not_ depend on accurate timestamps for correct operation.
+ * However, reasonably sane (e.g. non-random) timestamps are required in order
+ * to prevent an exponential performance characteristic. The occasional
+ * timestamp inaccuracy will not dramatically affect performance but may
+ * result in more nodes being processed than strictly necessary.
+ *
+ * This procedure sets *boundary to the address of the base commit. It returns
+ * non-zero if, and only if, there was a problem parsing one of the
+ * commits discovered during the traversal.
+ */
static int find_base_for_list(struct commit_list *list, struct commit **boundary)
{
-
int ret = 0;
-
struct commit_list *cleaner = NULL;
struct commit_list *pending = NULL;
-
- *boundary = NULL;
-
struct fraction injected;
-
init_fraction(&injected);
+ *boundary = NULL;
for (; list; list = list->next) {
-
struct commit *item = list->item;
if (item->object.util) {
- die("%s:%d:%s: logic error: this should not have happened - commit %s\n",
- __FILE__, __LINE__, __FUNCTION__, sha1_to_hex(item->object.sha1));
+ die("%s:%d:%s: logic error: this should not have happened - commit %s",
+ __FILE__, __LINE__, __FUNCTION__,
+ sha1_to_hex(item->object.sha1));
}
new_mass_counter(list->item, get_one());
@@ -242,81 +238,62 @@ static int find_base_for_list(struct com
}
while (!*boundary && pending && !ret) {
-
struct commit *latest = pop_commit(&pending);
-
struct mass_counter *latest_node = (struct mass_counter *) latest->object.util;
+ int num_parents;
if ((ret = parse_commit(latest)))
continue;
-
add(&latest_node->seen, &latest_node->seen, &latest_node->pending);
- int num_parents = count_parents(latest);
-
+ num_parents = count_parents(latest);
if (num_parents) {
-
struct fraction distribution;
struct commit_list *parents;
divide(init_fraction(&distribution), &latest_node->pending, num_parents);
for (parents = latest->parents; parents; parents = parents->next) {
-
struct commit *parent = parents->item;
struct mass_counter *parent_node = (struct mass_counter *) parent->object.util;
if (!parent_node) {
-
parent_node = new_mass_counter(parent, &distribution);
-
insert_by_date(&pending, parent);
commit_list_insert(parent, &cleaner);
-
} else {
-
- if (!compare(&parent_node->pending, get_zero())) {
+ if (!compare(&parent_node->pending, get_zero()))
insert_by_date(&pending, parent);
- }
add(&parent_node->pending, &parent_node->pending, &distribution);
-
}
}
clear_fraction(&distribution);
-
}
- if (!compare(&latest_node->seen, &injected)) {
+ if (!compare(&latest_node->seen, &injected))
*boundary = latest;
- }
-
copy(&latest_node->pending, get_zero());
-
}
while (cleaner) {
-
struct commit *next = pop_commit(&cleaner);
free_mass_counter((struct mass_counter *) next->object.util);
next->object.util = NULL;
-
}
if (pending)
free_commit_list(pending);
clear_fraction(&injected);
-
return ret;
-
}
-//
-// Finds the base of an minimal, non-linear epoch, headed at head, by
-// applying the find_base_for_list to a list consisting of the parents
-//
+/*
+ * Finds the base of an minimal, non-linear epoch, headed at head, by
+ * applying the find_base_for_list to a list consisting of the parents
+ */
static int find_base(struct commit *head, struct commit **boundary)
{
int ret = 0;
@@ -332,14 +309,14 @@ static int find_base(struct commit *head
return ret;
}
-//
-// This procedure traverses to the boundary of the first epoch in the epoch
-// sequence of the epoch headed at head_of_epoch. This is either the end of
-// the maximal linear epoch or the base of a minimal non-linear epoch.
-//
-// The queue of pending nodes is sorted in reverse date order and each node
-// is currently in the queue at most once.
-//
+/*
+ * This procedure traverses to the boundary of the first epoch in the epoch
+ * sequence of the epoch headed at head_of_epoch. This is either the end of
+ * the maximal linear epoch or the base of a minimal non-linear epoch.
+ *
+ * The queue of pending nodes is sorted in reverse date order and each node
+ * is currently in the queue at most once.
+ */
static int find_next_epoch_boundary(struct commit *head_of_epoch, struct commit **boundary)
{
int ret;
@@ -350,10 +327,10 @@ static int find_next_epoch_boundary(stru
return ret;
if (HAS_EXACTLY_ONE_PARENT(item)) {
-
- // we are at the start of a maximimal linear epoch .. traverse to the end
-
- // traverse to the end of a maximal linear epoch
+ /*
+ * We are at the start of a maximimal linear epoch.
+ * Traverse to the end.
+ */
while (HAS_EXACTLY_ONE_PARENT(item) && !ret) {
item = item->parents->item;
ret = parse_commit(item);
@@ -361,35 +338,35 @@ static int find_next_epoch_boundary(stru
*boundary = item;
} else {
-
- // otherwise, we are at the start of a minimal, non-linear
- // epoch - find the common base of all parents.
-
+ /*
+ * Otherwise, we are at the start of a minimal, non-linear
+ * epoch - find the common base of all parents.
+ */
ret = find_base(item, boundary);
-
}
return ret;
}
-//
-// Returns non-zero if parent is known to be a parent of child.
-//
+/*
+ * Returns non-zero if parent is known to be a parent of child.
+ */
static int is_parent_of(struct commit *parent, struct commit *child)
{
struct commit_list *parents;
for (parents = child->parents; parents; parents = parents->next) {
- if (!memcmp(parent->object.sha1, parents->item->object.sha1, sizeof(parents->item->object.sha1)))
+ if (!memcmp(parent->object.sha1, parents->item->object.sha1,
+ sizeof(parents->item->object.sha1)))
return 1;
}
return 0;
}
-//
-// Pushes an item onto the merge order stack. If the top of the stack is
-// marked as being a possible "break", we check to see whether it actually
-// is a break.
-//
+/*
+ * Pushes an item onto the merge order stack. If the top of the stack is
+ * marked as being a possible "break", we check to see whether it actually
+ * is a break.
+ */
static void push_onto_merge_order_stack(struct commit_list **stack, struct commit *item)
{
struct commit_list *top = *stack;
@@ -401,54 +378,53 @@ static void push_onto_merge_order_stack(
commit_list_insert(item, stack);
}
-//
-// Marks all interesting, visited commits reachable from this commit
-// as uninteresting. We stop recursing when we reach the epoch boundary,
-// an unvisited node or a node that has already been marking uninteresting.
-// This doesn't actually mark all ancestors between the start node and the
-// epoch boundary uninteresting, but does ensure that they will
-// eventually be marked uninteresting when the main sort_first_epoch
-// traversal eventually reaches them.
-//
+/*
+ * Marks all interesting, visited commits reachable from this commit
+ * as uninteresting. We stop recursing when we reach the epoch boundary,
+ * an unvisited node or a node that has already been marking uninteresting.
+ *
+ * This doesn't actually mark all ancestors between the start node and the
+ * epoch boundary uninteresting, but does ensure that they will eventually
+ * be marked uninteresting when the main sort_first_epoch() traversal
+ * eventually reaches them.
+ */
static void mark_ancestors_uninteresting(struct commit *commit)
{
unsigned int flags = commit->object.flags;
int visited = flags & VISITED;
int boundary = flags & BOUNDARY;
int uninteresting = flags & UNINTERESTING;
+ struct commit_list *next;
commit->object.flags |= UNINTERESTING;
- if (uninteresting || boundary || !visited) {
- return;
- // we only need to recurse if
- // we are not on the boundary, and,
- // we have not already been marked uninteresting, and,
- // we have already been visited.
-
- //
- // the main sort_first_epoch traverse will
- // mark unreachable all uninteresting, unvisited parents
- // as they are visited so there is no need to duplicate
- // that traversal here.
- //
- // similarly, if we are already marked uninteresting
- // then either all ancestors have already been marked
- // uninteresting or will be once the sort_first_epoch
- // traverse reaches them.
- //
- }
+ /*
+ * We only need to recurse if
+ * we are not on the boundary and
+ * we have not already been marked uninteresting and
+ * we have already been visited.
+ *
+ * The main sort_first_epoch traverse will mark unreachable
+ * all uninteresting, unvisited parents as they are visited
+ * so there is no need to duplicate that traversal here.
+ *
+ * Similarly, if we are already marked uninteresting
+ * then either all ancestors have already been marked
+ * uninteresting or will be once the sort_first_epoch
+ * traverse reaches them.
+ */
- struct commit_list *next;
+ if (uninteresting || boundary || !visited)
+ return;
for (next = commit->parents; next; next = next->next)
mark_ancestors_uninteresting(next->item);
}
-//
-// Sorts the nodes of the first epoch of the epoch sequence of the epoch headed at head
-// into merge order.
-//
+/*
+ * Sorts the nodes of the first epoch of the epoch sequence of the epoch headed at head
+ * into merge order.
+ */
static void sort_first_epoch(struct commit *head, struct commit_list **stack)
{
struct commit_list *parents;
@@ -456,63 +432,59 @@ static void sort_first_epoch(struct comm
head->object.flags |= VISITED;
- //
- // parse_commit builds the parent list in reverse order with respect to the order of
- // the git-commit-tree arguments.
- //
- // so we need to reverse this list to output the oldest (or most "local") commits last.
- //
-
+ /*
+ * parse_commit() builds the parent list in reverse order with respect
+ * to the order of the git-commit-tree arguments. So we need to reverse
+ * this list to output the oldest (or most "local") commits last.
+ */
for (parents = head->parents; parents; parents = parents->next)
commit_list_insert(parents->item, &reversed_parents);
- //
- // todo: by sorting the parents in a different order, we can alter the
- // merge order to show contemporaneous changes in parallel branches
- // occurring after "local" changes. This is useful for a developer
- // when a developer wants to see all changes that were incorporated
- // into the same merge as her own changes occur after her own
- // changes.
- //
+ /*
+ * TODO: By sorting the parents in a different order, we can alter the
+ * merge order to show contemporaneous changes in parallel branches
+ * occurring after "local" changes. This is useful for a developer
+ * when a developer wants to see all changes that were incorporated
+ * into the same merge as her own changes occur after her own
+ * changes.
+ */
while (reversed_parents) {
-
struct commit *parent = pop_commit(&reversed_parents);
if (head->object.flags & UNINTERESTING) {
- // propagates the uninteresting bit to
- // all parents. if we have already visited
- // this parent, then the uninteresting bit
- // will be propagated to each reachable
- // commit that is still not marked uninteresting
- // and won't otherwise be reached.
+ /*
+ * Propagates the uninteresting bit to all parents.
+ * if we have already visited this parent, then
+ * the uninteresting bit will be propagated to each
+ * reachable commit that is still not marked
+ * uninteresting and won't otherwise be reached.
+ */
mark_ancestors_uninteresting(parent);
}
if (!(parent->object.flags & VISITED)) {
if (parent->object.flags & BOUNDARY) {
-
if (*stack) {
- die("something else is on the stack - %s\n", sha1_to_hex((*stack)->item->object.sha1));
+ die("something else is on the stack - %s",
+ sha1_to_hex((*stack)->item->object.sha1));
}
-
push_onto_merge_order_stack(stack, parent);
parent->object.flags |= VISITED;
} else {
-
sort_first_epoch(parent, stack);
-
if (reversed_parents) {
- //
- // this indicates a possible discontinuity
- // it may not be be actual discontinuity if
- // the head of parent N happens to be the tail
- // of parent N+1
- //
- // the next push onto the stack will resolve the
- // question
- //
+ /*
+ * This indicates a possible
+ * discontinuity it may not be be
+ * actual discontinuity if the head
+ * of parent N happens to be the tail
+ * of parent N+1.
+ *
+ * The next push onto the stack will
+ * resolve the question.
+ */
(*stack)->item->object.flags |= DISCONTINUITY;
}
}
@@ -522,27 +494,23 @@ static void sort_first_epoch(struct comm
push_onto_merge_order_stack(stack, head);
}
-//
-// Emit the contents of the stack.
-//
-// The stack is freed and replaced by NULL.
-//
-// Sets the return value to STOP if no further output should be generated.
-//
+/*
+ * Emit the contents of the stack.
+ *
+ * The stack is freed and replaced by NULL.
+ *
+ * Sets the return value to STOP if no further output should be generated.
+ */
static int emit_stack(struct commit_list **stack, emitter_func emitter)
{
unsigned int seen = 0;
int action = CONTINUE;
while (*stack && (action != STOP)) {
-
struct commit *next = pop_commit(stack);
-
seen |= next->object.flags;
-
- if (*stack) {
+ if (*stack)
action = (*emitter) (next);
- }
}
if (*stack) {
@@ -553,13 +521,13 @@ static int emit_stack(struct commit_list
return (action == STOP || (seen & UNINTERESTING)) ? STOP : CONTINUE;
}
-//
-// Sorts an arbitrary epoch into merge order by sorting each epoch
-// of its epoch sequence into order.
-//
-// Note: this algorithm currently leaves traces of its execution in the
-// object flags of nodes it discovers. This should probably be fixed.
-//
+/*
+ * Sorts an arbitrary epoch into merge order by sorting each epoch
+ * of its epoch sequence into order.
+ *
+ * Note: this algorithm currently leaves traces of its execution in the
+ * object flags of nodes it discovers. This should probably be fixed.
+ */
static int sort_in_merge_order(struct commit *head_of_epoch, emitter_func emitter)
{
struct commit *next = head_of_epoch;
@@ -569,29 +537,24 @@ static int sort_in_merge_order(struct co
ret = parse_commit(head_of_epoch);
while (next && next->parents && !ret && (action != STOP)) {
-
struct commit *base = NULL;
- if ((ret = find_next_epoch_boundary(next, &base)))
+ ret = find_next_epoch_boundary(next, &base);
+ if (ret)
return ret;
-
next->object.flags |= BOUNDARY;
- if (base) {
+ if (base)
base->object.flags |= BOUNDARY;
- }
if (HAS_EXACTLY_ONE_PARENT(next)) {
-
while (HAS_EXACTLY_ONE_PARENT(next)
&& (action != STOP)
&& !ret) {
-
if (next->object.flags & UNINTERESTING) {
action = STOP;
} else {
action = (*emitter) (next);
}
-
if (action != STOP) {
next = next->parents->item;
ret = parse_commit(next);
@@ -599,14 +562,11 @@ static int sort_in_merge_order(struct co
}
} else {
-
struct commit_list *stack = NULL;
sort_first_epoch(next, &stack);
action = emit_stack(&stack, emitter);
next = base;
-
}
-
}
if (next && (action != STOP) && !ret) {
@@ -616,29 +576,27 @@ static int sort_in_merge_order(struct co
return ret;
}
-//
-// Sorts the nodes reachable from a starting list in merge order, we
-// first find the base for the starting list and then sort all nodes in this
-// subgraph using the sort_first_epoch algorithm. Once we have reached the base
-// we can continue sorting using sort_in_merge_order.
-//
+/*
+ * Sorts the nodes reachable from a starting list in merge order, we
+ * first find the base for the starting list and then sort all nodes
+ * in this subgraph using the sort_first_epoch algorithm. Once we have
+ * reached the base we can continue sorting using sort_in_merge_order.
+ */
int sort_list_in_merge_order(struct commit_list *list, emitter_func emitter)
{
struct commit_list *stack = NULL;
struct commit *base;
-
int ret = 0;
int action = CONTINUE;
-
struct commit_list *reversed = NULL;
for (; list; list = list->next) {
-
struct commit *next = list->item;
if (!(next->object.flags & UNINTERESTING)) {
if (next->object.flags & DUPCHECK) {
- fprintf(stderr, "%s: duplicate commit %s ignored\n", __FUNCTION__, sha1_to_hex(next->object.sha1));
+ fprintf(stderr, "%s: duplicate commit %s ignored\n",
+ __FUNCTION__, sha1_to_hex(next->object.sha1));
} else {
next->object.flags |= DUPCHECK;
commit_list_insert(list->item, &reversed);
@@ -647,36 +605,35 @@ int sort_list_in_merge_order(struct comm
}
if (!reversed->next) {
-
- // if there is only one element in the list, we can sort it using
- // sort_in_merge_order.
-
+ /*
+ * If there is only one element in the list, we can sort it
+ * using sort_in_merge_order.
+ */
base = reversed->item;
-
} else {
-
- // otherwise, we search for the base of the list
-
- if ((ret = find_base_for_list(reversed, &base)))
+ /*
+ * Otherwise, we search for the base of the list.
+ */
+ ret = find_base_for_list(reversed, &base);
+ if (ret)
return ret;
-
- if (base) {
+ if (base)
base->object.flags |= BOUNDARY;
- }
while (reversed) {
sort_first_epoch(pop_commit(&reversed), &stack);
if (reversed) {
- //
- // if we have more commits to push, then the
- // first push for the next parent may (or may not)
- // represent a discontinuity with respect to the
- // parent currently on the top of the stack.
- //
- // mark it for checking here, and check it
- // with the next push...see sort_first_epoch for
- // more details.
- //
+ /*
+ * If we have more commits to push, then the
+ * first push for the next parent may (or may
+ * not) represent a discontinuity with respect
+ * to the parent currently on the top of
+ * the stack.
+ *
+ * Mark it for checking here, and check it
+ * with the next push. See sort_first_epoch()
+ * for more details.
+ */
stack->item->object.flags |= DISCONTINUITY;
}
}
diff --git a/rev-list.c b/rev-list.c
--- a/rev-list.c
+++ b/rev-list.c
@@ -214,17 +214,13 @@ int main(int argc, char **argv)
usage(rev_list_usage);
if (!merge_order) {
-
- if (limited)
+ if (limited)
list = limit_list(list);
show_commit_list(list);
-
} else {
-
if (sort_list_in_merge_order(list, &process_commit)) {
die("merge order sort failed\n");
}
-
}
return 0;
^ permalink raw reply
* Re: [PATCH] Many new features for cg-diff and cg-log
From: Petr Baudis @ 2005-06-08 21:03 UTC (permalink / raw)
To: Dan Holmsand; +Cc: git
In-Reply-To: <20050608204012.GN982@pasky.ji.cz>
Dear diary, on Wed, Jun 08, 2005 at 10:40:13PM CEST, I got a letter
where Petr Baudis <pasky@ucw.cz> told me that...
> will make [cg-log] use git-diff-tree -v yet this evening
Ok, it turns out I won't. Feel free to hack on that. :-)
--
Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
<Espy> be careful, some twit might quote you out of context..
^ permalink raw reply
* Re: [PATCH] Many new features for cg-diff and cg-log
From: Dan Holmsand @ 2005-06-08 21:03 UTC (permalink / raw)
To: git; +Cc: Petr Baudis
In-Reply-To: <20050608204012.GN982@pasky.ji.cz>
Petr Baudis wrote:
> Dear diary, on Wed, Jun 08, 2005 at 10:28:05PM CEST, I got a letter
> where Dan Holmsand <holmsand@gmail.com> told me that...
>>Sorry about the monster patch, but I wanted to get it to you quickly...
>
>
> Well, it can always go to 0.11.3 or something. I probably wouldn't take
> it to the tree just before release anyway even if you sent it split up,
> since due to the size of the changes, it's bound to have some hidden
> bugs. ;-)
Nah... Seriously, that's a wise decision. I just saw that you we're
working on cg-log, and wanted to save you some potential doublework by
sending what I've got in a hurry.
I have, however, been using this myself for quite some time, so it's
reasonably well tested.
>>[PATCH] Many new features for cg-diff and cg-log
>
>
> Ok, this is really too big. Could you please split it up some? Also,
> I've been hacking on cg-log too (and will make it use git-diff-tree -v
> yet this evening), so you'll need to update it to apply to the latest
> version.
Sure. I'll try to split it up, somewhat (but the changes *are* pretty
inter-related...).
>
> I like what's inside (at least from the description), though! (Well,
> mostly. But I'll comment on specific patches. No major objections.)
>
>
>>- Selection of ranges by date or maximum number of commits to show.
>
>
> Ad date, isn't that already supported now? The -r arguments can be a
> date. Ad maximum number of commits, what'd be its use?
>
The new date thing doesn't work very well for cg-log: it's hardcoded to
HEAD. That means that attempts to do, say, "cg-log -rorigin:-1day" will
not at all do what you want. Not to mention "cg-log -m -r-1day". And I
think it's a little clearer to separate the two: "cg-log -rorigin
--max-age=-1day" (there's a short option too).
Max number of commits is perhaps not all that useful, unless you want to
save cg-log output to file, for example. But it's easy to do :-)
Oh, and I forgot to mention the "pickaxe" support. "cg-log -S foobar"
uses git-diff-tree -S to "search in diffs". Really very, very useful.
/dan
^ permalink raw reply
* [PATCH] Fix git-merge-one-file permissions auto-merging
From: Petr Baudis @ 2005-06-08 21:26 UTC (permalink / raw)
To: torvalds; +Cc: git
In the automerge case, permissions were not restored properly after the
merge tool was invoked and overwrote the target file.
Signed-off-by: Petr Baudis <pasky@ucw.cz>
---
commit d0a0933d6ed6190a767f6baad6c93aa79b3901b2
tree 0a278964e7cd15b2f35b00551747c4908d65b244
parent 9d6694e94c2ff7fc24ecb4124234cef6c6037ad5
author Petr Baudis <pasky@ucw.cz> Wed, 08 Jun 2005 23:26:23 +0200
committer Petr Baudis <xpasky@machine.sinus.cz> Wed, 08 Jun 2005 23:26:23 +0200
git-merge-one-file-script | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/git-merge-one-file-script b/git-merge-one-file-script
--- a/git-merge-one-file-script
+++ b/git-merge-one-file-script
@@ -63,10 +63,14 @@ case "${1:-.}${2:-.}${3:-.}" in
merge -p "$src1" "$orig" "$src2" > "$4"
ret=$?
rm -f -- "$orig" "$src1" "$src2"
+
if [ "$6" != "$7" ]; then
echo "ERROR: Permissions $5->$6->$7 don't match."
ret=1
fi
+ case "$6" in *7??) mode=+x;; *) mode=-x;; esac
+ chmod "$mode" "$4"
+
if [ $ret -ne 0 ]; then
# Reset the index to the first branch, making
# git-diff-file useful
|
--
Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
<Espy> be careful, some twit might quote you out of context..
^ permalink raw reply
* Re: Upstream merging and conflicts (was Re: Using cvs2git to track an external CVS project)
From: Martin Langhoff @ 2005-06-08 22:09 UTC (permalink / raw)
To: Git Mailing List
In-Reply-To: <Pine.LNX.4.58.0506080828240.2286@ppc970.osdl.org>
On 6/9/05, Linus Torvalds <torvalds@osdl.org> wrote:
> Yes, and right now that "manual" part is actualyl fairly high. I'll fix
> that thing up (today, I hope), making nontrivial merges much easier.
Wow -- I'll be tracking your tree closely then ;-)
> It's true that you can't skip patches, since a merge is always
> all-or-nothing, and the global history really requires that (in a very
> fundamental way). However, you _can_ merge from the HEAD, and then say
> "that patch is no longer relevant in this tree", and remove it. Then
> you'll never need to worry about that patch any more, because you've
> merged it and in your merged result, it no longer exists).
I had that strategy in my back-pocket already, but it doesn't sound right.
> That said, I don't claim that this is what you always want to do. In fact,
> we have this exact issue in the kernel, and I think it's a great thing to
> use a combination of a patch-based system _and_ git. You use git for the
> "core", you use the patch-based system for the more fluid stuff. In the
> case of the kernel, the patch-based system that seems to be used the most
> is "quilt", but that's a detail. The big issue is that git is simply part
> of a bigger process:
Sounds like I'll be reading up on quilt then. I guess that's what I
was looking for...
> Yes. I think this is fundamental. "git" needs to converge. It's how git
> works. git also "crystallizes" the history and makes it unbreakable.
> Both of these things are _wonderful_ for what they mean, but both of these
> fundamental issues are _horrible_ for other reasons.
Fair enough -- and actually I'm not convinced it's a horrible thing.
Having worked with forever-diverging tools like Arch, I can appreciate
the value of crystallizing and identifying when you've converged --
and rebasing all steps forward on the fact that you've converged. This
is huge.
A patch-based workflow is needed in the periphery of HEAD -- but
patch-based tools fail to see when they've converged. What I am
salivating about is the idea of some basic patch smarts based on
git/cogito that I can use to track things in simplistic scenarios.
Right now as soon as I'm one patch "off" all of git support breaks
down and it's really hard to keep merging forward. Unless I merge &
reverse as discussed.
> So I don't think that you should necessarily think of git as "the" souce
> control management in the big picture.
Yup. And quilt or other tools in the periphery. Something like the
git-aware darcs (which I haven't looked at yet).
> So I don't think any development effort that is big enough necessarily
> wants to use git as the _only_ way of doing development and merging stuff.
> The kernel certainly does not. Not now, and not in the long run.
Agreed. I'm happy to roll out some custom perl scripts around git (or
extend cogito a bit) if git can expose some stable holding points for
external tools to try and do some lightweight patch tracking.
> Whether the kernel model is applicable to anything else, I dunno.
I don't know either -- but I'm sure the toolset around git can support
a range of dev models. I don't think any other project has such a
large pool and strong convergence dynamics as the kernel. But git and
its tools and practices can be (I'm hoping) quite flexible to support
a range of dev models.
cheers,
martin
^ permalink raw reply
* [ANNOUNCE] Cogito-0.11.2
From: Petr Baudis @ 2005-06-08 23:07 UTC (permalink / raw)
To: git
Hello,
I'm happy to announce Cogito-0.11.2, next version of my SCMish layer
over Linus' GIT tree history storage tool. You can get it as usual on
kernel.org/pub/software/scm/cogito/
or by doing cg-update in your cogito.git repository.
The changes include especially some bugfixes and portability and
performance enhancements, as well as all the sweet stuff from Linus.
Note that I discovered a bug few minutes after releasing (as usual).
cg-log won't work correctly if ran with some files specified (the
"cg-log file" usage). I think it actually does not get used like this so
frequently, so I don't think it's worth another release by itself. But
expect new release as soon as some non-trivial amount of bugfixes piles
up (including core git bugfixes), quite soon hopefully.
Here's git-rev-list --pretty HEAD ^cogito-0.11.1 | git-shortlog
(BTW, Dan, what about another cg-log option for git-shortlog output? ;-):
C. Cooke:
Check whether the git repository is present before executing the command
Catalin Marinas:
cg-commit: Fix the log file readin from stdin
[PATCH Cogito] Add -f parameter also to cg-update
Chris Wedgwood:
cogitio: sh != bash
Christian Meder:
Miniscule correction of diff-format.txt
Dan Holmsand:
Make cg-add use xargs -0
Daniel Barkalow:
Document git-ssh-pull and git-ssh-push
-w support for git-ssh-pull/push
Generic support for pulling refs
rsh.c environment variable
Operations on refs
ssh-protocol version, command types, response code
Eugene Surovegin:
fix cg-commit new file handling
Jason McMullan:
Anal retentive 'const unsigned char *sha1'
Modify git-rev-list to linearise the commit history in merge order.
Jon Seymour:
three --merge-order bug fixes
Jonas Fonseca:
cg-commit: prefix pathspec argument with --
git-diff-cache: handle pathspec beginning with a dash
git-diff-cache: handle pathspec beginning with a dash
cg-log: cleanup line wrapping by using bash internals
Documentation improvements
Misc cg-log documentation fixes
Cleanup commit messages with git-stripspace
[PATCH 10/10] Add -s option to show log summary
[PATCH 9/10] Move file matching inside the loop.
[PATCH 8/10] Move the username matching inside the loop
[PATCH 7/10] Move log printing to separate function
[PATCH 6/10] Remove the catch all rule
[PATCH 5/10] Move printing of the commit info line inside the loop
[PATCH 4/10] First parse all commit header entries then print them
[PATCH 3/10] Separate handling of author and committer in commit headers
[PATCH 2/10] Separate handling of tree and parent in commit headers
[PATCH 1/10] Cleanup conversion to human readable date
cg-Xnormid: support revision ids specified by date
Junio C Hamano:
Tests: read-tree -m test updates.
Documentation: describe diff tweaking (fix).
Start cvs-migration documentation
read-tree: update documentation for 3-way merge.
read-tree: save more user hassles during fast-forward.
index locking like everybody else
3-way merge tests for new "git-read-tree -m"?
rename git-rpush and git-rpull to git-ssh-push and git-ssh-pull
Documentation: describe git extended diff headers.
Documentation: describe diff tweaking.
pull: gracefully recover from delta retrieval failure.
diffcore-break.c: various fixes.
diff.c: -B argument passing fix.
diff.c: locate_size_cache() fix.
diff: Update -B heuristics.
diff: Clean up diff_scoreopt_parse().
diff: Fix docs and add -O to diff-helper.
Tweak count-delta interface
Find size of SHA1 object without inflating everything.
Handle deltified object correctly in git-*-pull family.
Linus Torvalds:
Remove MERGE_HEAD after committing merge
Make "git commit" work correctly in the presense of a manual merge
cvs-migration: add more of a header to the "annotate" discussion
Leave merge failures in the filesystem
Fix SIGSEGV on unmerged files in git-diff-files -p
Make default merge messages denser.
git-apply: creatign empty files is nonfatal
Talk about "git cvsimport" in the cvs migration docs
git-read-tree: -u without -m is meaningless. Don't allow it.
git-read-tree: make one-way merge also honor the "update" flag
Add CVS import scripts and programs
git-ssh-push/pull: usability improvements
git-resolve-script: stop when the automated merge fails
Make fetch/pull scripts terminate cleanly on errors
git-resolve-script: don't wait for three seconds any more
git-read-tree: some "final" cleanups
git-read-tree: simplify merge loops enormously
Add "__noreturn__" attribute to die() and usage()
git-rev-list: make sure to link with ssl libraries
Fix off-by-one in new three-way-merge updates
Three-way merge: fix silly bug that made trivial merges not work
Fix entry.c dependency and compile problem
git-read-tree: fix up two-way merge
More work on merging with git-read-tree..
Make fiel checkout function available to the git library
git-read-tree: fix up three-way merge tests
git-read-tree: be a lot more careful about merging dirty trees
diff 'rename' format change.
git-apply: consider it an error to apply no changes
git-apply: fix rename header parsing
git-apply: actually apply patches and update the index
git-apply: fix apply of a new file
git-apply: find offset fragments, and really apply them
git-apply: first cut at actually checking fragment data
git-fsck-cache: complain if no default references found
pretty_print_commit: add different formats
git-shortlog: add name translations for 'sparse' repo
Add git-shortlog perl script
git-rev-list: allow arbitrary head selections, use git-rev-tree syntax
Clarify git-diff-cache semantics in the tutorial.
Mark Allen:
Modify cg-Xlib for non-GNU date.
Michal Rokos:
[cogito] Sync objects only when needed
[cogito] paged output for cg-diff
Abstracted out $PAGER invocation to a pager() function
Petr Baudis:
Fix cg-log called on specified files
cogito-0.11.2
Added trivial cg wrapper
Use portable sed stuff in cg-log Signed-off-by highlighting
showdate() now uses $(()) instead of $(expr)
Fixed cg-log -u
cg-merge now sometimes allows tree merge + local changes
Add the t6001 testcase which got missed out at the last merge.
Move commit line processing to process_commit_line
Improved cg-Xmergefile
Fix git-merge-one-file permissions auto-merging
Fix cg-patch reverting file removal
Reindent print_commit_log() body
cg-log is now pure git-rev-list --pretty=raw frontend
Fix cg-commit doing shell expansion on -m arguments
Fix mismerged git-r* -> git-ssh-* rename in Makefile
Move print_commit_log() in cg-log
Fix an errorneous cg-clone example in the README
Make git-update-cache --force-remove regular
Portability sed fix in cg-commit
Improve git-rev-list --header output
Implement cg-rm -n for untracking files
Fixed cg-Xnormid " " call
cg-commit now updates cache separately for different change types
Pass revisions to commit-id, parent-id, tree-id and cg-Xnormid quoted
Do rm -f in make uninstall
make dist will now produce tarball with sensible name
Rene Scharfe:
git-tar-tree: do only basic tests in t/t5000-git-tar-tree.sh
git-tar-tree: fix write_trailer
git-tar-tree: add a test case
git-tar-tree: small doc update
git-tar-tree: cleanup write_trailer()
Sven Verdoolaege:
git-cvs2git: create tags
Timo Hirvonen:
Use ntohs instead of htons to convert ce_flags to host byte order
Have fun,
--
Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
<Espy> be careful, some twit might quote you out of context..
^ permalink raw reply
* Re: Handling merge conflicts a bit more gracefully..
From: Junio C Hamano @ 2005-06-08 23:07 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.58.0506081336080.2286@ppc970.osdl.org>
>>>>> "LT" == Linus Torvalds <torvalds@osdl.org> writes:
LT> What happens now in the case of a merge conflict is:
LT> - the merge is obviously not committed
LT> - we do all the successful merges, and update the index file for them
LT> - for the files that conflict, we force the index to contain the old
LT> version of the file (ie we remove the merge from the index), and we
LT> write the (failed) output of the merge into the working directory, and
LT> we complain loudly:
LT> Comments? It would be good to have people test this and maybe even write a
LT> few automated tests that it all works as expected..
OK, I'll bite. Other than some minor details, the work tree
seems to be updated with the result of the merge, either
successful one or failed one.
2a68a8659f7dc55fd285d235ae2d19e7a8116c30 \
(from f9e7750621ca5e067f58a679caff5ff2f9881c4c)
diff --git a/git-merge-one-file-script b/git-merge-one-file-script
--- a/git-merge-one-file-script
+++ b/git-merge-one-file-script
@@ -19,22 +19,25 @@ case "${1:-.}${2:-.}${3:-.}" in
# Deleted in both.
#
"$1..")
- echo "ERROR: $4 is removed in both branches."
- echo "ERROR: This is a potential rename conflict."
- exit 1;;
+ echo "WARNING: $4 is removed in both branches."
+ echo "WARNING: This is a potential rename conflict."
+ exec git-update-cache --remove -- "$4" ;;
Making sure that the path does not exist in the work tree with
test -f "$4" would be more sensible, before running --remove.
#
# Deleted in one and unchanged in the other.
#
"$1.." | "$1.$1" | "$1$1.")
echo "Removing $4"
- exec git-update-cache --force-remove "$4" ;;
+ rm -f -- "$4"
+ exec git-update-cache --remove -- "$4" ;;
Make sure "$4" is not a directory, perhaps? At least barf if
that 'rm -f -- "$4"' fails?
#
# Modified in both, but differently.
#
@@ -55,19 +60,21 @@ case "${1:-.}${2:-.}${3:-.}" in
orig=`git-unpack-file $1`
src1=`git-unpack-file $2`
src2=`git-unpack-file $3`
- merge "$src2" "$orig" "$src1"
+ merge -p "$src1" "$orig" "$src2" > "$4"
ret=$?
+ rm -f -- "$orig" "$src1" "$src2"
if [ "$6" != "$7" ]; then
echo "ERROR: Permissions $5->$6->$7 don't match."
+ ret=1
fi
if [ $ret -ne 0 ]; then
- echo "ERROR: Leaving conflict merge in $src2."
+ # Reset the index to the first branch, making
+ # git-diff-file useful
+ git-update-cache --add --cacheinfo "$6" "$2" "$4"
+ echo "ERROR: Merge conflict in $4."
exit 1
fi
- sha1=`git-write-blob "$src2"` || {
- echo "ERROR: Leaving conflict merge in $src2."
- }
- exec git-update-cache --add --cacheinfo "$6" $sha1 "$4" ;;
+ exec git-update-cache --add -- "$4" ;;
*)
echo "ERROR: Not handling case $4: $1 -> $2 -> $3" ;;
esac
Again, make sure "$4" is not a directory before redirecting into
it from merge, so that you can tell merge failures from it?
^ permalink raw reply
* gitk (was Re: Linux v2.6.12-rc6)
From: Linus Torvalds @ 2005-06-08 23:16 UTC (permalink / raw)
To: Paul Mackerras; +Cc: Git Mailing List
In-Reply-To: <17062.21286.601768.751853@cargo.ozlabs.ibm.com>
Btw, Paul,
one thing I end up missing in gitk is that looking at merges doesn't show
any output, yet in many ways merges are actually the most interesting
ones where you'd like to see where a file comes from..
Now, handling multi-way merges may be hard, but at least the normal
two-way merges end up pretty straightforward, I think, and only have four
cases for each file:
- not touched by either side (ie it doesn't show up in either of
"git-diff-tree TREE PARENT1" or "git-diff-tree TREE PARENT2")
- changed by PARENT1 only (ie it shows up in the git-diff-tree between
TREE and PARENT2)
- changed by PARENT2 only
- changed since both
and it would be cool if the "filename list" panel on the right side
colorized the names by these things (only three cases - leave the "not
touched" files off entirely, of course).
Also, it should actually possible to do a diff for these things with just
doing a "diff3" on the two parents and on the merge result (diff3 normally
expects the "original", but hey, the "original" might as well be the
result), and thus color a merge file by whether the lines came from one
side or the other or both (or neither, which would be a manual merge
fixup).
Maybe I'm crazy. But it _seems_ like a good idea that shouldn't be
fundamentally hard.
Linus
^ permalink raw reply
* Re: Handling merge conflicts a bit more gracefully..
From: Linus Torvalds @ 2005-06-08 23:35 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vis0o30sc.fsf@assigned-by-dhcp.cox.net>
On Wed, 8 Jun 2005, Junio C Hamano wrote:
> # Deleted in both.
>
> Making sure that the path does not exist in the work tree with
> test -f "$4" would be more sensible, before running --remove.
Yeah, my (broken) thinking was that since it wasn't in both, it wasn't in
the working directory either, but you're right, that's just crazy talk.
There could be a stale file there.
Made it do a
rm -f -- "$4" || exit 1
instead (and changed the other one to do the "|| exit 1" too, since you're
also obviously right on the directory issue).
> # Modified in both, but differently.
> + merge -p "$src1" "$orig" "$src2" > "$4"
>
> Again, make sure "$4" is not a directory before redirecting into
> it from merge, so that you can tell merge failures from it?
Hmm.. What's the cleanest way to check for redirection errors, but still
be able to distinguish those cleanly from "merge" itself returning an
error?
Linus
^ permalink raw reply
* Re: [ANNOUNCE] Cogito-0.11.2
From: Dan Holmsand @ 2005-06-08 23:35 UTC (permalink / raw)
To: git; +Cc: Petr Baudis
In-Reply-To: <20050608230725.GR982@pasky.ji.cz>
Petr Baudis wrote:
> Here's git-rev-list --pretty HEAD ^cogito-0.11.1 | git-shortlog
> (BTW, Dan, what about another cg-log option for git-shortlog output? ;-):
Well, since I try to use the same output format as git-rev-list --pretty
does (most of the time, it *is* just that...), I can actually already do
cg-log -r:cogito-0.11.1 | git-shortlog
and get the same thing.
/dan
^ permalink raw reply
* [PATCH] git-merge-one-file-script cleanups from Cogito
From: Petr Baudis @ 2005-06-08 23:38 UTC (permalink / raw)
To: torvalds; +Cc: git
Chain the resolving sequences (e.g. git-cat-file - chmod -
git-update-cache) through &&s so we stop right away in case one of the
command fails, and report the error code to the script caller.
Also add a copyright notice, some blank lines, ;; on a separate line,
and nicer error messages.
Signed-off-by: Petr Baudis <pasky@ucw.cz>
---
commit 99169278864b1adba5494d34f86c00d08ec0aff2
tree 5b9129ffe38c4286f65a6ddf97a0674bfc8942e3
parent c7773b6b3ab4f03a4e64084c0dc67045b283bc34
author Petr Baudis <pasky@ucw.cz> Thu, 09 Jun 2005 01:03:14 +0200
committer Petr Baudis <xpasky@machine.sinus.cz> Thu, 09 Jun 2005 01:03:14 +0200
git-merge-one-file-script | 44 +++++++++++++++++++++++++++++---------------
1 files changed, 29 insertions(+), 15 deletions(-)
diff --git a/git-merge-one-file-script b/git-merge-one-file-script
--- a/git-merge-one-file-script
+++ b/git-merge-one-file-script
@@ -1,6 +1,8 @@
#!/bin/sh
#
-# This is the git merge script, called with
+# Copyright (c) Linus Torvalds, 2005
+#
+# This is the git per-file merge script, called with
#
# $1 - original file SHA1 (or empty)
# $2 - file in branch1 SHA1 (or empty)
@@ -12,7 +14,7 @@
#
# Handle some trivial cases.. The _really_ trivial cases have
# been handled already by git-read-tree, but that one doesn't
-# do any merges that migth change the tree layout.
+# do any merges that might change the tree layout.
case "${1:-.}${2:-.}${3:-.}" in
#
@@ -21,23 +23,29 @@ case "${1:-.}${2:-.}${3:-.}" in
"$1..")
echo "WARNING: $4 is removed in both branches."
echo "WARNING: This is a potential rename conflict."
- exec git-update-cache --remove -- "$4" ;;
+ exec git-update-cache --remove -- "$4"
+ ;;
+
#
# Deleted in one and unchanged in the other.
#
-"$1.." | "$1.$1" | "$1$1.")
+"$1.$1" | "$1$1.")
echo "Removing $4"
- rm -f -- "$4"
- exec git-update-cache --remove -- "$4" ;;
+ exec rm -f -- "$4" &&
+ git-update-cache --remove -- "$4"
+ ;;
+
#
# Added in one.
#
".$2." | "..$3" )
case "$6$7" in *7??) mode=+x;; *) mode=-x;; esac
echo "Adding $4 with perm $mode."
- git-cat-file blob "$2$3" > "$4"
- chmod $mode -- "$4"
- exec git-update-cache --add -- "$4" ;;
+ exec git-cat-file blob "$2$3" >"$4" &&
+ chmod $mode -- "$4" &&
+ git-update-cache --add -- "$4"
+ ;;
+
#
# Added in both (check for same permissions).
#
@@ -49,9 +57,11 @@ case "${1:-.}${2:-.}${3:-.}" in
fi
case "$6" in *7??) mode=+x;; *) mode=-x;; esac
echo "Adding $4 with perm $mode"
- git-cat-file blob "$2" > "$4"
- chmod $mode -- "$4"
- exec git-update-cache --add -- "$4" ;;
+ exec git-cat-file blob "$2" >"$4" &&
+ chmod $mode -- "$4" &&
+ git-update-cache --add -- "$4"
+ ;;
+
#
# Modified in both, but differently.
#
@@ -60,12 +70,13 @@ case "${1:-.}${2:-.}${3:-.}" in
orig=`git-unpack-file $1`
src1=`git-unpack-file $2`
src2=`git-unpack-file $3`
+
merge -p "$src1" "$orig" "$src2" > "$4"
ret=$?
rm -f -- "$orig" "$src1" "$src2"
if [ "$6" != "$7" ]; then
- echo "ERROR: Permissions $5->$6->$7 don't match."
+ echo "ERROR: Permissions conflict: $5->$6,$7."
ret=1
fi
case "$6" in *7??) mode=+x;; *) mode=-x;; esac
@@ -78,8 +89,11 @@ case "${1:-.}${2:-.}${3:-.}" in
echo "ERROR: Merge conflict in $4."
exit 1
fi
- exec git-update-cache --add -- "$4" ;;
+ exec git-update-cache --add -- "$4"
+ ;;
+
*)
- echo "ERROR: Not handling case $4: $1 -> $2 -> $3" ;;
+ echo "ERROR: $4: Not handling case $1 -> $2 -> $3"
+ ;;
esac
exit 1
|
--
Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
<Espy> be careful, some twit might quote you out of context..
^ permalink raw reply
* Re: Handling merge conflicts a bit more gracefully..
From: Junio C Hamano @ 2005-06-09 0:03 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.58.0506081629370.2286@ppc970.osdl.org>
>>>>> "LT" == Linus Torvalds <torvalds@osdl.org> writes:
>> # Modified in both, but differently.
>> + merge -p "$src1" "$orig" "$src2" > "$4"
>>
>> Again, make sure "$4" is not a directory before redirecting into
>> it from merge, so that you can tell merge failures from it?
LT> Hmm.. What's the cleanest way to check for redirection errors, but still
LT> be able to distinguish those cleanly from "merge" itself returning an
LT> error?
I do not think you can, unless you are willing to parse shell
error messages, which I do not want you to be willing to ;-).
: siamese; ls -dlF junk j.py
---------- 1 junio junio 845 May 7 2004 j.py
drwxrwxr-x 2 junio junio 4096 May 4 22:31 junk/
: siamese; echo foo >j.py ; echo $?
bash: j.py: Permission denied
1
: siamese; echo foo >junk ; echo $?
bash: junk: Is a directory
1
I think you have a bigger problem of leading paths, BTW.
Since we would want to have the merge result file at that path,
and not being able to create such is an error, how about doing
dumb and simple, like:
d=`dirname "$4"` &&
mkdir -p "$d" &&
rm -f -- "$4" &&
: >"$4" || {
echo "barf"
exit 1
}
merge -p "$src1" "$orig" "$src2" >"$4"
ret=$?
^ permalink raw reply
* Re: Handling merge conflicts a bit more gracefully..
From: Junio C Hamano @ 2005-06-09 0:11 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.58.0506081629370.2286@ppc970.osdl.org>
While I have your attention, I have been thinking about a
problem at lower level than what is being discussed.
Consider the following two command sequences:
(1) git-read-tree -m $H $M && git-write-tree
(2) I=`git-write-tree` &&
git-read-tree -m $H $I $M &&
git-merge-cache -o git-merge-one-file-script -a &&
git-write-tree
I think they should be equivalent in that:
- when (1) refuses to run, (2) should either cause
git-read-tree to refuse, or at least should result in an
unmerged cache and git-write-tree phase should fail;
- when (1) succeeds, (2) should also succeed, and the
resulting tree from both should be the same.
^ permalink raw reply
* Re: [RFC] rename/rename conflicts: do they matter?
From: Junio C Hamano @ 2005-06-09 0:34 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
In-Reply-To: <7vll5k69y0.fsf@assigned-by-dhcp.cox.net>
>>>>> "JCH" == Junio C Hamano <junkio@cox.net> writes:
JCH> I was reviewing git-merge-one-file-script, and started
JCH> thinking...
But somehow I got underwhelming responses.
I further think the "WARNING: " below is needlessly eating one
extra line of screen real estate without any additional value.
If one tree renamed a file (and creating the same or similar
file in another location) while the other tree kept the file
intact, then we would see "Removing $4" from the "deleted in one
and unchanged in the other" (and corresponding "Adding $4 with
perm $mode" for the rename destination). If the user wants to
be careful about renames then all "Removing ..." need to be
examined _anyway_. I would think it would be saner to collapse
these two case arms to catch "$1.." | "$1.$1" | "$1$1." pattern
and just say "Removing $4".
case "${1:-.}${2:-.}${3:-.}" in
#
# Deleted in both.
#
"$1..")
echo "WARNING: $4 is removed in both branches."
echo "WARNING: This is a potential rename conflict."
rm -f -- "$4" &&
exec git-update-cache --remove -- "$4"
;;
#
# Deleted in one and unchanged in the other.
#
"$1.$1" | "$1$1.")
echo "Removing $4"
exec rm -f -- "$4" &&
git-update-cache --remove -- "$4"
;;
^ permalink raw reply
* Re: Handling merge conflicts a bit more gracefully..
From: Linus Torvalds @ 2005-06-09 0:41 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vzmu01jmc.fsf@assigned-by-dhcp.cox.net>
On Wed, 8 Jun 2005, Junio C Hamano wrote:
>
> I do not think you can, unless you are willing to parse shell
> error messages, which I do not want you to be willing to ;-).
Yeah, no.
> I think you have a bigger problem of leading paths, BTW.
Gotcha. I committed a largely untested fix that hopefully does this all
right.
I'm currently using your suggested thing (inside a function), but I think
I'll instead make it do
git-update-cache --add --cacheinfo ... &&
git-checkout-cache -u -f "$4"
which seems even simpler.
Linus
^ permalink raw reply
* Re: [PATCH] git-merge-one-file-script cleanups from Cogito
From: Linus Torvalds @ 2005-06-08 23:56 UTC (permalink / raw)
To: Petr Baudis; +Cc: git
In-Reply-To: <20050608233820.GB9782@pasky.ji.cz>
On Thu, 9 Jun 2005, Petr Baudis wrote:
>
> Chain the resolving sequences (e.g. git-cat-file - chmod -
> git-update-cache) through &&s so we stop right away in case one of the
> command fails, and report the error code to the script caller.
Heh. This patch wouldn't apply, so I tried the new merge functionality on
it. Seems to work. Goodie.
Linus
^ permalink raw reply
* [PATCH] Add support reading default options from conf file
From: Jonas Fonseca @ 2005-06-09 1:00 UTC (permalink / raw)
To: Dan Holmsand; +Cc: git, Petr Baudis
Reply-To:
In-Reply-To: <42A754D5.10705@gmail.com>
Dan Holmsand <holmsand@gmail.com> wrote Wed, Jun 08, 2005:
> - Automatic color if the COGITO_AUTO_COLOR environment variable is set.
[ This has been discussed before. Default arguments. The 'new' cg
wrapper makes this very easy. Not as smart as your env variable
handling tho'. ]
The default options are read only for Cogito calls going through the new
cg wrapper which makes it trivial to 'overwrite' them by just calling
cg-COMMAMD.
Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---
Documentation/make-cogito-asciidoc | 12 ++++++++++++
cg | 6 +++++-
2 files changed, 17 insertions(+), 1 deletions(-)
diff --git a/Documentation/make-cogito-asciidoc b/Documentation/make-cogito-asciidoc
--- a/Documentation/make-cogito-asciidoc
+++ b/Documentation/make-cogito-asciidoc
@@ -140,6 +140,18 @@ FILE::
Indicates an already existing filename - always relative to the root
of the repository.
+FILES
+-----
+~/.cogito.conf::
+ This file is read when running the \`cg\` wrapper program and
+ contains information about default options. Each line consists
+ of a command name and a list of options. Empty lines and lines
+ starting with '#' are ignored. To always have \`cg log\` and
+ \`cg diff\` output colored put the following in ~/.cogito.conf:
+
+ log -c
+ diff -c
+
COPYRIGHT
---------
Copyright (C) Petr Baudis, 2005.
diff --git a/cg b/cg
--- a/cg
+++ b/cg
@@ -3,5 +3,9 @@
cmd="$1"; shift
[ x"$cmd" = x"--help" ] && cmd="help"
+if [ -e "$HOME/.cogito.conf" ]; then
+ defaults="$(grep "^$cmd" "$HOME/.cogito.conf" | sed "s/^$cmd //")"
+fi
+
exe="cg-$cmd"
-exec $exe "$@"
+exec $exe "$defaults" "$@"
--
Jonas Fonseca
^ permalink raw reply
* Re: Handling merge conflicts a bit more gracefully..
From: Junio C Hamano @ 2005-06-09 1:04 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.58.0506081738000.2286@ppc970.osdl.org>
>>>>> "LT" == Linus Torvalds <torvalds@osdl.org> writes:
LT> I'll instead make it do
LT> git-update-cache --add --cacheinfo ... &&
LT> git-checkout-cache -u -f "$4"
LT> which seems even simpler.
I like that one much much better. Consistently using
checkout-cache -f everywhere is much preferred. It creates the
leading paths itself, and even nukes interfering files it finds
while creating leading directories, which the verify_path using
mkdir -p would not give you.
^ permalink raw reply
* Re: [PATCH] Tidy up some rev-list-related stuff
From: Jon Seymour @ 2005-06-09 1:06 UTC (permalink / raw)
To: Petr Baudis; +Cc: torvalds, git
In-Reply-To: <20050608205943.GO982@pasky.ji.cz>
On 6/9/05, Petr Baudis <pasky@ucw.cz> wrote:
> This patch tidies up the git-rev-list documentation and epoch.c, which
> are in severe clash with the unwritten coding style now, and quite
> unreadable.
>
> The patch mostly wraps lines before or on the 80th column, removes
> plenty of superfluous empty lines and changes comments from // to /* */.
>
> Signed-off-by: Petr Baudis <pasky@ucw.cz>
>
> ---
>
> Jon, since this is your stuff, could you ack the patch, please?
> Thanks.
>
> I'm sorry to send patches like this, but I think the files are really
> ugly as of now, and not very readable. This should be a definite
> improvement in this regard, I hope.
>
Ack'd and tested.
Hey, no problem. I'll never learn unless someone corrects me. It does
make my next patch slightly tedious since I'll have to manually
reapply it, but hey, I am the new kid on the block, so kick dirt in my
face :-)
>From your patch I infer the following coding style rules:
Lines to wrap at column 80
One statement blocks should not include braces
Comment blocks should always be /* */ rather than //
Declarations should always be up the top of a block - never close to first use
No whitespace at top and bottom of blocks.
All indentation should use tabs and only tabs, set at tab stops of 8 apart.
Question: is // ever allowed?
Presumably, when in doubt should I use the kernel's CodingStyle
document as the default reference.
Speaking of which, I can't emacs to indent properly even when I use
this suggestion from that document:
(defun linux-c-mode ()
"C mode with adjusted defaults for use with the Linux kernel."
(interactive)
(c-mode)
(c-set-style "K&R")
(setq tab-width 8)
(setq indent-tabs-mode t)
(setq c-basic-offset 8))
This will define the M-x linux-c-mode command. When hacking on a
module, if you put the string -*- linux-c -*- somewhere on the first
two lines, this mode will be automatically invoked. Also, you may want
to add
(setq auto-mode-alist (cons '("/home/jon/.*/.*\\.[ch]$" . linux-c-mode)
auto-mode-alist))
It doesn't work when I execute linux-c-mode from the emacs command line either.
Any ideas at all what I am doing wrong? [ Apart from the ever so
constructive suggestion to use vi or vim - please! ]
jon.
^ permalink raw reply
* Re: Handling merge conflicts a bit more gracefully..
From: Linus Torvalds @ 2005-06-09 1:08 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7voeag1j9y.fsf@assigned-by-dhcp.cox.net>
On Wed, 8 Jun 2005, Junio C Hamano wrote:
>
> Consider the following two command sequences:
>
> (1) git-read-tree -m $H $M && git-write-tree
>
> (2) I=`git-write-tree` &&
> git-read-tree -m $H $I $M &&
> git-merge-cache -o git-merge-one-file-script -a &&
> git-write-tree
>
> I think they should be equivalent in that:
>
> - when (1) refuses to run, (2) should either cause
> git-read-tree to refuse, or at least should result in an
> unmerged cache and git-write-tree phase should fail;
>
> - when (1) succeeds, (2) should also succeed, and the
> resulting tree from both should be the same.
I think that sounds reasonable. Is it not the case now?
Linus
^ permalink raw reply
* Re: [PATCH] git-rev-list --merge-order resynched with Linus' head
From: Jon Seymour @ 2005-06-05 12:55 UTC (permalink / raw)
To: jon@blackcubes.dyndns.org; +Cc: git, torvalds
In-Reply-To: <20050605072336.14283.qmail@blackcubes.dyndns.org>
Just discovered a few bugs in my revised patch...will repost when I
have fixed them.
jon.
^ permalink raw reply
* Re: Handling merge conflicts a bit more gracefully..
From: Junio C Hamano @ 2005-06-09 2:15 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.58.0506081757170.2286@ppc970.osdl.org>
>>>>> "LT" == Linus Torvalds <torvalds@osdl.org> writes:
LT> I think that sounds reasonable. Is it not the case now?
Well, except that $I may validly be an empty tree ;-), so not
quite.
In case it was not clear, where I am headed is this. I would
like to rip out the two-tree "carry forward" implementation from
read-tree, and replace it with:
read_cache() -- current goes to stage0
read_tree(H) -- H goes to stage1
read_tree(M) -- M goes to stage3
for each path
if it appears in stage0, copy it to stage2
else if it appears in stage1, copy it to stage2
threeway_merge() !!
And then the resulting possibly unmerged cache can be resolved
exactly the same way with merge-cache.
The trouble I feel with the current "carry forward" code is that
when it works it does sensible thing, but otherwise does not
help the end user at all. With all the work going into making
merge-one-file-script nicer today, I think leveraging three-way
merge support for two-tree fast forward case would make a lot
more sense than keeping the all-or-nothing carry forward code I
recently added to it.
When/if that happens, then the current fast-forward code would
need to be changed from:
read-tree -m $H $M && echo $M >.git/HEAD
to
read-tree -m $H $M &&
if unmerged paths in the resulting cache
then
merge-cache -o merge-one-file-script -a
fi &&
echo $M >.git/HEAD
and the user's local changes since H when fast forwarding to M
would be handled with the same workflow as the three-way case.
Hmm.
^ permalink raw reply
* Re: Upstream merging and conflicts (was Re: Using cvs2git to track an external CVS project)
From: Linus Torvalds @ 2005-06-09 2:34 UTC (permalink / raw)
To: Martin Langhoff; +Cc: Git Mailing List
In-Reply-To: <46a038f905060815096382636a@mail.gmail.com>
On Thu, 9 Jun 2005, Martin Langhoff wrote:
> On 6/9/05, Linus Torvalds <torvalds@osdl.org> wrote:
> > Yes, and right now that "manual" part is actualyl fairly high. I'll fix
> > that thing up (today, I hope), making nontrivial merges much easier.
>
> Wow -- I'll be tracking your tree closely then ;-)
Well, it's done, and it's now "much easier" in the sense that anything
that doesn't have metadata changes should be picked up pretty trivially by
the three-way merge thing.
But if you move things around, then you'd need to have a merge that is
aware of movement, ie something much more sophisticated than just 3way
merge.
> > It's true that you can't skip patches, since a merge is always
> > all-or-nothing, and the global history really requires that (in a very
> > fundamental way). However, you _can_ merge from the HEAD, and then say
> > "that patch is no longer relevant in this tree", and remove it. Then
> > you'll never need to worry about that patch any more, because you've
> > merged it and in your merged result, it no longer exists).
>
> I had that strategy in my back-pocket already, but it doesn't sound right.
With global history, you really don't end up having much choice.
The alternative is to have per-file history, which sucks pretty bad
(you're screwed if you have a file that is touched by two things, so it
just moves the problem a bit, but more importantly you now have all the
CVS crud), or then you have to play games like arch or darcs which is all
about re-ordering patches (and then your history is totally malleable,
with all the problems that entails).
> > Yes. I think this is fundamental. "git" needs to converge. It's how git
> > works. git also "crystallizes" the history and makes it unbreakable.
> > Both of these things are _wonderful_ for what they mean, but both of these
> > fundamental issues are _horrible_ for other reasons.
>
> Fair enough -- and actually I'm not convinced it's a horrible thing.
It's absolutely not horrible, but it limits how you work. _I_ think it
limits you in good ways, but it's definitely a limitation.
> Having worked with forever-diverging tools like Arch, I can appreciate
> the value of crystallizing and identifying when you've converged --
> and rebasing all steps forward on the fact that you've converged. This
> is huge.
My gut feel is that it should be possible to have a hybrid system that
handles both the solid "crystalline" phase (aka git) and the "gas" phase
(aka free-lowing patches) and have them integrate with each other well.
That's kind of the way the kernel works, with people using quilt as a way
to capture the patches in between.
My read is that this analogy arch and darcs try to avoid the really solid
crystalline phase entirely and end up being amorphous. You can probably
have that too, but on the other hand it's fairly easy to merge between two
"crystallized" repositories and be totally unambigious about what the
result is, but if there's a lot of the amorpous stuff going on, it's not
clear any more.
> > Whether the kernel model is applicable to anything else, I dunno.
>
> I don't know either -- but I'm sure the toolset around git can support
> a range of dev models. I don't think any other project has such a
> large pool and strong convergence dynamics as the kernel. But git and
> its tools and practices can be (I'm hoping) quite flexible to support
> a range of dev models.
Hey, I obviously think you're right. Using git gives good ways of
communicating the core infrastructure between two (or more) groups, while
then internally within the group they may use loser patch-tracking systems
that don't have the same kind of convergence requirements (but which you
don't need for a "small" set of patches anyway, where "small" can
obviously be hundreds of internal patches).
Linus
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox