Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions Documentation/RelNotes/2.52.0.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,30 @@ including security updates, are included in this release.
ignored") did not work well with "--name-only" and friends.
(merge b55e6d36eb ly/diff-name-only-with-diff-from-content later to maint).

* Documentation for "git rebase" has been updated.
(merge 3f7f2b0359 je/doc-rebase later to maint).

* The start_delayed_progress() function in the progress eye-candy API
did not clear its internal state, making an initial delay value
larger than 1 second ineffective, which has been corrected.
(merge 457534d041 js/progress-delay-fix later to maint).

* The compatObjectFormat extension is used to hide an incomplete
feature that is not yet usable for any purpose other than
developing the feature further. Document it as such to discourage
its use by mere mortals.
(merge 716d905792 bc/doc-compat-object-format-not-working later to maint).

* "git log -L..." compared trees of multiple parents with the tree of the
merge result in an unnecessarily inefficient way.
(merge 0a15bb634c sg/line-log-merge-optim later to maint).

* Under a race against another process that is repacking the
repository, especially a partially cloned one, "git fetch" may
mistakenly think some objects we do have are missing, which has
been corrected.
(merge 8f32a5a6c0 jk/fetch-check-graph-objects-fix later to maint).

* Other code cleanup, docfix, build fix, etc.
(merge 823d537fa7 kh/doc-git-log-markup-fix later to maint).
(merge cf7efa4f33 rj/t6137-cygwin-fix later to maint).
Expand Down
4 changes: 4 additions & 0 deletions Documentation/config/extensions.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ compatObjectFormat::
compatObjectFormat. As well as being able to use oids encoded in
compatObjectFormat in addition to oids encoded with objectFormat to
locally specify objects.
+
Note that the functionality enabled by this extension is incomplete and subject
to change. It currently exists only to allow development and testing of
the underlying feature and is not designed to be enabled by end users.

noop::
This extension does not change git's behavior at all. It is useful only
Expand Down
149 changes: 58 additions & 91 deletions Documentation/git-rebase.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -16,94 +16,81 @@ SYNOPSIS

DESCRIPTION
-----------
If `<branch>` is specified, `git rebase` will perform an automatic
`git switch <branch>` before doing anything else. Otherwise
it remains on the current branch.
Transplant a series of commits onto a different starting point.
You can also use `git rebase` to reorder or combine commits: see INTERACTIVE
MODE below for how to do that.

If `<upstream>` is not specified, the upstream configured in
`branch.<name>.remote` and `branch.<name>.merge` options will be used (see
linkgit:git-config[1] for details) and the `--fork-point` option is
assumed. If you are currently not on any branch or if the current
branch does not have a configured upstream, the rebase will abort.

All changes made by commits in the current branch but that are not
in `<upstream>` are saved to a temporary area. This is the same set
of commits that would be shown by `git log <upstream>..HEAD`; or by
`git log 'fork_point'..HEAD`, if `--fork-point` is active (see the
description on `--fork-point` below); or by `git log HEAD`, if the
`--root` option is specified.

The current branch is reset to `<upstream>` or `<newbase>` if the
`--onto` option was supplied. This has the exact same effect as
`git reset --hard <upstream>` (or `<newbase>`). `ORIG_HEAD` is set
to point at the tip of the branch before the reset.

[NOTE]
`ORIG_HEAD` is not guaranteed to still point to the previous branch tip
at the end of the rebase if other commands that write that pseudo-ref
(e.g. `git reset`) are used during the rebase. The previous branch tip,
however, is accessible using the reflog of the current branch
(i.e. `@{1}`, see linkgit:gitrevisions[7]).

The commits that were previously saved into the temporary area are
then reapplied to the current branch, one by one, in order. Note that
any commits in `HEAD` which introduce the same textual changes as a commit
in `HEAD..<upstream>` are omitted (i.e., a patch already accepted upstream
with a different commit message or timestamp will be skipped).

It is possible that a merge failure will prevent this process from being
completely automatic. You will have to resolve any such merge failure
and run `git rebase --continue`. Another option is to bypass the commit
that caused the merge failure with `git rebase --skip`. To check out the
original `<branch>` and remove the `.git/rebase-apply` working files, use
the command `git rebase --abort` instead.

Assume the following history exists and the current branch is "topic":
For example, imagine that you have been working on the `topic` branch in this
history, and you want to "catch up" to the work done on the `master` branch.

------------
A---B---C topic
/
D---E---F---G master
------------

From this point, the result of either of the following commands:


git rebase master
git rebase master topic

would be:
You want to transplant the commits you made on `topic` since it diverged from
`master` (i.e. A, B, and C), on top of the current `master`. You can do this
by running `git rebase master` while the `topic` branch is checked out. If you
want to rebase `topic` while on another branch, `git rebase master topic` is a
shortcut for `git checkout topic && git rebase master`.

------------
A'--B'--C' topic
/
D---E---F---G master
------------

*NOTE:* The latter form is just a short-hand of `git checkout topic`
followed by `git rebase master`. When rebase exits `topic` will
remain the checked-out branch.

If the upstream branch already contains a change you have made (e.g.,
because you mailed a patch which was applied upstream), then that commit
will be skipped and warnings will be issued (if the 'merge' backend is
used). For example, running `git rebase master` on the following
history (in which `A'` and `A` introduce the same set of changes, but
have different committer information):
If there is a merge conflict during this process, `git rebase` will stop at the
first problematic commit and leave conflict markers. If this happens, you can do
one of these things:

------------
A---B---C topic
/
D---E---A'---F master
------------
1. Resolve the conflict. You can use `git diff` to find the markers (<<<<<<)
and make edits to resolve the conflict. For each file you edit, you need to
tell Git that the conflict has been resolved. You can mark the conflict as
resolved with `git add <filename>`. After resolving all of the conflicts,
you can continue the rebasing process with

will result in:
git rebase --continue

------------
B'---C' topic
/
D---E---A'---F master
------------
2. Stop the `git rebase` and return your branch to its original state with

git rebase --abort

3. Skip the commit that caused the merge conflict with

git rebase --skip

If you don't specify an `<upstream>` to rebase onto, the upstream configured in
`branch.<name>.remote` and `branch.<name>.merge` options will be used (see
linkgit:git-config[1] for details) and the `--fork-point` option is
assumed. If you are currently not on any branch or if the current
branch does not have a configured upstream, the rebase will abort.

Here is a simplified description of what `git rebase <upstream>` does:

1. Make a list of all commits on your current branch since it branched
off from `<upstream>` that do not have an equivalent commit in
`<upstream>`.
2. Check out `<upstream>` with the equivalent of
`git checkout --detach <upstream>`.
3. Replay the commits, one by one, in order. This is similar to running
`git cherry-pick <commit>` for each commit. See REBASING MERGES for how merges
are handled.
4. Update your branch to point to the final commit with the equivalent
of `git checkout -B <branch>`.

[NOTE]
When starting the rebase, `ORIG_HEAD` is set to point to the commit at the tip
of the to-be-rebased branch. However, `ORIG_HEAD` is not guaranteed to still
point to that commit at the end of the rebase if other commands that change
`ORIG_HEAD` (like `git reset`) are used during the rebase. The previous branch
tip, however, is accessible using the reflog of the current branch (i.e. `@{1}`,
see linkgit:gitrevisions[7].

TRANSPLANTING A TOPIC BRANCH WITH --ONTO
----------------------------------------

Here is how you would transplant a topic branch based on one
branch to another, to pretend that you forked the topic branch
Expand Down Expand Up @@ -186,28 +173,6 @@ This is useful if F and G were flawed in some way, or should not be
part of topicA. Note that the argument to `--onto` and the `<upstream>`
parameter can be any valid commit-ish.

In case of conflict, `git rebase` will stop at the first problematic commit
and leave conflict markers in the tree. You can use `git diff` to locate
the markers (<<<<<<) and make edits to resolve the conflict. For each
file you edit, you need to tell Git that the conflict has been resolved,
typically this would be done with


git add <filename>


After resolving the conflict manually and updating the index with the
desired resolution, you can continue the rebasing process with


git rebase --continue


Alternatively, you can undo the 'git rebase' with


git rebase --abort

MODE OPTIONS
------------

Expand Down Expand Up @@ -253,6 +218,8 @@ As a special case, you may use "A\...B" as a shortcut for the
merge base of A and B if there is exactly one merge base. You can
leave out at most one of A and B, in which case it defaults to HEAD.

See TRANSPLANTING A TOPIC BRANCH WITH --ONTO above for examples.

--keep-base::
Set the starting point at which to create the new commits to the
merge base of `<upstream>` and `<branch>`. Running
Expand Down
2 changes: 1 addition & 1 deletion Documentation/git.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,7 @@ other

`GIT_PROGRESS_DELAY`::
A number controlling how many seconds to delay before showing
optional progress indicators. Defaults to 2.
optional progress indicators. Defaults to 1.

`GIT_EDITOR`::
This environment variable overrides `$EDITOR` and `$VISUAL`.
Expand Down
3 changes: 2 additions & 1 deletion fetch-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ static struct commit *deref_without_lazy_fetch(const struct object_id *oid,
commit = lookup_commit_in_graph(the_repository, oid);
if (commit) {
if (mark_tags_complete_and_check_obj_db) {
if (!odb_has_object(the_repository->objects, oid, 0))
if (!odb_has_object(the_repository->objects, oid,
HAS_OBJECT_RECHECK_PACKED))
die_in_commit_graph_only(oid);
}
return commit;
Expand Down
50 changes: 20 additions & 30 deletions line-log.c
Original file line number Diff line number Diff line change
Expand Up @@ -1087,13 +1087,6 @@ static struct diff_filepair *diff_filepair_dup(struct diff_filepair *pair)
return new_filepair;
}

static void free_diffqueues(int n, struct diff_queue_struct *dq)
{
for (int i = 0; i < n; i++)
diff_queue_clear(&dq[i]);
free(dq);
}

static int process_all_files(struct line_log_data **range_out,
struct rev_info *rev,
struct diff_queue_struct *queue,
Expand Down Expand Up @@ -1189,7 +1182,7 @@ static int process_ranges_ordinary_commit(struct rev_info *rev, struct commit *c
struct line_log_data *range)
{
struct commit *parent = NULL;
struct diff_queue_struct queue;
struct diff_queue_struct queue = DIFF_QUEUE_INIT;
struct line_log_data *parent_range;
int changed;

Expand All @@ -1209,9 +1202,7 @@ static int process_ranges_ordinary_commit(struct rev_info *rev, struct commit *c
static int process_ranges_merge_commit(struct rev_info *rev, struct commit *commit,
struct line_log_data *range)
{
struct diff_queue_struct *diffqueues;
struct line_log_data **cand;
struct commit **parents;
struct commit_list *p;
int i;
int nparents = commit_list_count(commit->parents);
Expand All @@ -1220,28 +1211,27 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm
if (nparents > 1 && rev->first_parent_only)
nparents = 1;

ALLOC_ARRAY(diffqueues, nparents);
CALLOC_ARRAY(cand, nparents);
ALLOC_ARRAY(parents, nparents);

p = commit->parents;
for (i = 0; i < nparents; i++) {
parents[i] = p->item;
p = p->next;
queue_diffs(range, &rev->diffopt, &diffqueues[i], commit, parents[i]);
}

for (i = 0; i < nparents; i++) {
for (p = commit->parents, i = 0;
p && i < nparents;
p = p->next, i++) {
struct commit *parent = p->item;
struct diff_queue_struct diffqueue = DIFF_QUEUE_INIT;
int changed;
changed = process_all_files(&cand[i], rev, &diffqueues[i], range);

queue_diffs(range, &rev->diffopt, &diffqueue, commit, parent);

changed = process_all_files(&cand[i], rev, &diffqueue, range);
diff_queue_clear(&diffqueue);
if (!changed) {
/*
* This parent can take all the blame, so we
* don't follow any other path in history
*/
add_line_range(rev, parents[i], cand[i]);
add_line_range(rev, parent, cand[i]);
free_commit_list(commit->parents);
commit_list_append(parents[i], &commit->parents);
commit_list_append(parent, &commit->parents);

ret = 0;
goto out;
Expand All @@ -1252,22 +1242,22 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm
* No single parent took the blame. We add the candidates
* from the above loop to the parents.
*/
for (i = 0; i < nparents; i++)
add_line_range(rev, parents[i], cand[i]);
for (p = commit->parents, i = 0;
p && i < nparents;
p = p->next, i++)
add_line_range(rev, p->item, cand[i]);

ret = 1;

out:
clear_commit_line_range(rev, commit);
free(parents);
for (i = 0; i < nparents; i++) {
if (!cand[i])
continue;
line_log_data_clear(cand[i]);
free(cand[i]);
}
free(cand);
free_diffqueues(nparents, diffqueues);
return ret;

/* NEEDSWORK evil merge detection stuff */
Expand All @@ -1283,10 +1273,10 @@ int line_log_process_ranges_arbitrary_commit(struct rev_info *rev, struct commit
struct line_log_data *prange = line_log_data_copy(range);
add_line_range(rev, commit->parents->item, prange);
clear_commit_line_range(rev, commit);
} else if (!commit->parents || !commit->parents->next)
changed = process_ranges_ordinary_commit(rev, commit, range);
else
} else if (commit->parents && commit->parents->next)
changed = process_ranges_merge_commit(rev, commit, range);
else
changed = process_ranges_ordinary_commit(rev, commit, range);
}

if (!changed)
Expand Down
Loading