+
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
0b71555
Merge branch 'ps/object-store-midx-dedup-info' into ps/packfile-store
gitster Sep 2, 2025
e1d062e
odb: drop deprecated wrapper functions
pks-t Sep 10, 2025
b7983ad
packfile: introduce a new `struct packfile_store`
pks-t Sep 23, 2025
535b7a6
odb: move list of packfiles into `struct packfile_store`
pks-t Sep 23, 2025
3421cb5
odb: move initialization bit into `struct packfile_store`
pks-t Sep 23, 2025
14aaf5c
odb: move packfile map into `struct packfile_store`
pks-t Sep 23, 2025
fe835b0
odb: move MRU list of packfiles into `struct packfile_store`
pks-t Sep 23, 2025
bd1a521
odb: move kept cache into `struct packfile_store`
pks-t Sep 23, 2025
995ee88
packfile: reorder functions to avoid function declaration
pks-t Sep 23, 2025
c36ecc0
packfile: refactor `prepare_packed_git()` to work on packfile store
pks-t Sep 23, 2025
78237ea
packfile: split up responsibilities of `reprepare_packed_git()`
pks-t Sep 23, 2025
f6f236d
packfile: refactor `install_packed_git()` to work on packfile store
pks-t Sep 23, 2025
d67530f
packfile: introduce function to load and add packfiles
pks-t Sep 23, 2025
ab8aff4
packfile: move `get_multi_pack_index()` into "midx.c"
pks-t Sep 23, 2025
751808b
packfile: refactor `get_packed_git()` to work on packfile store
pks-t Sep 23, 2025
d2779be
packfile: refactor `get_all_packs()` to work on packfile store
pks-t Sep 23, 2025
dd52a29
packfile: refactor `get_packed_git_mru()` to work on packfile store
pks-t Sep 23, 2025
cc1cc31
doc: git-push: create PUSH RULES section
jvns Sep 23, 2025
657586a
doc: git-push: rewrite refspec specification
jvns Sep 23, 2025
e4efcd7
http: offer to cast `size_t` to `curl_off_t` safely
dscho Sep 26, 2025
580cf0f
imap-send: be more careful when casting to `curl_off_t`
dscho Sep 26, 2025
ecc5749
http-push: avoid new compile error
dscho Sep 26, 2025
3721541
clang-format: exclude control macros from SpaceBeforeParens
jltobler Sep 27, 2025
15eff6b
mailmap: change primary address for Jonathan Tan
jonathantanmy Oct 7, 2025
f4f7605
Merge branch 'je/doc-push'
gitster Oct 7, 2025
8c13c31
Merge branch 'ps/packfile-store'
gitster Oct 7, 2025
6623b73
Merge branch 'jt/clang-format-foreach-wo-space-before-parenthesis'
gitster Oct 7, 2025
c281795
Merge branch 'js/curl-off-t-fixes'
gitster Oct 7, 2025
fbd67ab
Merge branch 'ps/odb-clean-stale-wrappers'
gitster Oct 7, 2025
79cf913
The fifteenth batch
gitster Oct 7, 2025
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
2 changes: 1 addition & 1 deletion .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ SpaceBeforeCaseColon: false
# f();
# }
# }
SpaceBeforeParens: ControlStatements
SpaceBeforeParens: ControlStatementsExceptControlMacros

# Don't insert spaces inside empty '()'
SpaceInEmptyParentheses: false
Expand Down
1 change: 1 addition & 0 deletions .mailmap
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ Jon Loeliger <jdl@jdl.com> <jdl@freescale.org>
Jon Seymour <jon.seymour@gmail.com> <jon@blackcubes.dyndns.org>
Jonathan Nieder <jrnieder@gmail.com> <jrnieder@uchicago.edu>
Jonathan del Strother <jon.delStrother@bestbefore.tv> <maillist@steelskies.com>
Jonathan Tan <jonathantanmy@fastmail.com> <jonathantanmy@google.com>
Josh Triplett <josh@joshtriplett.org> <josh@freedesktop.org>
Josh Triplett <josh@joshtriplett.org> <josht@us.ibm.com>
Julian Phillips <julian@quantumfyre.co.uk> <jp3@quantumfyre.co.uk>
Expand Down
10 changes: 10 additions & 0 deletions Documentation/RelNotes/2.52.0.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,15 @@ including security updates, are included in this release.
updated.
(merge 54a60e5b38 kh/you-still-use-whatchanged-fix later to maint).

* Clang-format update to let our control macros formatted the way we
had them traditionally, e.g., "for_each_string_list_item()" without
space before the parentheses.
(merge 3721541d35 jt/clang-format-foreach-wo-space-before-parenthesis later to maint).

* A few places where an size_t value was cast to curl_off_t without
checking has been updated to use the existing helper function.
(merge ecc5749578 js/curl-off-t-fixes 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 All @@ -305,3 +314,4 @@ including security updates, are included in this release.
(merge ac7096723b jc/doc-includeif-hasconfig-remote-url-fix later to maint).
(merge fafc9b08b8 ag/doc-sendmail-gmail-example-update later to maint).
(merge a66fc22bf9 rs/get-oid-with-flags-cleanup later to maint).
(merge e1d062e8ba ps/odb-clean-stale-wrappers later to maint).
199 changes: 103 additions & 96 deletions Documentation/git-push.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -55,96 +55,66 @@ OPTIONS[[OPTIONS]]

<refspec>...::
Specify what destination ref to update with what source object.
The format of a <refspec> parameter is an optional plus
`+`, followed by the source object <src>, followed
by a colon `:`, followed by the destination ref <dst>.
+
The <src> is often the name of the branch you would want to push, but
it can be any arbitrary "SHA-1 expression", such as `master~4` or
`HEAD` (see linkgit:gitrevisions[7]).
+
The <dst> tells which ref on the remote side is updated with this
push. Arbitrary expressions cannot be used here, an actual ref must
be named.
If `git push [<repository>]` without any `<refspec>` argument is set to
update some ref at the destination with `<src>` with
`remote.<repository>.push` configuration variable, `:<dst>` part can
be omitted--such a push will update a ref that `<src>` normally updates
without any `<refspec>` on the command line. Otherwise, missing
`:<dst>` means to update the same ref as the `<src>`.
+
If <dst> doesn't start with `refs/` (e.g. `refs/heads/master`) we will
try to infer where in `refs/*` on the destination <repository> it
belongs based on the type of <src> being pushed and whether <dst>
is ambiguous.
+
--
* If <dst> unambiguously refers to a ref on the <repository> remote,
then push to that ref.

* If <src> resolves to a ref starting with refs/heads/ or refs/tags/,
then prepend that to <dst>.

* Other ambiguity resolutions might be added in the future, but for
now any other cases will error out with an error indicating what we
tried, and depending on the `advice.pushUnqualifiedRefname`
configuration (see linkgit:git-config[1]) suggest what refs/
namespace you may have wanted to push to.

--
+
The object referenced by <src> is used to update the <dst> reference
on the remote side. Whether this is allowed depends on where in
`refs/*` the <dst> reference lives as described in detail below, in
those sections "update" means any modifications except deletes, which
as noted after the next few sections are treated differently.
+
The `refs/heads/*` namespace will only accept commit objects, and
updates only if they can be fast-forwarded.
+
The `refs/tags/*` namespace will accept any kind of object (as
commits, trees and blobs can be tagged), and any updates to them will
be rejected.
+
It's possible to push any type of object to any namespace outside of
`refs/{tags,heads}/*`. In the case of tags and commits, these will be
treated as if they were the commits inside `refs/heads/*` for the
purposes of whether the update is allowed.
+
I.e. a fast-forward of commits and tags outside `refs/{tags,heads}/*`
is allowed, even in cases where what's being fast-forwarded is not a
commit, but a tag object which happens to point to a new commit which
is a fast-forward of the commit the last tag (or commit) it's
replacing. Replacing a tag with an entirely different tag is also
allowed, if it points to the same commit, as well as pushing a peeled
tag, i.e. pushing the commit that existing tag object points to, or a
new tag object which an existing commit points to.
+
Tree and blob objects outside of `refs/{tags,heads}/*` will be treated
the same way as if they were inside `refs/tags/*`, any update of them
will be rejected.
+
All of the rules described above about what's not allowed as an update
can be overridden by adding an the optional leading `+` to a refspec
(or using `--force` command line option). The only exception to this
is that no amount of forcing will make the `refs/heads/*` namespace
accept a non-commit object. Hooks and configuration can also override
or amend these rules, see e.g. `receive.denyNonFastForwards` in
linkgit:git-config[1] and `pre-receive` and `update` in
linkgit:githooks[5].
+
Pushing an empty <src> allows you to delete the <dst> ref from the
remote repository. Deletions are always accepted without a leading `+`
in the refspec (or `--force`), except when forbidden by configuration
or hooks. See `receive.denyDeletes` in linkgit:git-config[1] and
`pre-receive` and `update` in linkgit:githooks[5].
+
The special refspec `:` (or `+:` to allow non-fast-forward updates)
directs Git to push "matching" branches: for every branch that exists on
the local side, the remote side is updated if a branch of the same name
already exists on the remote side.
+
`tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`.
The format for a refspec is [+]<src>[:<dst>], for example `main`,
`main:other`, or `HEAD^:refs/heads/main`.
+
The `<src>` is often the name of the local branch to push, but it can be
any arbitrary "SHA-1 expression" (see linkgit:gitrevisions[7]).
+
The `<dst>` determines what ref to update on the remote side. It must be the
name of a branch, tag, or other ref, not an arbitrary expression.
+
The `+` is optional and does the same thing as `--force`.
+
You can write a refspec using the fully expanded form (for
example `refs/heads/main:refs/heads/main`) which specifies the exact source
and destination, or with a shorter form (for example `main` or
`main:other`). Here are the rules for how refspecs are expanded,
as well as various other special refspec forms:
+
* `<src>` without a `:<dst>` means to update the same ref as the
`<src>`, unless the `remote.<repository>.push` configuration specifies a
different <dst>. For example, if `main` is a branch, then the refspec
`main` expands to `main:refs/heads/main`.
* If `<dst>` unambiguously refers to a ref on the <repository> remote,
then expand it to that ref. For example, if `v1.0` is a tag on the
remote, then `HEAD:v1.0` expands to `HEAD:refs/tags/v1.0`.
* If `<src>` resolves to a ref starting with `refs/heads/` or `refs/tags/`,
then prepend that to <dst>. For example, if `main` is a branch, then
`main:other` expands to `main:refs/heads/other`
* The special refspec `:` (or `+:` to allow non-fast-forward updates)
directs Git to push "matching" branches: for every branch that exists on
the local side, the remote side is updated if a branch of the same name
already exists on the remote side.
* <src> may contain a * to indicate a simple pattern match.
This works like a glob that matches any ref matching the pattern.
There must be only one * in both the `<src>` and `<dst>`.
It will map refs to the destination by replacing the * with the
contents matched from the source. For example, `refs/heads/*:refs/heads/*`
will push all branches.
* A refspec starting with `^` is a negative refspec.
This specifies refs to exclude. A ref will be considered to
match if it matches at least one positive refspec, and does not
match any negative refspec. Negative refspecs can be pattern refspecs.
They must only contain a `<src>`.
Fully spelled out hex object names are also not supported.
For example, `git push origin 'refs/heads/*' '^refs/heads/dev-*'`
will push all branches except for those starting with `dev-`
* If `<src>` is empty, it deletes the `<dst>` ref from the remote
repository. For example, `git push origin :dev` will
delete the `dev` branch.
* `tag <tag>` expands to `refs/tags/<tag>:refs/tags/<tag>`.
This is technically a special syntax for `git push` and not a refspec,
since in `git push origin tag v1.0` the arguments `tag` and `v1.0`
are separate.
* If the refspec can't be expanded unambiguously, error out
with an error indicating what was tried, and depending
on the `advice.pushUnqualifiedRefname` configuration (see
linkgit:git-config[1]) suggest what refs/ namespace you may have
wanted to push to.

Not all updates are allowed: see PUSH RULES below for the details.

--all::
--branches::
Expand Down Expand Up @@ -335,14 +305,12 @@ allowing a forced update.

-f::
--force::
Usually, the command refuses to update a remote ref that is
not an ancestor of the local ref used to overwrite it.
Also, when `--force-with-lease` option is used, the command refuses
to update a remote ref whose current value does not match
what is expected.
Usually, `git push` will refuse to update a branch that is not an
ancestor of the commit being pushed.
+
This flag disables these checks, and can cause the remote repository
to lose commits; use it with care.
This flag disables that check, the other safety checks in PUSH RULES
below, and the checks in --force-with-lease. It can cause the remote
repository to lose commits; use it with care.
+
Note that `--force` applies to all the refs that are pushed, hence
using it with `push.default` set to `matching` or with multiple push
Expand Down Expand Up @@ -514,6 +482,45 @@ reason::
refs, no explanation is needed. For a failed ref, the reason for
failure is described.

PUSH RULES
----------

As a safety feature, the `git push` command only allows certain kinds of
updates to prevent you from accidentally losing data on the remote.

Because branches and tags are intended to be used differently, the
safety rules for pushing to a branch are different from the rules
for pushing to a tag. In the following rules "update" means any
modifications except deletions and creations. Deletions and creations
are always allowed, except when forbidden by configuration or hooks.

1. If the push destination is a **branch** (`refs/heads/*`): only
fast-forward updates are allowed, which means the destination must be
an ancestor of the source commit. The source must be a commit.
2. If the push destination is a **tag** (`refs/tags/*`): all updates will
be rejected. The source can be any object.
3. If the push destination is not a branch or tag:
* If the source is a tree or blob object, any updates will be rejected
* If the source is a tag or commit object, any fast-forward update
is allowed, even in cases where what's being fast-forwarded is not a
commit, but a tag object which happens to point to a new commit which
is a fast-forward of the commit the last tag (or commit) it's
replacing. Replacing a tag with an entirely different tag is also
allowed, if it points to the same commit, as well as pushing a peeled
tag, i.e. pushing the commit that existing tag object points to, or a
new tag object which an existing commit points to.

You can override these rules by passing `--force` or by adding the
optional leading `+` to a refspec. The only exceptions are that no
amount of forcing will make a branch accept a non-commit object,
and forcing won't make the remote repository accept a push that it's
configured to deny.

Hooks and configuration can also override or amend these rules,
see e.g. `receive.denyNonFastForwards` and `receive.denyDeletes`
in linkgit:git-config[1] and `pre-receive` and `update` in
linkgit:githooks[5].

NOTE ABOUT FAST-FORWARDS
------------------------

Expand Down
2 changes: 1 addition & 1 deletion builtin/backfill.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ static void download_batch(struct backfill_context *ctx)
* We likely have a new packfile. Add it to the packed list to
* avoid possible duplicate downloads of the same objects.
*/
reprepare_packed_git(ctx->repo);
odb_reprepare(ctx->repo->objects);
}

static int fill_missing_blobs(const char *path UNUSED,
Expand Down
3 changes: 2 additions & 1 deletion builtin/cat-file.c
Original file line number Diff line number Diff line change
Expand Up @@ -852,9 +852,10 @@ static void batch_each_object(struct batch_options *opt,

if (bitmap && !for_each_bitmapped_object(bitmap, &opt->objects_filter,
batch_one_object_bitmapped, &payload)) {
struct packfile_store *packs = the_repository->objects->packfiles;
struct packed_git *pack;

for (pack = get_all_packs(the_repository); pack; pack = pack->next) {
for (pack = packfile_store_get_all_packs(packs); pack; pack = pack->next) {
if (bitmap_index_contains_pack(bitmap, pack) ||
open_pack_index(pack))
continue;
Expand Down
3 changes: 2 additions & 1 deletion builtin/count-objects.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,15 @@ int cmd_count_objects(int argc,
count_loose, count_cruft, NULL, NULL);

if (verbose) {
struct packfile_store *packs = the_repository->objects->packfiles;
struct packed_git *p;
unsigned long num_pack = 0;
off_t size_pack = 0;
struct strbuf loose_buf = STRBUF_INIT;
struct strbuf pack_buf = STRBUF_INIT;
struct strbuf garbage_buf = STRBUF_INIT;

for (p = get_all_packs(the_repository); p; p = p->next) {
for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
if (!p->pack_local)
continue;
if (open_pack_index(p))
Expand Down
10 changes: 6 additions & 4 deletions builtin/fast-import.c
Original file line number Diff line number Diff line change
Expand Up @@ -899,11 +899,11 @@ static void end_packfile(void)
idx_name = keep_pack(create_index());

/* Register the packfile with core git's machinery. */
new_p = add_packed_git(pack_data->repo, idx_name, strlen(idx_name), 1);
new_p = packfile_store_load_pack(pack_data->repo->objects->packfiles,
idx_name, 1);
if (!new_p)
die("core git rejected index %s", idx_name);
all_packs[pack_id] = new_p;
install_packed_git(the_repository, new_p);
free(idx_name);

/* Print the boundary */
Expand Down Expand Up @@ -954,6 +954,7 @@ static int store_object(
struct object_id *oidout,
uintmax_t mark)
{
struct packfile_store *packs = the_repository->objects->packfiles;
void *out, *delta;
struct object_entry *e;
unsigned char hdr[96];
Expand All @@ -977,7 +978,7 @@ static int store_object(
if (e->idx.offset) {
duplicate_count_by_type[type]++;
return 1;
} else if (find_oid_pack(&oid, get_all_packs(the_repository))) {
} else if (find_oid_pack(&oid, packfile_store_get_all_packs(packs))) {
e->type = type;
e->pack_id = MAX_PACK_ID;
e->idx.offset = 1; /* just not zero! */
Expand Down Expand Up @@ -1094,6 +1095,7 @@ static void truncate_pack(struct hashfile_checkpoint *checkpoint)

static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
{
struct packfile_store *packs = the_repository->objects->packfiles;
size_t in_sz = 64 * 1024, out_sz = 64 * 1024;
unsigned char *in_buf = xmalloc(in_sz);
unsigned char *out_buf = xmalloc(out_sz);
Expand Down Expand Up @@ -1177,7 +1179,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
duplicate_count_by_type[OBJ_BLOB]++;
truncate_pack(&checkpoint);

} else if (find_oid_pack(&oid, get_all_packs(the_repository))) {
} else if (find_oid_pack(&oid, packfile_store_get_all_packs(packs))) {
e->type = OBJ_BLOB;
e->pack_id = MAX_PACK_ID;
e->idx.offset = 1; /* just not zero! */
Expand Down
11 changes: 7 additions & 4 deletions builtin/fsck.c
Original file line number Diff line number Diff line change
Expand Up @@ -867,19 +867,20 @@ static int mark_packed_for_connectivity(const struct object_id *oid,

static int check_pack_rev_indexes(struct repository *r, int show_progress)
{
struct packfile_store *packs = r->objects->packfiles;
struct progress *progress = NULL;
uint32_t pack_count = 0;
int res = 0;

if (show_progress) {
for (struct packed_git *p = get_all_packs(r); p; p = p->next)
for (struct packed_git *p = packfile_store_get_all_packs(packs); p; p = p->next)
pack_count++;
progress = start_delayed_progress(the_repository,
"Verifying reverse pack-indexes", pack_count);
pack_count = 0;
}

for (struct packed_git *p = get_all_packs(r); p; p = p->next) {
for (struct packed_git *p = packfile_store_get_all_packs(packs); p; p = p->next) {
int load_error = load_pack_revindex_from_disk(p);

if (load_error < 0) {
Expand Down Expand Up @@ -999,6 +1000,8 @@ int cmd_fsck(int argc,
for_each_packed_object(the_repository,
mark_packed_for_connectivity, NULL, 0);
} else {
struct packfile_store *packs = the_repository->objects->packfiles;

odb_prepare_alternates(the_repository->objects);
for (source = the_repository->objects->sources; source; source = source->next)
fsck_source(source);
Expand All @@ -1009,7 +1012,7 @@ int cmd_fsck(int argc,
struct progress *progress = NULL;

if (show_progress) {
for (p = get_all_packs(the_repository); p;
for (p = packfile_store_get_all_packs(packs); p;
p = p->next) {
if (open_pack_index(p))
continue;
Expand All @@ -1019,7 +1022,7 @@ int cmd_fsck(int argc,
progress = start_progress(the_repository,
_("Checking objects"), total);
}
for (p = get_all_packs(the_repository); p;
for (p = packfile_store_get_all_packs(packs); p;
p = p->next) {
/* verify gives error messages itself */
if (verify_pack(the_repository,
Expand Down
Loading
Loading
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载