Compare commits
33 Commits
v2.6.0-rc0
...
v2.5.2
Author | SHA1 | Date | |
---|---|---|---|
27ea6f85be | |||
3d3caf0b78 | |||
74b6763816 | |||
ef0e938a1a | |||
ecad27cf98 | |||
8267cd11d6 | |||
441c4a4017 | |||
f54cb059b1 | |||
78f23bdf68 | |||
5015f01c12 | |||
c29edfefb6 | |||
f514ef9787 | |||
fb8880dea3 | |||
5af77d1352 | |||
9d939886db | |||
311e5ce2cc | |||
1c82039228 | |||
ae6ac8483b | |||
8136099a31 | |||
dc4e7b0244 | |||
659227be2e | |||
57a2bb1f92 | |||
c1fa16b193 | |||
d6c196abfd | |||
e654e3b574 | |||
fa6d3749ed | |||
0b2cef2805 | |||
969560bddc | |||
d11448f685 | |||
8b2707101a | |||
6c0850f2dd | |||
cbcd3dcaa8 | |||
03ea02771a |
1
.gitignore
vendored
1
.gitignore
vendored
@ -205,7 +205,6 @@
|
||||
/test-sha1-array
|
||||
/test-sigchain
|
||||
/test-string-list
|
||||
/test-submodule-config
|
||||
/test-subprocess
|
||||
/test-svn-fe
|
||||
/test-urlmatch-normalization
|
||||
|
9
Documentation/RelNotes/2.2.3.txt
Normal file
9
Documentation/RelNotes/2.2.3.txt
Normal 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.
|
9
Documentation/RelNotes/2.3.9.txt
Normal file
9
Documentation/RelNotes/2.3.9.txt
Normal 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.
|
9
Documentation/RelNotes/2.4.9.txt
Normal file
9
Documentation/RelNotes/2.4.9.txt
Normal 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.
|
63
Documentation/RelNotes/2.5.2.txt
Normal file
63
Documentation/RelNotes/2.5.2.txt
Normal 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.
|
@ -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).
|
@ -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`
|
||||
|
@ -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::
|
||||
|
@ -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
|
||||
--------
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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 (`/`)
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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'::
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
-------
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
---
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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].
|
||||
|
@ -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
|
||||
|
@ -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).
|
||||
|
||||
|
@ -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.
|
||||
|
220
Documentation/technical/api-lockfile.txt
Normal file
220
Documentation/technical/api-lockfile.txt
Normal 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.
|
@ -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()`.
|
||||
|
||||
|
@ -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.
|
@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
GVF=GIT-VERSION-FILE
|
||||
DEF_VER=v2.6.0-rc0
|
||||
DEF_VER=v2.5.2
|
||||
|
||||
LF='
|
||||
'
|
||||
|
8
Makefile
8
Makefile
@ -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
|
||||
|
8
advice.c
8
advice.c
@ -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[] =
|
||||
|
1
advice.h
1
advice.h
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
4
attr.c
@ -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
125
bisect.c
@ -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)
|
||||
|
2
bisect.h
2
bisect.h
@ -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
103
branch.c
@ -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"));
|
||||
}
|
||||
|
15
branch.h
15
branch.h
@ -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
|
||||
|
@ -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);
|
||||
|
2389
builtin/am.c
2389
builtin/am.c
File diff suppressed because it is too large
Load Diff
@ -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 */
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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, "ed);
|
||||
printf(dry_run ? _(msg_would_skip_git_dir) : _(msg_skip_git_dir),
|
||||
|
123
builtin/clone.c
123
builtin/clone.c
@ -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)
|
||||
|
@ -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"
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,6 @@
|
||||
*/
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "refs.h"
|
||||
#include "commit.h"
|
||||
#include "object.h"
|
||||
#include "tag.h"
|
||||
|
@ -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)
|
||||
|
@ -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
@ -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) {
|
||||
|
34
builtin/gc.c
34
builtin/gc.c
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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++;
|
||||
|
@ -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."));
|
||||
|
@ -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());
|
||||
|
@ -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,
|
||||
|
887
builtin/pull.c
887
builtin/pull.c
@ -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();
|
||||
}
|
@ -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"));
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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/"));
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
26
bundle.c
26
bundle.c
@ -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) {
|
||||
|
29
cache-tree.c
29
cache-tree.c
@ -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;
|
||||
|
@ -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
174
cache.h
@ -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);
|
||||
|
@ -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
|
||||
|
49
commit.c
49
commit.c
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
4
commit.h
4
commit.h
@ -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
Reference in New Issue
Block a user