Compare commits

..

33 Commits

Author SHA1 Message Date
27ea6f85be Git 2.5.2
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-04 10:46:07 -07:00
3d3caf0b78 Sync with 2.4.9 2015-09-04 10:43:23 -07:00
74b6763816 Git 2.4.9
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-04 10:36:14 -07:00
ef0e938a1a Sync with 2.3.9 2015-09-04 10:34:19 -07:00
ecad27cf98 Git 2.3.9
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-04 10:32:15 -07:00
8267cd11d6 Sync with 2.2.3 2015-09-04 10:29:28 -07:00
441c4a4017 Git 2.2.3
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-04 10:26:23 -07:00
f54cb059b1 Merge branch 'jk/long-paths' into maint-2.2 2015-09-04 10:25:23 -07:00
78f23bdf68 show-branch: use a strbuf for reflog descriptions
When we show "branch@{0}", we format into a fixed-size
buffer using sprintf. This can overflow if you have long
branch names. We can fix it by using a temporary strbuf.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-04 09:48:26 -07:00
5015f01c12 read_info_alternates: handle paths larger than PATH_MAX
This function assumes that the relative_base path passed
into it is no larger than PATH_MAX, and writes into a
fixed-size buffer. However, this path may not have actually
come from the filesystem; for example, add_submodule_odb
generates a path using a strbuf and passes it in. This is
hard to trigger in practice, though, because the long
submodule directory would have to exist on disk before we
would try to open its info/alternates file.

We can easily avoid the bug, though, by simply creating the
filename on the heap.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-04 09:36:51 -07:00
c29edfefb6 notes: use a strbuf in add_non_note
When we are loading a notes tree into our internal hash
table, we also collect any files that are clearly non-notes.
We format the name of the file into a PATH_MAX buffer, but
unlike true notes (which cannot be larger than a fanned-out
sha1 hash), these tree entries can be arbitrarily long,
overflowing our buffer.

We can fix this by switching to a strbuf. It doesn't even
cost us an extra allocation, as we can simply hand ownership
of the buffer over to the non-note struct.

This is of moderate security interest, as you might fetch
notes trees from an untrusted remote. However, we do not do
so by default, so you would have to manually fetch into the
notes namespace.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-04 09:36:28 -07:00
f514ef9787 verify_absent: allow filenames longer than PATH_MAX
When unpack-trees wants to know whether a path will
overwrite anything in the working tree, we use lstat() to
see if there is anything there. But if we are going to write
"foo/bar", we can't just lstat("foo/bar"); we need to look
for leading prefixes (e.g., "foo"). So we use the lstat cache
to find the length of the leading prefix, and copy the
filename up to that length into a temporary buffer (since
the original name is const, we cannot just stick a NUL in
it).

The copy we make goes into a PATH_MAX-sized buffer, which
will overflow if the prefix is longer than PATH_MAX. How
this happens is a little tricky, since in theory PATH_MAX is
the biggest path we will have read from the filesystem. But
this can happen if:

  - the compiled-in PATH_MAX does not accurately reflect
    what the filesystem is capable of

  - the leading prefix is not _quite_ what is on disk; it
    contains the next element from the name we are checking.
    So if we want to write "aaa/bbb/ccc/ddd" and "aaa/bbb"
    exists, the prefix of interest is "aaa/bbb/ccc". If
    "aaa/bbb" approaches PATH_MAX, then "ccc" can overflow
    it.

So this can be triggered, but it's hard to do. In
particular, you cannot just "git clone" a bogus repo. The
verify_absent checks happen before unpack-trees writes
anything to the filesystem, so there are never any leading
prefixes during the initial checkout, and the bug doesn't
trigger. And by definition, these files are larger than
PATH_MAX, so writing them will fail, and clone will
complain (though it may write a partial path, which will
cause a subsequent "git checkout" to hit the bug).

We can fix it by creating the temporary path on the heap.
The extra malloc overhead is not important, as we are
already making at least one stat() call (and probably more
for the prefix discovery).

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-04 08:50:50 -07:00
fb8880dea3 Merge branch 'ee/clean-test-fixes' into maint
* ee/clean-test-fixes:
  t7300: fix broken && chains
2015-09-03 19:18:05 -07:00
5af77d1352 Merge branch 'jk/log-missing-default-HEAD' into maint
"git init empty && git -C empty log" said "bad default revision 'HEAD'",
which was found to be a bit confusing to new users.

* jk/log-missing-default-HEAD:
  log: diagnose empty HEAD more clearly
2015-09-03 19:18:04 -07:00
9d939886db Merge branch 'cc/trailers-corner-case-fix' into maint
The "interpret-trailers" helper mistook a multi-paragraph title of
a commit log message with a colon in it as the end of the trailer
block.

* cc/trailers-corner-case-fix:
  trailer: support multiline title
  trailer: retitle a test and correct an in-comment message
  trailer: ignore first line of message
2015-09-03 19:18:03 -07:00
311e5ce2cc Merge branch 'dt/commit-preserve-base-index-upon-opportunistic-cache-tree-update' into maint
When re-priming the cache-tree opportunistically while committing
the in-core index as-is, we mistakenly invalidated the in-core
index too aggressively, causing the experimental split-index code
to unnecessarily rewrite the on-disk index file(s).

* dt/commit-preserve-base-index-upon-opportunistic-cache-tree-update:
  commit: don't rewrite shared index unnecessarily
2015-09-03 19:18:02 -07:00
1c82039228 Merge branch 'rs/archive-zip-many' into maint
"git archive" did not use zip64 extension when creating an archive
with more than 64k entries, which nobody should need, right ;-)?

* rs/archive-zip-many:
  archive-zip: support more than 65535 entries
  archive-zip: use a local variable to store the creator version
  t5004: test ZIP archives with many entries
2015-09-03 19:18:01 -07:00
ae6ac8483b Merge branch 'jc/calloc-pathspec' into maint
Minor code cleanup.

* jc/calloc-pathspec:
  ps_matched: xcalloc() takes nmemb and then element size
2015-09-03 19:18:00 -07:00
8136099a31 Merge branch 'ss/fix-config-fd-leak' into maint
* ss/fix-config-fd-leak:
  config: close config file handle in case of error
2015-09-03 19:17:59 -07:00
dc4e7b0244 Merge branch 'sg/wt-status-header-inclusion' into maint
* sg/wt-status-header-inclusion:
  wt-status: move #include "pathspec.h" to the header
2015-09-03 19:17:57 -07:00
659227be2e Merge branch 'po/po-readme' into maint
Doc updates for i18n.

* po/po-readme:
  po/README: Update directions for l10n contributors
2015-09-03 19:17:56 -07:00
57a2bb1f92 Merge branch 'sg/t3020-typofix' into maint
* sg/t3020-typofix:
  t3020: fix typo in test description
2015-09-03 19:17:55 -07:00
c1fa16b193 Merge branch 'as/docfix-reflog-expire-unreachable' into maint
Docfix.

* as/docfix-reflog-expire-unreachable:
  Documentation/config: fix inconsistent label on gc.*.reflogExpireUnreachable
2015-09-03 19:17:53 -07:00
d6c196abfd Merge branch 'nd/fixup-linked-gitdir' into maint
The code in "multiple-worktree" support that attempted to recover
from an inconsistent state updated an incorrect file.

* nd/fixup-linked-gitdir:
  setup: update the right file in multiple checkouts
2015-09-03 19:17:53 -07:00
e654e3b574 Merge branch 'jk/rev-list-has-no-notes' into maint
"git rev-list" does not take "--notes" option, but did not complain
when one is given.

* jk/rev-list-has-no-notes:
  rev-list: make it obvious that we do not support notes
2015-09-03 19:17:53 -07:00
fa6d3749ed Merge branch 'jk/fix-alias-pager-config-key-warnings' into maint
Because the configuration system does not allow "alias.0foo" and
"pager.0foo" as the configuration key, the user cannot use '0foo'
as a custom command name anyway, but "git 0foo" tried to look these
keys up and emitted useless warnings before saying '0foo is not a
git command'.  These warning messages have been squelched.

* jk/fix-alias-pager-config-key-warnings:
  config: silence warnings for command names with invalid keys
2015-09-03 19:17:52 -07:00
0b2cef2805 Merge branch 'nd/dwim-wildcards-as-pathspecs' into maint
Test updates for Windows.

* nd/dwim-wildcards-as-pathspecs:
  t2019: skip test requiring '*' in a file name non Windows
2015-09-03 19:17:51 -07:00
969560bddc Merge branch 'sg/help-group' into maint
We rewrote one of the build scripts in Perl but this reimplements
in Bourne shell.

* sg/help-group:
  generate-cmdlist: re-implement as shell script
2015-09-03 19:17:51 -07:00
d11448f685 Merge branch 'ps/t1509-chroot-test-fixup' into maint
t1509 test that requires a dedicated VM environment had some
bitrot, which has been corrected.

* ps/t1509-chroot-test-fixup:
  tests: fix cleanup after tests in t1509-root-worktree
  tests: fix broken && chains in t1509-root-worktree
2015-09-03 19:17:50 -07:00
8b2707101a Merge branch 'jh/strbuf-read-use-read-in-full' into maint
strbuf_read() used to have one extra iteration (and an unnecessary
strbuf_grow() of 8kB), which was eliminated.

* jh/strbuf-read-use-read-in-full:
  strbuf_read(): skip unnecessary strbuf_grow() at eof
2015-09-03 19:17:50 -07:00
6c0850f2dd Merge branch 'jk/long-error-messages' into maint
The codepath to produce error messages had a hard-coded limit to
the size of the message, primarily to avoid memory allocation while
calling die().

* jk/long-error-messages:
  vreportf: avoid intermediate buffer
  vreportf: report to arbitrary filehandles
2015-09-03 19:17:49 -07:00
cbcd3dcaa8 Merge branch 'cb/open-noatime-clear-errno' into maint
When trying to see that an object does not exist, a state errno
leaked from our "first try to open a packfile with O_NOATIME and
then if it fails retry without it" logic on a system that refuses
O_NOATIME.  This confused us and caused us to die, saying that the
packfile is unreadable, when we should have just reported that the
object does not exist in that packfile to the caller.

* cb/open-noatime-clear-errno:
  git_open_noatime: return with errno=0 on success
2015-09-03 19:17:49 -07:00
03ea02771a Merge branch 'mh/get-remote-group-fix' into maint
An off-by-one error made "git remote" to mishandle a remote with a
single letter nickname.

* mh/get-remote-group-fix:
  get_remote_group(): use skip_prefix()
  get_remote_group(): eliminate superfluous call to strcspn()
  get_remote_group(): rename local variable "space" to "wordlen"
  get_remote_group(): handle remotes with single-character names
2015-09-03 19:17:48 -07:00
245 changed files with 3928 additions and 13678 deletions

1
.gitignore vendored
View File

@ -205,7 +205,6 @@
/test-sha1-array
/test-sigchain
/test-string-list
/test-submodule-config
/test-subprocess
/test-svn-fe
/test-urlmatch-normalization

View File

@ -0,0 +1,9 @@
Git v2.2.3 Release Notes
========================
Fixes since v2.2.2
------------------
* A handful of codepaths that used to use fixed-sized arrays to hold
pathnames have been corrected to use strbuf and other mechanisms to
allow longer pathnames without fearing overflows.

View File

@ -0,0 +1,9 @@
Git v2.3.9 Release Notes
========================
Fixes since v2.3.8
------------------
* A handful of codepaths that used to use fixed-sized arrays to hold
pathnames have been corrected to use strbuf and other mechanisms to
allow longer pathnames without fearing overflows.

View File

@ -0,0 +1,9 @@
Git v2.4.9 Release Notes
========================
Fixes since v2.4.9
------------------
* A handful of codepaths that used to use fixed-sized arrays to hold
pathnames have been corrected to use strbuf and other mechanisms to
allow longer pathnames without fearing overflows.

View File

@ -0,0 +1,63 @@
Git v2.5.2 Release Notes
========================
Fixes since v2.5.1
------------------
* "git init empty && git -C empty log" said "bad default revision 'HEAD'",
which was found to be a bit confusing to new users.
* The "interpret-trailers" helper mistook a multi-paragraph title of
a commit log message with a colon in it as the end of the trailer
block.
* When re-priming the cache-tree opportunistically while committing
the in-core index as-is, we mistakenly invalidated the in-core
index too aggressively, causing the experimental split-index code
to unnecessarily rewrite the on-disk index file(s).
* "git archive" did not use zip64 extension when creating an archive
with more than 64k entries, which nobody should need, right ;-)?
* The code in "multiple-worktree" support that attempted to recover
from an inconsistent state updated an incorrect file.
* "git rev-list" does not take "--notes" option, but did not complain
when one is given.
* Because the configuration system does not allow "alias.0foo" and
"pager.0foo" as the configuration key, the user cannot use '0foo'
as a custom command name anyway, but "git 0foo" tried to look these
keys up and emitted useless warnings before saying '0foo is not a
git command'. These warning messages have been squelched.
* We recently rewrote one of the build scripts in Perl, which made it
necessary to have Perl to build Git. Reduced Perl dependency by
rewriting it again using sed.
* t1509 test that requires a dedicated VM environment had some
bitrot, which has been corrected.
* strbuf_read() used to have one extra iteration (and an unnecessary
strbuf_grow() of 8kB), which was eliminated.
* The codepath to produce error messages had a hard-coded limit to
the size of the message, primarily to avoid memory allocation while
calling die().
* When trying to see that an object does not exist, a state errno
leaked from our "first try to open a packfile with O_NOATIME and
then if it fails retry without it" logic on a system that refuses
O_NOATIME. This confused us and caused us to die, saying that the
packfile is unreadable, when we should have just reported that the
object does not exist in that packfile to the caller.
* An off-by-one error made "git remote" to mishandle a remote with a
single letter nickname.
* A handful of codepaths that used to use fixed-sized arrays to hold
pathnames have been corrected to use strbuf and other mechanisms to
allow longer pathnames without fearing overflows.
Also contains typofixes, documentation updates and trivial code
clean-ups.

View File

@ -1,351 +0,0 @@
Git 2.6 Release Notes
=====================
Updates since v2.5
------------------
UI, Workflows & Features
* An asterisk as a substring (as opposed to the entirety) of a path
component for both side of a refspec, e.g.
"refs/heads/o*:refs/remotes/heads/i*", is now allowed.
* New userdiff pattern definition for fountain screenwriting markup
format has been added.
* "git log" and friends learned a new "--date=format:..." option to
format timestamps using system's strftime(3).
* "git fast-import" learned to respond to the get-mark command via
its cat-blob-fd interface.
* "git rebase -i" learned "drop commit-object-name subject" command
as another way to skip replaying of a commit.
* A new configuration variable can enable "--follow" automatically
when "git log" is run with one pathspec argument.
* "git status" learned to show a more detailed information regarding
the "rebase -i" session in progress.
* "git cat-file" learned "--batch-all-objects" option to enumerate all
available objects in the repository more quickly than "rev-list
--all --objects" (the output includes unreachable objects, though).
* "git fsck" learned to ignore errors on a set of known-to-be-bad
objects, and also allows the warning levels of various kinds of
non-critical breakages to be tweaked.
* "git rebase -i"'s list of todo is made configurable.
* "git send-email" now performs alias-expansion on names that are
given via --cccmd, etc.
* An environment variable GIT_REPLACE_REF_BASE tells Git to look into
refs hierarchy other than refs/replace/ for the object replacement
data.
* Allow untracked cache (experimental) to be used when sparse
checkout (experimental) is also in use.
* "git pull --rebase" has been taught to pay attention to
rebase.autostash configuration.
* The command-line completion script (in contrib/) has been updated.
* A negative !ref entry in multi-value transfer.hideRefs
configuration can be used to say "don't hide this one".
* After "git am" without "-3" stops, running "git am -" pays attention
to "-3" only for the patch that caused the original invocation
to stop.
* When linked worktree is used, simultaneous "notes merge" instances
for the same ref in refs/notes/* are prevented from stomping on
each other.
* "git send-email" learned a new option --smtp-auth to limit the SMTP
AUTH mechanisms to be used to a subset of what the system library
supports.
* A new configuration variable http.sslVersion can be used to specify
what specific version of SSL/TLS to use to make a connection.
* "git notes merge" can be told with "--strategy=<how>" option how to
automatically handle conflicts; this can now be configured by
setting notes.mergeStrategy configuration variable.
* "git log --cc" did not show any patch, even though most of the time
the user meant "git log --cc -p -m" to see patch output for commits
with a single parent, and combined diff for merge commits. The
command is taught to DWIM "--cc" (without "--raw" and other forms
of output specification) to "--cc -p -m".
* "git config --list" output was hard to parse when values consist of
multiple lines. "--name-only" option is added to help this.
Performance, Internal Implementation, Development Support etc.
* In preparation for allowing different "backends" to store the refs
in a way different from the traditional "one ref per file in
$GIT_DIR or in a $GIT_DIR/packed-refs file" filesystem storage,
direct filesystem access to ref-like things like CHERRY_PICK_HEAD
from scripts and programs has been reduced.
* Computation of untracked status indicator by bash prompt
script (in contrib/) has been optimized.
* Memory use reduction when commit-slab facility is used to annotate
sparsely (which is not recommended in the first place).
* Clean up refs API and make "git clone" less intimate with the
implementation detail.
* "git pull" was reimplemented in C.
* The packet tracing machinery allows to capture an incoming pack
data to a file for debugging.
* Move machinery to parse human-readable scaled numbers like 1k, 4M,
and 2G as an option parameter's value from pack-objects to
parse-options API, to make it available to other codepaths.
* "git verify-tag" and "git verify-commit" have been taught to share
more code, and then learned to optionally show the verification
message from the underlying GPG implementation.
* Various enhancements around "git am" reading patches generated by
foreign SCM have been made.
* Ref listing by "git branch -l" and "git tag -l" commands has
started to be rebuilt, based on the for-each-ref machinery.
* The code to perform multi-tree merges has been taught to repopulate
the cache-tree upon a successful merge into the index, so that
subsequent "diff-index --cached" (hence "status") and "write-tree"
(hence "commit") will go faster.
The same logic in "git checkout" may now be removed, but that is a
separate issue.
* Tests that assume how reflogs are represented on the filesystem too
much have been corrected.
* "git am" has been rewritten in "C".
* git_path() and mkpath() are handy helper functions but it is easy
to misuse, as the callers need to be careful to keep the number of
active results below 4. Their uses have been reduced.
* The "lockfile" API has been rebuilt on top of a new "tempfile" API.
* To prepare for allowing a different "ref" backend to be plugged in
to the system, update_ref()/delete_ref() have been taught about
ref-like things like MERGE_HEAD that are per-worktree (they will
always be written to the filesystem inside $GIT_DIR).
* The gitmodules API that is accessed from the C code learned to
cache stuff lazily.
Also contains various documentation updates and code clean-ups.
Fixes since v2.5
----------------
Unless otherwise noted, all the fixes since v2.5 in the maintenance
track are contained in this release (see the maintenance releases'
notes for details).
* "git subtree" (in contrib/) depended on "git log" output to be
stable, which was a no-no. Apply a workaround to force a
particular date format.
(merge e7aac44 da/subtree-date-confusion later to maint).
* An attempt to delete a ref by pushing into a repository whose HEAD
symbolic reference points at an unborn branch that cannot be
created due to ref D/F conflict (e.g. refs/heads/a/b exists, HEAD
points at refs/heads/a) failed.
(merge b112b14 jx/do-not-crash-receive-pack-wo-head later to maint).
* The low-level "git send-pack" did not honor 'user.signingkey'
configuration variable when sending a signed-push.
(merge d830d39 db/send-pack-user-signingkey later to maint).
* "sparse checkout" misbehaved for a path that is excluded from the
checkout when switching between branches that differ at the path.
(merge 7d78241 as/sparse-checkout-removal later to maint).
* An experimental "untracked cache" feature used uname(2) in a
slightly unportable way.
(merge 100e433 cb/uname-in-untracked later to maint).
* A "rebase" replays changes of the local branch on top of something
else, as such they are placed in stage #3 and referred to as
"theirs", while the changes in the new base, typically a foreign
work, are placed in stage #2 and referred to as "ours". Clarify
the "checkout --ours/--theirs".
(merge f303016 se/doc-checkout-ours-theirs later to maint).
* The "rev-parse --parseopt" mode parsed the option specification
and the argument hint in a strange way to allow '=' and other
special characters in the option name while forbidding them from
the argument hint. This made it impossible to define an option
like "--pair <key>=<value>" with "pair=key=value" specification,
which instead would have defined a "--pair=key <value>" option.
(merge 2d893df ib/scripted-parse-opt-better-hint-string later to maint).
* Often a fast-import stream builds a new commit on top of the
previous commit it built, and it often unconditionally emits a
"from" command to specify the first parent, which can be omitted in
such a case. This caused fast-import to forget the tree of the
previous commit and then re-read it from scratch, which was
inefficient. Optimize for this common case.
(merge 0df3245 mh/fast-import-optimize-current-from later to maint).
* Running an aliased command from a subdirectory when the .git thing
in the working tree is a gitfile pointing elsewhere did not work.
(merge d95138e nd/export-worktree later to maint).
* "Is this subdirectory a separate repository that should not be
touched?" check "git clean" was inefficient. This was replaced
with a more optimized check.
(merge fbf2fec ee/clean-remove-dirs later to maint).
* The "new-worktree-mode" hack in "checkout" that was added in
nd/multiple-work-trees topic has been removed by updating the
implementation of new "worktree add".
(merge 65f9b75 es/worktree-add-cleanup later to maint).
* Remove remaining cruft from "git checkout --to", which
transitioned to "git worktree add".
(merge 114ff88 es/worktree-add later to maint).
* An off-by-one error made "git remote" to mishandle a remote with a
single letter nickname.
(merge bc598c3 mh/get-remote-group-fix later to maint).
* "git clone $URL", when cloning from a site whose sole purpose is to
host a single repository (hence, no path after <scheme>://<site>/),
tried to use the site name as the new repository name, but did not
remove username or password when <site> part was of the form
<user>@<pass>:<host>. The code is taught to redact these.
(merge adef956 ps/guess-repo-name-at-root later to maint).
* Running tests with the "-x" option to make them verbose had some
unpleasant interactions with other features of the test suite.
(merge 9b5fe78 jk/test-with-x later to maint).
* t1509 test that requires a dedicated VM environment had some
bitrot, which has been corrected.
(merge faacc5a ps/t1509-chroot-test-fixup later to maint).
* "git pull" in recent releases of Git has a regression in the code
that allows custom path to the --upload-pack=<program>. This has
been corrected.
Note that this is irrelevant for 'master' with "git pull" rewritten
in C.
(merge 13e0e28 mm/pull-upload-pack later to maint).
* When trying to see that an object does not exist, a state errno
leaked from our "first try to open a packfile with O_NOATIME and
then if it fails retry without it" logic on a system that refuses
O_NOATIME. This confused us and caused us to die, saying that the
packfile is unreadable, when we should have just reported that the
object does not exist in that packfile to the caller.
(merge dff6f28 cb/open-noatime-clear-errno later to maint).
* The codepath to produce error messages had a hard-coded limit to
the size of the message, primarily to avoid memory allocation while
calling die().
(merge f4c3edc jk/long-error-messages later to maint).
* strbuf_read() used to have one extra iteration (and an unnecessary
strbuf_grow() of 8kB), which was eliminated.
(merge 3ebbd00 jh/strbuf-read-use-read-in-full later to maint).
* We rewrote one of the build scripts in Perl but this reimplements
in Bourne shell.
(merge 82aec45 sg/help-group later to maint).
* The experimental untracked-cache feature were buggy when paths with
a few levels of subdirectories are involved.
(merge 73f9145 dt/untracked-subdir later to maint).
* "interpret-trailers" helper mistook a single-liner log message that
has a colon as the end of existing trailer.
* The "interpret-trailers" helper mistook a multi-paragraph title of
a commit log message with a colon in it as the end of the trailer
block.
(merge 5c99995 cc/trailers-corner-case-fix later to maint).
* "git describe" without argument defaulted to describe the HEAD
commit, but "git describe --contains" didn't. Arguably, in a
repository used for active development, such defaulting would not
be very useful as the tip of branch is typically not tagged, but it
is better to be consistent.
(merge 2bd0706 sg/describe-contains later to maint).
* The client side codepaths in "git push" have been cleaned up
and the user can request to perform an optional "signed push",
i.e. sign only when the other end accepts signed push.
(merge 68c757f db/push-sign-if-asked later to maint).
* Because the configuration system does not allow "alias.0foo" and
"pager.0foo" as the configuration key, the user cannot use '0foo'
as a custom command name anyway, but "git 0foo" tried to look these
keys up and emitted useless warnings before saying '0foo is not a
git command'. These warning messages have been squelched.
(merge 9e9de18 jk/fix-alias-pager-config-key-warnings later to maint).
* "git rev-list" does not take "--notes" option, but did not complain
when one is given.
(merge 2aea7a5 jk/rev-list-has-no-notes later to maint).
* When re-priming the cache-tree opportunistically while committing
the in-core index as-is, we mistakenly invalidated the in-core
index too aggressively, causing the experimental split-index code
to unnecessarily rewrite the on-disk index file(s).
(merge 475a344 dt/commit-preserve-base-index-upon-opportunistic-cache-tree-update later to maint).
* "git archive" did not use zip64 extension when creating an archive
with more than 64k entries, which nobody should need, right ;-)?
(merge 88329ca rs/archive-zip-many later to maint).
* The code in "multiple-worktree" support that attempted to recover
from an inconsistent state updated an incorrect file.
(merge 82fde87 nd/fixup-linked-gitdir later to maint).
* On case insensitive systems, "git p4" did not work well with client
specs.
* "git init empty && git -C empty log" said "bad default revision 'HEAD'",
which was found to be a bit confusing to new users.
(merge ce11360 jk/log-missing-default-HEAD later to maint).
* Code cleanups and documentation updates.
(merge 1c601af es/doc-clean-outdated-tools later to maint).
(merge 3581304 kn/tag-doc-fix later to maint).
(merge 3a59e59 kb/i18n-doc later to maint).
(merge 45abdee sb/remove-unused-var-from-builtin-add later to maint).
(merge 14691e3 sb/parse-options-codeformat later to maint).
(merge 4a6ada3 ad/bisect-cleanup later to maint).
(merge da4c5ad ta/docfix-index-format-tech later to maint).
(merge ae25fd3 sb/check-return-from-read-ref later to maint).
(merge b3325df nd/dwim-wildcards-as-pathspecs later to maint).
(merge 7aa9b9b sg/wt-status-header-inclusion later to maint).
(merge f04c690 as/docfix-reflog-expire-unreachable later to maint).
(merge 1269847 sg/t3020-typofix later to maint).
(merge 8b54c23 jc/calloc-pathspec later to maint).
(merge a6926b8 po/po-readme later to maint).
(merge 54d160e ss/fix-config-fd-leak later to maint).
(merge b80fa84 ah/submodule-typofix-in-error later to maint).
(merge 99885bc ah/reflog-typofix-in-error later to maint).
(merge 9476c2c ah/read-tree-usage-string later to maint).
(merge b8c1d27 ah/pack-objects-usage-strings later to maint).
(merge 486e1e1 br/svn-doc-include-paths-config later to maint).
(merge 1733ed3 ee/clean-test-fixes later to maint).

View File

@ -769,14 +769,6 @@ am.keepcr::
by giving '--no-keep-cr' from the command line.
See linkgit:git-am[1], linkgit:git-mailsplit[1].
am.threeWay::
By default, `git am` will fail if the patch does not apply cleanly. When
set to true, this setting tells `git am` to fall back on 3-way merge if
the patch records the identity of blobs it is supposed to apply to and
we have those blobs available locally (equivalent to giving the `--3way`
option from the command line). Defaults to `false`.
See linkgit:git-am[1].
apply.ignoreWhitespace::
When set to 'change', tells 'git apply' to ignore changes in
whitespace, in the same way as the '--ignore-space-change'
@ -1250,25 +1242,6 @@ filter.<driver>.smudge::
object to a worktree file upon checkout. See
linkgit:gitattributes[5] for details.
fsck.<msg-id>::
Allows overriding the message type (error, warn or ignore) of a
specific message ID such as `missingEmail`.
+
For convenience, fsck prefixes the error/warning with the message ID,
e.g. "missingEmail: invalid author/committer line - missing email" means
that setting `fsck.missingEmail = ignore` will hide that issue.
+
This feature is intended to support working with legacy repositories
which cannot be repaired without disruptive changes.
fsck.skipList::
The path to a sorted list of object names (i.e. one SHA-1 per
line) that are known to be broken in a non-fatal way and should
be ignored. This feature is useful when an established project
should be accepted despite early commits containing errors that
can be safely ignored such as invalid committer email addresses.
Note: corrupt objects cannot be skipped with this setting.
gc.aggressiveDepth::
The depth parameter used in the delta compression
algorithm used by 'git gc --aggressive'. This defaults
@ -1307,24 +1280,20 @@ gc.packRefs::
gc.pruneExpire::
When 'git gc' is run, it will call 'prune --expire 2.weeks.ago'.
Override the grace period with this config variable. The value
"now" may be used to disable this grace period and always prune
unreachable objects immediately, or "never" may be used to
suppress pruning.
"now" may be used to disable this grace period and always prune
unreachable objects immediately.
gc.worktreePruneExpire::
When 'git gc' is run, it calls
'git worktree prune --expire 3.months.ago'.
This config variable can be used to set a different grace
period. The value "now" may be used to disable the grace
period and prune $GIT_DIR/worktrees immediately, or "never"
may be used to suppress pruning.
gc.pruneWorktreesExpire::
When 'git gc' is run, it will call
'prune --worktrees --expire 3.months.ago'.
Override the grace period with this config variable. The value
"now" may be used to disable the grace period and prune
$GIT_DIR/worktrees immediately.
gc.reflogExpire::
gc.<pattern>.reflogExpire::
'git reflog expire' removes reflog entries older than
this time; defaults to 90 days. The value "now" expires all
entries immediately, and "never" suppresses expiration
altogether. With "<pattern>" (e.g.
this time; defaults to 90 days. With "<pattern>" (e.g.
"refs/stash") in the middle the setting applies only to
the refs that match the <pattern>.
@ -1332,9 +1301,7 @@ gc.reflogExpireUnreachable::
gc.<pattern>.reflogExpireUnreachable::
'git reflog expire' removes reflog entries older than
this time and are not reachable from the current tip;
defaults to 30 days. The value "now" expires all entries
immediately, and "never" suppresses expiration altogether.
With "<pattern>" (e.g. "refs/stash")
defaults to 30 days. With "<pattern>" (e.g. "refs/stash")
in the middle, the setting applies only to the refs that
match the <pattern>.
@ -1609,29 +1576,6 @@ http.saveCookies::
If set, store cookies received during requests to the file specified by
http.cookieFile. Has no effect if http.cookieFile is unset.
http.sslVersion::
The SSL version to use when negotiating an SSL connection, if you
want to force the default. The available and default version
depend on whether libcurl was built against NSS or OpenSSL and the
particular configuration of the crypto library in use. Internally
this sets the 'CURLOPT_SSL_VERSION' option; see the libcurl
documentation for more details on the format of this option and
for the ssl version supported. Actually the possible values of
this option are:
- sslv2
- sslv3
- tlsv1
- tlsv1.0
- tlsv1.1
- tlsv1.2
+
Can be overridden by the 'GIT_SSL_VERSION' environment variable.
To force git to use libcurl's default ssl version and ignore any
explicit http.sslversion option, set 'GIT_SSL_VERSION' to the
empty string.
http.sslCipherList::
A list of SSL ciphers to use when negotiating an SSL connection.
The available ciphers depend on whether libcurl was built against
@ -1942,18 +1886,6 @@ mergetool.writeToTemp::
mergetool.prompt::
Prompt before each invocation of the merge resolution program.
notes.mergeStrategy::
Which merge strategy to choose by default when resolving notes
conflicts. Must be one of `manual`, `ours`, `theirs`, `union`, or
`cat_sort_uniq`. Defaults to `manual`. See "NOTES MERGE STRATEGIES"
section of linkgit:git-notes[1] for more information on each strategy.
notes.<name>.mergeStrategy::
Which merge strategy to choose when doing a notes merge into
refs/notes/<name>. This overrides the more general
"notes.mergeStrategy". See the "NOTES MERGE STRATEGIES" section in
linkgit:git-notes[1] for more information on the available strategies.
notes.displayRef::
The (fully qualified) refname from which to show notes when
showing commit messages. The value of this variable can be set
@ -1982,8 +1914,8 @@ notes.rewriteMode::
When copying notes during a rewrite (see the
"notes.rewrite.<command>" option), determines what to do if
the target commit already has a note. Must be one of
`overwrite`, `concatenate`, `cat_sort_uniq`, or `ignore`.
Defaults to `concatenate`.
`overwrite`, `concatenate`, or `ignore`. Defaults to
`concatenate`.
+
This setting can be overridden with the `GIT_NOTES_REWRITE_MODE`
environment variable.
@ -2213,14 +2145,6 @@ push.followTags::
may override this configuration at time of push by specifying
'--no-follow-tags'.
push.gpgSign::
May be set to a boolean value, or the string 'if-asked'. A true
value causes all pushes to be GPG signed, as if '--signed' is
passed to linkgit:git-push[1]. The string 'if-asked' causes
pushes to be signed if the server supports it, as if
'--signed=if-asked' is passed to 'git push'. A false value may
override a value from a lower-priority config file. An explicit
command-line flag always overrides this config option.
rebase.stat::
Whether to show a diffstat of what changed upstream since the last
@ -2237,22 +2161,6 @@ rebase.autoStash::
successful rebase might result in non-trivial conflicts.
Defaults to false.
rebase.missingCommitsCheck::
If set to "warn", git rebase -i will print a warning if some
commits are removed (e.g. a line was deleted), however the
rebase will still proceed. If set to "error", it will print
the previous warning and stop the rebase, 'git rebase
--edit-todo' can then be used to correct the error. If set to
"ignore", no checking is done.
To drop a commit without warning or error, use the `drop`
command in the todo-list.
Defaults to "ignore".
rebase.instructionFormat
A format string, as specified in linkgit:git-log[1], to be used for
the instruction list during an interactive rebase. The format will automatically
have the long commit hash prepended to the format.
receive.advertiseAtomic::
By default, git-receive-pack will advertise the atomic push
capability to its clients. If you don't want to this capability
@ -2289,28 +2197,6 @@ receive.fsckObjects::
Defaults to false. If not set, the value of `transfer.fsckObjects`
is used instead.
receive.fsck.<msg-id>::
When `receive.fsckObjects` is set to true, errors can be switched
to warnings and vice versa by configuring the `receive.fsck.<msg-id>`
setting where the `<msg-id>` is the fsck message ID and the value
is one of `error`, `warn` or `ignore`. For convenience, fsck prefixes
the error/warning with the message ID, e.g. "missingEmail: invalid
author/committer line - missing email" means that setting
`receive.fsck.missingEmail = ignore` will hide that issue.
+
This feature is intended to support working with legacy repositories
which would not pass pushing when `receive.fsckObjects = true`, allowing
the host to accept repositories with certain known issues but still catch
other issues.
receive.fsck.skipList::
The path to a sorted list of object names (i.e. one SHA-1 per
line) that are known to be broken in a non-fatal way and should
be ignored. This feature is useful when an established project
should be accepted despite early commits containing errors that
can be safely ignored such as invalid committer email addresses.
Note: corrupt objects cannot be skipped with this setting.
receive.unpackLimit::
If the number of objects received in a push is below this
limit then the objects will be unpacked into loose object
@ -2356,10 +2242,13 @@ receive.denyNonFastForwards::
set when initializing a shared repository.
receive.hideRefs::
This variable is the same as `transfer.hideRefs`, but applies
only to `receive-pack` (and so affects pushes, but not fetches).
An attempt to update or delete a hidden ref by `git push` is
rejected.
String(s) `receive-pack` uses to decide which refs to omit
from its initial advertisement. Use more than one
definitions to specify multiple prefix strings. A ref that
are under the hierarchies listed on the value of this
variable is excluded, and is hidden when responding to `git
push`, and an attempt to update or delete a hidden ref by
`git push` is rejected.
receive.updateServerInfo::
If set to true, git-receive-pack will run git-update-server-info
@ -2647,18 +2536,9 @@ transfer.fsckObjects::
Defaults to false.
transfer.hideRefs::
String(s) `receive-pack` and `upload-pack` use to decide which
refs to omit from their initial advertisements. Use more than
one definition to specify multiple prefix strings. A ref that is
under the hierarchies listed in the value of this variable is
excluded, and is hidden when responding to `git push` or `git
fetch`. See `receive.hideRefs` and `uploadpack.hideRefs` for
program-specific versions of this config.
+
You may also include a `!` in front of the ref name to negate the entry,
explicitly exposing it, even if an earlier entry marked it as hidden.
If you have multiple hideRefs values, later entries override earlier ones
(and entries in more-specific config files override less-specific ones).
This variable can be used to set both `receive.hideRefs`
and `uploadpack.hideRefs` at the same time to the same
values. See entries for these other variables.
transfer.unpackLimit::
When `fetch.unpackLimit` or `receive.unpackLimit` are
@ -2673,10 +2553,13 @@ uploadarchive.allowUnreachable::
`false`.
uploadpack.hideRefs::
This variable is the same as `transfer.hideRefs`, but applies
only to `upload-pack` (and so affects only fetches, not pushes).
An attempt to fetch a hidden ref by `git fetch` will fail. See
also `uploadpack.allowTipSHA1InWant`.
String(s) `upload-pack` uses to decide which refs to omit
from its initial advertisement. Use more than one
definitions to specify multiple prefix strings. A ref that
are under the hierarchies listed on the value of this
variable is excluded, and is hidden from `git ls-remote`,
`git fetch`, etc. An attempt to fetch a hidden ref by `git
fetch` will fail. See also `uploadpack.allowTipSHA1InWant`.
uploadpack.allowTipSHA1InWant::
When `uploadpack.hideRefs` is in effect, allow `upload-pack`

View File

@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git am' [--signoff] [--keep] [--[no-]keep-cr] [--[no-]utf8]
[--[no-]3way] [--interactive] [--committer-date-is-author-date]
[--3way] [--interactive] [--committer-date-is-author-date]
[--ignore-date] [--ignore-space-change | --ignore-whitespace]
[--whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>]
[--exclude=<path>] [--include=<path>] [--reject] [-q | --quiet]
@ -90,13 +90,10 @@ default. You can use `--no-utf8` to override this.
-3::
--3way::
--no-3way::
When the patch does not apply cleanly, fall back on
3-way merge if the patch records the identity of blobs
it is supposed to apply to and we have those blobs
available locally. `--no-3way` can be used to override
am.threeWay configuration variable. For more information,
see am.threeWay in linkgit:git-config[1].
available locally.
--ignore-space-change::
--ignore-whitespace::

View File

@ -3,7 +3,7 @@ git-bisect(1)
NAME
----
git-bisect - Use binary search to find the commit that introduced a bug
git-bisect - Find by binary search the change that introduced a bug
SYNOPSIS
@ -16,6 +16,7 @@ DESCRIPTION
The command takes various subcommands, and different options depending
on the subcommand:
git bisect help
git bisect start [--no-checkout] [<bad> [<good>...]] [--] [<paths>...]
git bisect bad [<rev>]
git bisect good [<rev>...]
@ -25,71 +26,64 @@ on the subcommand:
git bisect replay <logfile>
git bisect log
git bisect run <cmd>...
git bisect help
This command uses a binary search algorithm to find which commit in
your project's history introduced a bug. You use it by first telling
it a "bad" commit that is known to contain the bug, and a "good"
commit that is known to be before the bug was introduced. Then `git
bisect` picks a commit between those two endpoints and asks you
whether the selected commit is "good" or "bad". It continues narrowing
down the range until it finds the exact commit that introduced the
change.
This command uses 'git rev-list --bisect' to help drive the
binary search process to find which change introduced a bug, given an
old "good" commit object name and a later "bad" commit object name.
Getting help
~~~~~~~~~~~~
Use "git bisect" to get a short usage description, and "git bisect
help" or "git bisect -h" to get a long usage description.
Basic bisect commands: start, bad, good
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As an example, suppose you are trying to find the commit that broke a
feature that was known to work in version `v2.6.13-rc2` of your
project. You start a bisect session as follows:
Using the Linux kernel tree as an example, basic use of the bisect
command is as follows:
------------------------------------------------
$ git bisect start
$ git bisect bad # Current version is bad
$ git bisect good v2.6.13-rc2 # v2.6.13-rc2 is known to be good
$ git bisect good v2.6.13-rc2 # v2.6.13-rc2 was the last version
# tested that was good
------------------------------------------------
Once you have specified at least one bad and one good commit, `git
bisect` selects a commit in the middle of that range of history,
checks it out, and outputs something similar to the following:
When you have specified at least one bad and one good version, the
command bisects the revision tree and outputs something similar to
the following:
------------------------------------------------
Bisecting: 675 revisions left to test after this (roughly 10 steps)
Bisecting: 675 revisions left to test after this
------------------------------------------------
You should now compile the checked-out version and test it. If that
version works correctly, type
The state in the middle of the set of revisions is then checked out.
You would now compile that kernel and boot it. If the booted kernel
works correctly, you would then issue the following command:
------------------------------------------------
$ git bisect good
$ git bisect good # this one is good
------------------------------------------------
If that version is broken, type
The output of this command would be something similar to the following:
------------------------------------------------
$ git bisect bad
Bisecting: 337 revisions left to test after this
------------------------------------------------
Then `git bisect` will respond with something like
------------------------------------------------
Bisecting: 337 revisions left to test after this (roughly 9 steps)
------------------------------------------------
Keep repeating the process: compile the tree, test it, and depending
on whether it is good or bad run `git bisect good` or `git bisect bad`
to ask for the next commit that needs testing.
Eventually there will be no more revisions left to inspect, and the
command will print out a description of the first bad commit. The
reference `refs/bisect/bad` will be left pointing at that commit.
You keep repeating this process, compiling the tree, testing it, and
depending on whether it is good or bad issuing the command "git bisect good"
or "git bisect bad" to ask for the next bisection.
Eventually there will be no more revisions left to bisect, and you
will have been left with the first bad kernel revision in "refs/bisect/bad".
Bisect reset
~~~~~~~~~~~~
After a bisect session, to clean up the bisection state and return to
the original HEAD, issue the following command:
the original HEAD (i.e., to quit bisecting), issue the following command:
------------------------------------------------
$ git bisect reset
@ -106,10 +100,9 @@ instead:
$ git bisect reset <commit>
------------------------------------------------
For example, `git bisect reset bisect/bad` will check out the first
bad revision, while `git bisect reset HEAD` will leave you on the
current bisection commit and avoid switching commits at all.
For example, `git bisect reset HEAD` will leave you on the current
bisection commit and avoid switching commits at all, while `git bisect
reset bisect/bad` will check out the first bad revision.
Bisect visualize
~~~~~~~~~~~~~~~~
@ -154,17 +147,17 @@ $ git bisect replay that-file
Avoiding testing a commit
~~~~~~~~~~~~~~~~~~~~~~~~~
If, in the middle of a bisect session, you know that the suggested
revision is not a good one to test (e.g. it fails to build and you
know that the failure does not have anything to do with the bug you
are chasing), you can manually select a nearby commit and test that
one instead.
If, in the middle of a bisect session, you know that the next suggested
revision is not a good one to test (e.g. the change the commit
introduces is known not to work in your environment and you know it
does not have anything to do with the bug you are chasing), you may
want to find a nearby commit and try that instead.
For example:
------------
$ git bisect good/bad # previous round was good or bad.
Bisecting: 337 revisions left to test after this (roughly 9 steps)
Bisecting: 337 revisions left to test after this
$ git bisect visualize # oops, that is uninteresting.
$ git reset --hard HEAD~3 # try 3 revisions before what
# was suggested
@ -176,19 +169,18 @@ the revision as good or bad in the usual manner.
Bisect skip
~~~~~~~~~~~~
Instead of choosing a nearby commit by yourself, you can ask Git to do
it for you by issuing the command:
Instead of choosing by yourself a nearby commit, you can ask Git
to do it for you by issuing the command:
------------
$ git bisect skip # Current version cannot be tested
------------
However, if you skip a commit adjacent to the one you are looking for,
Git will be unable to tell exactly which of those commits was the
first bad one.
But Git may eventually be unable to tell the first bad commit among
a bad commit and one or more skipped commits.
You can also skip a range of commits, instead of just one commit,
using range notation. For example:
You can even skip a range of commits, instead of just one commit,
using the "'<commit1>'..'<commit2>'" notation. For example:
------------
$ git bisect skip v2.5..v2.6
@ -204,8 +196,8 @@ would issue the command:
$ git bisect skip v2.5 v2.5..v2.6
------------
This tells the bisect process that the commits between `v2.5` and
`v2.6` (inclusive) should be skipped.
This tells the bisect process that the commits between `v2.5` included
and `v2.6` included should be skipped.
Cutting down bisection by giving more parameters to bisect start
@ -239,14 +231,14 @@ or bad, you can bisect by issuing the command:
$ git bisect run my_script arguments
------------
Note that the script (`my_script` in the above example) should exit
with code 0 if the current source code is good/old, and exit with a
code between 1 and 127 (inclusive), except 125, if the current source
code is bad/new.
Note that the script (`my_script` in the above example) should
exit with code 0 if the current source code is good, and exit with a
code between 1 and 127 (inclusive), except 125, if the current
source code is bad.
Any other exit code will abort the bisect process. It should be noted
that a program that terminates via `exit(-1)` leaves $? = 255, (see the
exit(3) manual page), as the value is chopped with `& 0377`.
that a program that terminates via "exit(-1)" leaves $? = 255, (see the
exit(3) manual page), as the value is chopped with "& 0377".
The special exit code 125 should be used when the current source code
cannot be tested. If the script exits with this code, the current
@ -255,7 +247,7 @@ as the highest sensible value to use for this purpose, because 126 and 127
are used by POSIX shells to signal specific error status (127 is for
command not found, 126 is for command found but not executable---these
details do not matter, as they are normal errors in the script, as far as
`bisect run` is concerned).
"bisect run" is concerned).
You may often find that during a bisect session you want to have
temporary modifications (e.g. s/#define DEBUG 0/#define DEBUG 1/ in a
@ -268,7 +260,7 @@ next revision to test, the script can apply the patch
before compiling, run the real test, and afterwards decide if the
revision (possibly with the needed patch) passed the test and then
rewind the tree to the pristine state. Finally the script should exit
with the status of the real test to let the `git bisect run` command loop
with the status of the real test to let the "git bisect run" command loop
determine the eventual outcome of the bisect session.
OPTIONS
@ -315,12 +307,12 @@ $ git bisect run ~/test.sh
$ git bisect reset # quit the bisect session
------------
+
Here we use a `test.sh` custom script. In this script, if `make`
Here we use a "test.sh" custom script. In this script, if "make"
fails, we skip the current commit.
`check_test_case.sh` should `exit 0` if the test case passes,
and `exit 1` otherwise.
"check_test_case.sh" should "exit 0" if the test case passes,
and "exit 1" otherwise.
+
It is safer if both `test.sh` and `check_test_case.sh` are
It is safer if both "test.sh" and "check_test_case.sh" are
outside the repository to prevent interactions between the bisect,
make and test processes and the scripts.
@ -387,11 +379,6 @@ In this case, when 'git bisect run' finishes, bisect/bad will refer to a commit
has at least one parent whose reachable graph is fully traversable in the sense
required by 'git pack objects'.
Getting help
~~~~~~~~~~~~
Use `git bisect` to get a short usage description, and `git bisect
help` or `git bisect -h` to get a long usage description.
SEE ALSO
--------

View File

@ -69,20 +69,6 @@ OPTIONS
not be combined with any other options or arguments. See the
section `BATCH OUTPUT` below for details.
--batch-all-objects::
Instead of reading a list of objects on stdin, perform the
requested batch operation on all objects in the repository and
any alternate object stores (not just reachable objects).
Requires `--batch` or `--batch-check` be specified. Note that
the objects are visited in order sorted by their hashes.
--buffer::
Normally batch output is flushed after each object is output, so
that a process can interactively read and write from
`cat-file`. With this option, the output uses normal stdio
buffering; this is much more efficient when invoking
`--batch-check` on a large number of objects.
--allow-unknown-type::
Allow -s or -t to query broken/corrupt objects of unknown type.

View File

@ -94,8 +94,8 @@ OPTIONS
Interpret <refname> as a reference name pattern for a refspec
(as used with remote repositories). If this option is
enabled, <refname> is allowed to contain a single `*`
in the refspec (e.g., `foo/bar*/baz` or `foo/bar*baz/`
but not `foo/bar*/baz*`).
in place of a one full pathname component (e.g.,
`foo/*/bar` but not `foo/bar*`).
--normalize::
Normalize 'refname' by removing any leading slash (`/`)

View File

@ -14,13 +14,13 @@ SYNOPSIS
'git config' [<file-option>] [type] --replace-all name value [value_regex]
'git config' [<file-option>] [type] [-z|--null] --get name [value_regex]
'git config' [<file-option>] [type] [-z|--null] --get-all name [value_regex]
'git config' [<file-option>] [type] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
'git config' [<file-option>] [type] [-z|--null] --get-regexp name_regex [value_regex]
'git config' [<file-option>] [type] [-z|--null] --get-urlmatch name URL
'git config' [<file-option>] --unset name [value_regex]
'git config' [<file-option>] --unset-all name [value_regex]
'git config' [<file-option>] --rename-section old_name new_name
'git config' [<file-option>] --remove-section name
'git config' [<file-option>] [-z|--null] [--name-only] -l | --list
'git config' [<file-option>] [-z|--null] -l | --list
'git config' [<file-option>] --get-color name [default]
'git config' [<file-option>] --get-colorbool name [stdout-is-tty]
'git config' [<file-option>] -e | --edit
@ -159,7 +159,7 @@ See also <<FILES>>.
-l::
--list::
List all variables set in config file, along with their values.
List all variables set in config file.
--bool::
'git config' will ensure that the output is "true" or "false"
@ -190,10 +190,6 @@ See also <<FILES>>.
output without getting confused e.g. by values that
contain line breaks.
--name-only::
Output only the names of config variables for `--list` or
`--get-regexp`.
--get-colorbool name [stdout-is-tty]::
Find the color setting for `name` (e.g. `color.diff`) and output

View File

@ -9,7 +9,7 @@ git-describe - Describe a commit using the most recent tag reachable from it
SYNOPSIS
--------
[verse]
'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] [<commit-ish>...]
'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] <commit-ish>...
'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]
DESCRIPTION
@ -27,7 +27,7 @@ see the -a and -s options to linkgit:git-tag[1].
OPTIONS
-------
<commit-ish>...::
Commit-ish object names to describe. Defaults to HEAD if omitted.
Commit-ish object names to describe.
--dirty[=<mark>]::
Describe the working tree.

View File

@ -54,7 +54,7 @@ Options for Frontends
~~~~~~~~~~~~~~~~~~~~~
--cat-blob-fd=<fd>::
Write responses to `get-mark`, `cat-blob`, and `ls` queries to the
Write responses to `cat-blob` and `ls` queries to the
file descriptor <fd> instead of `stdout`. Allows `progress`
output intended for the end-user to be separated from other
output.
@ -350,11 +350,6 @@ and control the current import process. More detailed discussion
unless the `done` feature was requested using the
`--done` command-line option or `feature done` command.
`get-mark`::
Causes fast-import to print the SHA-1 corresponding to a mark
to the file descriptor set with `--cat-blob-fd`, or `stdout` if
unspecified.
`cat-blob`::
Causes fast-import to print a blob in 'cat-file --batch'
format to the file descriptor set with `--cat-blob-fd` or
@ -935,25 +930,6 @@ Placing a `progress` command immediately after a `checkpoint` will
inform the reader when the `checkpoint` has been completed and it
can safely access the refs that fast-import updated.
`get-mark`
~~~~~~~~~~
Causes fast-import to print the SHA-1 corresponding to a mark to
stdout or to the file descriptor previously arranged with the
`--cat-blob-fd` argument. The command otherwise has no impact on the
current import; its purpose is to retrieve SHA-1s that later commits
might want to refer to in their commit messages.
....
'get-mark' SP ':' <idnum> LF
....
This command can be used anywhere in the stream that comments are
accepted. In particular, the `get-mark` command can be used in the
middle of a commit but not in the middle of a `data` command.
See ``Responses To Commands'' below for details about how to read
this output safely.
`cat-blob`
~~~~~~~~~~
Causes fast-import to print a blob to a file descriptor previously
@ -1024,8 +1000,7 @@ Output uses the same format as `git ls-tree <tree> -- <path>`:
====
The <dataref> represents the blob, tree, or commit object at <path>
and can be used in later 'get-mark', 'cat-blob', 'filemodify', or
'ls' commands.
and can be used in later 'cat-blob', 'filemodify', or 'ls' commands.
If there is no file or subtree at that path, 'git fast-import' will
instead report
@ -1067,11 +1042,9 @@ import-marks-if-exists::
"feature import-marks-if-exists" like a corresponding
command-line option silently skips a nonexistent file.
get-mark::
cat-blob::
ls::
Require that the backend support the 'get-mark', 'cat-blob',
or 'ls' command respectively.
Require that the backend support the 'cat-blob' or 'ls' command.
Versions of fast-import not supporting the specified command
will exit with a message indicating so.
This lets the import error out early with a clear message,
@ -1151,11 +1124,11 @@ bidirectional pipes:
git fast-import >fast-import-output
====
A frontend set up this way can use `progress`, `get-mark`, `ls`, and
`cat-blob` commands to read information from the import in progress.
A frontend set up this way can use `progress`, `ls`, and `cat-blob`
commands to read information from the import in progress.
To avoid deadlock, such frontends must completely consume any
pending output from `progress`, `ls`, `get-mark`, and `cat-blob` before
pending output from `progress`, `ls`, and `cat-blob` before
performing writes to fast-import that might block.
Crash Reports

View File

@ -11,7 +11,7 @@ SYNOPSIS
[verse]
'git fsck' [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]
[--[no-]full] [--strict] [--verbose] [--lost-found]
[--[no-]dangling] [--[no-]progress] [--connectivity-only] [<object>*]
[--[no-]dangling] [--[no-]progress] [<object>*]
DESCRIPTION
-----------
@ -60,11 +60,6 @@ index file, all SHA-1 references in `refs` namespace, and all reflogs
object pools. This is now default; you can turn it off
with --no-full.
--connectivity-only::
Check only the connectivity of tags, commits and tree objects. By
avoiding to unpack blobs, this speeds up the operation, at the
expense of missing corrupt objects or other problematic issues.
--strict::
Enable more strict checking, namely to catch a file mode
recorded with g+w bit set, which was created by older

View File

@ -184,12 +184,6 @@ log.date::
`--date` option.) Defaults to "default", which means to write
dates like `Sat May 8 19:35:34 2010 -0500`.
log.follow::
If a single <path> is given to git log, it will act as
if the `--follow` option was also used. This has the same
limitations as `--follow`, i.e. it cannot be used to follow
multiple files and does not work well on non-linear history.
log.showRoot::
If `false`, `git log` and related commands will not treat the
initial commit as a big creation event. Any root commits in

View File

@ -101,7 +101,7 @@ merge::
any) into the current notes ref (called "local").
+
If conflicts arise and a strategy for automatically resolving
conflicting notes (see the "NOTES MERGE STRATEGIES" section) is not given,
conflicting notes (see the -s/--strategy option) is not given,
the "manual" resolver is used. This resolver checks out the
conflicting notes in a special worktree (`.git/NOTES_MERGE_WORKTREE`),
and instructs the user to manually resolve the conflicts there.
@ -183,7 +183,6 @@ OPTIONS
When merging notes, resolve notes conflicts using the given
strategy. The following strategies are recognized: "manual"
(default), "ours", "theirs", "union" and "cat_sort_uniq".
This option overrides the "notes.mergeStrategy" configuration setting.
See the "NOTES MERGE STRATEGIES" section below for more
information on each notes merge strategy.
@ -248,9 +247,6 @@ When done, the user can either finalize the merge with
'git notes merge --commit', or abort the merge with
'git notes merge --abort'.
Users may select an automated merge strategy from among the following using
either -s/--strategy option or configuring notes.mergeStrategy accordingly:
"ours" automatically resolves conflicting notes in favor of the local
version (i.e. the current notes ref).
@ -314,20 +310,6 @@ core.notesRef::
This setting can be overridden through the environment and
command line.
notes.mergeStrategy::
Which merge strategy to choose by default when resolving notes
conflicts. Must be one of `manual`, `ours`, `theirs`, `union`, or
`cat_sort_uniq`. Defaults to `manual`. See "NOTES MERGE STRATEGIES"
section above for more information on each strategy.
+
This setting can be overridden by passing the `--strategy` option.
notes.<name>.mergeStrategy::
Which merge strategy to choose when doing a notes merge into
refs/notes/<name>. This overrides the more general
"notes.mergeStrategy". See the "NOTES MERGE STRATEGIES" section above
for more information on each available strategy.
notes.displayRef::
Which ref (or refs, if a glob or specified more than once), in
addition to the default set by `core.notesRef` or
@ -349,8 +331,7 @@ environment variable.
notes.rewriteMode::
When copying notes during a rewrite, what to do if the target
commit already has a note. Must be one of `overwrite`,
`concatenate`, `cat_sort_uniq`, or `ignore`. Defaults to
`concatenate`.
`concatenate`, and `ignore`. Defaults to `concatenate`.
+
This setting can be overridden with the `GIT_NOTES_REWRITE_MODE`
environment variable.
@ -387,7 +368,7 @@ does not match any refs is silently ignored.
'GIT_NOTES_REWRITE_MODE'::
When copying notes during a rewrite, what to do if the target
commit already has a note.
Must be one of `overwrite`, `concatenate`, `cat_sort_uniq`, or `ignore`.
Must be one of `overwrite`, `concatenate`, and `ignore`.
This overrides the `core.rewriteMode` setting.
'GIT_NOTES_REWRITE_REF'::

View File

@ -11,8 +11,7 @@ SYNOPSIS
[verse]
'git push' [--all | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
[--repo=<repository>] [-f | --force] [--prune] [-v | --verbose]
[-u | --set-upstream]
[--[no-]signed|--sign=(true|false|if-asked)]
[-u | --set-upstream] [--signed]
[--force-with-lease[=<refname>[:<expect>]]]
[--no-verify] [<repository> [<refspec>...]]
@ -133,16 +132,12 @@ already exists on the remote side.
with configuration variable 'push.followTags'. For more
information, see 'push.followTags' in linkgit:git-config[1].
--[no-]signed::
--sign=(true|false|if-asked)::
--signed::
GPG-sign the push request to update refs on the receiving
side, to allow it to be checked by the hooks and/or be
logged. If `false` or `--no-signed`, no signing will be
attempted. If `true` or `--signed`, the push will fail if the
server does not support signed pushes. If set to `if-asked`,
sign if and only if the server supports signed pushes. The push
will also fail if the actual call to `gpg --sign` fails. See
linkgit:git-receive-pack[1] for the details on the receiving end.
logged. See linkgit:git-receive-pack[1] for the details
on the receiving end.
--[no-]atomic::
Use an atomic transaction on the remote side if available.

View File

@ -213,15 +213,6 @@ rebase.autoSquash::
rebase.autoStash::
If set to true enable '--autostash' option by default.
rebase.missingCommitsCheck::
If set to "warn", print warnings about removed commits in
interactive mode. If set to "error", print the warnings and
stop the rebase. If set to "ignore", no checking is
done. "ignore" by default.
rebase.instructionFormat::
Custom commit list format to use during an '--interactive' rebase.
OPTIONS
-------
--onto <newbase>::
@ -368,10 +359,6 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.
Make a list of the commits which are about to be rebased. Let the
user edit that list before rebasing. This mode can also be used to
split commits (see SPLITTING COMMITS below).
+
The commit list format can be changed by setting the configuration option
rebase.instructionFormat. A customized instruction format will automatically
have the long commit hash prepended to the format.
-p::
--preserve-merges::
@ -527,9 +514,6 @@ rebasing.
If you just want to edit the commit message for a commit, replace the
command "pick" with the command "reword".
To drop a commit, replace the command "pick" with "drop", or just
delete the matching line.
If you want to fold two or more commits into one, replace the command
"pick" for the second and subsequent commits with "squash" or "fixup".
If the commits had different authors, the folded commit will be

View File

@ -23,7 +23,6 @@ depending on the subcommand:
[--dry-run] [--verbose] [--all | <refs>...]
'git reflog delete' [--rewrite] [--updateref]
[--dry-run] [--verbose] ref@\{specifier\}...
'git reflog exists' <ref>
Reference logs, or "reflogs", record when the tips of branches and
other references were updated in the local repository. Reflogs are
@ -53,9 +52,6 @@ argument must be an _exact_ entry (e.g. "`git reflog delete
master@{2}`"). This subcommand is also typically not used directly by
end users.
The "exists" subcommand checks whether a ref has a reflog. It exits
with zero status if the reflog exists, and non-zero status if it does
not.
OPTIONS
-------

View File

@ -49,17 +49,17 @@ Composing
of 'sendemail.annotate'. See the CONFIGURATION section for
'sendemail.multiEdit'.
--bcc=<address>,...::
--bcc=<address>::
Specify a "Bcc:" value for each email. Default is the value of
'sendemail.bcc'.
+
This option may be specified multiple times.
The --bcc option must be repeated for each user you want on the bcc list.
--cc=<address>,...::
--cc=<address>::
Specify a starting "Cc:" value for each email.
Default is the value of 'sendemail.cc'.
+
This option may be specified multiple times.
The --cc option must be repeated for each user you want on the cc list.
--compose::
Invoke a text editor (see GIT_EDITOR in linkgit:git-var[1])
@ -110,13 +110,13 @@ is not set, this will be prompted for.
Only necessary if --compose is also set. If --compose
is not set, this will be prompted for.
--to=<address>,...::
--to=<address>::
Specify the primary recipient of the emails generated. Generally, this
will be the upstream maintainer of the project involved. Default is the
value of the 'sendemail.to' configuration value; if that is unspecified,
and --to-cmd is not specified, this will be prompted for.
+
This option may be specified multiple times.
The --to option must be repeated for each user you want on the to list.
--8bit-encoding=<encoding>::
When encountering a non-ASCII message or subject that does not
@ -171,19 +171,6 @@ Sending
to determine your FQDN automatically. Default is the value of
'sendemail.smtpDomain'.
--smtp-auth=<mechanisms>::
Whitespace-separated list of allowed SMTP-AUTH mechanisms. This setting
forces using only the listed mechanisms. Example:
+
------
$ git send-email --smtp-auth="PLAIN LOGIN GSSAPI" ...
------
+
If at least one of the specified mechanisms matches the ones advertised by the
SMTP server and if it is supported by the utilized SASL library, the mechanism
is used for authentication. If neither 'sendemail.smtpAuth' nor '--smtp-auth'
is specified, all mechanisms supported by the SASL library can be used.
--smtp-pass[=<password>]::
Password for SMTP-AUTH. The argument is optional: If no
argument is specified, then the empty string is used as

View File

@ -9,10 +9,7 @@ git-send-pack - Push objects over Git protocol to another repository
SYNOPSIS
--------
[verse]
'git send-pack' [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>]
[--verbose] [--thin] [--atomic]
[--[no-]signed|--sign=(true|false|if-asked)]
[<host>:]<directory> [<ref>...]
'git send-pack' [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [--atomic] [<host>:]<directory> [<ref>...]
DESCRIPTION
-----------
@ -70,17 +67,6 @@ be in a separate packet, and the list must end with a flush packet.
fails to update then the entire push will fail without changing any
refs.
--[no-]signed::
--sign=(true|false|if-asked)::
GPG-sign the push request to update refs on the receiving
side, to allow it to be checked by the hooks and/or be
logged. If `false` or `--no-signed`, no signing will be
attempted. If `true` or `--signed`, the push will fail if the
server does not support signed pushes. If set to `if-asked`,
sign if and only if the server supports signed pushes. The push
will also fail if the actual call to `gpg --sign` fails. See
linkgit:git-receive-pack[1] for the details on the receiving end.
<host>::
A remote host to house the repository. When this
part is specified, 'git-receive-pack' is invoked via

View File

@ -174,9 +174,6 @@ Skip "branches" and "tags" of first level directories;;
(including automatic fetches due to 'clone', 'dcommit',
'rebase', etc) on a given repository. '--ignore-paths' takes
precedence over '--include-paths'.
+
[verse]
config key: svn-remote.<name>.include-paths
--log-window-size=<n>;;
Fetch <n> log entries per request when scanning Subversion history.

View File

@ -13,7 +13,7 @@ SYNOPSIS
<tagname> [<commit> | <object>]
'git tag' -d <tagname>...
'git tag' [-n[<num>]] -l [--contains <commit>] [--points-at <object>]
[--column[=<options>] | --no-column] [--create-reflog] [<pattern>...]
[--column[=<options>] | --no-column] [<pattern>...]
'git tag' -v <tagname>...
DESCRIPTION
@ -142,9 +142,6 @@ This option is only applicable when listing tags without annotation lines.
all, 'whitespace' removes just leading/trailing whitespace lines and
'strip' removes both whitespace and commentary.
--create-reflog::
Create a reflog for the tag.
<tagname>::
The name of the tag to create, delete, or describe.
The new tag name must pass all checks defined by

View File

@ -8,7 +8,7 @@ git-update-ref - Update the object name stored in a ref safely
SYNOPSIS
--------
[verse]
'git update-ref' [-m <reason>] (-d <ref> [<oldvalue>] | [--no-deref] [--create-reflog] <ref> <newvalue> [<oldvalue>] | --stdin [-z])
'git update-ref' [-m <reason>] (-d <ref> [<oldvalue>] | [--no-deref] <ref> <newvalue> [<oldvalue>] | --stdin [-z])
DESCRIPTION
-----------
@ -67,9 +67,6 @@ performs all modifications together. Specify commands of the form:
verify SP <ref> [SP <oldvalue>] LF
option SP <opt> LF
With `--create-reflog`, update-ref will create a reflog for each ref
even if one would not ordinarily be created.
Quote fields containing whitespace as if they were strings in C source
code; i.e., surrounded by double-quotes and with backslash escapes.
Use 40 "0" characters or the empty string to specify a zero value. To

View File

@ -16,10 +16,6 @@ Validates the gpg signature created by 'git commit -S'.
OPTIONS
-------
--raw::
Print the raw gpg status output to standard error instead of the normal
human-readable output.
-v::
--verbose::
Print the contents of the commit object before validating it.

View File

@ -16,10 +16,6 @@ Validates the gpg signature created by 'git tag'.
OPTIONS
-------
--raw::
Print the raw gpg status output to standard error instead of the normal
human-readable output.
-v::
--verbose::
Print the contents of the tag object before validating it.

View File

@ -3,7 +3,7 @@ git-worktree(1)
NAME
----
git-worktree - Manage multiple working trees
git-worktree - Manage multiple worktrees
SYNOPSIS
@ -15,7 +15,7 @@ SYNOPSIS
DESCRIPTION
-----------
Manage multiple working trees attached to the same repository.
Manage multiple worktrees attached to the same repository.
A git repository can support multiple working trees, allowing you to check
out more than one branch at a time. With `git worktree add` a new working
@ -27,19 +27,19 @@ bare repository) and zero or more linked working trees.
When you are done with a linked working tree you can simply delete it.
The working tree's administrative files in the repository (see
"DETAILS" below) will eventually be removed automatically (see
`gc.worktreePruneExpire` in linkgit:git-config[1]), or you can run
`gc.pruneworktreesexpire` in linkgit::git-config[1]), or you can run
`git worktree prune` in the main or any linked working tree to
clean up any stale administrative files.
If you move a linked working tree to another file system, or
If you move a linked working directory to another file system, or
within a file system that does not support hard links, you need to run
at least one git command inside the linked working tree
at least one git command inside the linked working directory
(e.g. `git status`) in order to update its administrative files in the
repository so that they do not get automatically pruned.
If a linked working tree is stored on a portable device or network share
which is not always mounted, you can prevent its administrative files from
being pruned by creating a file named 'locked' alongside the other
being pruned by creating a file named 'lock' alongside the other
administrative files, optionally containing a plain text reason that
pruning should be suppressed. See section "DETAILS" for more information.
@ -51,9 +51,9 @@ Create `<path>` and checkout `<branch>` into it. The new working directory
is linked to the current repository, sharing everything except working
directory specific files such as HEAD, index, etc.
+
If `<branch>` is omitted and neither `-b` nor `-B` nor `--detached` used,
then, as a convenience, a new branch based at HEAD is created automatically,
as if `-b $(basename <path>)` was specified.
If `<branch>` is omitted and neither `-b` nor `-B` is used, then, as a
convenience, a new branch based at HEAD is created automatically, as if
`-b $(basename <path>)` was specified.
prune::
@ -64,22 +64,22 @@ OPTIONS
-f::
--force::
By default, `add` refuses to create a new working tree when `<branch>`
is already checked out by another working tree. This option overrides
By default, `add` refuses to create a new worktree when `<branch>`
is already checked out by another worktree. This option overrides
that safeguard.
-b <new-branch>::
-B <new-branch>::
With `add`, create a new branch named `<new-branch>` starting at
`<branch>`, and check out `<new-branch>` into the new working tree.
`<branch>`, and check out `<new-branch>` into the new worktree.
If `<branch>` is omitted, it defaults to HEAD.
By default, `-b` refuses to create a new branch if it already
exists. `-B` overrides this safeguard, resetting `<new-branch>` to
`<branch>`.
--detach::
With `add`, detach HEAD in the new working tree. See "DETACHED HEAD"
in linkgit:git-checkout[1].
With `add`, detach HEAD in the new worktree. See "DETACHED HEAD" in
linkgit:git-checkout[1].
-n::
--dry-run::
@ -91,7 +91,7 @@ OPTIONS
With `prune`, report all removals.
--expire <time>::
With `prune`, only expire unused working trees older than <time>.
With `prune`, only expire unused worktrees older than <time>.
DETAILS
-------
@ -124,7 +124,7 @@ thumb is do not make any assumption about whether a path belongs to
$GIT_DIR or $GIT_COMMON_DIR when you need to directly access something
inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.
To prevent a $GIT_DIR/worktrees entry from being pruned (which
To prevent a $GIT_DIR/worktrees entry from from being pruned (which
can be useful in some situations, such as when the
entry's working tree is stored on a portable device), add a file named
'locked' to the entry's directory. The file contains the reason in
@ -139,9 +139,9 @@ EXAMPLES
You are in the middle of a refactoring session and your boss comes in and
demands that you fix something immediately. You might typically use
linkgit:git-stash[1] to store your changes away temporarily, however, your
working tree is in such a state of disarray (with new, moved, and removed
files, and other bits and pieces strewn around) that you don't want to risk
disturbing any of it. Instead, you create a temporary linked working tree to
worktree is in such a state of disarray (with new, moved, and removed files,
and other bits and pieces strewn around) that you don't want to risk
disturbing any of it. Instead, you create a temporary linked worktree to
make the emergency fix, remove it when done, and then resume your earlier
refactoring session.
@ -164,12 +164,12 @@ checkouts of a superproject.
git-worktree could provide more automation for tasks currently
performed manually, such as:
- `remove` to remove a linked working tree and its administrative files (and
warn if the working tree is dirty)
- `mv` to move or rename a working tree and update its administrative files
- `list` to list linked working trees
- `remove` to remove a linked worktree and its administrative files (and
warn if the worktree is dirty)
- `mv` to move or rename a worktree and update its administrative files
- `list` to list linked worktrees
- `lock` to prevent automatic pruning of administrative files (for instance,
for a working tree on a portable device)
for a worktree on a portable device)
GIT
---

View File

@ -43,15 +43,17 @@ unreleased) version of Git, that is available from the 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
* link:v2.5.1/git.html[documentation for release 2.5.1]
* link:v2.5.2/git.html[documentation for release 2.5.2]
* release notes for
link:RelNotes/2.5.2.txt[2.5.2],
link:RelNotes/2.5.1.txt[2.5.1],
link:RelNotes/2.5.0.txt[2.5].
* link:v2.4.8/git.html[documentation for release 2.4.8]
* link:v2.4.9/git.html[documentation for release 2.4.9]
* release notes for
link:RelNotes/2.4.9.txt[2.4.9],
link:RelNotes/2.4.8.txt[2.4.8],
link:RelNotes/2.4.7.txt[2.4.7],
link:RelNotes/2.4.6.txt[2.4.6],
@ -62,9 +64,10 @@ Documentation for older releases are available here:
link:RelNotes/2.4.1.txt[2.4.1],
link:RelNotes/2.4.0.txt[2.4].
* link:v2.3.8/git.html[documentation for release 2.3.8]
* link:v2.3.9/git.html[documentation for release 2.3.9]
* release notes for
link:RelNotes/2.3.9.txt[2.3.9],
link:RelNotes/2.3.8.txt[2.3.8],
link:RelNotes/2.3.7.txt[2.3.7],
link:RelNotes/2.3.6.txt[2.3.6],
@ -75,9 +78,10 @@ Documentation for older releases are available here:
link:RelNotes/2.3.1.txt[2.3.1],
link:RelNotes/2.3.0.txt[2.3].
* link:v2.2.2/git.html[documentation for release 2.2.2]
* link:v2.2.3/git.html[documentation for release 2.2.3]
* release notes for
link:RelNotes/2.2.3.txt[2.2.3],
link:RelNotes/2.2.2.txt[2.2.2],
link:RelNotes/2.2.1.txt[2.2.1],
link:RelNotes/2.2.0.txt[2.2].
@ -1011,20 +1015,9 @@ Unsetting the variable, or setting it to empty, "0" or
Enables trace messages for all packets coming in or out of a
given program. This can help with debugging object negotiation
or other protocol issues. Tracing is turned off at a packet
starting with "PACK" (but see 'GIT_TRACE_PACKFILE' below).
starting with "PACK".
See 'GIT_TRACE' for available trace output options.
'GIT_TRACE_PACKFILE'::
Enables tracing of packfiles sent or received by a
given program. Unlike other trace output, this trace is
verbatim: no headers, and no quoting of binary data. You almost
certainly want to direct into a file (e.g.,
`GIT_TRACE_PACKFILE=/tmp/my.pack`) rather than displaying it on
the terminal or mixing it with other trace output.
+
Note that this is currently only implemented for the client side
of clones and fetches.
'GIT_TRACE_PERFORMANCE'::
Enables performance related trace messages, e.g. total execution
time of each Git command.

View File

@ -527,8 +527,6 @@ patterns are available:
- `fortran` suitable for source code in the Fortran language.
- `fountain` suitable for Fountain documents.
- `html` suitable for HTML/XHTML documents.
- `java` suitable for source code in the Java language.

View File

@ -448,9 +448,6 @@ set by Git if the remote helper has the 'option' capability.
'option update-shallow {'true'|'false'}::
Allow to extend .git/shallow if the new refs require it.
'option pushcert {'true'|'false'}::
GPG sign pushes.
SEE ALSO
--------
linkgit:git-remote[1]

View File

@ -251,25 +251,25 @@ modules::
Contains the git-repositories of the submodules.
worktrees::
Contains administrative data for linked
working trees. Each subdirectory contains the working tree-related
part of a linked working tree. This directory is ignored if
$GIT_COMMON_DIR is set, in which case
"$GIT_COMMON_DIR/worktrees" will be used instead.
Contains worktree specific information of linked
checkouts. Each subdirectory contains the worktree-related
part of a linked checkout. This directory is ignored if
$GIT_COMMON_DIR is set and "$GIT_COMMON_DIR/worktrees" will be
used instead.
worktrees/<id>/gitdir::
A text file containing the absolute path back to the .git file
that points to here. This is used to check if the linked
repository has been manually removed and there is no need to
keep this directory any more. The mtime of this file should be
keep this directory any more. mtime of this file should be
updated every time the linked repository is accessed.
worktrees/<id>/locked::
If this file exists, the linked working tree may be on a
portable device and not available. The presence of this file
prevents `worktrees/<id>` from being pruned either automatically
or manually by `git worktree prune`. The file may contain a string
explaining why the repository is locked.
If this file exists, the linked repository may be on a
portable device and not available. It does not mean that the
linked repository is gone and `worktrees/<id>` could be
removed. The file's content contains a reason string on why
the repository is locked.
worktrees/<id>/link::
If this file exists, it is a hard link to the linked .git

View File

@ -411,27 +411,6 @@ exclude;;
core Git. Porcelains expose more of a <<def_SCM,SCM>>
interface than the <<def_plumbing,plumbing>>.
[[def_per_worktree_ref]]per-worktree ref::
Refs that are per-<<def_working_tree,worktree>>, rather than
global. This is presently only <<def_HEAD,HEAD>>, but might
later include other unusual refs.
[[def_pseudoref]]pseudoref::
Pseudorefs are a class of files under `$GIT_DIR` which behave
like refs for the purposes of rev-parse, but which are treated
specially by git. Pseudorefs both have names that are all-caps,
and always start with a line consisting of a
<<def_SHA1,SHA-1>> followed by whitespace. So, HEAD is not a
pseudoref, because it is sometimes a symbolic ref. They might
optionally contain some additional data. `MERGE_HEAD` and
`CHERRY_PICK_HEAD` are examples. Unlike
<<def_per_worktree_ref,per-worktree refs>>, these files cannot
be symbolic refs, and never have reflogs. They also cannot be
updated through the normal ref update machinery. Instead,
they are updated by directly writing to the files. However,
they can be read as if they were refs, so `git rev-parse
MERGE_HEAD` will work.
[[def_pull]]pull::
Pulling a <<def_branch,branch>> means to <<def_fetch,fetch>> it and
<<def_merge,merge>> it. See also linkgit:git-pull[1].

View File

@ -1,31 +1,18 @@
Git is to some extent character encoding agnostic.
At the core level, Git is character encoding agnostic.
- The pathnames recorded in the index and in the tree objects
are treated as uninterpreted sequences of non-NUL bytes.
What readdir(2) returns are what are recorded and compared
with the data Git keeps track of, which in turn are expected
to be what lstat(2) and creat(2) accepts. There is no such
thing as pathname encoding translation.
- The contents of the blob objects are uninterpreted sequences
of bytes. There is no encoding translation at the core
level.
- Path names are encoded in UTF-8 normalization form C. This
applies to tree objects, the index file, ref names, as well as
path names in command line arguments, environment variables
and config files (`.git/config` (see linkgit:git-config[1]),
linkgit:gitignore[5], linkgit:gitattributes[5] and
linkgit:gitmodules[5]).
+
Note that Git at the core level treats path names simply as
sequences of non-NUL bytes, there are no path name encoding
conversions (except on Mac and Windows). Therefore, using
non-ASCII path names will mostly work even on platforms and file
systems that use legacy extended ASCII encodings. However,
repositories created on such systems will not work properly on
UTF-8-based systems (e.g. Linux, Mac, Windows) and vice versa.
Additionally, many Git-based tools simply assume path names to
be UTF-8 and will fail to display other encodings correctly.
- Commit log messages are typically encoded in UTF-8, but other
extended ASCII encodings are also supported. This includes
ISO-8859-x, CP125x and many others, but _not_ UTF-16/32,
EBCDIC and CJK multi-byte encodings (GBK, Shift-JIS, Big5,
EUC-x, CP9xx etc.).
- The commit log messages are uninterpreted sequences of non-NUL
bytes.
Although we encourage that the commit log messages are encoded
in UTF-8, both the core and Git Porcelain are designed not to

View File

@ -729,11 +729,6 @@ format, often found in email messages.
+
`--date=raw` shows the date in the internal raw Git format `%s %z` format.
+
`--date=format:...` feeds the format `...` to your system `strftime`.
Use `--date=format:%c` to show the date in your system locale's
preferred format. See the `strftime` manual for a complete list of
format placeholders.
+
`--date=default` shows timestamps in the original time zone
(either committer's or author's).

View File

@ -46,9 +46,6 @@ Functions
Format a string and push it onto the end of the array. This is a
convenience wrapper combining `strbuf_addf` and `argv_array_push`.
`argv_array_pushv`::
Push a null-terminated array of strings onto the end of the array.
`argv_array_pop`::
Remove the final element from the array. If there are no
elements in the array, do nothing.

View File

@ -0,0 +1,220 @@
lockfile API
============
The lockfile API serves two purposes:
* Mutual exclusion and atomic file updates. When we want to change a
file, we create a lockfile `<filename>.lock`, write the new file
contents into it, and then rename the lockfile to its final
destination `<filename>`. We create the `<filename>.lock` file with
`O_CREAT|O_EXCL` so that we can notice and fail if somebody else has
already locked the file, then atomically rename the lockfile to its
final destination to commit the changes and unlock the file.
* Automatic cruft removal. If the program exits after we lock a file
but before the changes have been committed, we want to make sure
that we remove the lockfile. This is done by remembering the
lockfiles we have created in a linked list and setting up an
`atexit(3)` handler and a signal handler that clean up the
lockfiles. This mechanism ensures that outstanding lockfiles are
cleaned up if the program exits (including when `die()` is called)
or if the program dies on a signal.
Please note that lockfiles only block other writers. Readers do not
block, but they are guaranteed to see either the old contents of the
file or the new contents of the file (assuming that the filesystem
implements `rename(2)` atomically).
Calling sequence
----------------
The caller:
* Allocates a `struct lock_file` either as a static variable or on the
heap, initialized to zeros. Once you use the structure to call the
`hold_lock_file_*` family of functions, it belongs to the lockfile
subsystem and its storage must remain valid throughout the life of
the program (i.e. you cannot use an on-stack variable to hold this
structure).
* Attempts to create a lockfile by passing that variable and the path
of the final destination (e.g. `$GIT_DIR/index`) to
`hold_lock_file_for_update` or `hold_lock_file_for_append`.
* Writes new content for the destination file by either:
* writing to the file descriptor returned by the `hold_lock_file_*`
functions (also available via `lock->fd`).
* calling `fdopen_lock_file` to get a `FILE` pointer for the open
file and writing to the file using stdio.
When finished writing, the caller can:
* Close the file descriptor and rename the lockfile to its final
destination by calling `commit_lock_file` or `commit_lock_file_to`.
* Close the file descriptor and remove the lockfile by calling
`rollback_lock_file`.
* Close the file descriptor without removing or renaming the lockfile
by calling `close_lock_file`, and later call `commit_lock_file`,
`commit_lock_file_to`, `rollback_lock_file`, or `reopen_lock_file`.
Even after the lockfile is committed or rolled back, the `lock_file`
object must not be freed or altered by the caller. However, it may be
reused; just pass it to another call of `hold_lock_file_for_update` or
`hold_lock_file_for_append`.
If the program exits before you have called one of `commit_lock_file`,
`commit_lock_file_to`, `rollback_lock_file`, or `close_lock_file`, an
`atexit(3)` handler will close and remove the lockfile, rolling back
any uncommitted changes.
If you need to close the file descriptor you obtained from a
`hold_lock_file_*` function yourself, do so by calling
`close_lock_file`. You should never call `close(2)` or `fclose(3)`
yourself! Otherwise the `struct lock_file` structure would still think
that the file descriptor needs to be closed, and a commit or rollback
would result in duplicate calls to `close(2)`. Worse yet, if you close
and then later open another file descriptor for a completely different
purpose, then a commit or rollback might close that unrelated file
descriptor.
Error handling
--------------
The `hold_lock_file_*` functions return a file descriptor on success
or -1 on failure (unless `LOCK_DIE_ON_ERROR` is used; see below). On
errors, `errno` describes the reason for failure. Errors can be
reported by passing `errno` to one of the following helper functions:
unable_to_lock_message::
Append an appropriate error message to a `strbuf`.
unable_to_lock_error::
Emit an appropriate error message using `error()`.
unable_to_lock_die::
Emit an appropriate error message and `die()`.
Similarly, `commit_lock_file`, `commit_lock_file_to`, and
`close_lock_file` return 0 on success. On failure they set `errno`
appropriately, do their best to roll back the lockfile, and return -1.
Flags
-----
The following flags can be passed to `hold_lock_file_for_update` or
`hold_lock_file_for_append`:
LOCK_NO_DEREF::
Usually symbolic links in the destination path are resolved
and the lockfile is created by adding ".lock" to the resolved
path. If `LOCK_NO_DEREF` is set, then the lockfile is created
by adding ".lock" to the path argument itself. This option is
used, for example, when locking a symbolic reference, which
for backwards-compatibility reasons can be a symbolic link
containing the name of the referred-to-reference.
LOCK_DIE_ON_ERROR::
If a lock is already taken for the file, `die()` with an error
message. If this option is not specified, trying to lock a
file that is already locked returns -1 to the caller.
The functions
-------------
hold_lock_file_for_update::
Take a pointer to `struct lock_file`, the path of the file to
be locked (e.g. `$GIT_DIR/index`) and a flags argument (see
above). Attempt to create a lockfile for the destination and
return the file descriptor for writing to the file.
hold_lock_file_for_append::
Like `hold_lock_file_for_update`, but before returning copy
the existing contents of the file (if any) to the lockfile and
position its write pointer at the end of the file.
fdopen_lock_file::
Associate a stdio stream with the lockfile. Return NULL
(*without* rolling back the lockfile) on error. The stream is
closed automatically when `close_lock_file` is called or when
the file is committed or rolled back.
get_locked_file_path::
Return the path of the file that is locked by the specified
lock_file object. The caller must free the memory.
commit_lock_file::
Take a pointer to the `struct lock_file` initialized with an
earlier call to `hold_lock_file_for_update` or
`hold_lock_file_for_append`, close the file descriptor, and
rename the lockfile to its final destination. Return 0 upon
success. On failure, roll back the lock file and return -1,
with `errno` set to the value from the failing call to
`close(2)` or `rename(2)`. It is a bug to call
`commit_lock_file` for a `lock_file` object that is not
currently locked.
commit_lock_file_to::
Like `commit_lock_file()`, except that it takes an explicit
`path` argument to which the lockfile should be renamed. The
`path` must be on the same filesystem as the lock file.
rollback_lock_file::
Take a pointer to the `struct lock_file` initialized with an
earlier call to `hold_lock_file_for_update` or
`hold_lock_file_for_append`, close the file descriptor and
remove the lockfile. It is a NOOP to call
`rollback_lock_file()` for a `lock_file` object that has
already been committed or rolled back.
close_lock_file::
Take a pointer to the `struct lock_file` initialized with an
earlier call to `hold_lock_file_for_update` or
`hold_lock_file_for_append`. Close the file descriptor (and
the file pointer if it has been opened using
`fdopen_lock_file`). Return 0 upon success. On failure to
`close(2)`, return a negative value and roll back the lock
file. Usually `commit_lock_file`, `commit_lock_file_to`, or
`rollback_lock_file` should eventually be called if
`close_lock_file` succeeds.
reopen_lock_file::
Re-open a lockfile that has been closed (using
`close_lock_file`) but not yet committed or rolled back. This
can be used to implement a sequence of operations like the
following:
* Lock file.
* Write new contents to lockfile, then `close_lock_file` to
cause the contents to be written to disk.
* Pass the name of the lockfile to another program to allow it
(and nobody else) to inspect the contents you wrote, while
still holding the lock yourself.
* `reopen_lock_file` to reopen the lockfile. Make further
updates to the contents.
* `commit_lock_file` to make the final version permanent.

View File

@ -168,12 +168,6 @@ There are some macros to easily define options:
Introduce an option with integer argument.
The integer is put into `int_var`.
`OPT_MAGNITUDE(short, long, &unsigned_long_var, description)`::
Introduce an option with a size argument. The argument must be a
non-negative integer and may include a suffix of 'k', 'm' or 'g' to
scale the provided value by 1024, 1024^2 or 1024^3 respectively.
The scaled value is put into `unsigned_long_var`.
`OPT_DATE(short, long, &int_var, description)`::
Introduce an option with date argument, see `approxidate()`.
The timestamp is put into `int_var`.
@ -218,19 +212,6 @@ There are some macros to easily define options:
Use it to hide deprecated options that are still to be recognized
and ignored silently.
`OPT_PASSTHRU(short, long, &char_var, arg_str, description, flags)`::
Introduce an option that will be reconstructed into a char* string,
which must be initialized to NULL. This is useful when you need to
pass the command-line option to another command. Any previous value
will be overwritten, so this should only be used for options where
the last one specified on the command line wins.
`OPT_PASSTHRU_ARGV(short, long, &argv_array_var, arg_str, description, flags)`::
Introduce an option where all instances of it on the command-line will
be reconstructed into an argv_array. This is useful when you need to
pass the command-line option, which can be specified multiple times,
to another command.
The last element of the array must be `OPT_END()`.

View File

@ -1,62 +0,0 @@
submodule config cache API
==========================
The submodule config cache API allows to read submodule
configurations/information from specified revisions. Internally
information is lazily read into a cache that is used to avoid
unnecessary parsing of the same .gitmodule files. Lookups can be done by
submodule path or name.
Usage
-----
To initialize the cache with configurations from the worktree the caller
typically first calls `gitmodules_config()` to read values from the
worktree .gitmodules and then to overlay the local git config values
`parse_submodule_config_option()` from the config parsing
infrastructure.
The caller can look up information about submodules by using the
`submodule_from_path()` or `submodule_from_name()` functions. They return
a `struct submodule` which contains the values. The API automatically
initializes and allocates the needed infrastructure on-demand. If the
caller does only want to lookup values from revisions the initialization
can be skipped.
If the internal cache might grow too big or when the caller is done with
the API, all internally cached values can be freed with submodule_free().
Data Structures
---------------
`struct submodule`::
This structure is used to return the information about one
submodule for a certain revision. It is returned by the lookup
functions.
Functions
---------
`void submodule_free()`::
Use these to free the internally cached values.
`int parse_submodule_config_option(const char *var, const char *value)`::
Can be passed to the config parsing infrastructure to parse
local (worktree) submodule configurations.
`const struct submodule *submodule_from_path(const unsigned char *commit_sha1, const char *path)`::
Lookup values for one submodule by its commit_sha1 and path.
`const struct submodule *submodule_from_name(const unsigned char *commit_sha1, const char *name)`::
The same as above but lookup by name.
If given the null_sha1 as commit_sha1 the local configuration of a
submodule will be returned (e.g. consolidated values from local git
configuration and the .gitmodules file in the worktree).
For an example usage see test-submodule-config.c.

View File

@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
DEF_VER=v2.6.0-rc0
DEF_VER=v2.5.2
LF='
'

View File

@ -467,6 +467,7 @@ TEST_PROGRAMS_NEED_X =
# interactive shell sessions without exporting it.
unexport CDPATH
SCRIPT_SH += git-am.sh
SCRIPT_SH += git-bisect.sh
SCRIPT_SH += git-difftool--helper.sh
SCRIPT_SH += git-filter-branch.sh
@ -474,6 +475,7 @@ SCRIPT_SH += git-merge-octopus.sh
SCRIPT_SH += git-merge-one-file.sh
SCRIPT_SH += git-merge-resolve.sh
SCRIPT_SH += git-mergetool.sh
SCRIPT_SH += git-pull.sh
SCRIPT_SH += git-quiltimport.sh
SCRIPT_SH += git-rebase.sh
SCRIPT_SH += git-remote-testgit.sh
@ -593,7 +595,6 @@ TEST_PROGRAMS_NEED_X += test-sha1
TEST_PROGRAMS_NEED_X += test-sha1-array
TEST_PROGRAMS_NEED_X += test-sigchain
TEST_PROGRAMS_NEED_X += test-string-list
TEST_PROGRAMS_NEED_X += test-submodule-config
TEST_PROGRAMS_NEED_X += test-subprocess
TEST_PROGRAMS_NEED_X += test-svn-fe
TEST_PROGRAMS_NEED_X += test-urlmatch-normalization
@ -762,7 +763,6 @@ LIB_OBJS += reachable.o
LIB_OBJS += read-cache.o
LIB_OBJS += reflog-walk.o
LIB_OBJS += refs.o
LIB_OBJS += ref-filter.o
LIB_OBJS += remote.o
LIB_OBJS += replace_object.o
LIB_OBJS += rerere.o
@ -785,10 +785,8 @@ LIB_OBJS += strbuf.o
LIB_OBJS += streaming.o
LIB_OBJS += string-list.o
LIB_OBJS += submodule.o
LIB_OBJS += submodule-config.o
LIB_OBJS += symlinks.o
LIB_OBJS += tag.o
LIB_OBJS += tempfile.o
LIB_OBJS += trace.o
LIB_OBJS += trailer.o
LIB_OBJS += transport.o
@ -815,7 +813,6 @@ LIB_OBJS += xdiff-interface.o
LIB_OBJS += zlib.o
BUILTIN_OBJS += builtin/add.o
BUILTIN_OBJS += builtin/am.o
BUILTIN_OBJS += builtin/annotate.o
BUILTIN_OBJS += builtin/apply.o
BUILTIN_OBJS += builtin/archive.o
@ -881,7 +878,6 @@ BUILTIN_OBJS += builtin/pack-refs.o
BUILTIN_OBJS += builtin/patch-id.o
BUILTIN_OBJS += builtin/prune-packed.o
BUILTIN_OBJS += builtin/prune.o
BUILTIN_OBJS += builtin/pull.o
BUILTIN_OBJS += builtin/push.o
BUILTIN_OBJS += builtin/read-tree.o
BUILTIN_OBJS += builtin/receive-pack.o

View File

@ -1 +1 @@
Documentation/RelNotes/2.6.0.txt
Documentation/RelNotes/2.5.2.txt

View File

@ -96,14 +96,6 @@ void NORETURN die_resolve_conflict(const char *me)
die("Exiting because of an unresolved conflict.");
}
void NORETURN die_conclude_merge(void)
{
error(_("You have not concluded your merge (MERGE_HEAD exists)."));
if (advice_resolve_conflict)
advise(_("Please, commit your changes before you can merge."));
die(_("Exiting because of unfinished merge."));
}
void detach_advice(const char *new_name)
{
const char fmt[] =

View File

@ -24,7 +24,6 @@ __attribute__((format (printf, 1, 2)))
void advise(const char *advice, ...);
int error_resolve_conflict(const char *me);
extern void NORETURN die_resolve_conflict(const char *me);
void NORETURN die_conclude_merge(void);
void detach_advice(const char *new_name);
#endif /* ADVICE_H */

View File

@ -1,5 +1,4 @@
#include "cache.h"
#include "refs.h"
#include "commit.h"
#include "tree-walk.h"
#include "attr.h"
@ -34,7 +33,7 @@ static void format_subst(const struct commit *commit,
char *to_free = NULL;
struct strbuf fmt = STRBUF_INIT;
struct pretty_print_context ctx = {0};
ctx.date_mode.type = DATE_NORMAL;
ctx.date_mode = DATE_NORMAL;
ctx.abbrev = DEFAULT_ABBREV;
if (src == buf->buf)

View File

@ -49,12 +49,6 @@ void argv_array_pushl(struct argv_array *array, ...)
va_end(ap);
}
void argv_array_pushv(struct argv_array *array, const char **argv)
{
for (; *argv; argv++)
argv_array_push(array, *argv);
}
void argv_array_pop(struct argv_array *array)
{
if (!array->argc)

View File

@ -17,7 +17,6 @@ __attribute__((format (printf,2,3)))
void argv_array_pushf(struct argv_array *, const char *fmt, ...);
LAST_ARG_MUST_BE_NULL
void argv_array_pushl(struct argv_array *, ...);
void argv_array_pushv(struct argv_array *, const char **);
void argv_array_pop(struct argv_array *);
void argv_array_clear(struct argv_array *);

4
attr.c
View File

@ -490,8 +490,6 @@ static int git_attr_system(void)
return !git_env_bool("GIT_ATTR_NOSYSTEM", 0);
}
static GIT_PATH_FUNC(git_path_info_attributes, INFOATTRIBUTES_FILE)
static void bootstrap_attr_stack(void)
{
struct attr_stack *elem;
@ -533,7 +531,7 @@ static void bootstrap_attr_stack(void)
debug_push(elem);
}
elem = read_attr_from_file(git_path_info_attributes(), 1);
elem = read_attr_from_file(git_path(INFOATTRIBUTES_FILE), 1);
if (!elem)
elem = xcalloc(1, sizeof(*elem));
elem->origin = NULL;

125
bisect.c
View File

@ -19,9 +19,7 @@ static struct object_id *current_bad_oid;
static const char *argv_checkout[] = {"checkout", "-q", NULL, "--", NULL};
static const char *argv_show_branch[] = {"show-branch", NULL, NULL};
static const char *term_bad;
static const char *term_good;
static const char *argv_update_ref[] = {"update-ref", "--no-deref", "BISECT_HEAD", NULL, NULL};
/* Remember to update object flag allocation in object.h */
#define COUNTED (1u<<16)
@ -405,21 +403,15 @@ struct commit_list *find_bisection(struct commit_list *list,
static int register_ref(const char *refname, const struct object_id *oid,
int flags, void *cb_data)
{
struct strbuf good_prefix = STRBUF_INIT;
strbuf_addstr(&good_prefix, term_good);
strbuf_addstr(&good_prefix, "-");
if (!strcmp(refname, term_bad)) {
if (!strcmp(refname, "bad")) {
current_bad_oid = xmalloc(sizeof(*current_bad_oid));
oidcpy(current_bad_oid, oid);
} else if (starts_with(refname, good_prefix.buf)) {
} else if (starts_with(refname, "good-")) {
sha1_array_append(&good_revs, oid->hash);
} else if (starts_with(refname, "skip-")) {
sha1_array_append(&skipped_revs, oid->hash);
}
strbuf_release(&good_prefix);
return 0;
}
@ -428,13 +420,10 @@ static int read_bisect_refs(void)
return for_each_ref_in("refs/bisect/", register_ref, NULL);
}
static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
static void read_bisect_paths(struct argv_array *array)
{
struct strbuf str = STRBUF_INIT;
const char *filename = git_path_bisect_names();
const char *filename = git_path("BISECT_NAMES");
FILE *fp = fopen(filename, "r");
if (!fp)
@ -645,7 +634,7 @@ static void exit_if_skipped_commits(struct commit_list *tried,
return;
printf("There are only 'skip'ped commits left to test.\n"
"The first %s commit could be any of:\n", term_bad);
"The first bad commit could be any of:\n");
print_commit_list(tried, "%s\n", "%s\n");
if (bad)
printf("%s\n", oid_to_hex(bad));
@ -655,7 +644,7 @@ static void exit_if_skipped_commits(struct commit_list *tried,
static int is_expected_rev(const struct object_id *oid)
{
const char *filename = git_path_bisect_expected_rev();
const char *filename = git_path("BISECT_EXPECTED_REV");
struct stat st;
struct strbuf str = STRBUF_INIT;
FILE *fp;
@ -677,16 +666,34 @@ static int is_expected_rev(const struct object_id *oid)
return res;
}
static int bisect_checkout(const unsigned char *bisect_rev, int no_checkout)
static void mark_expected_rev(char *bisect_rev_hex)
{
char bisect_rev_hex[GIT_SHA1_HEXSZ + 1];
int len = strlen(bisect_rev_hex);
const char *filename = git_path("BISECT_EXPECTED_REV");
int fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
memcpy(bisect_rev_hex, sha1_to_hex(bisect_rev), GIT_SHA1_HEXSZ + 1);
update_ref(NULL, "BISECT_EXPECTED_REV", bisect_rev, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
if (fd < 0)
die_errno("could not create file '%s'", filename);
bisect_rev_hex[len] = '\n';
write_or_die(fd, bisect_rev_hex, len + 1);
bisect_rev_hex[len] = '\0';
if (close(fd) < 0)
die("closing file %s: %s", filename, strerror(errno));
}
static int bisect_checkout(char *bisect_rev_hex, int no_checkout)
{
mark_expected_rev(bisect_rev_hex);
argv_checkout[2] = bisect_rev_hex;
if (no_checkout) {
update_ref(NULL, "BISECT_HEAD", bisect_rev, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
argv_update_ref[3] = bisect_rev_hex;
if (run_command_v_opt(argv_update_ref, RUN_GIT_CMD))
die("update-ref --no-deref HEAD failed on %s",
bisect_rev_hex);
} else {
int res;
res = run_command_v_opt(argv_checkout, RUN_GIT_CMD);
@ -725,24 +732,18 @@ static void handle_bad_merge_base(void)
if (is_expected_rev(current_bad_oid)) {
char *bad_hex = oid_to_hex(current_bad_oid);
char *good_hex = join_sha1_array_hex(&good_revs, ' ');
if (!strcmp(term_bad, "bad") && !strcmp(term_good, "good")) {
fprintf(stderr, "The merge base %s is bad.\n"
"This means the bug has been fixed "
"between %s and [%s].\n",
bad_hex, bad_hex, good_hex);
} else {
fprintf(stderr, "The merge base %s is %s.\n"
"This means the first '%s' commit is "
"between %s and [%s].\n",
bad_hex, term_bad, term_good, bad_hex, good_hex);
}
fprintf(stderr, "The merge base %s is bad.\n"
"This means the bug has been fixed "
"between %s and [%s].\n",
bad_hex, bad_hex, good_hex);
exit(3);
}
fprintf(stderr, "Some %s revs are not ancestor of the %s rev.\n"
fprintf(stderr, "Some good revs are not ancestor of the bad rev.\n"
"git bisect cannot work properly in this case.\n"
"Maybe you mistook %s and %s revs?\n",
term_good, term_bad, term_good, term_bad);
"Maybe you mistake good and bad revs?\n");
exit(1);
}
@ -754,10 +755,10 @@ static void handle_skipped_merge_base(const unsigned char *mb)
warning("the merge base between %s and [%s] "
"must be skipped.\n"
"So we cannot be sure the first %s commit is "
"So we cannot be sure the first bad commit is "
"between %s and %s.\n"
"We continue anyway.",
bad_hex, good_hex, term_bad, mb_hex, bad_hex);
bad_hex, good_hex, mb_hex, bad_hex);
free(good_hex);
}
@ -788,7 +789,7 @@ static void check_merge_bases(int no_checkout)
handle_skipped_merge_base(mb);
} else {
printf("Bisecting: a merge base must be tested\n");
exit(bisect_checkout(mb, no_checkout));
exit(bisect_checkout(sha1_to_hex(mb), no_checkout));
}
}
@ -838,7 +839,7 @@ static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)
int fd;
if (!current_bad_oid)
die("a %s revision is needed", term_bad);
die("a bad revision is needed");
/* Check if file BISECT_ANCESTORS_OK exists. */
if (!stat(filename, &st) && S_ISREG(st.st_mode))
@ -888,36 +889,6 @@ static void show_diff_tree(const char *prefix, struct commit *commit)
log_tree_commit(&opt, commit);
}
/*
* The terms used for this bisect session are stored in BISECT_TERMS.
* We read them and store them to adapt the messages accordingly.
* Default is bad/good.
*/
void read_bisect_terms(const char **read_bad, const char **read_good)
{
struct strbuf str = STRBUF_INIT;
const char *filename = git_path("BISECT_TERMS");
FILE *fp = fopen(filename, "r");
if (!fp) {
if (errno == ENOENT) {
*read_bad = "bad";
*read_good = "good";
return;
} else {
die("could not read file '%s': %s", filename,
strerror(errno));
}
} else {
strbuf_getline(&str, fp, '\n');
*read_bad = strbuf_detach(&str, NULL);
strbuf_getline(&str, fp, '\n');
*read_good = strbuf_detach(&str, NULL);
}
strbuf_release(&str);
fclose(fp);
}
/*
* We use the convention that exiting with an exit code 10 means that
* the bisection process finished successfully.
@ -932,8 +903,8 @@ int bisect_next_all(const char *prefix, int no_checkout)
struct commit_list *tried;
int reaches = 0, all = 0, nr, steps;
const unsigned char *bisect_rev;
char bisect_rev_hex[GIT_SHA1_HEXSZ + 1];
read_bisect_terms(&term_bad, &term_good);
if (read_bisect_refs())
die("reading bisect refs failed");
@ -955,10 +926,8 @@ int bisect_next_all(const char *prefix, int no_checkout)
*/
exit_if_skipped_commits(tried, NULL);
printf("%s was both %s and %s\n",
oid_to_hex(current_bad_oid),
term_good,
term_bad);
printf("%s was both good and bad\n",
oid_to_hex(current_bad_oid));
exit(1);
}
@ -969,11 +938,11 @@ int bisect_next_all(const char *prefix, int no_checkout)
}
bisect_rev = revs.commits->item->object.sha1;
memcpy(bisect_rev_hex, sha1_to_hex(bisect_rev), GIT_SHA1_HEXSZ + 1);
if (!hashcmp(bisect_rev, current_bad_oid->hash)) {
exit_if_skipped_commits(tried, current_bad_oid);
printf("%s is the first %s commit\n", sha1_to_hex(bisect_rev),
term_bad);
printf("%s is the first bad commit\n", bisect_rev_hex);
show_diff_tree(prefix, revs.commits->item);
/* This means the bisection process succeeded. */
exit(10);
@ -985,7 +954,7 @@ int bisect_next_all(const char *prefix, int no_checkout)
"(roughly %d step%s)\n", nr, (nr == 1 ? "" : "s"),
steps, (steps == 1 ? "" : "s"));
return bisect_checkout(bisect_rev, no_checkout);
return bisect_checkout(bisect_rev_hex, no_checkout);
}
static inline int log2i(int n)

View File

@ -26,6 +26,4 @@ extern int bisect_next_all(const char *prefix, int no_checkout);
extern int estimate_bisect_steps(int all);
extern void read_bisect_terms(const char **bad, const char **good);
#endif

103
branch.c
View File

@ -302,100 +302,11 @@ void create_branch(const char *head,
void remove_branch_state(void)
{
unlink(git_path_cherry_pick_head());
unlink(git_path_revert_head());
unlink(git_path_merge_head());
unlink(git_path_merge_rr());
unlink(git_path_merge_msg());
unlink(git_path_merge_mode());
unlink(git_path_squash_msg());
}
static char *find_linked_symref(const char *symref, const char *branch,
const char *id)
{
struct strbuf sb = STRBUF_INIT;
struct strbuf path = STRBUF_INIT;
struct strbuf gitdir = STRBUF_INIT;
char *existing = NULL;
/*
* $GIT_COMMON_DIR/$symref (e.g. HEAD) is practically outside
* $GIT_DIR so resolve_ref_unsafe() won't work (it uses
* git_path). Parse the ref ourselves.
*/
if (id)
strbuf_addf(&path, "%s/worktrees/%s/%s", get_git_common_dir(), id, symref);
else
strbuf_addf(&path, "%s/%s", get_git_common_dir(), symref);
if (!strbuf_readlink(&sb, path.buf, 0)) {
if (!starts_with(sb.buf, "refs/") ||
check_refname_format(sb.buf, 0))
goto done;
} else if (strbuf_read_file(&sb, path.buf, 0) >= 0 &&
starts_with(sb.buf, "ref:")) {
strbuf_remove(&sb, 0, strlen("ref:"));
strbuf_trim(&sb);
} else
goto done;
if (strcmp(sb.buf, branch))
goto done;
if (id) {
strbuf_reset(&path);
strbuf_addf(&path, "%s/worktrees/%s/gitdir", get_git_common_dir(), id);
if (strbuf_read_file(&gitdir, path.buf, 0) <= 0)
goto done;
strbuf_rtrim(&gitdir);
} else
strbuf_addstr(&gitdir, get_git_common_dir());
strbuf_strip_suffix(&gitdir, ".git");
existing = strbuf_detach(&gitdir, NULL);
done:
strbuf_release(&path);
strbuf_release(&sb);
strbuf_release(&gitdir);
return existing;
}
char *find_shared_symref(const char *symref, const char *target)
{
struct strbuf path = STRBUF_INIT;
DIR *dir;
struct dirent *d;
char *existing;
if ((existing = find_linked_symref(symref, target, NULL)))
return existing;
strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
dir = opendir(path.buf);
strbuf_release(&path);
if (!dir)
return NULL;
while ((d = readdir(dir)) != NULL) {
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
existing = find_linked_symref(symref, target, d->d_name);
if (existing)
goto done;
}
done:
closedir(dir);
return existing;
}
void die_if_checked_out(const char *branch)
{
char *existing;
existing = find_shared_symref("HEAD", branch);
if (existing) {
skip_prefix(branch, "refs/heads/", &branch);
die(_("'%s' is already checked out at '%s'"), branch, existing);
}
unlink(git_path("CHERRY_PICK_HEAD"));
unlink(git_path("REVERT_HEAD"));
unlink(git_path("MERGE_HEAD"));
unlink(git_path("MERGE_RR"));
unlink(git_path("MERGE_MSG"));
unlink(git_path("MERGE_MODE"));
unlink(git_path("SQUASH_MSG"));
}

View File

@ -52,19 +52,4 @@ extern void install_branch_config(int flag, const char *local, const char *origi
*/
extern int read_branch_desc(struct strbuf *, const char *branch_name);
/*
* Check if a branch is checked out in the main worktree or any linked
* worktree and die (with a message describing its checkout location) if
* it is.
*/
extern void die_if_checked_out(const char *branch);
/*
* Check if a per-worktree symref points to a ref in the main worktree
* or any linked worktree, and return the path to the exising worktree
* if it is. Returns NULL if there is no existing ref. The caller is
* responsible for freeing the returned path.
*/
extern char *find_shared_symref(const char *symref, const char *target);
#endif

View File

@ -30,7 +30,6 @@ extern int textconv_object(const char *path, unsigned mode, const unsigned char
extern int is_builtin(const char *s);
extern int cmd_add(int argc, const char **argv, const char *prefix);
extern int cmd_am(int argc, const char **argv, const char *prefix);
extern int cmd_annotate(int argc, const char **argv, const char *prefix);
extern int cmd_apply(int argc, const char **argv, const char *prefix);
extern int cmd_archive(int argc, const char **argv, const char *prefix);
@ -99,7 +98,6 @@ extern int cmd_pack_redundant(int argc, const char **argv, const char *prefix);
extern int cmd_patch_id(int argc, const char **argv, const char *prefix);
extern int cmd_prune(int argc, const char **argv, const char *prefix);
extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);
extern int cmd_pull(int argc, const char **argv, const char *prefix);
extern int cmd_push(int argc, const char **argv, const char *prefix);
extern int cmd_read_tree(int argc, const char **argv, const char *prefix);
extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,6 @@
*/
#include "cache.h"
#include "refs.h"
#include "builtin.h"
#include "blob.h"
#include "commit.h"
@ -51,7 +50,7 @@ static int xdl_opts;
static int abbrev = -1;
static int no_whole_file_rename;
static struct date_mode blame_date_mode = { DATE_ISO8601 };
static enum date_mode blame_date_mode = DATE_ISO8601;
static size_t blame_date_width;
static struct string_list mailmap;
@ -1828,7 +1827,7 @@ static const char *format_time(unsigned long time, const char *tz_str,
size_t time_width;
int tz;
tz = atoi(tz_str);
time_str = show_date(time, tz, &blame_date_mode);
time_str = show_date(time, tz, blame_date_mode);
strbuf_addstr(&time_buf, time_str);
/*
* Add space paddings to time_buf to display a fixed width
@ -2188,7 +2187,7 @@ static int git_blame_config(const char *var, const char *value, void *cb)
if (!strcmp(var, "blame.date")) {
if (!value)
return config_error_nonbool(var);
parse_date_format(value, &blame_date_mode);
blame_date_mode = parse_date_format(value);
return 0;
}
@ -2227,19 +2226,20 @@ static struct commit_list **append_parent(struct commit_list **tail, const unsig
static void append_merge_parents(struct commit_list **tail)
{
int merge_head;
const char *merge_head_file = git_path("MERGE_HEAD");
struct strbuf line = STRBUF_INIT;
merge_head = open(git_path_merge_head(), O_RDONLY);
merge_head = open(merge_head_file, O_RDONLY);
if (merge_head < 0) {
if (errno == ENOENT)
return;
die("cannot open '%s' for reading", git_path_merge_head());
die("cannot open '%s' for reading", merge_head_file);
}
while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) {
unsigned char sha1[20];
if (line.len < 40 || get_sha1_hex(line.buf, sha1))
die("unknown line in '%s': %s", git_path_merge_head(), line.buf);
die("unknown line in '%s': %s", merge_head_file, line.buf);
tail = append_parent(tail, sha1);
}
close(merge_head);
@ -2569,13 +2569,13 @@ parse_done:
if (cmd_is_annotate) {
output_option |= OUTPUT_ANNOTATE_COMPAT;
blame_date_mode.type = DATE_ISO8601;
blame_date_mode = DATE_ISO8601;
} else {
blame_date_mode = revs.date_mode;
}
/* The maximum width used to show the dates */
switch (blame_date_mode.type) {
switch (blame_date_mode) {
case DATE_RFC2822:
blame_date_width = sizeof("Thu, 19 Oct 2006 16:00:04 -0700");
break;
@ -2604,9 +2604,6 @@ parse_done:
case DATE_NORMAL:
blame_date_width = sizeof("Thu Oct 19 16:00:04 2006 -0700");
break;
case DATE_STRFTIME:
blame_date_width = strlen(show_date(0, 0, &blame_date_mode)) + 1; /* add the null */
break;
}
blame_date_width -= 1; /* strip the null */

View File

@ -160,7 +160,7 @@ static int branch_merged(int kind, const char *name,
}
static int check_branch_commit(const char *branchname, const char *refname,
const unsigned char *sha1, struct commit *head_rev,
unsigned char *sha1, struct commit *head_rev,
int kinds, int force)
{
struct commit *rev = lookup_commit_reference(sha1);
@ -253,8 +253,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
continue;
}
if (delete_ref(name, is_null_sha1(sha1) ? NULL : sha1,
REF_NODEREF)) {
if (delete_ref(name, sha1, REF_NODEREF)) {
error(remote_branch
? _("Error deleting remote-tracking branch '%s'")
: _("Error deleting branch '%s'"),
@ -776,7 +775,7 @@ static int edit_branch_description(const char *branch_name)
" %s\n"
"Lines starting with '%c' will be stripped.\n",
branch_name, comment_line_char);
if (write_file_gently(git_path(edit_description), "%s", buf.buf)) {
if (write_file(git_path(edit_description), 0, "%s", buf.buf)) {
strbuf_release(&buf);
return error(_("could not write branch description template: %s"),
strerror(errno));

View File

@ -9,16 +9,6 @@
#include "userdiff.h"
#include "streaming.h"
#include "tree-walk.h"
#include "sha1-array.h"
struct batch_options {
int enabled;
int follow_symlinks;
int print_contents;
int buffer_output;
int all_objects;
const char *format;
};
static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
int unknown_type)
@ -214,25 +204,14 @@ static size_t expand_format(struct strbuf *sb, const char *start, void *data)
return end - start + 1;
}
static void batch_write(struct batch_options *opt, const void *data, int len)
{
if (opt->buffer_output) {
if (fwrite(data, 1, len, stdout) != len)
die_errno("unable to write to stdout");
} else
write_or_die(1, data, len);
}
static void print_object_or_die(struct batch_options *opt, struct expand_data *data)
static void print_object_or_die(int fd, struct expand_data *data)
{
const unsigned char *sha1 = data->sha1;
assert(data->info.typep);
if (data->type == OBJ_BLOB) {
if (opt->buffer_output)
fflush(stdout);
if (stream_blob_to_fd(1, sha1, NULL, 0) < 0)
if (stream_blob_to_fd(fd, sha1, NULL, 0) < 0)
die("unable to stream %s to stdout", sha1_to_hex(sha1));
}
else {
@ -248,40 +227,29 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
if (data->info.sizep && size != data->size)
die("object %s changed size!?", sha1_to_hex(sha1));
batch_write(opt, contents, size);
write_or_die(fd, contents, size);
free(contents);
}
}
static void batch_object_write(const char *obj_name, struct batch_options *opt,
struct expand_data *data)
struct batch_options {
int enabled;
int follow_symlinks;
int print_contents;
const char *format;
};
static int batch_one_object(const char *obj_name, struct batch_options *opt,
struct expand_data *data)
{
struct strbuf buf = STRBUF_INIT;
if (sha1_object_info_extended(data->sha1, &data->info, LOOKUP_REPLACE_OBJECT) < 0) {
printf("%s missing\n", obj_name ? obj_name : sha1_to_hex(data->sha1));
fflush(stdout);
return;
}
strbuf_expand(&buf, opt->format, expand_format, data);
strbuf_addch(&buf, '\n');
batch_write(opt, buf.buf, buf.len);
strbuf_release(&buf);
if (opt->print_contents) {
print_object_or_die(opt, data);
batch_write(opt, "\n", 1);
}
}
static void batch_one_object(const char *obj_name, struct batch_options *opt,
struct expand_data *data)
{
struct object_context ctx;
int flags = opt->follow_symlinks ? GET_SHA1_FOLLOW_SYMLINKS : 0;
enum follow_symlinks_result result;
if (!obj_name)
return 1;
result = get_sha1_with_context(obj_name, flags, data->sha1, &ctx);
if (result != FOUND) {
switch (result) {
@ -306,7 +274,7 @@ static void batch_one_object(const char *obj_name, struct batch_options *opt,
break;
}
fflush(stdout);
return;
return 0;
}
if (ctx.mode == 0) {
@ -314,38 +282,24 @@ static void batch_one_object(const char *obj_name, struct batch_options *opt,
(uintmax_t)ctx.symlink_path.len,
ctx.symlink_path.buf);
fflush(stdout);
return;
return 0;
}
batch_object_write(obj_name, opt, data);
}
if (sha1_object_info_extended(data->sha1, &data->info, LOOKUP_REPLACE_OBJECT) < 0) {
printf("%s missing\n", obj_name);
fflush(stdout);
return 0;
}
struct object_cb_data {
struct batch_options *opt;
struct expand_data *expand;
};
strbuf_expand(&buf, opt->format, expand_format, data);
strbuf_addch(&buf, '\n');
write_or_die(1, buf.buf, buf.len);
strbuf_release(&buf);
static void batch_object_cb(const unsigned char sha1[20], void *vdata)
{
struct object_cb_data *data = vdata;
hashcpy(data->expand->sha1, sha1);
batch_object_write(NULL, data->opt, data->expand);
}
static int batch_loose_object(const unsigned char *sha1,
const char *path,
void *data)
{
sha1_array_append(data, sha1);
return 0;
}
static int batch_packed_object(const unsigned char *sha1,
struct packed_git *pack,
uint32_t pos,
void *data)
{
sha1_array_append(data, sha1);
if (opt->print_contents) {
print_object_or_die(1, data);
write_or_die(1, "\n", 1);
}
return 0;
}
@ -376,21 +330,6 @@ static int batch_objects(struct batch_options *opt)
if (opt->print_contents)
data.info.typep = &data.type;
if (opt->all_objects) {
struct sha1_array sa = SHA1_ARRAY_INIT;
struct object_cb_data cb;
for_each_loose_object(batch_loose_object, &sa, 0);
for_each_packed_object(batch_packed_object, &sa, 0);
cb.opt = opt;
cb.expand = &data;
sha1_array_for_each_unique(&sa, batch_object_cb, &cb);
sha1_array_clear(&sa);
return 0;
}
/*
* We are going to call get_sha1 on a potentially very large number of
* objects. In most large cases, these will be actual object sha1s. The
@ -416,7 +355,9 @@ static int batch_objects(struct batch_options *opt)
data.rest = p;
}
batch_one_object(buf.buf, opt, &data);
retval = batch_one_object(buf.buf, opt, &data);
if (retval)
break;
}
strbuf_release(&buf);
@ -471,9 +412,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
OPT_CMDMODE('p', NULL, &opt, N_("pretty-print object's content"), 'p'),
OPT_CMDMODE(0, "textconv", &opt,
N_("for blob objects, run textconv on object's content"), 'c'),
OPT_BOOL(0, "allow-unknown-type", &unknown_type,
OPT_BOOL( 0, "allow-unknown-type", &unknown_type,
N_("allow -s and -t to work with broken/corrupt objects")),
OPT_BOOL(0, "buffer", &batch.buffer_output, N_("buffer --batch output")),
{ OPTION_CALLBACK, 0, "batch", &batch, "format",
N_("show info and content of objects fed from the standard input"),
PARSE_OPT_OPTARG, batch_option_callback },
@ -482,8 +422,6 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
PARSE_OPT_OPTARG, batch_option_callback },
OPT_BOOL(0, "follow-symlinks", &batch.follow_symlinks,
N_("follow in-tree symlinks (used with --batch or --batch-check)")),
OPT_BOOL(0, "batch-all-objects", &batch.all_objects,
N_("show all objects with --batch or --batch-check")),
OPT_END()
};
@ -508,7 +446,7 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
usage_with_options(cat_file_usage, options);
}
if ((batch.follow_symlinks || batch.all_objects) && !batch.enabled) {
if (batch.follow_symlinks && !batch.enabled) {
usage_with_options(cat_file_usage, options);
}

View File

@ -18,7 +18,6 @@
#include "xdiff-interface.h"
#include "ll-merge.h"
#include "resolve-undo.h"
#include "submodule-config.h"
#include "submodule.h"
static const char * const checkout_usage[] = {
@ -49,6 +48,8 @@ struct checkout_opts {
const char *prefix;
struct pathspec pathspec;
struct tree *source_tree;
int new_worktree_mode;
};
static int post_checkout_hook(struct commit *old, struct commit *new,
@ -508,7 +509,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
topts.dir->flags |= DIR_SHOW_IGNORED;
setup_standard_excludes(topts.dir);
}
tree = parse_tree_indirect(old->commit ?
tree = parse_tree_indirect(old->commit && !opts->new_worktree_mode ?
old->commit->object.sha1 :
EMPTY_TREE_SHA1_BIN);
init_tree_desc(&trees[0], tree->buffer, tree->size);
@ -611,20 +612,22 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
if (opts->new_branch) {
if (opts->new_orphan_branch) {
if (opts->new_branch_log && !log_all_ref_updates) {
int temp;
struct strbuf log_file = STRBUF_INIT;
int ret;
char *refname;
struct strbuf err = STRBUF_INIT;
const char *ref_name;
refname = mkpathdup("refs/heads/%s", opts->new_orphan_branch);
ret = safe_create_reflog(refname, 1, &err);
free(refname);
ref_name = mkpath("refs/heads/%s", opts->new_orphan_branch);
temp = log_all_ref_updates;
log_all_ref_updates = 1;
ret = log_ref_setup(ref_name, &log_file);
log_all_ref_updates = temp;
strbuf_release(&log_file);
if (ret) {
fprintf(stderr, _("Can not do reflog for '%s': %s\n"),
opts->new_orphan_branch, err.buf);
strbuf_release(&err);
fprintf(stderr, _("Can not do reflog for '%s'\n"),
opts->new_orphan_branch);
return;
}
strbuf_release(&err);
}
}
else
@ -829,7 +832,8 @@ static int switch_branches(const struct checkout_opts *opts,
return ret;
}
if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
if (!opts->quiet && !old.path && old.commit &&
new->commit != old.commit && !opts->new_worktree_mode)
orphaned_commit_warning(old.commit, new->commit);
update_refs_for_switch(opts, &old, new);
@ -894,6 +898,71 @@ static const char *unique_tracking_name(const char *name, unsigned char *sha1)
return NULL;
}
static void check_linked_checkout(struct branch_info *new, const char *id)
{
struct strbuf sb = STRBUF_INIT;
struct strbuf path = STRBUF_INIT;
struct strbuf gitdir = STRBUF_INIT;
const char *start, *end;
if (id)
strbuf_addf(&path, "%s/worktrees/%s/HEAD", get_git_common_dir(), id);
else
strbuf_addf(&path, "%s/HEAD", get_git_common_dir());
if (strbuf_read_file(&sb, path.buf, 0) < 0 ||
!skip_prefix(sb.buf, "ref:", &start))
goto done;
while (isspace(*start))
start++;
end = start;
while (*end && !isspace(*end))
end++;
if (strncmp(start, new->path, end - start) || new->path[end - start] != '\0')
goto done;
if (id) {
strbuf_reset(&path);
strbuf_addf(&path, "%s/worktrees/%s/gitdir", get_git_common_dir(), id);
if (strbuf_read_file(&gitdir, path.buf, 0) <= 0)
goto done;
strbuf_rtrim(&gitdir);
} else
strbuf_addstr(&gitdir, get_git_common_dir());
die(_("'%s' is already checked out at '%s'"), new->name, gitdir.buf);
done:
strbuf_release(&path);
strbuf_release(&sb);
strbuf_release(&gitdir);
}
static void check_linked_checkouts(struct branch_info *new)
{
struct strbuf path = STRBUF_INIT;
DIR *dir;
struct dirent *d;
strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
if ((dir = opendir(path.buf)) == NULL) {
strbuf_release(&path);
return;
}
/*
* $GIT_COMMON_DIR/HEAD is practically outside
* $GIT_DIR so resolve_ref_unsafe() won't work (it
* uses git_path). Parse the ref ourselves.
*/
check_linked_checkout(new, NULL);
while ((d = readdir(dir)) != NULL) {
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
check_linked_checkout(new, d->d_name);
}
strbuf_release(&path);
closedir(dir);
}
static int parse_branchname_arg(int argc, const char **argv,
int dwim_new_local_branch_ok,
struct branch_info *new,
@ -1101,14 +1170,14 @@ static int checkout_branch(struct checkout_opts *opts,
die(_("Cannot switch branch to a non-commit '%s'"),
new->name);
if (new->path && !opts->force_detach && !opts->new_branch &&
!opts->ignore_other_worktrees) {
if (new->path && !opts->force_detach && !opts->new_branch) {
unsigned char sha1[20];
int flag;
char *head_ref = resolve_refdup("HEAD", 0, sha1, &flag);
if (head_ref &&
(!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)))
die_if_checked_out(new->path);
(!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)) &&
!opts->ignore_other_worktrees)
check_linked_checkouts(new);
free(head_ref);
}
@ -1172,6 +1241,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, checkout_usage,
PARSE_OPT_KEEP_DASHDASH);
opts.new_worktree_mode = getenv("GIT_CHECKOUT_NEW_WORKTREE") != NULL;
if (conflict_style) {
opts.merge = 1; /* implied */
git_xmerge_config("merge.conflictstyle", conflict_style, NULL);

View File

@ -10,6 +10,7 @@
#include "cache.h"
#include "dir.h"
#include "parse-options.h"
#include "refs.h"
#include "string-list.h"
#include "quote.h"
#include "column.h"
@ -147,31 +148,6 @@ static int exclude_cb(const struct option *opt, const char *arg, int unset)
return 0;
}
/*
* Return 1 if the given path is the root of a git repository or
* submodule else 0. Will not return 1 for bare repositories with the
* exception of creating a bare repository in "foo/.git" and calling
* is_git_repository("foo").
*/
static int is_git_repository(struct strbuf *path)
{
int ret = 0;
int gitfile_error;
size_t orig_path_len = path->len;
assert(orig_path_len != 0);
if (path->buf[orig_path_len - 1] != '/')
strbuf_addch(path, '/');
strbuf_addstr(path, ".git");
if (read_gitfile_gently(path->buf, &gitfile_error) || is_git_directory(path->buf))
ret = 1;
if (gitfile_error == READ_GITFILE_ERR_OPEN_FAILED ||
gitfile_error == READ_GITFILE_ERR_READ_FAILED)
ret = 1; /* This could be a real .git file, take the
* safe option and avoid cleaning */
strbuf_setlen(path, orig_path_len);
return ret;
}
static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
int dry_run, int quiet, int *dir_gone)
{
@ -179,11 +155,13 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
struct strbuf quoted = STRBUF_INIT;
struct dirent *e;
int res = 0, ret = 0, gone = 1, original_len = path->len, len;
unsigned char submodule_head[20];
struct string_list dels = STRING_LIST_INIT_DUP;
*dir_gone = 1;
if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) && is_git_repository(path)) {
if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) &&
!resolve_gitlink_ref(path->buf, "HEAD", submodule_head)) {
if (!quiet) {
quote_path_relative(path->buf, prefix, &quoted);
printf(dry_run ? _(msg_would_skip_git_dir) : _(msg_skip_git_dir),

View File

@ -99,130 +99,77 @@ static const char *argv_submodule[] = {
"submodule", "update", "--init", "--recursive", NULL
};
static const char *get_repo_path_1(struct strbuf *path, int *is_bundle)
static char *get_repo_path(const char *repo, int *is_bundle)
{
static char *suffix[] = { "/.git", "", ".git/.git", ".git" };
static char *bundle_suffix[] = { ".bundle", "" };
size_t baselen = path->len;
struct stat st;
int i;
for (i = 0; i < ARRAY_SIZE(suffix); i++) {
strbuf_setlen(path, baselen);
strbuf_addstr(path, suffix[i]);
if (stat(path->buf, &st))
const char *path;
path = mkpath("%s%s", repo, suffix[i]);
if (stat(path, &st))
continue;
if (S_ISDIR(st.st_mode) && is_git_directory(path->buf)) {
if (S_ISDIR(st.st_mode) && is_git_directory(path)) {
*is_bundle = 0;
return path->buf;
return xstrdup(absolute_path(path));
} else if (S_ISREG(st.st_mode) && st.st_size > 8) {
/* Is it a "gitfile"? */
char signature[8];
const char *dst;
int len, fd = open(path->buf, O_RDONLY);
int len, fd = open(path, O_RDONLY);
if (fd < 0)
continue;
len = read_in_full(fd, signature, 8);
close(fd);
if (len != 8 || strncmp(signature, "gitdir: ", 8))
continue;
dst = read_gitfile(path->buf);
if (dst) {
path = read_gitfile(path);
if (path) {
*is_bundle = 0;
return dst;
return xstrdup(absolute_path(path));
}
}
}
for (i = 0; i < ARRAY_SIZE(bundle_suffix); i++) {
strbuf_setlen(path, baselen);
strbuf_addstr(path, bundle_suffix[i]);
if (!stat(path->buf, &st) && S_ISREG(st.st_mode)) {
const char *path;
path = mkpath("%s%s", repo, bundle_suffix[i]);
if (!stat(path, &st) && S_ISREG(st.st_mode)) {
*is_bundle = 1;
return path->buf;
return xstrdup(absolute_path(path));
}
}
return NULL;
}
static char *get_repo_path(const char *repo, int *is_bundle)
{
struct strbuf path = STRBUF_INIT;
const char *raw;
char *canon;
strbuf_addstr(&path, repo);
raw = get_repo_path_1(&path, is_bundle);
canon = raw ? xstrdup(absolute_path(raw)) : NULL;
strbuf_release(&path);
return canon;
}
static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
{
const char *end = repo + strlen(repo), *start, *ptr;
const char *end = repo + strlen(repo), *start;
size_t len;
char *dir;
/*
* Skip scheme.
*/
start = strstr(repo, "://");
if (start == NULL)
start = repo;
else
start += 3;
/*
* Skip authentication data. The stripping does happen
* greedily, such that we strip up to the last '@' inside
* the host part.
*/
for (ptr = start; ptr < end && !is_dir_sep(*ptr); ptr++) {
if (*ptr == '@')
start = ptr + 1;
}
/*
* Strip trailing spaces, slashes and /.git
*/
while (start < end && (is_dir_sep(end[-1]) || isspace(end[-1])))
while (repo < end && (is_dir_sep(end[-1]) || isspace(end[-1])))
end--;
if (end - start > 5 && is_dir_sep(end[-5]) &&
if (end - repo > 5 && is_dir_sep(end[-5]) &&
!strncmp(end - 4, ".git", 4)) {
end -= 5;
while (start < end && is_dir_sep(end[-1]))
while (repo < end && is_dir_sep(end[-1]))
end--;
}
/*
* Strip trailing port number if we've got only a
* hostname (that is, there is no dir separator but a
* colon). This check is required such that we do not
* strip URI's like '/foo/bar:2222.git', which should
* result in a dir '2222' being guessed due to backwards
* compatibility.
* Find last component, but be prepared that repo could have
* the form "remote.example.com:foo.git", i.e. no slash
* in the directory part.
*/
if (memchr(start, '/', end - start) == NULL
&& memchr(start, ':', end - start) != NULL) {
ptr = end;
while (start < ptr && isdigit(ptr[-1]) && ptr[-1] != ':')
ptr--;
if (start < ptr && ptr[-1] == ':')
end = ptr - 1;
}
/*
* Find last component. To remain backwards compatible we
* also regard colons as path separators, such that
* cloning a repository 'foo:bar.git' would result in a
* directory 'bar' being guessed.
*/
ptr = end;
while (start < ptr && !is_dir_sep(ptr[-1]) && ptr[-1] != ':')
ptr--;
start = ptr;
start = end;
while (repo < start && !is_dir_sep(start[-1]) && start[-1] != ':')
start--;
/*
* Strip .{bundle,git}.
@ -230,10 +177,6 @@ static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
len = end - start;
strip_suffix_mem(start, &len, is_bundle ? ".bundle" : ".git");
if (!len || (len == 1 && *start == '/'))
die("No directory name could be guessed.\n"
"Please specify a directory on the command line");
if (is_bare)
dir = xstrfmt("%.*s.git", (int)len, start);
else
@ -542,26 +485,16 @@ static void write_remote_refs(const struct ref *local_refs)
{
const struct ref *r;
struct ref_transaction *t;
struct strbuf err = STRBUF_INIT;
t = ref_transaction_begin(&err);
if (!t)
die("%s", err.buf);
lock_packed_refs(LOCK_DIE_ON_ERROR);
for (r = local_refs; r; r = r->next) {
if (!r->peer_ref)
continue;
if (ref_transaction_create(t, r->peer_ref->name, r->old_sha1,
0, NULL, &err))
die("%s", err.buf);
add_packed_ref(r->peer_ref->name, r->old_sha1);
}
if (initial_ref_transaction_commit(t, &err))
die("%s", err.buf);
strbuf_release(&err);
ref_transaction_free(t);
if (commit_packed_refs())
die_errno("unable to overwrite old ref-pack file");
}
static void write_followtags(const struct ref *refs, const char *msg)

View File

@ -166,9 +166,9 @@ static int opt_parse_m(const struct option *opt, const char *arg, int unset)
static void determine_whence(struct wt_status *s)
{
if (file_exists(git_path_merge_head()))
if (file_exists(git_path("MERGE_HEAD")))
whence = FROM_MERGE;
else if (file_exists(git_path_cherry_pick_head())) {
else if (file_exists(git_path("CHERRY_PICK_HEAD"))) {
whence = FROM_CHERRY_PICK;
if (file_exists(git_path(SEQ_DIR)))
sequencer_in_use = 1;
@ -324,7 +324,6 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
struct string_list partial;
struct pathspec pathspec;
int refresh_flags = REFRESH_QUIET;
const char *ret;
if (is_status)
refresh_flags |= REFRESH_UNMERGED;
@ -345,7 +344,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
die(_("unable to create temporary index"));
old_index_env = getenv(INDEX_ENVIRONMENT);
setenv(INDEX_ENVIRONMENT, get_lock_file_path(&index_lock), 1);
setenv(INDEX_ENVIRONMENT, index_lock.filename.buf, 1);
if (interactive_add(argc, argv, prefix, patch_interactive) != 0)
die(_("interactive add failed"));
@ -356,7 +355,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
unsetenv(INDEX_ENVIRONMENT);
discard_cache();
read_cache_from(get_lock_file_path(&index_lock));
read_cache_from(index_lock.filename.buf);
if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) {
if (reopen_lock_file(&index_lock) < 0)
die(_("unable to write index file"));
@ -366,7 +365,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
warning(_("Failed to update main cache tree"));
commit_style = COMMIT_NORMAL;
return get_lock_file_path(&index_lock);
return index_lock.filename.buf;
}
/*
@ -389,7 +388,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
die(_("unable to write new_index file"));
commit_style = COMMIT_NORMAL;
return get_lock_file_path(&index_lock);
return index_lock.filename.buf;
}
/*
@ -474,9 +473,9 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
die(_("unable to write temporary index file"));
discard_cache();
ret = get_lock_file_path(&false_lock);
read_cache_from(ret);
return ret;
read_cache_from(false_lock.filename.buf);
return false_lock.filename.buf;
}
static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn,
@ -724,12 +723,12 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
format_commit_message(commit, "fixup! %s\n\n",
&sb, &ctx);
hook_arg1 = "message";
} else if (!stat(git_path_merge_msg(), &statbuf)) {
if (strbuf_read_file(&sb, git_path_merge_msg(), 0) < 0)
} else if (!stat(git_path("MERGE_MSG"), &statbuf)) {
if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0)
die_errno(_("could not read MERGE_MSG"));
hook_arg1 = "merge";
} else if (!stat(git_path_squash_msg(), &statbuf)) {
if (strbuf_read_file(&sb, git_path_squash_msg(), 0) < 0)
} else if (!stat(git_path("SQUASH_MSG"), &statbuf)) {
if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0)
die_errno(_("could not read SQUASH_MSG"));
hook_arg1 = "squash";
} else if (template_file) {
@ -855,7 +854,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
_("%s"
"Date: %s"),
ident_shown++ ? "" : "\n",
show_ident_date(&ai, DATE_MODE(NORMAL)));
show_ident_date(&ai, DATE_NORMAL));
if (!committer_ident_sufficiently_given())
status_printf_ln(s, GIT_COLOR_NORMAL,
@ -1045,7 +1044,7 @@ static const char *find_author_by_nickname(const char *name)
commit = get_revision(&revs);
if (commit) {
struct pretty_print_context ctx = {0};
ctx.date_mode.type = DATE_NORMAL;
ctx.date_mode = DATE_NORMAL;
strbuf_release(&buf);
format_commit_message(commit, "%aN <%aE>", &buf, &ctx);
clear_mailmap(&mailmap);
@ -1683,10 +1682,10 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (!reflog_msg)
reflog_msg = "commit (merge)";
pptr = &commit_list_insert(current_head, pptr)->next;
fp = fopen(git_path_merge_head(), "r");
fp = fopen(git_path("MERGE_HEAD"), "r");
if (fp == NULL)
die_errno(_("could not open '%s' for reading"),
git_path_merge_head());
git_path("MERGE_HEAD"));
while (strbuf_getline(&m, fp, '\n') != EOF) {
struct commit *parent;
@ -1697,8 +1696,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
}
fclose(fp);
strbuf_release(&m);
if (!stat(git_path_merge_mode(), &statbuf)) {
if (strbuf_read_file(&sb, git_path_merge_mode(), 0) < 0)
if (!stat(git_path("MERGE_MODE"), &statbuf)) {
if (strbuf_read_file(&sb, git_path("MERGE_MODE"), 0) < 0)
die_errno(_("could not read MERGE_MODE"));
if (!strcmp(sb.buf, "no-ff"))
allow_fast_forward = 0;
@ -1774,12 +1773,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
}
ref_transaction_free(transaction);
unlink(git_path_cherry_pick_head());
unlink(git_path_revert_head());
unlink(git_path_merge_head());
unlink(git_path_merge_msg());
unlink(git_path_merge_mode());
unlink(git_path_squash_msg());
unlink(git_path("CHERRY_PICK_HEAD"));
unlink(git_path("REVERT_HEAD"));
unlink(git_path("MERGE_HEAD"));
unlink(git_path("MERGE_MSG"));
unlink(git_path("MERGE_MODE"));
unlink(git_path("SQUASH_MSG"));
if (commit_index_files())
die (_("Repository has been updated, but unable to write\n"

View File

@ -13,7 +13,6 @@ static char *key;
static regex_t *key_regexp;
static regex_t *regexp;
static int show_keys;
static int omit_values;
static int use_key_regexp;
static int do_all;
static int do_not_match;
@ -79,7 +78,6 @@ static struct option builtin_config_options[] = {
OPT_BIT(0, "path", &types, N_("value is a path (file or directory name)"), TYPE_PATH),
OPT_GROUP(N_("Other")),
OPT_BOOL('z', "null", &end_null, N_("terminate values with NUL byte")),
OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
OPT_BOOL(0, "includes", &respect_includes, N_("respect include directives on lookup")),
OPT_END(),
};
@ -93,7 +91,7 @@ static void check_argc(int argc, int min, int max) {
static int show_all_config(const char *key_, const char *value_, void *cb)
{
if (!omit_values && value_)
if (value_)
printf("%s%c%s%c", key_, delim, value_, term);
else
printf("%s%c", key_, term);
@ -108,40 +106,48 @@ struct strbuf_list {
static int format_config(struct strbuf *buf, const char *key_, const char *value_)
{
if (show_keys)
strbuf_addstr(buf, key_);
if (!omit_values) {
if (show_keys)
strbuf_addch(buf, key_delim);
int must_free_vptr = 0;
int must_print_delim = 0;
char value[256];
const char *vptr = value;
if (types == TYPE_INT)
strbuf_addf(buf, "%"PRId64,
git_config_int64(key_, value_ ? value_ : ""));
else if (types == TYPE_BOOL)
strbuf_addstr(buf, git_config_bool(key_, value_) ?
"true" : "false");
else if (types == TYPE_BOOL_OR_INT) {
int is_bool, v;
v = git_config_bool_or_int(key_, value_, &is_bool);
if (is_bool)
strbuf_addstr(buf, v ? "true" : "false");
else
strbuf_addf(buf, "%d", v);
} else if (types == TYPE_PATH) {
const char *v;
if (git_config_pathname(&v, key_, value_) < 0)
return -1;
strbuf_addstr(buf, v);
free((char *)v);
} else if (value_) {
strbuf_addstr(buf, value_);
} else {
/* Just show the key name; back out delimiter */
if (show_keys)
strbuf_setlen(buf, buf->len - 1);
}
strbuf_init(buf, 0);
if (show_keys) {
strbuf_addstr(buf, key_);
must_print_delim = 1;
}
if (types == TYPE_INT)
sprintf(value, "%"PRId64,
git_config_int64(key_, value_ ? value_ : ""));
else if (types == TYPE_BOOL)
vptr = git_config_bool(key_, value_) ? "true" : "false";
else if (types == TYPE_BOOL_OR_INT) {
int is_bool, v;
v = git_config_bool_or_int(key_, value_, &is_bool);
if (is_bool)
vptr = v ? "true" : "false";
else
sprintf(value, "%d", v);
} else if (types == TYPE_PATH) {
if (git_config_pathname(&vptr, key_, value_) < 0)
return -1;
must_free_vptr = 1;
} else if (value_) {
vptr = value_;
} else {
/* Just show the key name */
vptr = "";
must_print_delim = 0;
}
if (must_print_delim)
strbuf_addch(buf, key_delim);
strbuf_addstr(buf, vptr);
strbuf_addch(buf, term);
if (must_free_vptr)
free((char *)vptr);
return 0;
}
@ -158,7 +164,6 @@ static int collect_config(const char *key_, const char *value_, void *cb)
return 0;
ALLOC_GROW(values->items, values->nr + 1, values->alloc);
strbuf_init(&values->items[values->nr], 0);
return format_config(&values->items[values->nr++], key_, value_);
}
@ -425,11 +430,14 @@ static int get_urlmatch(const char *var, const char *url)
for_each_string_list_item(item, &values) {
struct urlmatch_current_candidate_value *matched = item->util;
struct strbuf key = STRBUF_INIT;
struct strbuf buf = STRBUF_INIT;
format_config(&buf, item->string,
strbuf_addstr(&key, item->string);
format_config(&buf, key.buf,
matched->value_is_null ? NULL : matched->value.buf);
fwrite(buf.buf, 1, buf.len, stdout);
strbuf_release(&key);
strbuf_release(&buf);
strbuf_release(&matched->value);
@ -541,11 +549,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
default:
usage_with_options(builtin_config_usage, builtin_config_options);
}
if (omit_values &&
!(actions == ACTION_LIST || actions == ACTION_GET_REGEXP)) {
error("--name-only is only applicable to --list or --get-regexp");
usage_with_options(builtin_config_usage, builtin_config_options);
}
if (actions == ACTION_LIST) {
check_argc(argc, 0, 0);
if (git_config_with_options(show_all_config, NULL,

View File

@ -443,10 +443,10 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
if (pattern)
argv_array_pushf(&args, "--refs=refs/tags/%s", pattern);
}
if (argc)
argv_array_pushv(&args, argv);
else
argv_array_push(&args, "HEAD");
while (*argv) {
argv_array_push(&args, *argv);
argv++;
}
return cmd_name_rev(args.argc, args.argv, prefix);
}

View File

@ -5,7 +5,6 @@
*/
#include "builtin.h"
#include "cache.h"
#include "refs.h"
#include "commit.h"
#include "object.h"
#include "tag.h"

View File

@ -11,7 +11,6 @@
#include "run-command.h"
#include "parse-options.h"
#include "sigchain.h"
#include "submodule-config.h"
#include "submodule.h"
#include "connected.h"
#include "argv-array.h"
@ -592,7 +591,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
const char *what, *kind;
struct ref *rm;
char *url;
const char *filename = dry_run ? "/dev/null" : git_path_fetch_head();
const char *filename = dry_run ? "/dev/null" : git_path("FETCH_HEAD");
int want_status;
fp = fopen(filename, "a");
@ -791,29 +790,20 @@ static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map,
if (4 < i && !strncmp(".git", url + i - 3, 4))
url_len = i - 3;
if (!dry_run) {
struct string_list refnames = STRING_LIST_INIT_NODUP;
for (ref = stale_refs; ref; ref = ref->next)
string_list_append(&refnames, ref->name);
result = delete_refs(&refnames);
string_list_clear(&refnames, 0);
}
if (verbosity >= 0) {
for (ref = stale_refs; ref; ref = ref->next) {
if (!shown_url) {
fprintf(stderr, _("From %.*s\n"), url_len, url);
shown_url = 1;
}
for (ref = stale_refs; ref; ref = ref->next) {
if (!dry_run)
result |= delete_ref(ref->name, NULL, 0);
if (verbosity >= 0 && !shown_url) {
fprintf(stderr, _("From %.*s\n"), url_len, url);
shown_url = 1;
}
if (verbosity >= 0) {
fprintf(stderr, " x %-*s %-*s -> %s\n",
TRANSPORT_SUMMARY(_("[deleted]")),
REFCOL_WIDTH, _("(none)"), prettify_refname(ref->name));
warn_dangling_symref(stderr, dangling_msg, ref->name);
}
}
free(url);
free_refs(stale_refs);
return result;
@ -835,7 +825,7 @@ static void check_not_current_branch(struct ref *ref_map)
static int truncate_fetch_head(void)
{
const char *filename = git_path_fetch_head();
const char *filename = git_path("FETCH_HEAD");
FILE *fp = fopen(filename, "w");
if (!fp)

View File

@ -1,6 +1,5 @@
#include "builtin.h"
#include "cache.h"
#include "refs.h"
#include "commit.h"
#include "diff.h"
#include "revision.h"

File diff suppressed because it is too large Load Diff

View File

@ -23,11 +23,8 @@ static int show_tags;
static int show_unreachable;
static int include_reflogs = 1;
static int check_full = 1;
static int connectivity_only;
static int check_strict;
static int keep_cache_objects;
static struct fsck_options fsck_walk_options = FSCK_OPTIONS_DEFAULT;
static struct fsck_options fsck_obj_options = FSCK_OPTIONS_DEFAULT;
static struct object_id head_oid;
static const char *head_points_at;
static int errors_found;
@ -47,52 +44,39 @@ static int show_dangling = 1;
#define DIRENT_SORT_HINT(de) ((de)->d_ino)
#endif
static int fsck_config(const char *var, const char *value, void *cb)
static void objreport(struct object *obj, const char *severity,
const char *err, va_list params)
{
if (strcmp(var, "fsck.skiplist") == 0) {
const char *path;
struct strbuf sb = STRBUF_INIT;
if (git_config_pathname(&path, var, value))
return 1;
strbuf_addf(&sb, "skiplist=%s", path);
free((char *)path);
fsck_set_msg_types(&fsck_obj_options, sb.buf);
strbuf_release(&sb);
return 0;
}
if (skip_prefix(var, "fsck.", &var)) {
fsck_set_msg_type(&fsck_obj_options, var, value);
return 0;
}
return git_default_config(var, value, cb);
fprintf(stderr, "%s in %s %s: ",
severity, typename(obj->type), sha1_to_hex(obj->sha1));
vfprintf(stderr, err, params);
fputs("\n", stderr);
}
static void objreport(struct object *obj, const char *msg_type,
const char *err)
{
fprintf(stderr, "%s in %s %s: %s\n",
msg_type, typename(obj->type), sha1_to_hex(obj->sha1), err);
}
static int objerror(struct object *obj, const char *err)
__attribute__((format (printf, 2, 3)))
static int objerror(struct object *obj, const char *err, ...)
{
va_list params;
va_start(params, err);
errors_found |= ERROR_OBJECT;
objreport(obj, "error", err);
objreport(obj, "error", err, params);
va_end(params);
return -1;
}
static int fsck_error_func(struct object *obj, int type, const char *message)
__attribute__((format (printf, 3, 4)))
static int fsck_error_func(struct object *obj, int type, const char *err, ...)
{
objreport(obj, (type == FSCK_WARN) ? "warning" : "error", message);
va_list params;
va_start(params, err);
objreport(obj, (type == FSCK_WARN) ? "warning" : "error", err, params);
va_end(params);
return (type == FSCK_WARN) ? 0 : 1;
}
static struct object_array pending;
static int mark_object(struct object *obj, int type, void *data, struct fsck_options *options)
static int mark_object(struct object *obj, int type, void *data)
{
struct object *parent = data;
@ -135,7 +119,7 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt
static void mark_object_reachable(struct object *obj)
{
mark_object(obj, OBJ_ANY, NULL, NULL);
mark_object(obj, OBJ_ANY, NULL);
}
static int traverse_one_object(struct object *obj)
@ -148,7 +132,7 @@ static int traverse_one_object(struct object *obj)
if (parse_tree(tree) < 0)
return 1; /* error already displayed */
}
result = fsck_walk(obj, obj, &fsck_walk_options);
result = fsck_walk(obj, mark_object, obj);
if (tree)
free_tree_buffer(tree);
return result;
@ -174,7 +158,7 @@ static int traverse_reachable(void)
return !!result;
}
static int mark_used(struct object *obj, int type, void *data, struct fsck_options *options)
static int mark_used(struct object *obj, int type, void *data)
{
if (!obj)
return 1;
@ -195,8 +179,6 @@ static void check_reachable_object(struct object *obj)
if (!(obj->flags & HAS_OBJ)) {
if (has_sha1_pack(obj->sha1))
return; /* it is in pack - forget about it */
if (connectivity_only && has_sha1_file(obj->sha1))
return;
printf("missing %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1));
errors_found |= ERROR_REACHABLE;
return;
@ -243,14 +225,13 @@ static void check_unreachable_object(struct object *obj)
printf("dangling %s %s\n", typename(obj->type),
sha1_to_hex(obj->sha1));
if (write_lost_and_found) {
char *filename = git_pathdup("lost-found/%s/%s",
const char *filename = git_path("lost-found/%s/%s",
obj->type == OBJ_COMMIT ? "commit" : "other",
sha1_to_hex(obj->sha1));
FILE *f;
if (safe_create_leading_directories_const(filename)) {
error("Could not create lost-found");
free(filename);
return;
}
if (!(f = fopen(filename, "w")))
@ -263,7 +244,6 @@ static void check_unreachable_object(struct object *obj)
if (fclose(f))
die_errno("Could not finish '%s'",
filename);
free(filename);
}
return;
}
@ -316,9 +296,9 @@ static int fsck_obj(struct object *obj)
fprintf(stderr, "Checking %s %s\n",
typename(obj->type), sha1_to_hex(obj->sha1));
if (fsck_walk(obj, NULL, &fsck_obj_options))
if (fsck_walk(obj, mark_used, NULL))
objerror(obj, "broken links");
if (fsck_object(obj, NULL, 0, &fsck_obj_options))
if (fsck_object(obj, NULL, 0, check_strict, fsck_error_func))
return -1;
if (obj->type == OBJ_TREE) {
@ -641,7 +621,6 @@ static struct option fsck_opts[] = {
OPT_BOOL(0, "cache", &keep_cache_objects, N_("make index objects head nodes")),
OPT_BOOL(0, "reflogs", &include_reflogs, N_("make reflogs head nodes (default)")),
OPT_BOOL(0, "full", &check_full, N_("also consider packs and alternate objects")),
OPT_BOOL(0, "connectivity-only", &connectivity_only, N_("check only connectivity")),
OPT_BOOL(0, "strict", &check_strict, N_("enable more strict checking")),
OPT_BOOL(0, "lost-found", &write_lost_and_found,
N_("write dangling objects in .git/lost-found")),
@ -659,12 +638,6 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0);
fsck_walk_options.walk = mark_object;
fsck_obj_options.walk = mark_used;
fsck_obj_options.error_func = fsck_error_func;
if (check_strict)
fsck_obj_options.strict = 1;
if (show_progress == -1)
show_progress = isatty(2);
if (verbose)
@ -675,11 +648,8 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
include_reflogs = 0;
}
git_config(fsck_config, NULL);
fsck_head_link();
if (!connectivity_only)
fsck_object_dir(get_object_directory());
fsck_object_dir(get_object_directory());
prepare_alt_odb();
for (alt = alt_odb_list; alt; alt = alt->next) {

View File

@ -11,7 +11,6 @@
*/
#include "builtin.h"
#include "tempfile.h"
#include "lockfile.h"
#include "parse-options.h"
#include "run-command.h"
@ -43,7 +42,20 @@ static struct argv_array prune = ARGV_ARRAY_INIT;
static struct argv_array prune_worktrees = ARGV_ARRAY_INIT;
static struct argv_array rerere = ARGV_ARRAY_INIT;
static struct tempfile pidfile;
static char *pidfile;
static void remove_pidfile(void)
{
if (pidfile)
unlink(pidfile);
}
static void remove_pidfile_on_signal(int signo)
{
remove_pidfile();
sigchain_pop(signo);
raise(signo);
}
static void git_config_date_string(const char *key, const char **output)
{
@ -73,7 +85,7 @@ static void gc_config(void)
git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit);
git_config_get_bool("gc.autodetach", &detach_auto);
git_config_date_string("gc.pruneexpire", &prune_expire);
git_config_date_string("gc.worktreepruneexpire", &prune_worktrees_expire);
git_config_date_string("gc.pruneworktreesexpire", &prune_worktrees_expire);
git_config(git_default_config, NULL);
}
@ -187,22 +199,20 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
uintmax_t pid;
FILE *fp;
int fd;
char *pidfile_path;
if (is_tempfile_active(&pidfile))
if (pidfile)
/* already locked */
return NULL;
if (gethostname(my_host, sizeof(my_host)))
strcpy(my_host, "unknown");
pidfile_path = git_pathdup("gc.pid");
fd = hold_lock_file_for_update(&lock, pidfile_path,
fd = hold_lock_file_for_update(&lock, git_path("gc.pid"),
LOCK_DIE_ON_ERROR);
if (!force) {
static char locking_host[128];
int should_exit;
fp = fopen(pidfile_path, "r");
fp = fopen(git_path("gc.pid"), "r");
memset(locking_host, 0, sizeof(locking_host));
should_exit =
fp != NULL &&
@ -226,7 +236,6 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
if (fd >= 0)
rollback_lock_file(&lock);
*ret_pid = pid;
free(pidfile_path);
return locking_host;
}
}
@ -236,8 +245,11 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
write_in_full(fd, sb.buf, sb.len);
strbuf_release(&sb);
commit_lock_file(&lock);
register_tempfile(&pidfile, pidfile_path);
free(pidfile_path);
pidfile = git_pathdup("gc.pid");
sigchain_push_common(remove_pidfile_on_signal);
atexit(remove_pidfile);
return NULL;
}

View File

@ -75,7 +75,6 @@ static int nr_threads;
static int from_stdin;
static int strict;
static int do_fsck_object;
static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
static int verbose;
static int show_stat;
static int check_self_contained_and_connected;
@ -193,7 +192,7 @@ static void cleanup_thread(void)
#endif
static int mark_link(struct object *obj, int type, void *data, struct fsck_options *options)
static int mark_link(struct object *obj, int type, void *data)
{
if (!obj)
return -1;
@ -839,9 +838,10 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
if (!obj)
die(_("invalid %s"), typename(type));
if (do_fsck_object &&
fsck_object(obj, buf, size, &fsck_options))
fsck_object(obj, buf, size, 1,
fsck_error_function))
die(_("Error in object"));
if (fsck_walk(obj, NULL, &fsck_options))
if (fsck_walk(obj, mark_link, NULL))
die(_("Not all child objects of %s are reachable"), sha1_to_hex(obj->sha1));
if (obj->type == OBJ_TREE) {
@ -1421,7 +1421,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
get_object_directory(), sha1_to_hex(sha1));
final_pack_name = name;
}
if (finalize_object_file(curr_pack_name, final_pack_name))
if (move_temp_to_file(curr_pack_name, final_pack_name))
die(_("cannot store pack file"));
} else if (from_stdin)
chmod(final_pack_name, 0444);
@ -1432,7 +1432,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
get_object_directory(), sha1_to_hex(sha1));
final_index_name = name;
}
if (finalize_object_file(curr_index_name, final_index_name))
if (move_temp_to_file(curr_index_name, final_index_name))
die(_("cannot store index file"));
} else
chmod(final_index_name, 0444);
@ -1615,7 +1615,6 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
usage(index_pack_usage);
check_replace_refs = 0;
fsck_options.walk = mark_link;
reset_pack_idx_option(&opts);
git_config(git_index_pack_config, &opts);
@ -1633,10 +1632,6 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
} else if (!strcmp(arg, "--strict")) {
strict = 1;
do_fsck_object = 1;
} else if (skip_prefix(arg, "--strict=", &arg)) {
strict = 1;
do_fsck_object = 1;
fsck_set_msg_types(&fsck_options, arg);
} else if (!strcmp(arg, "--check-self-contained-and-connected")) {
strict = 1;
check_self_contained_and_connected = 1;

View File

@ -4,7 +4,6 @@
* Copyright (C) Linus Torvalds, 2005
*/
#include "cache.h"
#include "refs.h"
#include "builtin.h"
#include "exec_cmd.h"
#include "parse-options.h"
@ -378,7 +377,7 @@ static void separate_git_dir(const char *git_dir)
die_errno(_("unable to move %s to %s"), src, git_dir);
}
write_file(git_link, "gitdir: %s", git_dir);
write_file(git_link, 1, "gitdir: %s\n", git_dir);
}
int init_db(const char *template_dir, unsigned int flags)

View File

@ -5,7 +5,6 @@
* 2006 Junio Hamano
*/
#include "cache.h"
#include "refs.h"
#include "color.h"
#include "commit.h"
#include "diff.h"
@ -32,7 +31,6 @@ static const char *default_date_mode = NULL;
static int default_abbrev_commit;
static int default_show_root = 1;
static int default_follow;
static int decoration_style;
static int decoration_given;
static int use_mailmap_config;
@ -104,8 +102,6 @@ static void cmd_log_init_defaults(struct rev_info *rev)
{
if (fmt_pretty)
get_commit_format(fmt_pretty, rev);
if (default_follow)
DIFF_OPT_SET(&rev->diffopt, DEFAULT_FOLLOW_RENAMES);
rev->verbose_header = 1;
DIFF_OPT_SET(&rev->diffopt, RECURSIVE);
rev->diffopt.stat_width = -1; /* use full terminal width */
@ -116,7 +112,7 @@ static void cmd_log_init_defaults(struct rev_info *rev)
DIFF_OPT_SET(&rev->diffopt, ALLOW_TEXTCONV);
if (default_date_mode)
parse_date_format(default_date_mode, &rev->date_mode);
rev->date_mode = parse_date_format(default_date_mode);
rev->diffopt.touched_flags = 0;
}
@ -342,7 +338,8 @@ static int cmd_log_walk(struct rev_info *rev)
* retain that state information if replacing rev->diffopt in this loop
*/
while ((commit = get_revision(rev)) != NULL) {
if (!log_tree_commit(rev, commit) && rev->max_count >= 0)
if (!log_tree_commit(rev, commit) &&
rev->max_count >= 0)
/*
* We decremented max_count in get_revision,
* but we didn't actually show the commit.
@ -393,10 +390,6 @@ static int git_log_config(const char *var, const char *value, void *cb)
default_show_root = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "log.follow")) {
default_follow = git_config_bool(var, value);
return 0;
}
if (skip_prefix(var, "color.decorate.", &slot_name))
return parse_decorate_color_config(var, slot_name, value);
if (!strcmp(var, "log.mailmap")) {
@ -503,8 +496,7 @@ static int show_tree_object(const unsigned char *sha1,
return 0;
}
static void show_setup_revisions_tweak(struct rev_info *rev,
struct setup_revision_opt *opt)
static void show_rev_tweak_rev(struct rev_info *rev, struct setup_revision_opt *opt)
{
if (rev->ignore_merges) {
/* There was no "-m" on the command line */
@ -539,7 +531,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
opt.tweak = show_setup_revisions_tweak;
opt.tweak = show_rev_tweak_rev;
cmd_log_init(argc, argv, prefix, &rev, &opt);
if (!rev.no_walk)
@ -626,22 +618,6 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
return cmd_log_walk(&rev);
}
static void log_setup_revisions_tweak(struct rev_info *rev,
struct setup_revision_opt *opt)
{
if (DIFF_OPT_TST(&rev->diffopt, DEFAULT_FOLLOW_RENAMES) &&
rev->prune_data.nr == 1)
DIFF_OPT_SET(&rev->diffopt, FOLLOW_RENAMES);
/* Turn --cc/-c into -p --cc/-c when -p was not given */
if (!rev->diffopt.output_format && rev->combine_merges)
rev->diffopt.output_format = DIFF_FORMAT_PATCH;
/* Turn -m on when --cc/-c was given */
if (rev->combine_merges)
rev->ignore_merges = 0;
}
int cmd_log(int argc, const char **argv, const char *prefix)
{
struct rev_info rev;
@ -655,7 +631,6 @@ int cmd_log(int argc, const char **argv, const char *prefix)
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
opt.revarg_opt = REVARG_COMMITTISH;
opt.tweak = log_setup_revisions_tweak;
cmd_log_init(argc, argv, prefix, &rev, &opt);
return cmd_log_walk(&rev);
}
@ -964,7 +939,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
msg = body;
pp.fmt = CMIT_FMT_EMAIL;
pp.date_mode.type = DATE_RFC2822;
pp.date_mode = DATE_RFC2822;
pp_user_info(&pp, NULL, &sb, committer, encoding);
pp_title_line(&pp, &msg, &sb, encoding, need_8bit_cte);
pp_remainder(&pp, &msg, &sb, 0);
@ -1463,7 +1438,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
continue;
}
if (ignore_if_in_upstream && has_commit_patch_id(commit, &ids))
if (ignore_if_in_upstream &&
has_commit_patch_id(commit, &ids))
continue;
nr++;

View File

@ -231,9 +231,9 @@ static struct option builtin_merge_options[] = {
/* Cleans up metadata that is uninteresting after a succeeded merge. */
static void drop_save(void)
{
unlink(git_path_merge_head());
unlink(git_path_merge_msg());
unlink(git_path_merge_mode());
unlink(git_path("MERGE_HEAD"));
unlink(git_path("MERGE_MSG"));
unlink(git_path("MERGE_MODE"));
}
static int save_state(unsigned char *stash)
@ -338,7 +338,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead
struct pretty_print_context ctx = {0};
printf(_("Squash commit -- not updating HEAD\n"));
filename = git_path_squash_msg();
filename = git_path("SQUASH_MSG");
fd = open(filename, O_WRONLY | O_CREAT, 0666);
if (fd < 0)
die_errno(_("Could not write to '%s'"), filename);
@ -754,7 +754,7 @@ static void add_strategies(const char *string, unsigned attr)
static void write_merge_msg(struct strbuf *msg)
{
const char *filename = git_path_merge_msg();
const char *filename = git_path("MERGE_MSG");
int fd = open(filename, O_WRONLY | O_CREAT, 0666);
if (fd < 0)
die_errno(_("Could not open '%s' for writing"),
@ -766,7 +766,7 @@ static void write_merge_msg(struct strbuf *msg)
static void read_merge_msg(struct strbuf *msg)
{
const char *filename = git_path_merge_msg();
const char *filename = git_path("MERGE_MSG");
strbuf_reset(msg);
if (strbuf_read_file(msg, filename, 0) < 0)
die_errno(_("Could not read from '%s'"), filename);
@ -799,10 +799,10 @@ static void prepare_to_commit(struct commit_list *remoteheads)
strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
write_merge_msg(&msg);
if (run_commit_hook(0 < option_edit, get_index_file(), "prepare-commit-msg",
git_path_merge_msg(), "merge", NULL))
git_path("MERGE_MSG"), "merge", NULL))
abort_commit(remoteheads, NULL);
if (0 < option_edit) {
if (launch_editor(git_path_merge_msg(), NULL, NULL))
if (launch_editor(git_path("MERGE_MSG"), NULL, NULL))
abort_commit(remoteheads, NULL);
}
read_merge_msg(&msg);
@ -865,7 +865,7 @@ static int suggest_conflicts(void)
FILE *fp;
struct strbuf msgbuf = STRBUF_INIT;
filename = git_path_merge_msg();
filename = git_path("MERGE_MSG");
fp = fopen(filename, "a");
if (!fp)
die_errno(_("Could not open '%s' for writing"), filename);
@ -967,7 +967,7 @@ static void write_merge_state(struct commit_list *remoteheads)
}
strbuf_addf(&buf, "%s\n", sha1_to_hex(sha1));
}
filename = git_path_merge_head();
filename = git_path("MERGE_HEAD");
fd = open(filename, O_WRONLY | O_CREAT, 0666);
if (fd < 0)
die_errno(_("Could not open '%s' for writing"), filename);
@ -977,7 +977,7 @@ static void write_merge_state(struct commit_list *remoteheads)
strbuf_addch(&merge_msg, '\n');
write_merge_msg(&merge_msg);
filename = git_path_merge_mode();
filename = git_path("MERGE_MODE");
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0)
die_errno(_("Could not open '%s' for writing"), filename);
@ -1070,7 +1070,7 @@ static void handle_fetch_head(struct commit_list **remotes, struct strbuf *merge
if (!merge_names)
merge_names = &fetch_head_file;
filename = git_path_fetch_head();
filename = git_path("FETCH_HEAD");
fd = open(filename, O_RDONLY);
if (fd < 0)
die_errno(_("could not open '%s' for reading"), filename);
@ -1204,7 +1204,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
int nargc = 2;
const char *nargv[] = {"reset", "--merge", NULL};
if (!file_exists(git_path_merge_head()))
if (!file_exists(git_path("MERGE_HEAD")))
die(_("There is no merge to abort (MERGE_HEAD missing)."));
/* Invoke 'git reset --merge' */
@ -1215,7 +1215,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (read_cache_unmerged())
die_resolve_conflict("merge");
if (file_exists(git_path_merge_head())) {
if (file_exists(git_path("MERGE_HEAD"))) {
/*
* There is no unmerged entry, don't advise 'git
* add/rm <file>', just 'git commit'.
@ -1226,7 +1226,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
else
die(_("You have not concluded your merge (MERGE_HEAD exists)."));
}
if (file_exists(git_path_cherry_pick_head())) {
if (file_exists(git_path("CHERRY_PICK_HEAD"))) {
if (advice_resolve_conflict)
die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
"Please, commit your changes before you merge."));

View File

@ -19,7 +19,6 @@
#include "string-list.h"
#include "notes-merge.h"
#include "notes-utils.h"
#include "branch.h"
static const char * const git_notes_usage[] = {
N_("git notes [--ref <notes-ref>] [list [<object>]]"),
@ -738,19 +737,6 @@ static int merge_commit(struct notes_merge_options *o)
return ret;
}
static int git_config_get_notes_strategy(const char *key,
enum notes_merge_strategy *strategy)
{
const char *value;
if (git_config_get_string_const(key, &value))
return 1;
if (parse_notes_merge_strategy(value, strategy))
git_die_config(key, "unknown notes merge strategy %s", value);
return 0;
}
static int merge(int argc, const char **argv, const char *prefix)
{
struct strbuf remote_ref = STRBUF_INIT, msg = STRBUF_INIT;
@ -809,29 +795,25 @@ static int merge(int argc, const char **argv, const char *prefix)
expand_notes_ref(&remote_ref);
o.remote_ref = remote_ref.buf;
t = init_notes_check("merge");
if (strategy) {
if (parse_notes_merge_strategy(strategy, &o.strategy)) {
if (!strcmp(strategy, "manual"))
o.strategy = NOTES_MERGE_RESOLVE_MANUAL;
else if (!strcmp(strategy, "ours"))
o.strategy = NOTES_MERGE_RESOLVE_OURS;
else if (!strcmp(strategy, "theirs"))
o.strategy = NOTES_MERGE_RESOLVE_THEIRS;
else if (!strcmp(strategy, "union"))
o.strategy = NOTES_MERGE_RESOLVE_UNION;
else if (!strcmp(strategy, "cat_sort_uniq"))
o.strategy = NOTES_MERGE_RESOLVE_CAT_SORT_UNIQ;
else {
error("Unknown -s/--strategy: %s", strategy);
usage_with_options(git_notes_merge_usage, options);
}
} else {
struct strbuf merge_key = STRBUF_INIT;
const char *short_ref = NULL;
if (!skip_prefix(o.local_ref, "refs/notes/", &short_ref))
die("BUG: local ref %s is outside of refs/notes/",
o.local_ref);
strbuf_addf(&merge_key, "notes.%s.mergeStrategy", short_ref);
if (git_config_get_notes_strategy(merge_key.buf, &o.strategy))
git_config_get_notes_strategy("notes.mergeStrategy", &o.strategy);
strbuf_release(&merge_key);
}
t = init_notes_check("merge");
strbuf_addf(&msg, "notes: Merged notes from %s into %s",
remote_ref.buf, default_notes_ref());
strbuf_add(&(o.commit_msg), msg.buf + 7, msg.len - 7); /* skip "notes: " */
@ -843,15 +825,10 @@ static int merge(int argc, const char **argv, const char *prefix)
update_ref(msg.buf, default_notes_ref(), result_sha1, NULL,
0, UPDATE_REFS_DIE_ON_ERR);
else { /* Merge has unresolved conflicts */
char *existing;
/* Update .git/NOTES_MERGE_PARTIAL with partial merge result */
update_ref(msg.buf, "NOTES_MERGE_PARTIAL", result_sha1, NULL,
0, UPDATE_REFS_DIE_ON_ERR);
/* Store ref-to-be-updated into .git/NOTES_MERGE_REF */
existing = find_shared_symref("NOTES_MERGE_REF", default_notes_ref());
if (existing)
die(_("A notes merge into %s is already in-progress at %s"),
default_notes_ref(), existing);
if (create_symref("NOTES_MERGE_REF", default_notes_ref(), NULL))
die("Failed to store link to current notes ref (%s)",
default_notes_ref());

View File

@ -25,8 +25,8 @@
#include "argv-array.h"
static const char *pack_usage[] = {
N_("git pack-objects --stdout [<options>...] [< <ref-list> | < <object-list>]"),
N_("git pack-objects [<options>...] <base-name> [< <ref-list> | < <object-list>]"),
N_("git pack-objects --stdout [options...] [< ref-list | < object-list]"),
N_("git pack-objects [options...] base-name [< ref-list | < object-list]"),
NULL
};
@ -2588,6 +2588,23 @@ static int option_parse_unpack_unreachable(const struct option *opt,
return 0;
}
static int option_parse_ulong(const struct option *opt,
const char *arg, int unset)
{
if (unset)
die(_("option %s does not accept negative form"),
opt->long_name);
if (!git_parse_ulong(arg, opt->value))
die(_("unable to parse value '%s' for option %s"),
arg, opt->long_name);
return 0;
}
#define OPT_ULONG(s, l, v, h) \
{ OPTION_CALLBACK, (s), (l), (v), "n", (h), \
PARSE_OPT_NONEG, option_parse_ulong }
int cmd_pack_objects(int argc, const char **argv, const char *prefix)
{
int use_internal_rev_list = 0;
@ -2610,16 +2627,16 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
{ OPTION_CALLBACK, 0, "index-version", NULL, N_("version[,offset]"),
N_("write the pack index file in the specified idx format version"),
0, option_parse_index_version },
OPT_MAGNITUDE(0, "max-pack-size", &pack_size_limit,
N_("maximum size of each output pack file")),
OPT_ULONG(0, "max-pack-size", &pack_size_limit,
N_("maximum size of each output pack file")),
OPT_BOOL(0, "local", &local,
N_("ignore borrowed objects from alternate object store")),
OPT_BOOL(0, "incremental", &incremental,
N_("ignore packed objects")),
OPT_INTEGER(0, "window", &window,
N_("limit pack window by objects")),
OPT_MAGNITUDE(0, "window-memory", &window_memory_limit,
N_("limit pack window by memory in addition to object limit")),
OPT_ULONG(0, "window-memory", &window_memory_limit,
N_("limit pack window by memory in addition to object limit")),
OPT_INTEGER(0, "depth", &depth,
N_("maximum length of delta chain allowed in the resulting pack")),
OPT_BOOL(0, "reuse-delta", &reuse_delta,

View File

@ -1,887 +0,0 @@
/*
* Builtin "git pull"
*
* Based on git-pull.sh by Junio C Hamano
*
* Fetch one or more remote refs and merge it/them into the current HEAD.
*/
#include "cache.h"
#include "builtin.h"
#include "parse-options.h"
#include "exec_cmd.h"
#include "run-command.h"
#include "sha1-array.h"
#include "remote.h"
#include "dir.h"
#include "refs.h"
#include "revision.h"
#include "tempfile.h"
#include "lockfile.h"
enum rebase_type {
REBASE_INVALID = -1,
REBASE_FALSE = 0,
REBASE_TRUE,
REBASE_PRESERVE
};
/**
* Parses the value of --rebase. If value is a false value, returns
* REBASE_FALSE. If value is a true value, returns REBASE_TRUE. If value is
* "preserve", returns REBASE_PRESERVE. If value is a invalid value, dies with
* a fatal error if fatal is true, otherwise returns REBASE_INVALID.
*/
static enum rebase_type parse_config_rebase(const char *key, const char *value,
int fatal)
{
int v = git_config_maybe_bool("pull.rebase", value);
if (!v)
return REBASE_FALSE;
else if (v > 0)
return REBASE_TRUE;
else if (!strcmp(value, "preserve"))
return REBASE_PRESERVE;
if (fatal)
die(_("Invalid value for %s: %s"), key, value);
else
error(_("Invalid value for %s: %s"), key, value);
return REBASE_INVALID;
}
/**
* Callback for --rebase, which parses arg with parse_config_rebase().
*/
static int parse_opt_rebase(const struct option *opt, const char *arg, int unset)
{
enum rebase_type *value = opt->value;
if (arg)
*value = parse_config_rebase("--rebase", arg, 0);
else
*value = unset ? REBASE_FALSE : REBASE_TRUE;
return *value == REBASE_INVALID ? -1 : 0;
}
static const char * const pull_usage[] = {
N_("git pull [options] [<repository> [<refspec>...]]"),
NULL
};
/* Shared options */
static int opt_verbosity;
static char *opt_progress;
/* Options passed to git-merge or git-rebase */
static enum rebase_type opt_rebase = -1;
static char *opt_diffstat;
static char *opt_log;
static char *opt_squash;
static char *opt_commit;
static char *opt_edit;
static char *opt_ff;
static char *opt_verify_signatures;
static struct argv_array opt_strategies = ARGV_ARRAY_INIT;
static struct argv_array opt_strategy_opts = ARGV_ARRAY_INIT;
static char *opt_gpg_sign;
/* Options passed to git-fetch */
static char *opt_all;
static char *opt_append;
static char *opt_upload_pack;
static int opt_force;
static char *opt_tags;
static char *opt_prune;
static char *opt_recurse_submodules;
static int opt_dry_run;
static char *opt_keep;
static char *opt_depth;
static char *opt_unshallow;
static char *opt_update_shallow;
static char *opt_refmap;
static struct option pull_options[] = {
/* Shared options */
OPT__VERBOSITY(&opt_verbosity),
OPT_PASSTHRU(0, "progress", &opt_progress, NULL,
N_("force progress reporting"),
PARSE_OPT_NOARG),
/* Options passed to git-merge or git-rebase */
OPT_GROUP(N_("Options related to merging")),
{ OPTION_CALLBACK, 'r', "rebase", &opt_rebase,
N_("false|true|preserve"),
N_("incorporate changes by rebasing rather than merging"),
PARSE_OPT_OPTARG, parse_opt_rebase },
OPT_PASSTHRU('n', NULL, &opt_diffstat, NULL,
N_("do not show a diffstat at the end of the merge"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG),
OPT_PASSTHRU(0, "stat", &opt_diffstat, NULL,
N_("show a diffstat at the end of the merge"),
PARSE_OPT_NOARG),
OPT_PASSTHRU(0, "summary", &opt_diffstat, NULL,
N_("(synonym to --stat)"),
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN),
OPT_PASSTHRU(0, "log", &opt_log, N_("n"),
N_("add (at most <n>) entries from shortlog to merge commit message"),
PARSE_OPT_OPTARG),
OPT_PASSTHRU(0, "squash", &opt_squash, NULL,
N_("create a single commit instead of doing a merge"),
PARSE_OPT_NOARG),
OPT_PASSTHRU(0, "commit", &opt_commit, NULL,
N_("perform a commit if the merge succeeds (default)"),
PARSE_OPT_NOARG),
OPT_PASSTHRU(0, "edit", &opt_edit, NULL,
N_("edit message before committing"),
PARSE_OPT_NOARG),
OPT_PASSTHRU(0, "ff", &opt_ff, NULL,
N_("allow fast-forward"),
PARSE_OPT_NOARG),
OPT_PASSTHRU(0, "ff-only", &opt_ff, NULL,
N_("abort if fast-forward is not possible"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG),
OPT_PASSTHRU(0, "verify-signatures", &opt_verify_signatures, NULL,
N_("verify that the named commit has a valid GPG signature"),
PARSE_OPT_NOARG),
OPT_PASSTHRU_ARGV('s', "strategy", &opt_strategies, N_("strategy"),
N_("merge strategy to use"),
0),
OPT_PASSTHRU_ARGV('X', "strategy-option", &opt_strategy_opts,
N_("option=value"),
N_("option for selected merge strategy"),
0),
OPT_PASSTHRU('S', "gpg-sign", &opt_gpg_sign, N_("key-id"),
N_("GPG sign commit"),
PARSE_OPT_OPTARG),
/* Options passed to git-fetch */
OPT_GROUP(N_("Options related to fetching")),
OPT_PASSTHRU(0, "all", &opt_all, NULL,
N_("fetch from all remotes"),
PARSE_OPT_NOARG),
OPT_PASSTHRU('a', "append", &opt_append, NULL,
N_("append to .git/FETCH_HEAD instead of overwriting"),
PARSE_OPT_NOARG),
OPT_PASSTHRU(0, "upload-pack", &opt_upload_pack, N_("path"),
N_("path to upload pack on remote end"),
0),
OPT__FORCE(&opt_force, N_("force overwrite of local branch")),
OPT_PASSTHRU('t', "tags", &opt_tags, NULL,
N_("fetch all tags and associated objects"),
PARSE_OPT_NOARG),
OPT_PASSTHRU('p', "prune", &opt_prune, NULL,
N_("prune remote-tracking branches no longer on remote"),
PARSE_OPT_NOARG),
OPT_PASSTHRU(0, "recurse-submodules", &opt_recurse_submodules,
N_("on-demand"),
N_("control recursive fetching of submodules"),
PARSE_OPT_OPTARG),
OPT_BOOL(0, "dry-run", &opt_dry_run,
N_("dry run")),
OPT_PASSTHRU('k', "keep", &opt_keep, NULL,
N_("keep downloaded pack"),
PARSE_OPT_NOARG),
OPT_PASSTHRU(0, "depth", &opt_depth, N_("depth"),
N_("deepen history of shallow clone"),
0),
OPT_PASSTHRU(0, "unshallow", &opt_unshallow, NULL,
N_("convert to a complete repository"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG),
OPT_PASSTHRU(0, "update-shallow", &opt_update_shallow, NULL,
N_("accept refs that update .git/shallow"),
PARSE_OPT_NOARG),
OPT_PASSTHRU(0, "refmap", &opt_refmap, N_("refmap"),
N_("specify fetch refmap"),
PARSE_OPT_NONEG),
OPT_END()
};
/**
* Pushes "-q" or "-v" switches into arr to match the opt_verbosity level.
*/
static void argv_push_verbosity(struct argv_array *arr)
{
int verbosity;
for (verbosity = opt_verbosity; verbosity > 0; verbosity--)
argv_array_push(arr, "-v");
for (verbosity = opt_verbosity; verbosity < 0; verbosity++)
argv_array_push(arr, "-q");
}
/**
* Pushes "-f" switches into arr to match the opt_force level.
*/
static void argv_push_force(struct argv_array *arr)
{
int force = opt_force;
while (force-- > 0)
argv_array_push(arr, "-f");
}
/**
* Sets the GIT_REFLOG_ACTION environment variable to the concatenation of argv
*/
static void set_reflog_message(int argc, const char **argv)
{
int i;
struct strbuf msg = STRBUF_INIT;
for (i = 0; i < argc; i++) {
if (i)
strbuf_addch(&msg, ' ');
strbuf_addstr(&msg, argv[i]);
}
setenv("GIT_REFLOG_ACTION", msg.buf, 0);
strbuf_release(&msg);
}
/**
* If pull.ff is unset, returns NULL. If pull.ff is "true", returns "--ff". If
* pull.ff is "false", returns "--no-ff". If pull.ff is "only", returns
* "--ff-only". Otherwise, if pull.ff is set to an invalid value, die with an
* error.
*/
static const char *config_get_ff(void)
{
const char *value;
if (git_config_get_value("pull.ff", &value))
return NULL;
switch (git_config_maybe_bool("pull.ff", value)) {
case 0:
return "--no-ff";
case 1:
return "--ff";
}
if (!strcmp(value, "only"))
return "--ff-only";
die(_("Invalid value for pull.ff: %s"), value);
}
/**
* Returns the default configured value for --rebase. It first looks for the
* value of "branch.$curr_branch.rebase", where $curr_branch is the current
* branch, and if HEAD is detached or the configuration key does not exist,
* looks for the value of "pull.rebase". If both configuration keys do not
* exist, returns REBASE_FALSE.
*/
static enum rebase_type config_get_rebase(void)
{
struct branch *curr_branch = branch_get("HEAD");
const char *value;
if (curr_branch) {
char *key = xstrfmt("branch.%s.rebase", curr_branch->name);
if (!git_config_get_value(key, &value)) {
enum rebase_type ret = parse_config_rebase(key, value, 1);
free(key);
return ret;
}
free(key);
}
if (!git_config_get_value("pull.rebase", &value))
return parse_config_rebase("pull.rebase", value, 1);
return REBASE_FALSE;
}
/**
* Returns 1 if there are unstaged changes, 0 otherwise.
*/
static int has_unstaged_changes(const char *prefix)
{
struct rev_info rev_info;
int result;
init_revisions(&rev_info, prefix);
DIFF_OPT_SET(&rev_info.diffopt, IGNORE_SUBMODULES);
DIFF_OPT_SET(&rev_info.diffopt, QUICK);
diff_setup_done(&rev_info.diffopt);
result = run_diff_files(&rev_info, 0);
return diff_result_code(&rev_info.diffopt, result);
}
/**
* Returns 1 if there are uncommitted changes, 0 otherwise.
*/
static int has_uncommitted_changes(const char *prefix)
{
struct rev_info rev_info;
int result;
if (is_cache_unborn())
return 0;
init_revisions(&rev_info, prefix);
DIFF_OPT_SET(&rev_info.diffopt, IGNORE_SUBMODULES);
DIFF_OPT_SET(&rev_info.diffopt, QUICK);
add_head_to_pending(&rev_info);
diff_setup_done(&rev_info.diffopt);
result = run_diff_index(&rev_info, 1);
return diff_result_code(&rev_info.diffopt, result);
}
/**
* If the work tree has unstaged or uncommitted changes, dies with the
* appropriate message.
*/
static void die_on_unclean_work_tree(const char *prefix)
{
struct lock_file *lock_file = xcalloc(1, sizeof(*lock_file));
int do_die = 0;
hold_locked_index(lock_file, 0);
refresh_cache(REFRESH_QUIET);
update_index_if_able(&the_index, lock_file);
rollback_lock_file(lock_file);
if (has_unstaged_changes(prefix)) {
error(_("Cannot pull with rebase: You have unstaged changes."));
do_die = 1;
}
if (has_uncommitted_changes(prefix)) {
if (do_die)
error(_("Additionally, your index contains uncommitted changes."));
else
error(_("Cannot pull with rebase: Your index contains uncommitted changes."));
do_die = 1;
}
if (do_die)
exit(1);
}
/**
* Appends merge candidates from FETCH_HEAD that are not marked not-for-merge
* into merge_heads.
*/
static void get_merge_heads(struct sha1_array *merge_heads)
{
const char *filename = git_path("FETCH_HEAD");
FILE *fp;
struct strbuf sb = STRBUF_INIT;
unsigned char sha1[GIT_SHA1_RAWSZ];
if (!(fp = fopen(filename, "r")))
die_errno(_("could not open '%s' for reading"), filename);
while (strbuf_getline(&sb, fp, '\n') != EOF) {
if (get_sha1_hex(sb.buf, sha1))
continue; /* invalid line: does not start with SHA1 */
if (starts_with(sb.buf + GIT_SHA1_HEXSZ, "\tnot-for-merge\t"))
continue; /* ref is not-for-merge */
sha1_array_append(merge_heads, sha1);
}
fclose(fp);
strbuf_release(&sb);
}
/**
* Used by die_no_merge_candidates() as a for_each_remote() callback to
* retrieve the name of the remote if the repository only has one remote.
*/
static int get_only_remote(struct remote *remote, void *cb_data)
{
const char **remote_name = cb_data;
if (*remote_name)
return -1;
*remote_name = remote->name;
return 0;
}
/**
* Dies with the appropriate reason for why there are no merge candidates:
*
* 1. We fetched from a specific remote, and a refspec was given, but it ended
* up not fetching anything. This is usually because the user provided a
* wildcard refspec which had no matches on the remote end.
*
* 2. We fetched from a non-default remote, but didn't specify a branch to
* merge. We can't use the configured one because it applies to the default
* remote, thus the user must specify the branches to merge.
*
* 3. We fetched from the branch's or repo's default remote, but:
*
* a. We are not on a branch, so there will never be a configured branch to
* merge with.
*
* b. We are on a branch, but there is no configured branch to merge with.
*
* 4. We fetched from the branch's or repo's default remote, but the configured
* branch to merge didn't get fetched. (Either it doesn't exist, or wasn't
* part of the configured fetch refspec.)
*/
static void NORETURN die_no_merge_candidates(const char *repo, const char **refspecs)
{
struct branch *curr_branch = branch_get("HEAD");
const char *remote = curr_branch ? curr_branch->remote_name : NULL;
if (*refspecs) {
if (opt_rebase)
fprintf_ln(stderr, _("There is no candidate for rebasing against among the refs that you just fetched."));
else
fprintf_ln(stderr, _("There are no candidates for merging among the refs that you just fetched."));
fprintf_ln(stderr, _("Generally this means that you provided a wildcard refspec which had no\n"
"matches on the remote end."));
} else if (repo && curr_branch && (!remote || strcmp(repo, remote))) {
fprintf_ln(stderr, _("You asked to pull from the remote '%s', but did not specify\n"
"a branch. Because this is not the default configured remote\n"
"for your current branch, you must specify a branch on the command line."),
repo);
} else if (!curr_branch) {
fprintf_ln(stderr, _("You are not currently on a branch."));
if (opt_rebase)
fprintf_ln(stderr, _("Please specify which branch you want to rebase against."));
else
fprintf_ln(stderr, _("Please specify which branch you want to merge with."));
fprintf_ln(stderr, _("See git-pull(1) for details."));
fprintf(stderr, "\n");
fprintf_ln(stderr, " git pull <remote> <branch>");
fprintf(stderr, "\n");
} else if (!curr_branch->merge_nr) {
const char *remote_name = NULL;
if (for_each_remote(get_only_remote, &remote_name) || !remote_name)
remote_name = "<remote>";
fprintf_ln(stderr, _("There is no tracking information for the current branch."));
if (opt_rebase)
fprintf_ln(stderr, _("Please specify which branch you want to rebase against."));
else
fprintf_ln(stderr, _("Please specify which branch you want to merge with."));
fprintf_ln(stderr, _("See git-pull(1) for details."));
fprintf(stderr, "\n");
fprintf_ln(stderr, " git pull <remote> <branch>");
fprintf(stderr, "\n");
fprintf_ln(stderr, _("If you wish to set tracking information for this branch you can do so with:\n"
"\n"
" git branch --set-upstream-to=%s/<branch> %s\n"),
remote_name, curr_branch->name);
} else
fprintf_ln(stderr, _("Your configuration specifies to merge with the ref '%s'\n"
"from the remote, but no such ref was fetched."),
*curr_branch->merge_name);
exit(1);
}
/**
* Parses argv into [<repo> [<refspecs>...]], returning their values in `repo`
* as a string and `refspecs` as a null-terminated array of strings. If `repo`
* is not provided in argv, it is set to NULL.
*/
static void parse_repo_refspecs(int argc, const char **argv, const char **repo,
const char ***refspecs)
{
if (argc > 0) {
*repo = *argv++;
argc--;
} else
*repo = NULL;
*refspecs = argv;
}
/**
* Runs git-fetch, returning its exit status. `repo` and `refspecs` are the
* repository and refspecs to fetch, or NULL if they are not provided.
*/
static int run_fetch(const char *repo, const char **refspecs)
{
struct argv_array args = ARGV_ARRAY_INIT;
int ret;
argv_array_pushl(&args, "fetch", "--update-head-ok", NULL);
/* Shared options */
argv_push_verbosity(&args);
if (opt_progress)
argv_array_push(&args, opt_progress);
/* Options passed to git-fetch */
if (opt_all)
argv_array_push(&args, opt_all);
if (opt_append)
argv_array_push(&args, opt_append);
if (opt_upload_pack)
argv_array_push(&args, opt_upload_pack);
argv_push_force(&args);
if (opt_tags)
argv_array_push(&args, opt_tags);
if (opt_prune)
argv_array_push(&args, opt_prune);
if (opt_recurse_submodules)
argv_array_push(&args, opt_recurse_submodules);
if (opt_dry_run)
argv_array_push(&args, "--dry-run");
if (opt_keep)
argv_array_push(&args, opt_keep);
if (opt_depth)
argv_array_push(&args, opt_depth);
if (opt_unshallow)
argv_array_push(&args, opt_unshallow);
if (opt_update_shallow)
argv_array_push(&args, opt_update_shallow);
if (opt_refmap)
argv_array_push(&args, opt_refmap);
if (repo) {
argv_array_push(&args, repo);
argv_array_pushv(&args, refspecs);
} else if (*refspecs)
die("BUG: refspecs without repo?");
ret = run_command_v_opt(args.argv, RUN_GIT_CMD);
argv_array_clear(&args);
return ret;
}
/**
* "Pulls into void" by branching off merge_head.
*/
static int pull_into_void(const unsigned char *merge_head,
const unsigned char *curr_head)
{
/*
* Two-way merge: we treat the index as based on an empty tree,
* and try to fast-forward to HEAD. This ensures we will not lose
* index/worktree changes that the user already made on the unborn
* branch.
*/
if (checkout_fast_forward(EMPTY_TREE_SHA1_BIN, merge_head, 0))
return 1;
if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
return 1;
return 0;
}
/**
* Runs git-merge, returning its exit status.
*/
static int run_merge(void)
{
int ret;
struct argv_array args = ARGV_ARRAY_INIT;
argv_array_pushl(&args, "merge", NULL);
/* Shared options */
argv_push_verbosity(&args);
if (opt_progress)
argv_array_push(&args, opt_progress);
/* Options passed to git-merge */
if (opt_diffstat)
argv_array_push(&args, opt_diffstat);
if (opt_log)
argv_array_push(&args, opt_log);
if (opt_squash)
argv_array_push(&args, opt_squash);
if (opt_commit)
argv_array_push(&args, opt_commit);
if (opt_edit)
argv_array_push(&args, opt_edit);
if (opt_ff)
argv_array_push(&args, opt_ff);
if (opt_verify_signatures)
argv_array_push(&args, opt_verify_signatures);
argv_array_pushv(&args, opt_strategies.argv);
argv_array_pushv(&args, opt_strategy_opts.argv);
if (opt_gpg_sign)
argv_array_push(&args, opt_gpg_sign);
argv_array_push(&args, "FETCH_HEAD");
ret = run_command_v_opt(args.argv, RUN_GIT_CMD);
argv_array_clear(&args);
return ret;
}
/**
* Returns remote's upstream branch for the current branch. If remote is NULL,
* the current branch's configured default remote is used. Returns NULL if
* `remote` does not name a valid remote, HEAD does not point to a branch,
* remote is not the branch's configured remote or the branch does not have any
* configured upstream branch.
*/
static const char *get_upstream_branch(const char *remote)
{
struct remote *rm;
struct branch *curr_branch;
const char *curr_branch_remote;
rm = remote_get(remote);
if (!rm)
return NULL;
curr_branch = branch_get("HEAD");
if (!curr_branch)
return NULL;
curr_branch_remote = remote_for_branch(curr_branch, NULL);
assert(curr_branch_remote);
if (strcmp(curr_branch_remote, rm->name))
return NULL;
return branch_get_upstream(curr_branch, NULL);
}
/**
* Derives the remote tracking branch from the remote and refspec.
*
* FIXME: The current implementation assumes the default mapping of
* refs/heads/<branch_name> to refs/remotes/<remote_name>/<branch_name>.
*/
static const char *get_tracking_branch(const char *remote, const char *refspec)
{
struct refspec *spec;
const char *spec_src;
const char *merge_branch;
spec = parse_fetch_refspec(1, &refspec);
spec_src = spec->src;
if (!*spec_src || !strcmp(spec_src, "HEAD"))
spec_src = "HEAD";
else if (skip_prefix(spec_src, "heads/", &spec_src))
;
else if (skip_prefix(spec_src, "refs/heads/", &spec_src))
;
else if (starts_with(spec_src, "refs/") ||
starts_with(spec_src, "tags/") ||
starts_with(spec_src, "remotes/"))
spec_src = "";
if (*spec_src) {
if (!strcmp(remote, "."))
merge_branch = mkpath("refs/heads/%s", spec_src);
else
merge_branch = mkpath("refs/remotes/%s/%s", remote, spec_src);
} else
merge_branch = NULL;
free_refspec(1, spec);
return merge_branch;
}
/**
* Given the repo and refspecs, sets fork_point to the point at which the
* current branch forked from its remote tracking branch. Returns 0 on success,
* -1 on failure.
*/
static int get_rebase_fork_point(unsigned char *fork_point, const char *repo,
const char *refspec)
{
int ret;
struct branch *curr_branch;
const char *remote_branch;
struct child_process cp = CHILD_PROCESS_INIT;
struct strbuf sb = STRBUF_INIT;
curr_branch = branch_get("HEAD");
if (!curr_branch)
return -1;
if (refspec)
remote_branch = get_tracking_branch(repo, refspec);
else
remote_branch = get_upstream_branch(repo);
if (!remote_branch)
return -1;
argv_array_pushl(&cp.args, "merge-base", "--fork-point",
remote_branch, curr_branch->name, NULL);
cp.no_stdin = 1;
cp.no_stderr = 1;
cp.git_cmd = 1;
ret = capture_command(&cp, &sb, GIT_SHA1_HEXSZ);
if (ret)
goto cleanup;
ret = get_sha1_hex(sb.buf, fork_point);
if (ret)
goto cleanup;
cleanup:
strbuf_release(&sb);
return ret ? -1 : 0;
}
/**
* Sets merge_base to the octopus merge base of curr_head, merge_head and
* fork_point. Returns 0 if a merge base is found, 1 otherwise.
*/
static int get_octopus_merge_base(unsigned char *merge_base,
const unsigned char *curr_head,
const unsigned char *merge_head,
const unsigned char *fork_point)
{
struct commit_list *revs = NULL, *result;
commit_list_insert(lookup_commit_reference(curr_head), &revs);
commit_list_insert(lookup_commit_reference(merge_head), &revs);
if (!is_null_sha1(fork_point))
commit_list_insert(lookup_commit_reference(fork_point), &revs);
result = reduce_heads(get_octopus_merge_bases(revs));
free_commit_list(revs);
if (!result)
return 1;
hashcpy(merge_base, result->item->object.sha1);
return 0;
}
/**
* Given the current HEAD SHA1, the merge head returned from git-fetch and the
* fork point calculated by get_rebase_fork_point(), runs git-rebase with the
* appropriate arguments and returns its exit status.
*/
static int run_rebase(const unsigned char *curr_head,
const unsigned char *merge_head,
const unsigned char *fork_point)
{
int ret;
unsigned char oct_merge_base[GIT_SHA1_RAWSZ];
struct argv_array args = ARGV_ARRAY_INIT;
if (!get_octopus_merge_base(oct_merge_base, curr_head, merge_head, fork_point))
if (!is_null_sha1(fork_point) && !hashcmp(oct_merge_base, fork_point))
fork_point = NULL;
argv_array_push(&args, "rebase");
/* Shared options */
argv_push_verbosity(&args);
/* Options passed to git-rebase */
if (opt_rebase == REBASE_PRESERVE)
argv_array_push(&args, "--preserve-merges");
if (opt_diffstat)
argv_array_push(&args, opt_diffstat);
argv_array_pushv(&args, opt_strategies.argv);
argv_array_pushv(&args, opt_strategy_opts.argv);
if (opt_gpg_sign)
argv_array_push(&args, opt_gpg_sign);
argv_array_push(&args, "--onto");
argv_array_push(&args, sha1_to_hex(merge_head));
if (fork_point && !is_null_sha1(fork_point))
argv_array_push(&args, sha1_to_hex(fork_point));
else
argv_array_push(&args, sha1_to_hex(merge_head));
ret = run_command_v_opt(args.argv, RUN_GIT_CMD);
argv_array_clear(&args);
return ret;
}
int cmd_pull(int argc, const char **argv, const char *prefix)
{
const char *repo, **refspecs;
struct sha1_array merge_heads = SHA1_ARRAY_INIT;
unsigned char orig_head[GIT_SHA1_RAWSZ], curr_head[GIT_SHA1_RAWSZ];
unsigned char rebase_fork_point[GIT_SHA1_RAWSZ];
if (!getenv("GIT_REFLOG_ACTION"))
set_reflog_message(argc, argv);
argc = parse_options(argc, argv, prefix, pull_options, pull_usage, 0);
parse_repo_refspecs(argc, argv, &repo, &refspecs);
if (!opt_ff)
opt_ff = xstrdup_or_null(config_get_ff());
if (opt_rebase < 0)
opt_rebase = config_get_rebase();
git_config(git_default_config, NULL);
if (read_cache_unmerged())
die_resolve_conflict("Pull");
if (file_exists(git_path("MERGE_HEAD")))
die_conclude_merge();
if (get_sha1("HEAD", orig_head))
hashclr(orig_head);
if (opt_rebase) {
int autostash = 0;
if (is_null_sha1(orig_head) && !is_cache_unborn())
die(_("Updating an unborn branch with changes added to the index."));
git_config_get_bool("rebase.autostash", &autostash);
if (!autostash)
die_on_unclean_work_tree(prefix);
if (get_rebase_fork_point(rebase_fork_point, repo, *refspecs))
hashclr(rebase_fork_point);
}
if (run_fetch(repo, refspecs))
return 1;
if (opt_dry_run)
return 0;
if (get_sha1("HEAD", curr_head))
hashclr(curr_head);
if (!is_null_sha1(orig_head) && !is_null_sha1(curr_head) &&
hashcmp(orig_head, curr_head)) {
/*
* The fetch involved updating the current branch.
*
* The working tree and the index file are still based on
* orig_head commit, but we are merging into curr_head.
* Update the working tree to match curr_head.
*/
warning(_("fetch updated the current branch head.\n"
"fast-forwarding your working tree from\n"
"commit %s."), sha1_to_hex(orig_head));
if (checkout_fast_forward(orig_head, curr_head, 0))
die(_("Cannot fast-forward your working tree.\n"
"After making sure that you saved anything precious from\n"
"$ git diff %s\n"
"output, run\n"
"$ git reset --hard\n"
"to recover."), sha1_to_hex(orig_head));
}
get_merge_heads(&merge_heads);
if (!merge_heads.nr)
die_no_merge_candidates(repo, refspecs);
if (is_null_sha1(orig_head)) {
if (merge_heads.nr > 1)
die(_("Cannot merge multiple branches into empty head."));
return pull_into_void(*merge_heads.sha1, curr_head);
} else if (opt_rebase) {
if (merge_heads.nr > 1)
die(_("Cannot rebase onto multiple branches."));
return run_rebase(curr_head, *merge_heads.sha1, rebase_fork_point);
} else
return run_merge();
}

View File

@ -9,7 +9,6 @@
#include "transport.h"
#include "parse-options.h"
#include "submodule.h"
#include "send-pack.h"
static const char * const push_usage[] = {
N_("git push [<options>] [<repository> [<refspec>...]]"),
@ -472,24 +471,6 @@ static int option_parse_recurse_submodules(const struct option *opt,
return 0;
}
static void set_push_cert_flags(int *flags, int v)
{
switch (v) {
case SEND_PACK_PUSH_CERT_NEVER:
*flags &= ~(TRANSPORT_PUSH_CERT_ALWAYS | TRANSPORT_PUSH_CERT_IF_ASKED);
break;
case SEND_PACK_PUSH_CERT_ALWAYS:
*flags |= TRANSPORT_PUSH_CERT_ALWAYS;
*flags &= ~TRANSPORT_PUSH_CERT_IF_ASKED;
break;
case SEND_PACK_PUSH_CERT_IF_ASKED:
*flags |= TRANSPORT_PUSH_CERT_IF_ASKED;
*flags &= ~TRANSPORT_PUSH_CERT_ALWAYS;
break;
}
}
static int git_push_config(const char *k, const char *v, void *cb)
{
int *flags = cb;
@ -505,23 +486,6 @@ static int git_push_config(const char *k, const char *v, void *cb)
else
*flags &= ~TRANSPORT_PUSH_FOLLOW_TAGS;
return 0;
} else if (!strcmp(k, "push.gpgsign")) {
const char *value;
if (!git_config_get_value("push.gpgsign", &value)) {
switch (git_config_maybe_bool("push.gpgsign", value)) {
case 0:
set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_NEVER);
break;
case 1:
set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_ALWAYS);
break;
default:
if (value && !strcasecmp(value, "if-asked"))
set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_IF_ASKED);
else
return error("Invalid value for '%s'", k);
}
}
}
return git_default_config(k, v, NULL);
@ -531,7 +495,6 @@ int cmd_push(int argc, const char **argv, const char *prefix)
{
int flags = 0;
int tags = 0;
int push_cert = -1;
int rc;
const char *repo = NULL; /* default repository */
struct option options[] = {
@ -563,9 +526,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
OPT_BIT(0, "no-verify", &flags, N_("bypass pre-push hook"), TRANSPORT_PUSH_NO_HOOK),
OPT_BIT(0, "follow-tags", &flags, N_("push missing but relevant tags"),
TRANSPORT_PUSH_FOLLOW_TAGS),
{ OPTION_CALLBACK,
0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"),
PARSE_OPT_OPTARG, option_parse_push_signed },
OPT_BIT(0, "signed", &flags, N_("GPG sign the push"), TRANSPORT_PUSH_CERT),
OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC),
OPT_END()
};
@ -573,7 +534,6 @@ int cmd_push(int argc, const char **argv, const char *prefix)
packet_trace_identity("push");
git_config(git_push_config, &flags);
argc = parse_options(argc, argv, prefix, options, push_usage, 0);
set_push_cert_flags(&flags, push_cert);
if (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR))))
die(_("--delete is incompatible with --all, --mirror and --tags"));

View File

@ -34,7 +34,7 @@ static int list_tree(unsigned char *sha1)
}
static const char * const read_tree_usage[] = {
N_("git read-tree [(-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>) [-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"),
N_("git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"),
NULL
};

View File

@ -19,7 +19,6 @@
#include "tag.h"
#include "gpg-interface.h"
#include "sigchain.h"
#include "fsck.h"
static const char receive_pack_usage[] = "git receive-pack <git-dir>";
@ -37,7 +36,6 @@ static enum deny_action deny_current_branch = DENY_UNCONFIGURED;
static enum deny_action deny_delete_current = DENY_UNCONFIGURED;
static int receive_fsck_objects = -1;
static int transfer_fsck_objects = -1;
static struct strbuf fsck_msg_types = STRBUF_INIT;
static int receive_unpack_limit = -1;
static int transfer_unpack_limit = -1;
static int advertise_atomic_push = 1;
@ -117,26 +115,6 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
return 0;
}
if (strcmp(var, "receive.fsck.skiplist") == 0) {
const char *path;
if (git_config_pathname(&path, var, value))
return 1;
strbuf_addf(&fsck_msg_types, "%cskiplist=%s",
fsck_msg_types.len ? ',' : '=', path);
free((char *)path);
return 0;
}
if (skip_prefix(var, "receive.fsck.", &var)) {
if (is_valid_msg_type(var, value))
strbuf_addf(&fsck_msg_types, "%c%s=%s",
fsck_msg_types.len ? ',' : '=', var, value);
else
warning("Skipping unknown msg id '%s'", var);
return 0;
}
if (strcmp(var, "receive.fsckobjects") == 0) {
receive_fsck_objects = git_config_bool(var, value);
return 0;
@ -1512,8 +1490,7 @@ static const char *unpack(int err_fd, struct shallow_info *si)
if (quiet)
argv_array_push(&child.args, "-q");
if (fsck_objects)
argv_array_pushf(&child.args, "--strict%s",
fsck_msg_types.buf);
argv_array_push(&child.args, "--strict");
child.no_stdout = 1;
child.err = err_fd;
child.git_cmd = 1;
@ -1531,8 +1508,7 @@ static const char *unpack(int err_fd, struct shallow_info *si)
argv_array_pushl(&child.args, "index-pack",
"--stdin", hdr_arg, keep_arg, NULL);
if (fsck_objects)
argv_array_pushf(&child.args, "--strict%s",
fsck_msg_types.buf);
argv_array_push(&child.args, "--strict");
if (fix_thin)
argv_array_push(&child.args, "--fix-thin");
child.out = -1;

View File

@ -13,8 +13,6 @@ static const char reflog_expire_usage[] =
"git reflog expire [--expire=<time>] [--expire-unreachable=<time>] [--rewrite] [--updateref] [--stale-fix] [--dry-run | -n] [--verbose] [--all] <refs>...";
static const char reflog_delete_usage[] =
"git reflog delete [--rewrite] [--updateref] [--dry-run | -n] [--verbose] <refs>...";
static const char reflog_exists_usage[] =
"git reflog exists <ref>";
static unsigned long default_reflog_expire;
static unsigned long default_reflog_expire_unreachable;
@ -429,7 +427,7 @@ static int parse_expire_cfg_value(const char *var, const char *value, unsigned l
if (!value)
return config_error_nonbool(var);
if (parse_expiry_date(value, expire))
return error(_("'%s' for '%s' is not a valid timestamp"),
return error(_("%s' for '%s' is not a valid timestamp"),
value, var);
return 0;
}
@ -701,38 +699,12 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
return status;
}
static int cmd_reflog_exists(int argc, const char **argv, const char *prefix)
{
int i, start = 0;
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (!strcmp(arg, "--")) {
i++;
break;
}
else if (arg[0] == '-')
usage(reflog_exists_usage);
else
break;
}
start = i;
if (argc - start != 1)
usage(reflog_exists_usage);
if (check_refname_format(argv[start], REFNAME_ALLOW_ONELEVEL))
die("invalid ref format: %s", argv[start]);
return !reflog_exists(argv[start]);
}
/*
* main "reflog"
*/
static const char reflog_usage[] =
"git reflog [ show | expire | delete | exists ]";
"git reflog [ show | expire | delete ]";
int cmd_reflog(int argc, const char **argv, const char *prefix)
{
@ -752,8 +724,5 @@ int cmd_reflog(int argc, const char **argv, const char *prefix)
if (!strcmp(argv[1], "delete"))
return cmd_reflog_delete(argc - 1, argv + 1, prefix);
if (!strcmp(argv[1], "exists"))
return cmd_reflog_exists(argc - 1, argv + 1, prefix);
return cmd_log_reflog(argc, argv, prefix);
}

View File

@ -581,6 +581,7 @@ static int migrate_file(struct remote *remote)
{
struct strbuf buf = STRBUF_INIT;
int i;
const char *path = NULL;
strbuf_addf(&buf, "remote.%s.url", remote->name);
for (i = 0; i < remote->url_nr; i++)
@ -600,9 +601,11 @@ static int migrate_file(struct remote *remote)
return error(_("Could not append '%s' to '%s'"),
remote->fetch_refspec[i], buf.buf);
if (remote->origin == REMOTE_REMOTES)
unlink_or_warn(git_path("remotes/%s", remote->name));
path = git_path("remotes/%s", remote->name);
else if (remote->origin == REMOTE_BRANCHES)
unlink_or_warn(git_path("branches/%s", remote->name));
path = git_path("branches/%s", remote->name);
if (path)
unlink_or_warn(path);
return 0;
}
@ -743,6 +746,26 @@ static int mv(int argc, const char **argv)
return 0;
}
static int remove_branches(struct string_list *branches)
{
struct strbuf err = STRBUF_INIT;
int i, result = 0;
if (repack_without_refs(branches, &err))
result |= error("%s", err.buf);
strbuf_release(&err);
for (i = 0; i < branches->nr; i++) {
struct string_list_item *item = branches->items + i;
const char *refname = item->string;
if (delete_ref(refname, NULL, 0))
result |= error(_("Could not remove branch %s"), refname);
}
return result;
}
static int rm(int argc, const char **argv)
{
struct option options[] = {
@ -799,7 +822,7 @@ static int rm(int argc, const char **argv)
strbuf_release(&buf);
if (!result)
result = delete_refs(&branches);
result = remove_branches(&branches);
string_list_clear(&branches, 0);
if (skipped.nr) {
@ -1311,12 +1334,19 @@ static int prune_remote(const char *remote, int dry_run)
string_list_append(&refs_to_prune, item->util);
string_list_sort(&refs_to_prune);
if (!dry_run)
result |= delete_refs(&refs_to_prune);
if (!dry_run) {
struct strbuf err = STRBUF_INIT;
if (repack_without_refs(&refs_to_prune, &err))
result |= error("%s", err.buf);
strbuf_release(&err);
}
for_each_string_list_item(item, &states.stale) {
const char *refname = item->util;
if (!dry_run)
result |= delete_ref(refname, NULL, 0);
if (dry_run)
printf_ln(_(" * [would prune] %s"),
abbrev_ref(refname, "refs/remotes/"));

View File

@ -285,7 +285,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
failed = 0;
for_each_string_list_item(item, &names) {
for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
char *fname, *fname_old;
const char *fname_old;
char *fname;
fname = mkpathdup("%s/pack-%s%s", packdir,
item->string, exts[ext].name);
if (!file_exists(fname)) {
@ -293,7 +294,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
continue;
}
fname_old = mkpathdup("%s/old-%s%s", packdir,
fname_old = mkpath("%s/old-%s%s", packdir,
item->string, exts[ext].name);
if (file_exists(fname_old))
if (unlink(fname_old))
@ -301,12 +302,10 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (!failed && rename(fname, fname_old)) {
free(fname);
free(fname_old);
failed = 1;
break;
} else {
string_list_append(&rollback, fname);
free(fname_old);
}
}
if (failed)
@ -315,13 +314,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (failed) {
struct string_list rollback_failure = STRING_LIST_INIT_DUP;
for_each_string_list_item(item, &rollback) {
char *fname, *fname_old;
const char *fname_old;
char *fname;
fname = mkpathdup("%s/%s", packdir, item->string);
fname_old = mkpathdup("%s/old-%s", packdir, item->string);
fname_old = mkpath("%s/old-%s", packdir, item->string);
if (rename(fname_old, fname))
string_list_append(&rollback_failure, fname);
free(fname);
free(fname_old);
}
if (rollback_failure.nr) {
@ -369,14 +368,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
/* Remove the "old-" files */
for_each_string_list_item(item, &names) {
for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
char *fname;
fname = mkpathdup("%s/old-%s%s",
packdir,
item->string,
exts[ext].name);
const char *fname;
fname = mkpath("%s/old-%s%s",
packdir,
item->string,
exts[ext].name);
if (remove_path(fname))
warning(_("removing '%s' failed"), fname);
free(fname);
}
}

View File

@ -104,9 +104,9 @@ static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
continue;
}
full_hex = sha1_to_hex(sha1);
snprintf(ref, sizeof(ref), "%s%s", git_replace_ref_base, full_hex);
snprintf(ref, sizeof(ref), "refs/replace/%s", full_hex);
/* read_ref() may reuse the buffer */
full_hex = ref + strlen(git_replace_ref_base);
full_hex = ref + strlen("refs/replace/");
if (read_ref(ref, sha1)) {
error("replace ref '%s' not found.", full_hex);
had_error = 1;
@ -134,7 +134,7 @@ static void check_ref_valid(unsigned char object[20],
int force)
{
if (snprintf(ref, ref_size,
"%s%s", git_replace_ref_base,
"refs/replace/%s",
sha1_to_hex(object)) > ref_size - 1)
die("replace ref name too long: %.*s...", 50, ref);
if (check_refname_format(ref, 0))

View File

@ -36,7 +36,7 @@ static const char *reset_type_names[] = {
static inline int is_merge(void)
{
return !access(git_path_merge_head(), F_OK);
return !access(git_path("MERGE_HEAD"), F_OK);
}
static int reset_index(const unsigned char *sha1, int reset_type, int quiet)

View File

@ -12,15 +12,10 @@
#include "version.h"
#include "sha1-array.h"
#include "gpg-interface.h"
#include "gettext.h"
static const char * const send_pack_usage[] = {
N_("git send-pack [--all | --mirror] [--dry-run] [--force] "
"[--receive-pack=<git-receive-pack>] [--verbose] [--thin] [--atomic] "
"[<host>:]<directory> [<ref>...]\n"
" --all and explicit <ref> specification are mutually exclusive."),
NULL,
};
static const char send_pack_usage[] =
"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [--atomic] [<host>:]<directory> [<ref>...]\n"
" --all and explicit <ref> specification are mutually exclusive.";
static struct send_pack_args args;
@ -97,31 +92,6 @@ static void print_helper_status(struct ref *ref)
strbuf_release(&buf);
}
static int send_pack_config(const char *k, const char *v, void *cb)
{
git_gpg_config(k, v, NULL);
if (!strcmp(k, "push.gpgsign")) {
const char *value;
if (!git_config_get_value("push.gpgsign", &value)) {
switch (git_config_maybe_bool("push.gpgsign", value)) {
case 0:
args.push_cert = SEND_PACK_PUSH_CERT_NEVER;
break;
case 1:
args.push_cert = SEND_PACK_PUSH_CERT_ALWAYS;
break;
default:
if (value && !strcasecmp(value, "if-asked"))
args.push_cert = SEND_PACK_PUSH_CERT_IF_ASKED;
else
return error("Invalid value for '%s'", k);
}
}
}
return 0;
}
int cmd_send_pack(int argc, const char **argv, const char *prefix)
{
int i, nr_refspecs = 0;
@ -137,68 +107,116 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
int ret;
int helper_status = 0;
int send_all = 0;
int verbose = 0;
const char *receivepack = "git-receive-pack";
unsigned dry_run = 0;
unsigned send_mirror = 0;
unsigned force_update = 0;
unsigned quiet = 0;
int push_cert = 0;
unsigned use_thin_pack = 0;
unsigned atomic = 0;
unsigned stateless_rpc = 0;
int flags;
unsigned int reject_reasons;
int progress = -1;
int from_stdin = 0;
struct push_cas_option cas = {0};
struct option options[] = {
OPT__VERBOSITY(&verbose),
OPT_STRING(0, "receive-pack", &receivepack, "receive-pack", N_("receive pack program")),
OPT_STRING(0, "exec", &receivepack, "receive-pack", N_("receive pack program")),
OPT_STRING(0, "remote", &remote_name, "remote", N_("remote name")),
OPT_BOOL(0, "all", &send_all, N_("push all refs")),
OPT_BOOL('n' , "dry-run", &dry_run, N_("dry run")),
OPT_BOOL(0, "mirror", &send_mirror, N_("mirror all refs")),
OPT_BOOL('f', "force", &force_update, N_("force updates")),
{ OPTION_CALLBACK,
0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"),
PARSE_OPT_OPTARG, option_parse_push_signed },
OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
OPT_BOOL(0, "thin", &use_thin_pack, N_("use thin pack")),
OPT_BOOL(0, "atomic", &atomic, N_("request atomic transaction on remote side")),
OPT_BOOL(0, "stateless-rpc", &stateless_rpc, N_("use stateless RPC protocol")),
OPT_BOOL(0, "stdin", &from_stdin, N_("read refs from stdin")),
OPT_BOOL(0, "helper-status", &helper_status, N_("print status from remote helper")),
{ OPTION_CALLBACK,
0, CAS_OPT_NAME, &cas, N_("refname>:<expect"),
N_("require old value of ref to be at this value"),
PARSE_OPT_OPTARG, parseopt_push_cas_option },
OPT_END()
};
git_config(git_gpg_config, NULL);
git_config(send_pack_config, NULL);
argc = parse_options(argc, argv, prefix, options, send_pack_usage, 0);
if (argc > 0) {
dest = argv[0];
refspecs = (const char **)(argv + 1);
nr_refspecs = argc - 1;
argv++;
for (i = 1; i < argc; i++, argv++) {
const char *arg = *argv;
if (*arg == '-') {
if (starts_with(arg, "--receive-pack=")) {
receivepack = arg + 15;
continue;
}
if (starts_with(arg, "--exec=")) {
receivepack = arg + 7;
continue;
}
if (starts_with(arg, "--remote=")) {
remote_name = arg + 9;
continue;
}
if (!strcmp(arg, "--all")) {
send_all = 1;
continue;
}
if (!strcmp(arg, "--dry-run")) {
args.dry_run = 1;
continue;
}
if (!strcmp(arg, "--mirror")) {
args.send_mirror = 1;
continue;
}
if (!strcmp(arg, "--force")) {
args.force_update = 1;
continue;
}
if (!strcmp(arg, "--quiet")) {
args.quiet = 1;
continue;
}
if (!strcmp(arg, "--verbose")) {
args.verbose = 1;
continue;
}
if (!strcmp(arg, "--signed")) {
args.push_cert = 1;
continue;
}
if (!strcmp(arg, "--progress")) {
progress = 1;
continue;
}
if (!strcmp(arg, "--no-progress")) {
progress = 0;
continue;
}
if (!strcmp(arg, "--thin")) {
args.use_thin_pack = 1;
continue;
}
if (!strcmp(arg, "--atomic")) {
args.atomic = 1;
continue;
}
if (!strcmp(arg, "--stateless-rpc")) {
args.stateless_rpc = 1;
continue;
}
if (!strcmp(arg, "--stdin")) {
from_stdin = 1;
continue;
}
if (!strcmp(arg, "--helper-status")) {
helper_status = 1;
continue;
}
if (!strcmp(arg, "--" CAS_OPT_NAME)) {
if (parse_push_cas_option(&cas, NULL, 0) < 0)
exit(1);
continue;
}
if (!strcmp(arg, "--no-" CAS_OPT_NAME)) {
if (parse_push_cas_option(&cas, NULL, 1) < 0)
exit(1);
continue;
}
if (starts_with(arg, "--" CAS_OPT_NAME "=")) {
if (parse_push_cas_option(&cas,
strchr(arg, '=') + 1, 0) < 0)
exit(1);
continue;
}
usage(send_pack_usage);
}
if (!dest) {
dest = arg;
continue;
}
refspecs = (const char **) argv;
nr_refspecs = argc - i;
break;
}
if (!dest)
usage_with_options(send_pack_usage, options);
args.verbose = verbose;
args.dry_run = dry_run;
args.send_mirror = send_mirror;
args.force_update = force_update;
args.quiet = quiet;
args.push_cert = push_cert;
args.progress = progress;
args.use_thin_pack = use_thin_pack;
args.atomic = atomic;
args.stateless_rpc = stateless_rpc;
usage(send_pack_usage);
if (from_stdin) {
struct argv_array all_refspecs = ARGV_ARRAY_INIT;
@ -227,7 +245,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
*/
if ((refspecs && (send_all || args.send_mirror)) ||
(send_all && args.send_mirror))
usage_with_options(send_pack_usage, options);
usage(send_pack_usage);
if (remote_name) {
remote = remote_get(remote_name);

View File

@ -138,7 +138,7 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
ctx.abbrev = log->abbrev;
ctx.subject = "";
ctx.after_subject = "";
ctx.date_mode.type = DATE_NORMAL;
ctx.date_mode = DATE_NORMAL;
ctx.output_encoding = get_log_output_encoding();
pretty_print_commit(&ctx, commit, &ufbuf);
buffer = ufbuf.buf;

View File

@ -730,7 +730,6 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
if (reflog) {
struct object_id oid;
char nth_desc[256];
char *ref;
int base = 0;
unsigned int flags = 0;
@ -769,6 +768,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
for (i = 0; i < reflog; i++) {
char *logmsg;
char *nth_desc;
const char *msg;
unsigned long timestamp;
int tz;
@ -784,12 +784,13 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
else
msg++;
reflog_msg[i] = xstrfmt("(%s) %s",
show_date(timestamp, tz,
DATE_MODE(RELATIVE)),
show_date(timestamp, tz, 1),
msg);
free(logmsg);
sprintf(nth_desc, "%s@{%d}", *av, base+i);
nth_desc = xstrfmt("%s@{%d}", *av, base+i);
append_ref(nth_desc, &oid, 1);
free(nth_desc);
}
free(ref);
}

View File

@ -579,7 +579,6 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
struct create_tag_options opt;
char *cleanup_arg = NULL;
int annotate = 0, force = 0, lines = -1;
int create_reflog = 0;
int cmdmode = 0;
const char *msgfile = NULL, *keyid = NULL;
struct msg_arg msg = { 0, STRBUF_INIT };
@ -606,7 +605,6 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
OPT_STRING('u', "local-user", &keyid, N_("key-id"),
N_("use another key to sign the tag")),
OPT__FORCE(&force, N_("replace the tag if exists")),
OPT_BOOL(0, "create-reflog", &create_reflog, N_("create_reflog")),
OPT_GROUP(N_("Tag listing options")),
OPT_COLUMN(0, "column", &colopts, N_("show tag list in columns")),
@ -735,8 +733,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
transaction = ref_transaction_begin(&err);
if (!transaction ||
ref_transaction_update(transaction, ref.buf, object, prev,
create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
NULL, &err) ||
0, NULL, &err) ||
ref_transaction_commit(transaction, &err))
die("%s", err.buf);
ref_transaction_free(transaction);

View File

@ -20,7 +20,6 @@ static unsigned char buffer[4096];
static unsigned int offset, len;
static off_t consumed_bytes;
static git_SHA_CTX ctx;
static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
/*
* When running under --strict mode, objects whose reachability are
@ -179,7 +178,7 @@ static void write_cached_object(struct object *obj, struct obj_buffer *obj_buf)
* that have reachability requirements and calls this function.
* Verify its reachability and validity recursively and write it out.
*/
static int check_object(struct object *obj, int type, void *data, struct fsck_options *options)
static int check_object(struct object *obj, int type, void *data)
{
struct obj_buffer *obj_buf;
@ -204,10 +203,10 @@ static int check_object(struct object *obj, int type, void *data, struct fsck_op
obj_buf = lookup_object_buffer(obj);
if (!obj_buf)
die("Whoops! Cannot find object '%s'", sha1_to_hex(obj->sha1));
if (fsck_object(obj, obj_buf->buffer, obj_buf->size, &fsck_options))
if (fsck_object(obj, obj_buf->buffer, obj_buf->size, 1,
fsck_error_function))
die("Error in object");
fsck_options.walk = check_object;
if (fsck_walk(obj, NULL, &fsck_options))
if (fsck_walk(obj, check_object, NULL))
die("Error on reachable objects of %s", sha1_to_hex(obj->sha1));
write_cached_object(obj, obj_buf);
return 0;
@ -218,7 +217,7 @@ static void write_rest(void)
unsigned i;
for (i = 0; i < nr_objects; i++) {
if (obj_list[i].obj)
check_object(obj_list[i].obj, OBJ_ANY, NULL, NULL);
check_object(obj_list[i].obj, OBJ_ANY, NULL);
}
}
@ -530,11 +529,6 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
strict = 1;
continue;
}
if (skip_prefix(arg, "--strict=", &arg)) {
strict = 1;
fsck_set_msg_types(&fsck_options, arg);
continue;
}
if (starts_with(arg, "--pack_header=")) {
struct pack_header *hdr;
char *c;

View File

@ -14,7 +14,6 @@ static const char * const git_update_ref_usage[] = {
static char line_termination = '\n';
static int update_flags;
static unsigned create_reflog_flag;
static const char *msg;
/*
@ -201,8 +200,7 @@ static const char *parse_cmd_update(struct ref_transaction *transaction,
if (ref_transaction_update(transaction, refname,
new_sha1, have_old ? old_sha1 : NULL,
update_flags | create_reflog_flag,
msg, &err))
update_flags, msg, &err))
die("%s", err.buf);
update_flags = 0;
@ -233,8 +231,7 @@ static const char *parse_cmd_create(struct ref_transaction *transaction,
die("create %s: extra input: %s", refname, next);
if (ref_transaction_create(transaction, refname, new_sha1,
update_flags | create_reflog_flag,
msg, &err))
update_flags, msg, &err))
die("%s", err.buf);
update_flags = 0;
@ -357,7 +354,6 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
unsigned char sha1[20], oldsha1[20];
int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0;
unsigned int flags = 0;
int create_reflog = 0;
struct option options[] = {
OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")),
OPT_BOOL('d', NULL, &delete, N_("delete the reference")),
@ -365,7 +361,6 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
N_("update <refname> not the one it points to")),
OPT_BOOL('z', NULL, &end_null, N_("stdin has NUL-terminated arguments")),
OPT_BOOL( 0 , "stdin", &read_stdin, N_("read updates from stdin")),
OPT_BOOL( 0 , "create-reflog", &create_reflog, N_("create_reflog")),
OPT_END(),
};
@ -375,8 +370,6 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
if (msg && !*msg)
die("Refusing to perform update with empty message.");
create_reflog_flag = create_reflog ? REF_FORCE_CREATE_REFLOG : 0;
if (read_stdin) {
struct strbuf err = STRBUF_INIT;
struct ref_transaction *transaction;
@ -415,29 +408,15 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
die("%s: not a valid SHA1", value);
}
if (oldval) {
if (!*oldval)
/*
* The empty string implies that the reference
* must not already exist:
*/
hashclr(oldsha1);
else if (get_sha1(oldval, oldsha1))
die("%s: not a valid old SHA1", oldval);
}
hashclr(oldsha1); /* all-zero hash in case oldval is the empty string */
if (oldval && *oldval && get_sha1(oldval, oldsha1))
die("%s: not a valid old SHA1", oldval);
if (no_deref)
flags = REF_NODEREF;
if (delete)
/*
* For purposes of backwards compatibility, we treat
* NULL_SHA1 as "don't care" here:
*/
return delete_ref(refname,
(oldval && !is_null_sha1(oldsha1)) ? oldsha1 : NULL,
flags);
return delete_ref(refname, oldval ? oldsha1 : NULL, flags);
else
return update_ref(msg, refname, sha1, oldval ? oldsha1 : NULL,
flags | create_reflog_flag,
UPDATE_REFS_DIE_ON_ERR);
flags, UPDATE_REFS_DIE_ON_ERR);
}

View File

@ -18,21 +18,25 @@ static const char * const verify_commit_usage[] = {
NULL
};
static int run_gpg_verify(const unsigned char *sha1, const char *buf, unsigned long size, unsigned flags)
static int run_gpg_verify(const unsigned char *sha1, const char *buf, unsigned long size, int verbose)
{
struct signature_check signature_check;
int ret;
memset(&signature_check, 0, sizeof(signature_check));
ret = check_commit_signature(lookup_commit(sha1), &signature_check);
print_signature_buffer(&signature_check, flags);
check_commit_signature(lookup_commit(sha1), &signature_check);
if (verbose && signature_check.payload)
fputs(signature_check.payload, stdout);
if (signature_check.gpg_output)
fputs(signature_check.gpg_output, stderr);
signature_check_clear(&signature_check);
return ret;
return signature_check.result != 'G';
}
static int verify_commit(const char *name, unsigned flags)
static int verify_commit(const char *name, int verbose)
{
enum object_type type;
unsigned char sha1[20];
@ -50,7 +54,7 @@ static int verify_commit(const char *name, unsigned flags)
return error("%s: cannot verify a non-commit object of type %s.",
name, typename(type));
ret = run_gpg_verify(sha1, buf, size, flags);
ret = run_gpg_verify(sha1, buf, size, verbose);
free(buf);
return ret;
@ -67,10 +71,8 @@ static int git_verify_commit_config(const char *var, const char *value, void *cb
int cmd_verify_commit(int argc, const char **argv, const char *prefix)
{
int i = 1, verbose = 0, had_error = 0;
unsigned flags = 0;
const struct option verify_commit_options[] = {
OPT__VERBOSE(&verbose, N_("print commit contents")),
OPT_BIT(0, "raw", &flags, N_("print raw gpg status output"), GPG_VERIFY_RAW),
OPT_END()
};
@ -81,14 +83,11 @@ int cmd_verify_commit(int argc, const char **argv, const char *prefix)
if (argc <= i)
usage_with_options(verify_commit_usage, verify_commit_options);
if (verbose)
flags |= GPG_VERIFY_VERBOSE;
/* sometimes the program was terminated because this signal
* was received in the process of writing the gpg input: */
signal(SIGPIPE, SIG_IGN);
while (i < argc)
if (verify_commit(argv[i++], flags))
if (verify_commit(argv[i++], verbose))
had_error = 1;
return had_error;
}

View File

@ -18,30 +18,21 @@ static const char * const verify_tag_usage[] = {
NULL
};
static int run_gpg_verify(const char *buf, unsigned long size, unsigned flags)
static int run_gpg_verify(const char *buf, unsigned long size, int verbose)
{
struct signature_check sigc;
int len;
int ret;
memset(&sigc, 0, sizeof(sigc));
len = parse_signature(buf, size);
if (verbose)
write_in_full(1, buf, len);
if (size == len) {
if (flags & GPG_VERIFY_VERBOSE)
write_in_full(1, buf, len);
if (size == len)
return error("no signature found");
}
ret = check_signature(buf, len, buf + len, size - len, &sigc);
print_signature_buffer(&sigc, flags);
signature_check_clear(&sigc);
return ret;
return verify_signed_buffer(buf, len, buf + len, size - len, NULL, NULL);
}
static int verify_tag(const char *name, unsigned flags)
static int verify_tag(const char *name, int verbose)
{
enum object_type type;
unsigned char sha1[20];
@ -61,7 +52,7 @@ static int verify_tag(const char *name, unsigned flags)
if (!buf)
return error("%s: unable to read file.", name);
ret = run_gpg_verify(buf, size, flags);
ret = run_gpg_verify(buf, size, verbose);
free(buf);
return ret;
@ -78,10 +69,8 @@ static int git_verify_tag_config(const char *var, const char *value, void *cb)
int cmd_verify_tag(int argc, const char **argv, const char *prefix)
{
int i = 1, verbose = 0, had_error = 0;
unsigned flags = 0;
const struct option verify_tag_options[] = {
OPT__VERBOSE(&verbose, N_("print tag contents")),
OPT_BIT(0, "raw", &flags, N_("print raw gpg status output"), GPG_VERIFY_RAW),
OPT_END()
};
@ -92,14 +81,11 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
if (argc <= i)
usage_with_options(verify_tag_usage, verify_tag_options);
if (verbose)
flags |= GPG_VERIFY_VERBOSE;
/* sometimes the program was terminated because this signal
* was received in the process of writing the gpg input: */
signal(SIGPIPE, SIG_IGN);
while (i < argc)
if (verify_tag(argv[i++], flags))
if (verify_tag(argv[i++], verbose))
had_error = 1;
return had_error;
}

View File

@ -3,8 +3,6 @@
#include "dir.h"
#include "parse-options.h"
#include "argv-array.h"
#include "branch.h"
#include "refs.h"
#include "run-command.h"
#include "sigchain.h"
#include "refs.h"
@ -15,13 +13,6 @@ static const char * const worktree_usage[] = {
NULL
};
struct add_opts {
int force;
int detach;
const char *new_branch;
int force_new_branch;
};
static int show_only;
static int verbose;
static unsigned long expire;
@ -181,35 +172,19 @@ static const char *worktree_basename(const char *path, int *olen)
return name;
}
static int add_worktree(const char *path, const char *refname,
const struct add_opts *opts)
static int add_worktree(const char *path, const char **child_argv)
{
struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
struct strbuf sb = STRBUF_INIT;
const char *name;
struct stat st;
struct child_process cp;
struct argv_array child_env = ARGV_ARRAY_INIT;
int counter = 0, len, ret;
struct strbuf symref = STRBUF_INIT;
struct commit *commit = NULL;
unsigned char rev[20];
if (file_exists(path) && !is_empty_dir(path))
die(_("'%s' already exists"), path);
/* is 'refname' a branch or commit? */
if (opts->force_new_branch) /* definitely a branch */
;
else if (!opts->detach && !strbuf_check_branch_ref(&symref, refname) &&
ref_exists(symref.buf)) { /* it's a branch */
if (!opts->force)
die_if_checked_out(symref.buf);
} else { /* must be a commit */
commit = lookup_commit_reference_by_name(refname);
if (!commit)
die(_("invalid reference: %s"), refname);
}
name = worktree_basename(path, &len);
strbuf_addstr(&sb_repo,
git_path("worktrees/%.*s", (int)(path + len - name), name));
@ -238,7 +213,7 @@ static int add_worktree(const char *path, const char *refname,
* after the preparation is over.
*/
strbuf_addf(&sb, "%s/locked", sb_repo.buf);
write_file(sb.buf, "initializing");
write_file(sb.buf, 1, "initializing\n");
strbuf_addf(&sb_git, "%s/.git", path);
if (safe_create_leading_directories_const(sb_git.buf))
@ -248,45 +223,37 @@ static int add_worktree(const char *path, const char *refname,
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
write_file(sb.buf, "%s", real_path(sb_git.buf));
write_file(sb_git.buf, "gitdir: %s/worktrees/%s",
write_file(sb.buf, 1, "%s\n", real_path(sb_git.buf));
write_file(sb_git.buf, 1, "gitdir: %s/worktrees/%s\n",
real_path(get_git_common_dir()), name);
/*
* This is to keep resolve_ref() happy. We need a valid HEAD
* or is_git_directory() will reject the directory. Any value which
* looks like an object ID will do since it will be immediately
* replaced by the symbolic-ref or update-ref invocation in the new
* worktree.
* or is_git_directory() will reject the directory. Moreover, HEAD
* in the new worktree must resolve to the same value as HEAD in
* the current tree since the command invoked to populate the new
* worktree will be handed the branch/ref specified by the user.
* For instance, if the user asks for the new worktree to be based
* at HEAD~5, then the resolved HEAD~5 in the new worktree must
* match the resolved HEAD~5 in the current tree in order to match
* the user's expectation.
*/
if (!resolve_ref_unsafe("HEAD", 0, rev, NULL))
die(_("unable to resolve HEAD"));
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
write_file(sb.buf, "0000000000000000000000000000000000000000");
write_file(sb.buf, 1, "%s\n", sha1_to_hex(rev));
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
write_file(sb.buf, "../..");
write_file(sb.buf, 1, "../..\n");
fprintf_ln(stderr, _("Preparing %s (identifier %s)"), path, name);
fprintf_ln(stderr, _("Enter %s (identifier %s)"), path, name);
argv_array_pushf(&child_env, "%s=%s", GIT_DIR_ENVIRONMENT, sb_git.buf);
argv_array_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
setenv("GIT_CHECKOUT_NEW_WORKTREE", "1", 1);
setenv(GIT_DIR_ENVIRONMENT, sb_git.buf, 1);
setenv(GIT_WORK_TREE_ENVIRONMENT, path, 1);
memset(&cp, 0, sizeof(cp));
cp.git_cmd = 1;
if (commit)
argv_array_pushl(&cp.args, "update-ref", "HEAD",
sha1_to_hex(commit->object.sha1), NULL);
else
argv_array_pushl(&cp.args, "symbolic-ref", "HEAD",
symref.buf, NULL);
cp.env = child_env.argv;
ret = run_command(&cp);
if (ret)
goto done;
cp.argv = NULL;
argv_array_clear(&cp.args);
argv_array_pushl(&cp.args, "reset", "--hard", NULL);
cp.env = child_env.argv;
cp.argv = child_argv;
ret = run_command(&cp);
if (!ret) {
is_junk = 0;
@ -295,13 +262,10 @@ static int add_worktree(const char *path, const char *refname,
junk_work_tree = NULL;
junk_git_dir = NULL;
}
done:
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/locked", sb_repo.buf);
unlink_or_warn(sb.buf);
argv_array_clear(&child_env);
strbuf_release(&sb);
strbuf_release(&symref);
strbuf_release(&sb_repo);
strbuf_release(&sb_git);
return ret;
@ -309,54 +273,47 @@ done:
static int add(int ac, const char **av, const char *prefix)
{
struct add_opts opts;
const char *new_branch_force = NULL;
int force = 0, detach = 0;
const char *new_branch = NULL, *new_branch_force = NULL;
const char *path, *branch;
struct argv_array cmd = ARGV_ARRAY_INIT;
struct option options[] = {
OPT__FORCE(&opts.force, N_("checkout <branch> even if already checked out in other worktree")),
OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
OPT__FORCE(&force, N_("checkout <branch> even if already checked out in other worktree")),
OPT_STRING('b', NULL, &new_branch, N_("branch"),
N_("create a new branch")),
OPT_STRING('B', NULL, &new_branch_force, N_("branch"),
N_("create or reset a branch")),
OPT_BOOL(0, "detach", &opts.detach, N_("detach HEAD at named commit")),
OPT_BOOL(0, "detach", &detach, N_("detach HEAD at named commit")),
OPT_END()
};
memset(&opts, 0, sizeof(opts));
ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
if (!!opts.detach + !!opts.new_branch + !!new_branch_force > 1)
die(_("-b, -B, and --detach are mutually exclusive"));
if (new_branch && new_branch_force)
die(_("-b and -B are mutually exclusive"));
if (ac < 1 || ac > 2)
usage_with_options(worktree_usage, options);
path = prefix ? prefix_filename(prefix, strlen(prefix), av[0]) : av[0];
branch = ac < 2 ? "HEAD" : av[1];
opts.force_new_branch = !!new_branch_force;
if (opts.force_new_branch)
opts.new_branch = new_branch_force;
if (ac < 2 && !opts.new_branch && !opts.detach) {
if (ac < 2 && !new_branch && !new_branch_force) {
int n;
const char *s = worktree_basename(path, &n);
opts.new_branch = xstrndup(s, n);
new_branch = xstrndup(s, n);
}
if (opts.new_branch) {
struct child_process cp;
memset(&cp, 0, sizeof(cp));
cp.git_cmd = 1;
argv_array_push(&cp.args, "branch");
if (opts.force_new_branch)
argv_array_push(&cp.args, "--force");
argv_array_push(&cp.args, opts.new_branch);
argv_array_push(&cp.args, branch);
if (run_command(&cp))
return -1;
branch = opts.new_branch;
}
argv_array_push(&cmd, "checkout");
if (force)
argv_array_push(&cmd, "--ignore-other-worktrees");
if (new_branch)
argv_array_pushl(&cmd, "-b", new_branch, NULL);
if (new_branch_force)
argv_array_pushl(&cmd, "-B", new_branch_force, NULL);
if (detach)
argv_array_push(&cmd, "--detach");
argv_array_push(&cmd, branch);
return add_worktree(path, branch, &opts);
return add_worktree(path, cmd.argv);
}
int cmd_worktree(int ac, const char **av, const char *prefix)

View File

@ -235,9 +235,7 @@ out:
return result;
}
/* Write the pack data to bundle_fd, then close it if it is > 1. */
static int write_pack_data(int bundle_fd, struct rev_info *revs)
static int write_pack_data(int bundle_fd, struct lock_file *lock, struct rev_info *revs)
{
struct child_process pack_objects = CHILD_PROCESS_INIT;
int i;
@ -252,6 +250,13 @@ static int write_pack_data(int bundle_fd, struct rev_info *revs)
if (start_command(&pack_objects))
return error(_("Could not spawn pack-objects"));
/*
* start_command closed bundle_fd if it was > 1
* so set the lock fd to -1 so commit_lock_file()
* won't fail trying to close it.
*/
lock->fd = -1;
for (i = 0; i < revs->pending.nr; i++) {
struct object *object = revs->pending.objects[i].item;
if (object->flags & UNINTERESTING)
@ -411,21 +416,10 @@ int create_bundle(struct bundle_header *header, const char *path,
bundle_to_stdout = !strcmp(path, "-");
if (bundle_to_stdout)
bundle_fd = 1;
else {
else
bundle_fd = hold_lock_file_for_update(&lock, path,
LOCK_DIE_ON_ERROR);
/*
* write_pack_data() will close the fd passed to it,
* but commit_lock_file() will also try to close the
* lockfile's fd. So make a copy of the file
* descriptor to avoid trying to close it twice.
*/
bundle_fd = dup(bundle_fd);
if (bundle_fd < 0)
die_errno("unable to dup file descriptor");
}
/* write signature */
write_or_die(bundle_fd, bundle_signature, strlen(bundle_signature));
@ -451,7 +445,7 @@ int create_bundle(struct bundle_header *header, const char *path,
return -1;
/* write pack */
if (write_pack_data(bundle_fd, &revs))
if (write_pack_data(bundle_fd, &lock, &revs))
return -1;
if (!bundle_to_stdout) {

View File

@ -592,7 +592,7 @@ static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *pat
return it;
}
int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, const char *index_path, int flags, const char *prefix)
int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix)
{
int entries, was_valid, newfd;
struct lock_file *lock_file;
@ -603,23 +603,23 @@ int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, co
*/
lock_file = xcalloc(1, sizeof(struct lock_file));
newfd = hold_lock_file_for_update(lock_file, index_path, LOCK_DIE_ON_ERROR);
newfd = hold_locked_index(lock_file, 1);
entries = read_index_from(index_state, index_path);
entries = read_cache();
if (entries < 0)
return WRITE_TREE_UNREADABLE_INDEX;
if (flags & WRITE_TREE_IGNORE_CACHE_TREE)
cache_tree_free(&index_state->cache_tree);
cache_tree_free(&(active_cache_tree));
if (!index_state->cache_tree)
index_state->cache_tree = cache_tree();
if (!active_cache_tree)
active_cache_tree = cache_tree();
was_valid = cache_tree_fully_valid(index_state->cache_tree);
was_valid = cache_tree_fully_valid(active_cache_tree);
if (!was_valid) {
if (cache_tree_update(index_state, flags) < 0)
if (cache_tree_update(&the_index, flags) < 0)
return WRITE_TREE_UNMERGED_INDEX;
if (0 <= newfd) {
if (!write_locked_index(index_state, lock_file, COMMIT_LOCK))
if (!write_locked_index(&the_index, lock_file, COMMIT_LOCK))
newfd = -1;
}
/* Not being able to write is fine -- we are only interested
@ -631,14 +631,14 @@ int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, co
}
if (prefix) {
struct cache_tree *subtree;
subtree = cache_tree_find(index_state->cache_tree, prefix);
struct cache_tree *subtree =
cache_tree_find(active_cache_tree, prefix);
if (!subtree)
return WRITE_TREE_PREFIX_ERROR;
hashcpy(sha1, subtree->sha1);
}
else
hashcpy(sha1, index_state->cache_tree->sha1);
hashcpy(sha1, active_cache_tree->sha1);
if (0 <= newfd)
rollback_lock_file(lock_file);
@ -646,11 +646,6 @@ int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, co
return 0;
}
int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix)
{
return write_index_as_tree(sha1, &the_index, get_index_file(), flags, prefix);
}
static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree)
{
struct tree_desc desc;

View File

@ -46,7 +46,6 @@ int update_main_cache_tree(int);
#define WRITE_TREE_UNMERGED_INDEX (-2)
#define WRITE_TREE_PREFIX_ERROR (-3)
int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, const char *index_path, int flags, const char *prefix);
int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix);
void prime_cache_tree(struct index_state *, struct tree *);

174
cache.h
View File

@ -397,7 +397,6 @@ static inline enum object_type object_type(unsigned int mode)
#define EXEC_PATH_ENVIRONMENT "GIT_EXEC_PATH"
#define CEILING_DIRECTORIES_ENVIRONMENT "GIT_CEILING_DIRECTORIES"
#define NO_REPLACE_OBJECTS_ENVIRONMENT "GIT_NO_REPLACE_OBJECTS"
#define GIT_REPLACE_REF_BASE_ENVIRONMENT "GIT_REPLACE_REF_BASE"
#define GITATTRIBUTES_FILE ".gitattributes"
#define INFOATTRIBUTES_FILE "info/attributes"
#define ATTRIBUTE_MACRO_PREFIX "[attr]"
@ -447,17 +446,7 @@ extern int get_common_dir(struct strbuf *sb, const char *gitdir);
extern const char *get_git_namespace(void);
extern const char *strip_namespace(const char *namespaced_ref);
extern const char *get_git_work_tree(void);
#define READ_GITFILE_ERR_STAT_FAILED 1
#define READ_GITFILE_ERR_NOT_A_FILE 2
#define READ_GITFILE_ERR_OPEN_FAILED 3
#define READ_GITFILE_ERR_READ_FAILED 4
#define READ_GITFILE_ERR_INVALID_FORMAT 5
#define READ_GITFILE_ERR_NO_PATH 6
#define READ_GITFILE_ERR_NOT_A_REPO 7
#define READ_GITFILE_ERR_TOO_LARGE 8
extern const char *read_gitfile_gently(const char *path, int *return_error_code);
#define read_gitfile(path) read_gitfile_gently((path), NULL)
extern const char *read_gitfile(const char *path);
extern const char *resolve_gitdir(const char *suspect);
extern void set_git_work_tree(const char *tree);
@ -596,6 +585,8 @@ extern void update_index_if_able(struct index_state *, struct lock_file *);
extern int hold_locked_index(struct lock_file *, int);
extern void set_alternate_index_output(const char *);
extern int delete_ref(const char *, const unsigned char *sha1, unsigned int flags);
/* Environment bits from configuration mechanism */
extern int trust_executable_bit;
extern int trust_ctime;
@ -631,7 +622,6 @@ extern unsigned long pack_size_limit_cfg;
* been sought but there were none.
*/
extern int check_replace_refs;
extern char *git_replace_ref_base;
extern int fsync_object_files;
extern int core_preload_index;
@ -708,59 +698,22 @@ extern int check_repository_format(void);
#define DATA_CHANGED 0x0020
#define TYPE_CHANGED 0x0040
/*
* Return a statically allocated filename, either generically (mkpath), in
* the repository directory (git_path), or in a submodule's repository
* directory (git_path_submodule). In all cases, note that the result
* may be overwritten by another call to _any_ of the functions. Consider
* using the safer "dup" or "strbuf" formats below (in some cases, the
* unsafe versions have already been removed).
*/
extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
__attribute__((format (printf, 3, 4)));
extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
__attribute__((format (printf, 2, 3)));
extern void strbuf_git_path_submodule(struct strbuf *sb, const char *path,
const char *fmt, ...)
__attribute__((format (printf, 3, 4)));
extern char *git_pathdup(const char *fmt, ...)
__attribute__((format (printf, 1, 2)));
extern char *mkpathdup(const char *fmt, ...)
__attribute__((format (printf, 1, 2)));
extern char *git_pathdup_submodule(const char *path, const char *fmt, ...)
/* Return a statically allocated filename matching the sha1 signature */
extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
extern const char *git_path_submodule(const char *path, const char *fmt, ...)
__attribute__((format (printf, 2, 3)));
extern void report_linked_checkout_garbage(void);
/*
* You can define a static memoized git path like:
*
* static GIT_PATH_FUNC(git_path_foo, "FOO");
*
* or use one of the global ones below.
*/
#define GIT_PATH_FUNC(func, filename) \
const char *func(void) \
{ \
static char *ret; \
if (!ret) \
ret = git_pathdup(filename); \
return ret; \
}
const char *git_path_cherry_pick_head(void);
const char *git_path_revert_head(void);
const char *git_path_squash_msg(void);
const char *git_path_merge_msg(void);
const char *git_path_merge_rr(void);
const char *git_path_merge_mode(void);
const char *git_path_merge_head(void);
const char *git_path_fetch_head(void);
const char *git_path_shallow(void);
/*
* Return the name of the file in the local object database that would
* be used to store a loose object with the specified sha1. The
@ -982,7 +935,7 @@ extern int do_check_packed_object_crc;
extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
extern int finalize_object_file(const char *tmpfile, const char *filename);
extern int move_temp_to_file(const char *tmpfile, const char *filename);
extern int has_sha1_pack(const unsigned char *sha1);
@ -1067,10 +1020,76 @@ extern int get_oid_hex(const char *hex, struct object_id *sha1);
extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
extern char *oid_to_hex(const struct object_id *oid); /* same static buffer as sha1_to_hex */
extern int read_ref_full(const char *refname, int resolve_flags,
unsigned char *sha1, int *flags);
extern int read_ref(const char *refname, unsigned char *sha1);
/*
* Resolve a reference, recursively following symbolic refererences.
*
* Store the referred-to object's name in sha1 and return the name of
* the non-symbolic reference that ultimately pointed at it. The
* return value, if not NULL, is a pointer into either a static buffer
* or the input ref.
*
* If the reference cannot be resolved to an object, the behavior
* depends on the RESOLVE_REF_READING flag:
*
* - If RESOLVE_REF_READING is set, return NULL.
*
* - If RESOLVE_REF_READING is not set, clear sha1 and return the name of
* the last reference name in the chain, which will either be a non-symbolic
* reference or an undefined reference. If this is a prelude to
* "writing" to the ref, the return value is the name of the ref
* that will actually be created or changed.
*
* If the RESOLVE_REF_NO_RECURSE flag is passed, only resolves one
* level of symbolic reference. The value stored in sha1 for a symbolic
* reference will always be null_sha1 in this case, and the return
* value is the reference that the symref refers to directly.
*
* If flags is non-NULL, set the value that it points to the
* combination of REF_ISPACKED (if the reference was found among the
* packed references), REF_ISSYMREF (if the initial reference was a
* symbolic reference), REF_BAD_NAME (if the reference name is ill
* formed --- see RESOLVE_REF_ALLOW_BAD_NAME below), and REF_ISBROKEN
* (if the ref is malformed or has a bad name). See refs.h for more detail
* on each flag.
*
* If ref is not a properly-formatted, normalized reference, return
* NULL. If more than MAXDEPTH recursive symbolic lookups are needed,
* give up and return NULL.
*
* RESOLVE_REF_ALLOW_BAD_NAME allows resolving refs even when their
* name is invalid according to git-check-ref-format(1). If the name
* is bad then the value stored in sha1 will be null_sha1 and the two
* flags REF_ISBROKEN and REF_BAD_NAME will be set.
*
* Even with RESOLVE_REF_ALLOW_BAD_NAME, names that escape the refs/
* directory and do not consist of all caps and underscores cannot be
* resolved. The function returns NULL for such ref names.
* Caps and underscores refers to the special refs, such as HEAD,
* FETCH_HEAD and friends, that all live outside of the refs/ directory.
*/
#define RESOLVE_REF_READING 0x01
#define RESOLVE_REF_NO_RECURSE 0x02
#define RESOLVE_REF_ALLOW_BAD_NAME 0x04
extern const char *resolve_ref_unsafe(const char *ref, int resolve_flags, unsigned char *sha1, int *flags);
extern char *resolve_refdup(const char *ref, int resolve_flags, unsigned char *sha1, int *flags);
extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
extern int interpret_branch_name(const char *str, int len, struct strbuf *);
extern int get_sha1_mb(const char *str, unsigned char *sha1);
/*
* Return true iff abbrev_name is a possible abbreviation for
* full_name according to the rules defined by ref_rev_parse_rules in
* refs.c.
*/
extern int refname_match(const char *abbrev_name, const char *full_name);
extern int create_symref(const char *ref, const char *refs_heads_master, const char *logmsg);
extern int validate_headref(const char *ref);
extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
@ -1086,30 +1105,18 @@ extern void *read_object_with_reference(const unsigned char *sha1,
extern struct object *peel_to_type(const char *name, int namelen,
struct object *o, enum object_type);
struct date_mode {
enum date_mode_type {
DATE_NORMAL = 0,
DATE_RELATIVE,
DATE_SHORT,
DATE_LOCAL,
DATE_ISO8601,
DATE_ISO8601_STRICT,
DATE_RFC2822,
DATE_STRFTIME,
DATE_RAW
} type;
const char *strftime_fmt;
enum date_mode {
DATE_NORMAL = 0,
DATE_RELATIVE,
DATE_SHORT,
DATE_LOCAL,
DATE_ISO8601,
DATE_ISO8601_STRICT,
DATE_RFC2822,
DATE_RAW
};
/*
* Convenience helper for passing a constant type, like:
*
* show_date(t, tz, DATE_MODE(NORMAL));
*/
#define DATE_MODE(t) date_mode_from_type(DATE_##t)
struct date_mode *date_mode_from_type(enum date_mode_type type);
const char *show_date(unsigned long time, int timezone, const struct date_mode *mode);
const char *show_date(unsigned long time, int timezone, enum date_mode mode);
void show_date_relative(unsigned long time, int tz, const struct timeval *now,
struct strbuf *timebuf);
int parse_date(const char *date, struct strbuf *out);
@ -1119,7 +1126,7 @@ void datestamp(struct strbuf *out);
#define approxidate(s) approxidate_careful((s), NULL)
unsigned long approxidate_careful(const char *, int *);
unsigned long approxidate_relative(const char *date, const struct timeval *now);
void parse_date_format(const char *format, struct date_mode *mode);
enum date_mode parse_date_format(const char *format);
int date_overflows(unsigned long date);
#define IDENT_STRICT 1
@ -1156,8 +1163,7 @@ extern int split_ident_line(struct ident_split *, const char *, int);
* the ident_split. It will also sanity-check the values and produce
* a well-known sentinel date if they appear bogus.
*/
const char *show_ident_date(const struct ident_split *id,
const struct date_mode *mode);
const char *show_ident_date(const struct ident_split *id, enum date_mode mode);
/*
* Compare split idents for equality or strict ordering. Note that we
@ -1429,7 +1435,6 @@ extern int git_config_with_options(config_fn_t fn, void *,
int respect_includes);
extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
extern int git_parse_ulong(const char *, unsigned long *);
extern int git_parse_maybe_bool(const char *);
extern int git_config_int(const char *, const char *);
extern int64_t git_config_int64(const char *, const char *);
extern unsigned long git_config_ulong(const char *, const char *);
@ -1578,9 +1583,8 @@ static inline ssize_t write_str_in_full(int fd, const char *str)
{
return write_in_full(fd, str, strlen(str));
}
extern int write_file(const char *path, const char *fmt, ...);
extern int write_file_gently(const char *path, const char *fmt, ...);
__attribute__((format (printf, 3, 4)))
extern int write_file(const char *path, int fatal, const char *fmt, ...);
/* pager.c */
extern void setup_pager(void);

View File

@ -15,13 +15,7 @@
* - int *indegree_at(struct indegree *, struct commit *);
*
* This function locates the data associated with the given commit in
* the indegree slab, and returns the pointer to it. The location to
* store the data is allocated as necessary.
*
* - int *indegree_peek(struct indegree *, struct commit *);
*
* This function is similar to indegree_at(), but it will return NULL
* until a call to indegree_at() was made for the commit.
* the indegree slab, and returns the pointer to it.
*
* - void init_indegree(struct indegree *);
* void init_indegree_with_stride(struct indegree *, int);
@ -86,9 +80,8 @@ static MAYBE_UNUSED void clear_ ##slabname(struct slabname *s) \
s->slab = NULL; \
} \
\
static MAYBE_UNUSED elemtype *slabname## _at_peek(struct slabname *s, \
const struct commit *c, \
int add_if_missing) \
static MAYBE_UNUSED elemtype *slabname## _at(struct slabname *s, \
const struct commit *c) \
{ \
int nth_slab, nth_slot; \
\
@ -97,33 +90,16 @@ static MAYBE_UNUSED elemtype *slabname## _at_peek(struct slabname *s, \
\
if (s->slab_count <= nth_slab) { \
int i; \
if (!add_if_missing) \
return NULL; \
REALLOC_ARRAY(s->slab, nth_slab + 1); \
stat_ ##slabname## realloc++; \
for (i = s->slab_count; i <= nth_slab; i++) \
s->slab[i] = NULL; \
s->slab_count = nth_slab + 1; \
} \
if (!s->slab[nth_slab]) { \
if (!add_if_missing) \
return NULL; \
if (!s->slab[nth_slab]) \
s->slab[nth_slab] = xcalloc(s->slab_size, \
sizeof(**s->slab) * s->stride); \
} \
return &s->slab[nth_slab][nth_slot * s->stride]; \
} \
\
static MAYBE_UNUSED elemtype *slabname## _at(struct slabname *s, \
const struct commit *c) \
{ \
return slabname##_at_peek(s, c, 1); \
} \
\
static MAYBE_UNUSED elemtype *slabname## _peek(struct slabname *s, \
const struct commit *c) \
{ \
return slabname##_at_peek(s, c, 0); \
return &s->slab[nth_slab][nth_slot * s->stride]; \
} \
\
static int stat_ ##slabname## realloc

View File

@ -245,12 +245,7 @@ void set_commit_buffer(struct commit *commit, void *buffer, unsigned long size)
const void *get_cached_commit_buffer(const struct commit *commit, unsigned long *sizep)
{
struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
if (!v) {
if (sizep)
*sizep = 0;
return NULL;
}
struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
if (sizep)
*sizep = v->size;
return v->buffer;
@ -277,31 +272,24 @@ const void *get_commit_buffer(const struct commit *commit, unsigned long *sizep)
void unuse_commit_buffer(const struct commit *commit, const void *buffer)
{
struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
if (!(v && v->buffer == buffer))
struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
if (v->buffer != buffer)
free((void *)buffer);
}
void free_commit_buffer(struct commit *commit)
{
struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
if (v) {
free(v->buffer);
v->buffer = NULL;
v->size = 0;
}
struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
free(v->buffer);
v->buffer = NULL;
v->size = 0;
}
const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep)
{
struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
void *ret;
if (!v) {
if (sizep)
*sizep = 0;
return NULL;
}
ret = v->buffer;
if (sizep)
*sizep = v->size;
@ -1244,24 +1232,33 @@ free_return:
free(buf);
}
int check_commit_signature(const struct commit *commit, struct signature_check *sigc)
void check_commit_signature(const struct commit *commit, struct signature_check *sigc)
{
struct strbuf payload = STRBUF_INIT;
struct strbuf signature = STRBUF_INIT;
int ret = 1;
struct strbuf gpg_output = STRBUF_INIT;
struct strbuf gpg_status = STRBUF_INIT;
int status;
sigc->result = 'N';
if (parse_signed_commit(commit, &payload, &signature) <= 0)
goto out;
ret = check_signature(payload.buf, payload.len, signature.buf,
signature.len, sigc);
status = verify_signed_buffer(payload.buf, payload.len,
signature.buf, signature.len,
&gpg_output, &gpg_status);
if (status && !gpg_output.len)
goto out;
sigc->payload = strbuf_detach(&payload, NULL);
sigc->gpg_output = strbuf_detach(&gpg_output, NULL);
sigc->gpg_status = strbuf_detach(&gpg_status, NULL);
parse_gpg_output(sigc);
out:
strbuf_release(&gpg_status);
strbuf_release(&gpg_output);
strbuf_release(&payload);
strbuf_release(&signature);
return ret;
}

View File

@ -145,7 +145,7 @@ struct pretty_print_context {
const char *subject;
const char *after_subject;
int preserve_subject;
struct date_mode date_mode;
enum date_mode date_mode;
unsigned date_mode_explicit:1;
int need_8bit_cte;
char *notes_message;
@ -379,7 +379,7 @@ extern void print_commit_list(struct commit_list *list,
* at all. This may allocate memory for sig->gpg_output, sig->gpg_status,
* sig->signer and sig->key.
*/
extern int check_commit_signature(const struct commit *commit, struct signature_check *sigc);
extern void check_commit_signature(const struct commit *commit, struct signature_check *sigc);
int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused);

Some files were not shown because too many files have changed in this diff Show More