Compare commits

..

71 Commits

Author SHA1 Message Date
68372c8879 Git 2.18-rc2
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-13 12:57:07 -07:00
549ca8aa7c Merge branch 'jk/index-pack-maint'
"index-pack --strict" has been taught to make sure that it runs the
final object integrity checks after making the freshly indexed
packfile available to itself.

* jk/index-pack-maint:
  index-pack: correct install_packed_git() args
  index-pack: handle --strict checks of non-repo packs
  prepare_commit_graft: treat non-repository as a noop
2018-06-13 12:50:46 -07:00
4d605b0f38 Merge branch 'sg/completion-zsh-workaround'
Work around zsh segfaulting when loading git-completion.zsh

* sg/completion-zsh-workaround:
  completion: correct zsh detection when run from git-completion.zsh
2018-06-13 12:50:45 -07:00
8d0d53a8cf Merge branch 'sb/submodule-merge-in-merge-recursive'
Finishing touches to a topic that already is in 'master'.

* sb/submodule-merge-in-merge-recursive:
  merge-submodule: reduce output verbosity
2018-06-13 12:50:45 -07:00
fb6ac9e79a Merge branch 'jk/submodule-fsck-loose-fixup'
Finishing touches to a topic that already is in 'maint'.

* jk/submodule-fsck-loose-fixup:
  fsck: avoid looking at NULL blob->object
  t7415: don't bother creating commit for symlink test
2018-06-13 12:50:44 -07:00
b2453d3449 RelNotes 2.18: clarify where directory rename detection applies
Mention that this feature works with some commands (merge and cherry-pick,
implying that it also works with commands that build on these like rebase
-m and rebase -i).  Explicitly mentioning two commands hopefully implies
that it may not always work with other commands (am, and rebase without
flags that imply either -m or -i).

Also, since the directory rename detection from this cycle was
specifically added in merge-recursive and not diffcore-rename, remove the
'in "diff" family" phrase from the note.  (Folks have requested in the
past that `git diff` detect directory renames and somehow simplify its
output, so it may be helpful to avoid implying that diff has any new
capability here.)

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-13 10:47:13 -07:00
61d48c66ea completion: correct zsh detection when run from git-completion.zsh
v2.18.0-rc0~90^2 (completion: reduce overhead of clearing cached
--options, 2018-04-18) worked around a bug in bash's "set" builtin on
MacOS by using compgen instead.  It was careful to avoid breaking zsh
by guarding this workaround with

	if [[ -n ${ZSH_VERSION-}} ]]

Alas, this interacts poorly with git-completion.zsh's bash emulation:

	ZSH_VERSION='' . "$script"

Correct it by instead using a new GIT_SOURCING_ZSH_COMPLETION shell
variable to detect whether git-completion.bash is being sourced from
git-completion.zsh.  This way, the zsh variant is used both when run
from zsh directly and when run via git-completion.zsh.

Reproduction recipe:

 1. cd git/contrib/completion && cp git-completion.zsh _git
 2. Put the following in a new ~/.zshrc file:

 	autoload -U compinit; compinit
	autoload -U bashcompinit; bashcompinit
	fpath=(~/src/git/contrib/completion $fpath)

 3. Open zsh and "git <TAB>".

With this patch:
Triggers nice git-completion.bash based tab completion

Without:
 contrib/completion/git-completion.bash:354: read-only variable: QISUFFIX
 zsh:12: command not found: ___main
 zsh:15: _default: function definition file not found
 _dispatch:70: bad math expression: operand expected at `/usr/bin/g...'
 Segmentation fault

Reported-by: Rick van Hattem <wolph@wol.ph>
Reported-by: Dave Borowitz <dborowitz@google.com>
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-12 10:13:44 -07:00
3737746120 index-pack: correct install_packed_git() args
The function does not start taking the repository object as a
parameter before v2.18 track.  Make the topic mergeable to v2.17
maintenance track by dropping it.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-11 15:09:18 -07:00
40aac22b43 merge-submodule: reduce output verbosity
The output shall behave more similar to ordinary file merges' output to provide
a more consistent user experience.

Signed-off-by: Leif Middelschulte <Leif.Middelschulte@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-11 11:03:55 -07:00
47cc91310a fsck: avoid looking at NULL blob->object
Commit 159e7b080b (fsck: detect gitmodules files,
2018-05-02) taught fsck to look at the content of
.gitmodules files. If the object turns out not to be a blob
at all, we just complain and punt on checking the content.
And since this was such an obvious and trivial code path, I
didn't even bother to add a test.

Except it _does_ do one non-trivial thing, which is call the
report() function, which wants us to pass a pointer to a
"struct object". Which we don't have (we have only a "struct
object_id"). So we erroneously pass a NULL object to
report(), which gets dereferenced and causes a segfault.

It seems like we could refactor report() to just take the
object_id itself. But we pass the object pointer along to
a callback function, and indeed this ends up in
builtin/fsck.c's objreport() which does want to look at
other parts of the object (like the type).

So instead, let's just use lookup_unknown_object() to get
the real "struct object", and pass that.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-11 10:56:06 -07:00
431acd2de8 t7415: don't bother creating commit for symlink test
Early versions of the fsck .gitmodules detection code
actually required a tree to be at the root of a commit for
it to be checked for .gitmodules. What we ended up with in
159e7b080b (fsck: detect gitmodules files, 2018-05-02),
though, finds a .gitmodules file in _any_ tree (see that
commit for more discussion).

As a result, there's no need to create a commit in our
tests. Let's drop it in the name of simplicity. And since
that was the only thing referencing $tree, we can pull our
tree creation out of a command substitution.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-11 10:56:04 -07:00
6f333ff2fb RelNotes 2.18: typofixes
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-11 09:15:34 -07:00
3e5524907b Git 2.18-rc1
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-04 21:41:41 +09:00
e66e8f9be8 Merge branch 'bc/t3430-fixup'
Test fix.

* bc/t3430-fixup:
  t3430: test clean-up
2018-06-04 21:39:50 +09:00
01cbd9eab5 Merge branch 'bw/refspec-api'
Hotfix.

* bw/refspec-api:
  refspec-api: avoid uninitialized field in refspec item
2018-06-04 21:39:50 +09:00
7fe48cb396 Merge branch 'tg/doc-sec-list'
Doc update.

* tg/doc-sec-list:
  note git-security@googlegroups.com in more places
  SubmittingPatches: replace numbered attributes with names
2018-06-04 21:39:49 +09:00
c45505d081 Merge branch 'rd/p4-doc-markup-env'
Doc markup update.

* rd/p4-doc-markup-env:
  p4.txt: Use backquotes for variable names
2018-06-04 21:39:49 +09:00
643a9ea3e0 Merge branch 'nd/remote-update-doc'
"git remote update" can take both a single remote nickname and a
nickname for remote groups, but only one of them was documented.

* nd/remote-update-doc:
  remote: doc typofix
  remote.txt: update documentation for 'update' command
2018-06-04 21:39:49 +09:00
f635b8d17b Merge branch 'jt/submodule-pull-recurse-rebase'
"git pull -recurse-submodules --rebase", when the submodule
repository's history did not have anything common between ours and
the upstream's, failed to execute.  We need to fetch from them to
continue even in such a case.

* jt/submodule-pull-recurse-rebase:
  submodule: do not pass null OID to setup_revisions
2018-06-04 21:39:48 +09:00
a97447a42a remote: doc typofix
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-04 20:04:33 +09:00
0c5a779c67 t3430: test clean-up
Remove unnecessary test_tick etc...

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-04 11:21:28 +09:00
c2c7d17b03 A bit more topics before -rc1
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-01 15:16:15 +09:00
026b8ef9f7 Merge branch 'bw/ref-prefix-for-configured-refspec'
* bw/ref-prefix-for-configured-refspec:
  fetch: do not pass ref-prefixes for fetch by exact SHA1
2018-06-01 15:15:35 +09:00
6c301adb0a fetch: do not pass ref-prefixes for fetch by exact SHA1
When v2.18.0-rc0~10^2~1 (refspec: consolidate ref-prefix generation
logic, 2018-05-16) factored out the ref-prefix generation code for
reuse, it left out the 'if (!item->exact_sha1)' test in the original
ref-prefix generation code. As a result, fetches by SHA-1 generate
ref-prefixes as though the SHA-1 being fetched were an abbreviated ref
name:

 $ GIT_TRACE_PACKET=1 bin-wrappers/git -c protocol.version=2 \
	fetch origin 12039e008f
[...]
 packet:        fetch> ref-prefix 12039e008f
 packet:        fetch> ref-prefix refs/12039e008f9a4e3394f3f94f8ea897785cb09448
 packet:        fetch> ref-prefix refs/tags/12039e008f9a4e3394f3f94f8ea897785cb09448
 packet:        fetch> ref-prefix refs/heads/12039e008f9a4e3394f3f94f8ea897785cb09448
 packet:        fetch> ref-prefix refs/remotes/12039e008f9a4e3394f3f94f8ea897785cb09448
 packet:        fetch> ref-prefix refs/remotes/12039e008f9a4e3394f3f94f8ea897785cb09448/HEAD
 packet:        fetch> 0000

If there is another ref name on the command line or the object being
fetched is already available locally, then that's mostly harmless.
But otherwise, we error out with

 fatal: no matching remote head

since the server did not send any refs we are interested in.  Filter
out the exact_sha1 refspecs to avoid this.

This patch adds a test to check this behavior that notices another
behavior difference between protocol v0 and v2 in the process.  Add a
NEEDSWORK comment to clear it up.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-01 15:15:22 +09:00
d6e5484208 Merge branch 'cc/tests-without-assuming-ref-files-backend'
Quite a many tests assumed that newly created refs are made as
loose refs using the files backend, which have been updated to use
proper plumbing like rev-parse and update-ref, to avoid breakage
once we start using different ref backends.

* cc/tests-without-assuming-ref-files-backend:
  t990X: use '.git/objects' as 'deep inside .git' path
  t: make many tests depend less on the refs being files
2018-06-01 15:06:41 +09:00
ba928e9740 Merge branch 'rd/init-typo'
Message fix.

* rd/init-typo:
  init: fix grammar in "templates not found" msg
2018-06-01 15:06:40 +09:00
95dd4b2b14 Merge branch 'js/rebase-recreate-merge'
Hotfixes.

* js/rebase-recreate-merge:
  sequencer: ensure labels that are object IDs are rewritten
  git-rebase--interactive: fix copy-paste mistake
2018-06-01 15:06:40 +09:00
cbb408e6ae Merge branch 'rd/tag-doc-lightweight'
Docfix.

* rd/tag-doc-lightweight:
  tag: clarify in the doc that a tag can refer to a non-commit object
2018-06-01 15:06:39 +09:00
7659bda0f3 Merge branch 'rd/doc-options-placeholder'
Docfix.

* rd/doc-options-placeholder:
  Use proper syntax for replaceables in command docs
2018-06-01 15:06:39 +09:00
7cb4a974d3 Merge branch 'en/rev-parse-invalid-range'
"git rev-parse Y..." etc. misbehaved when given endpoints were
not committishes.

* en/rev-parse-invalid-range:
  rev-parse: check lookup'ed commit references for NULL
2018-06-01 15:06:39 +09:00
caf0c98c63 Merge branch 'ld/p4-unshelve'
"git p4" learned to "unshelve" shelved commit from P4.

* ld/p4-unshelve:
  git-p4: add unshelve command
2018-06-01 15:06:38 +09:00
e1149fd7d9 Merge branch 'nd/use-opt-int-set-f'
Code simplification.

* nd/use-opt-int-set-f:
  Use OPT_SET_INT_F() for cmdline option specification
2018-06-01 15:06:38 +09:00
2bd108ff65 Merge branch 'pa/import-tars-long-names'
The import-tars script (in contrib/) has been taught to handle
tarballs with overly long paths that use PAX extended headers.

* pa/import-tars-long-names:
  import-tars: read overlong names from pax extended header
2018-06-01 15:06:38 +09:00
2289880f78 Merge branch 'nd/command-list'
The list of commands with their various attributes were spread
across a few places in the build procedure, but it now is getting a
bit more consolidated to allow more automation.

* nd/command-list:
  completion: allow to customize the completable command list
  completion: add and use --list-cmds=alias
  completion: add and use --list-cmds=nohelpers
  Move declaration for alias.c to alias.h
  completion: reduce completable command list
  completion: let git provide the completable command list
  command-list.txt: documentation and guide line
  help: use command-list.txt for the source of guides
  help: add "-a --verbose" to list all commands with synopsis
  git: support --list-cmds=list-<category>
  completion: implement and use --list-cmds=main,others
  git --list-cmds: collect command list in a string_list
  git.c: convert --list-* to --list-cmds=*
  Remove common-cmds.h
  help: use command-list.h for common command list
  generate-cmds.sh: export all commands to command-list.h
  generate-cmds.sh: factor out synopsis extract code
2018-06-01 15:06:37 +09:00
368b4e5906 index-pack: handle --strict checks of non-repo packs
Commit 73c3f0f704 (index-pack: check .gitmodules files with
--strict, 2018-05-04) added a call to add_packed_git(), with
the intent that the newly-indexed objects would be available
to the process when we run fsck_finish().  But that's not
what add_packed_git() does. It only allocates the struct,
and you must install_packed_git() on the result. So that
call was effectively doing nothing (except leaking a
struct).

But wait, we passed all of the tests! Does that mean we
don't need the call at all?

For normal cases, no. When we run "index-pack --stdin"
inside a repository, we write the new pack into the object
directory. If fsck_finish() needs to access one of the new
objects, then our initial lookup will fail to find it, but
we'll follow up by running reprepare_packed_git() and
looking again. That logic was meant to handle somebody else
repacking simultaneously, but it ends up working for us
here.

But there is a case that does need this, that we were not
testing. You can run "git index-pack foo.pack" on any file,
even when it is not inside the object directory. Or you may
not even be in a repository at all! This case fails without
doing the proper install_packed_git() call.

We can make this work by adding the install call.

Note that we should be prepared to handle add_packed_git()
failing. We can just silently ignore this case, though. If
fsck_finish() later needs the objects and they're not
available, it will complain itself. And if it doesn't
(because we were able to resolve the whole fsck in the first
pass), then it actually isn't an interesting error at all.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-01 11:48:56 +09:00
14a9bd2898 prepare_commit_graft: treat non-repository as a noop
The parse_commit_buffer() function consults lookup_commit_graft()
to see if we need to rewrite parents. The latter will look
at $GIT_DIR/info/grafts. If you're outside of a repository,
then this will trigger a BUG() as of b1ef400eec (setup_git_env:
avoid blind fall-back to ".git", 2016-10-20).

It's probably uncommon to actually parse a commit outside of
a repository, but you can see it in action with:

  cd /not/a/git/repo
  git index-pack --strict /some/file.pack

This works fine without --strict, but the fsck checks will
try to parse any commits, triggering the BUG(). We can fix
that by teaching the graft code to behave as if there are no
grafts when we aren't in a repository.

Arguably index-pack (and fsck) are wrong to consider grafts
at all. So another solution is to disable grafts entirely
for those commands. But given that the graft feature is
deprecated anyway, it's not worth even thinking through the
ramifications that might have.

There is one other corner case I considered here. What
should:

  cd /not/a/git/repo
  export GIT_GRAFT_FILE=/file/with/grafts
  git index-pack --strict /some/file.pack

do? We don't have a repository, but the user has pointed us
directly at a graft file, which we could respect. I believe
this case did work that way prior to b1ef400eec. However,
fixing it now would be pretty invasive. Back then we would
just call into setup_git_env() even without a repository.
But these days it actually takes a git_dir argument. So
there would be a fair bit of refactoring of the setup code
involved.

Given the obscurity of this case, plus the fact that grafts
are deprecated and probably shouldn't work under index-pack
anyway, it's not worth pursuing further. This patch at least
un-breaks the common case where you're _not_ using grafts,
but we BUG() anyway trying to even find that out.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-01 11:48:54 +09:00
c3072c6e4d refspec-api: avoid uninitialized field in refspec item
When parse_refspec() function was created at 3eec3700 ("refspec:
factor out parsing a single refspec", 2018-05-16) to take a caller
supplied piece of memory to fill parsed refspec_item, it forgot that
a refspec without colon must set item->dst to NULL to let the users
of refspec know that the result of the fetch does not get stored in
an ref on our side.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-01 11:46:07 +09:00
f156a0934a p4.txt: Use backquotes for variable names
For consistency, use backquotes when referring to environment
variables, as is done in other man pages.

Signed-off-by: Robert P. J. Day <rpjday@crashcourse.ca>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-01 10:47:05 +09:00
86f0b3727c remote.txt: update documentation for 'update' command
Commit b344e1614b (git remote update: Fallback to remote if group does
not exist - 2009-04-06) lets "git remote update" accept individual
remotes as well. Previously this command only accepted remote
groups. The commit updates the command syntax but not the actual
document of this subcommand. Update it.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-01 10:46:03 +09:00
2161ed8098 RelNotes: remove duplicate release note
In the 2.18 cycle, directory rename detection was merged, then reverted,
then reworked in such a way to fix another prominent bug in addition to
the original problem causing it to be reverted.  When the reworked series
was merged, we ended up with two nearly duplicate release notes.  Remove
the second copy, but preserve the information about the extra bug fix.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-01 10:08:53 +09:00
2a00502b14 note git-security@googlegroups.com in more places
Add a mention of the security mailing list to the README, and to
Documentation/SubmittingPatches..  2caa7b8d27 ("git manpage: note
git-security@googlegroups.com", 2018-03-08) already added it to the
man page, but for developers either the README, or the documentation
on how to contribute (SubmittingPatches) may be the first place to
look.

Use the same wording as we already have on the git-scm.com website and
in the man page for the README, while the wording is adjusted in
SubmittingPatches to match the surrounding document better.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-01 09:24:11 +09:00
a27cd1ab7f SubmittingPatches: replace numbered attributes with names
Use names instead of numbers for the AsciiDoc attributes that are used
for the footnotes.  We will add more footnotes in subsequent commits,
and attributes should ideally all be unique.  Having named attributes
will help ensure uniqueness, and we won't have to re-number the
attributes if we add a footnote earlier in the document.

In addition it also clarifies that the attribute name/number is not
related to the number the footnote will get in the output.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-01 09:24:11 +09:00
44f560fc16 init: fix grammar in "templates not found" msg
Signed-off-by: Robert P. J. Day <rpjday@crashcourse.ca>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-30 13:32:40 +09:00
5971b0836e sequencer: ensure labels that are object IDs are rewritten
When writing the todo script for --rebase-merges, we try to find a label
for certain commits.  If the label ends up being a valid object ID, such
as when we merge a detached commit, we want to rewrite it so it is no
longer a valid object ID.

However, the code path that does this checks for its length to be
equivalent to GIT_SHA1_RAWSZ, which isn't correct, since what we are
reading is a hex object ID.  Instead, check for the length being
equivalent to that of a hex object ID.  Use the_hash_algo so this code
works regardless of the hash size.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-30 13:32:16 +09:00
5340d47107 t990X: use '.git/objects' as 'deep inside .git' path
Tests t9902-completion.sh and t9903-bash-prompt.sh each have tests
that check what happens when we are "in the '.git' directory" and
when we are "deep inside the '.git' directory".

To test the case when we are "deep inside the '.git' directory" the
test scripts used to perform a `cd .git/refs/heads`.

As there are plans to implement other ref storage systems, let's
use '.git/objects' instead of '.git/refs/heads' as the "deep inside
the '.git' directory" path.

This makes it clear to readers that these tests do not depend on
which ref backend is used.

The internals of the loose refs backend are still tested in
t1400-update-ref.sh.

Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: David Turner <dturner@twopensource.com>
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Reviewed-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-30 12:55:53 +09:00
590551ca2c tag: clarify in the doc that a tag can refer to a non-commit object
Reword "man git-tag" to clarify that a tag can refer directly to an
arbitrary object, not just a commit object.

Signed-off-by: Robert P. J. Day <rpjday@crashcourse.ca>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-29 11:55:34 +09:00
35d515b53f git-rebase--interactive: fix copy-paste mistake
exec argument is a command, not a commit.

Signed-off-by: Orgad Shaneh <orgads@gmail.com>
Acked-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-28 23:29:32 +09:00
de613050ef Use proper syntax for replaceables in command docs
The standard for command documentation synopses appears to be:

  [...] means optional
  <...> means replaceable
  [<...>] means both optional and replaceable

So fix a number of doc pages that use incorrect variations of the
above.

Signed-off-by: Robert P. J. Day <rpjday@crashcourse.ca>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-25 17:16:47 +09:00
4d36f88be7 submodule: do not pass null OID to setup_revisions
If "git pull --recurse-submodules --rebase" is invoked when the current
branch and its corresponding remote-tracking branch have no merge base,
a "bad object" fatal error occurs. This issue was introduced with commit
a6d7eb2c7a ("pull: optionally rebase submodules (remote submodule
changes only)", 2017-06-23), which also introduced this feature.

This is because cmd_pull() in builtin/pull.c thus invokes
submodule_touches_in_range() with a null OID as the first parameter.
Ensure that this case works, and document what happens in this case.

Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
Reviewed-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-25 15:25:42 +09:00
0ed556d38f rev-parse: check lookup'ed commit references for NULL
Commits 2122f8b963 ("rev-parse: Add support for the ^! and ^@ syntax",
2008-07-26) and 3dd4e7320d ("Teach rev-parse the ... syntax.", 2006-07-04)
taught rev-parse new syntax, and used lookup_commit_reference() as part of
their logic.  Neither usage checked the returned commit to see if it was
non-NULL before using it.  Check for NULL and ensure an appropriate error
is reported to the user.

Reported by Florian Weimer and Todd Zullinger.

Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Elijah Newren <newren@gmail.com>
Reviewed-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-25 10:46:42 +09:00
3e4a67b47d Use OPT_SET_INT_F() for cmdline option specification
The only thing these commands need is extra parseopt flag which can be
passed in by OPT_SET_INT_F() and it is a bit more compact than full
struct initialization.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-24 16:12:29 +09:00
123f631761 git-p4: add unshelve command
This can be used to "unshelve" a shelved P4 commit into
a git commit.

For example:

  $ git p4 unshelve 12345

The resulting commit ends up in the branch:
   refs/remotes/p4/unshelved/12345

If that branch already exists, it is renamed - for example
the above branch would be saved as p4/unshelved/12345.1.

git-p4 checks that the shelved changelist is based on files
which are at the same Perforce revision as the origin branch
being used for the unshelve (HEAD by default). If they are not,
it will refuse to unshelve. This is to ensure that the unshelved
change does not contain other changes mixed-in.

The reference branch can be changed manually with the "--origin"
option.

The change adds a new Unshelve command class. This just runs the
existing P4Sync code tweaked to handle a shelved changelist.

Signed-off-by: Luke Diamand <luke@diamand.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-24 08:58:28 +09:00
12ecea46e3 import-tars: read overlong names from pax extended header
Importing gcc tarballs[1] with import-tars script (in contrib) fails
when hitting a pax extended header.

Make sure we always read the extended attributes from the pax entries,
and store the 'path' value if found to be used in the next ustar entry.

The code to parse pax extended headers was written consulting the Pax
Pax Interchange Format documentation [2].

[1] http://ftp.gnu.org/gnu/gcc/gcc-7.3.0/gcc-7.3.0.tar.xz
[2] https://www.freebsd.org/cgi/man.cgi?manpath=FreeBSD+8-current&query=tar&sektion=5

Signed-off-by: Pedro Alvarez <palvarez89@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-24 08:35:51 +09:00
cbc5cf7ce5 t: make many tests depend less on the refs being files
Many tests are very focused on the file system representation of the
loose and packed refs code. As there are plans to implement other
ref storage systems, let's migrate these tests to a form that test
the intent of the refs storage system instead of it internals.

This will make clear to readers that these tests do not depend on
which ref backend is used.

The internals of the loose refs backend are still tested in
t1400-update-ref.sh, whereas the tests changed in this patch focus
on testing other aspects.

This patch just takes care of many low hanging fruits. It does not
try to completely solves the issue.

Helped-by: Stefan Beller <sbeller@google.com>
Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: David Turner <dturner@twopensource.com>
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-23 14:59:38 +09:00
6532f3740b completion: allow to customize the completable command list
By default we show porcelain, external commands and a couple others
that are also popular. If you are not happy with this list, you can
now customize it a new config variable.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-21 13:23:14 +09:00
3301d36b29 completion: add and use --list-cmds=alias
By providing aliases via --list-cmds=, we could simplify command
collection code in the script. We only issue one git command. Before
this patch that is "git config", after it's "git --list-cmds=". In
"git help" completion case we actually reduce one "git" process (for
getting guides) but that call was added in this series so it does not
really count.

A couple of bash functions are removed because they are not needed
anymore. __git_compute_all_commands() and $__git_all_commands stay
because they are still needed for completing pager.* config and
without "alias" group, the result is still cacheable.

There is a slight (good) change in _git_help() with this patch: before
"git help <tab>" shows external commands (as in _not_ part of git) as
well as part of $__git_all_commands. We have finer control over
command listing now and can exclude that because we can't provide a
man page for external commands anyway.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-21 13:23:14 +09:00
e11dca10cf completion: add and use --list-cmds=nohelpers
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-21 13:23:14 +09:00
65b5f9483e Move declaration for alias.c to alias.h
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-21 13:23:14 +09:00
d9fcc7f871 completion: reduce completable command list
The following commands are removed from the complete list:

- annotate             obsolete, discouraged to use
- filter-branch        not often used
- get-tar-commit-id    not often used
- imap-send            not often used
- interpreter-trailers not for interactive use
- name-rev             plumbing, just use git-describe
- p4                   too short and probably not often used (*)
- svn                  same category as p4 (*)
- verify-commit        not often used

(*) to be fair, send-email command which is in the same foreignscminterface
group as svn and p4 does get completion, just because it's used by git
and kernel development. So maybe we should include them.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-21 13:23:14 +09:00
84a9713106 completion: let git provide the completable command list
Instead of maintaining a separate list of command classification,
which often could go out of date, let's centralize the information
back in git.

While the function in git-completion.bash implies "list porcelain
commands", that's not exactly what it does. It gets all commands (aka
--list-cmds=main,others) then exclude certain non-porcelain ones. We
could almost recreate this list two lists list-mainporcelain and
others. The non-porcelain-but-included-anyway is added by the third
category list-complete.

Note that the current completion script incorrectly classifies
filter-branch as porcelain and t9902 tests this behavior. We keep it
this way in t9902 because this test does not really care which
particular command is porcelain or plumbing, they're just names.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-21 13:23:14 +09:00
fe902f2cef command-list.txt: documentation and guide line
This is intended to help anybody who needs to update command-list.txt.
It gives a brief introduction of all attributes a command can take.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-21 13:23:14 +09:00
1b81d8cb19 help: use command-list.txt for the source of guides
The help command currently hard codes the list of guides and their
summary in C. Let's move this list to command-list.txt. This lets us
extract summary lines from Documentation/git*.txt. This also
potentially lets us list guides in git.txt, but I'll leave that for
now.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-21 13:23:14 +09:00
63eae83f8f help: add "-a --verbose" to list all commands with synopsis
This lists all recognized commands [1] by category. The group order
follows closely git.txt.

[1] We may actually show commands that are not built (e.g. if you set
NO_PERL you don't have git-instaweb but it's still listed here). I
ignore the problem because on Linux a git package could be split
anyway. The "git-core" package may not contain git-instaweb even if
it's built because it may end up in a separate package. We can't know
anyway.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-21 13:23:14 +09:00
3c7777672b git: support --list-cmds=list-<category>
This allows us to select any group of commands by a category defined
in command-list.txt. This is an internal/hidden option so we don't
have to be picky about the category name or worried about exposing too
much.

This will be used later by git-completion.bash to retrieve certain
command groups.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-21 13:23:14 +09:00
6bb2dc0b94 completion: implement and use --list-cmds=main,others
This is part of the effort to break down and provide commands by
category in machine-readable form. This could be helpful later on when
completion script switches to use --list-cmds for selecting
completable commands. It would be much easier for the user to choose
to complete _all_ commands instead of the default selection by passing
different values to --list-cmds in git-completino.bash.

While at there, replace "git help -a" in git-completion.bash with
--list-cmds since it's better suited for this task.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-21 13:23:14 +09:00
e5d7a61953 git --list-cmds: collect command list in a string_list
Instead of printing the command directly one by one, keep them in a
list and print at the end. This allows more modification before we
print out (e.g. sorting, removing duplicates or even excluding some
items).

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-21 13:23:14 +09:00
0089521cac git.c: convert --list-* to --list-cmds=*
Even if these are hidden options, let's make them a bit more generic
since we're introducing more listing types shortly. The code is
structured to allow combining multiple listing types together because
we will soon add more types the 'builtins'.

'parseopt' remains separate because it has separate (SPC) to match
git-completion.bash needs and will not combine with others.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-21 13:23:13 +09:00
60f487ac0e Remove common-cmds.h
After the last patch, common-cmds.h is no longer used (and it was
actually broken). Remove all related code. command-list.h will take
its place from now on.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-10 19:52:47 +09:00
cfb22a02ab help: use command-list.h for common command list
The previous commit added code generation for all_cmd_desc[] which
includes almost everything we need to generate common command list.
Convert help code to use that array instead and drop common_cmds[] array.

The description of each common command group is removed from
command-list.txt. This keeps this file format simpler. common-cmds.h
will not be generated correctly after this change due to the
command-list.txt format change. But it does not matter and
common-cmds.h will be removed.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-10 19:52:47 +09:00
f318d73915 generate-cmds.sh: export all commands to command-list.h
The current generate-cmds.sh generates just enough to print "git help"
output. That is, it only extracts help text for common commands.

The script is now updated to extract help text for all commands and
keep command classification a new file, command-list.h. This will be
useful later:

- "git help -a" could print a short summary of all commands instead of
  just the common ones.

- "git" could produce a list of commands of one or more category. One
  of its use is to reduce another command classification embedded in
  git-completion.bash.

The new file can be generated but is not used anywhere yet. The plan
is we migrate away from common-cmds.h. Then we can kill off
common-cmds.h build rules and generation code (and also delete
duplicate content in command-list.h which we keep for now to not mess
generate-cmds.sh up too much).

PS. The new fixed column requirement on command-list.txt is
technically not needed. But it helps simplify the code a bit at this
stage. We could lift this restriction later if we want to.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-10 19:52:47 +09:00
75ba897e30 generate-cmds.sh: factor out synopsis extract code
This makes it easier to reuse the same code in another place (very
soon).

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-10 19:52:47 +09:00
92 changed files with 1306 additions and 523 deletions

2
.gitignore vendored
View File

@ -182,7 +182,7 @@
/gitweb/gitweb.cgi
/gitweb/static/gitweb.js
/gitweb/static/gitweb.min.*
/common-cmds.h
/command-list.h
*.tar.gz
*.dsc
*.deb

View File

@ -6,13 +6,15 @@ Updates since v2.17
UI, Workflows & Features
* Rename detection logic in "diff" family that is used in "merge" has
* Rename detection logic that is used in "merge" and "cherry-pick" has
learned to guess when all of x/a, x/b and x/c have moved to z/a,
z/b and z/c, it is likely that x/d added in the meantime would also
want to move to z/d by taking the hint that the entire directory
'x' moved to 'z'. A bug causing dirty files involved in a rename
to be overwritten during merge has also been fixed as part of this
work.
work. Incidentally, this also avoids updating a file in the
working tree after a (non-trivial) merge whose result matches what
our side originally had.
* "git filter-branch" learned to use a different exit code to allow
the callers to tell the case where there was no new commits to
@ -48,7 +50,7 @@ UI, Workflows & Features
have been replaced with a stub that errors out and tells the user
there are replacements.
* The new "checkout-encoding" attribute can ask Git to convert the
* The new "working-tree-encoding" attribute can ask Git to convert the
contents to the specified encoding when checking out to the working
tree (and the other way around when checking in).
@ -142,6 +144,9 @@ UI, Workflows & Features
from the other side; instead, just let cURL library to advertise
and negotiate the best one.
* "git p4" learned to "unshelve" shelved commit from P4.
(merge 123f631761 ld/p4-unshelve later to maint).
Performance, Internal Implementation, Development Support etc.
@ -256,16 +261,6 @@ Performance, Internal Implementation, Development Support etc.
repository object (which in turn tells the API which object store
the objects are to be located).
* Rename detection logic in "diff" family that is used in "merge" has
learned to guess when all of x/a, x/b and x/c have moved to z/a,
z/b and z/c, it is likely that x/d added in the meantime would also
want to move to z/d by taking the hint that the entire directory
'x' moved to 'z'. A bug causing dirty files involved in a rename
to be overwritten during merge has also been fixed as part of this
work. Incidentally, this also avoids updating a file in the
working tree after a (non-trivial) merge whose result matches what
our side originally had.
* "git pack-objects" needs to allocate tons of "struct object_entry"
while doing its work, and shrinking its size helps the performance
quite a bit.
@ -298,6 +293,15 @@ Performance, Internal Implementation, Development Support etc.
to test the moral equivalent of the original without hardcoding the
actual object names.
* The list of commands with their various attributes were spread
across a few places in the build procedure, but it now is getting a
bit more consolidated to allow more automation.
* Quite a many tests assumed that newly created refs are made as
loose refs using the files backend, which have been updated to use
proper plumbing like rev-parse and update-ref, to avoid breakage
once we start using different ref backends.
Also contains various documentation updates and code clean-ups.
@ -496,6 +500,29 @@ Fixes since v2.17
which have been corrected.
(merge 17154b1576 ma/regex-no-regfree-after-comp-fail later to maint).
* The import-tars script (in contrib/) has been taught to handle
tarballs with overly long paths that use PAX extended headers.
(merge 12ecea46e3 pa/import-tars-long-names later to maint).
* "git rev-parse Y..." etc. misbehaved when given endpoints were
not committishes.
(merge 0ed556d38f en/rev-parse-invalid-range later to maint).
* "git pull --recurse-submodules --rebase", when the submodule
repository's history did not have anything common between ours and
the upstream's, failed to execute. We need to fetch from them to
continue even in such a case.
(merge 4d36f88be7 jt/submodule-pull-recurse-rebase later to maint).
* "git remote update" can take both a single remote nickname and a
nickname for remote groups, but only one of them was documented.
(merge a97447a42a nd/remote-update-doc later to maint).
* "index-pack --strict" has been taught to make sure that it runs the
final object integrity checks after making the freshly indexed
packfile available to itself.
(merge 3737746120 jk/index-pack-maint later to maint).
* Other minor doc, test and build updates and code cleanups.
(merge 248f66ed8e nd/trace-with-env later to maint).
(merge 14ced5562c ys/bisect-object-id-missing-conversion-fix later to maint).
@ -527,3 +554,8 @@ Fixes since v2.17
(merge 58bd77b66a nd/pack-unreachable-objects-doc later to maint).
(merge 4ed79d5203 sg/t6500-no-redirect-of-stdin later to maint).
(merge 17b8a2d6cd jk/config-blob-sans-repo later to maint).
(merge 590551ca2c rd/tag-doc-lightweight later to maint).
(merge 44f560fc16 rd/init-typo later to maint).
(merge f156a0934a rd/p4-doc-markup-env later to maint).
(merge 2a00502b14 tg/doc-sec-list later to maint).
(merge 47cc91310a jk/submodule-fsck-loose-fixup later to maint).

View File

@ -176,6 +176,12 @@ that is fine, but please mark it as such.
[[send-patches]]
=== Sending your patches.
:security-ml: footnoteref:[security-ml,The Git Security mailing list: git-security@googlegroups.com]
Before sending any patches, please note that patches that may be
security relevant should be submitted privately to the Git Security
mailing list{security-ml}, instead of the public mailing list.
Learn to use format-patch and send-email if possible. These commands
are optimized for the workflow of sending patches, avoiding many ways
your existing e-mail client that is optimized for "multipart/*" mime
@ -259,17 +265,24 @@ patch, format it as "multipart/signed", not a text/plain message
that starts with `-----BEGIN PGP SIGNED MESSAGE-----`. That is
not a text/plain, it's something else.
:security-ml-ref: footnoteref:[security-ml]
As mentioned at the beginning of the section, patches that may be
security relevant should not be submitted to the public mailing list
mentioned below, but should instead be sent privately to the Git
Security mailing list{security-ml-ref}.
Send your patch with "To:" set to the mailing list, with "cc:" listing
people who are involved in the area you are touching (the `git
contacts` command in `contrib/contacts/` can help to
identify them), to solicit comments and reviews.
:1: footnote:[The current maintainer: gitster@pobox.com]
:2: footnote:[The mailing list: git@vger.kernel.org]
:current-maintainer: footnote:[The current maintainer: gitster@pobox.com]
:git-ml: footnote:[The mailing list: git@vger.kernel.org]
After the list reached a consensus that it is a good idea to apply the
patch, re-send it with "To:" set to the maintainer{1} and "cc:" the
list{2} for inclusion.
patch, re-send it with "To:" set to the maintainer{current-maintainer} and "cc:" the
list{git-ml} for inclusion.
Do not forget to add trailers such as `Acked-by:`, `Reviewed-by:` and
`Tested-by:` lines as necessary to credit people who helped your

View File

@ -1412,6 +1412,14 @@ credential.<url>.*::
credentialCache.ignoreSIGHUP::
Tell git-credential-cache--daemon to ignore SIGHUP, instead of quitting.
completion.commands::
This is only used by git-completion.bash to add or remove
commands from the list of completed commands. Normally only
porcelain commands and a few select others are completed. You
can add more commands, separated by space, in this
variable. Prefixing the command with '-' will remove it from
the existing list.
include::diff-config.txt[]
difftool.<tool>.path::

View File

@ -8,7 +8,7 @@ git-annotate - Annotate file lines with commit information
SYNOPSIS
--------
[verse]
'git annotate' [options] file [revision]
'git annotate' [<options>] <file> [<revision>]
DESCRIPTION
-----------

View File

@ -9,8 +9,8 @@ git-check-attr - Display gitattributes information
SYNOPSIS
--------
[verse]
'git check-attr' [-a | --all | attr...] [--] pathname...
'git check-attr' --stdin [-z] [-a | --all | attr...]
'git check-attr' [-a | --all | <attr>...] [--] <pathname>...
'git check-attr' --stdin [-z] [-a | --all | <attr>...]
DESCRIPTION
-----------

View File

@ -9,8 +9,8 @@ git-check-ignore - Debug gitignore / exclude files
SYNOPSIS
--------
[verse]
'git check-ignore' [options] pathname...
'git check-ignore' [options] --stdin
'git check-ignore' [<options>] <pathname>...
'git check-ignore' [<options>] --stdin
DESCRIPTION
-----------

View File

@ -9,7 +9,7 @@ git-check-mailmap - Show canonical names and email addresses of contacts
SYNOPSIS
--------
[verse]
'git check-mailmap' [options] <contact>...
'git check-mailmap' [<options>] <contact>...
DESCRIPTION

View File

@ -8,7 +8,7 @@ git-credential-cache - Helper to temporarily store passwords in memory
SYNOPSIS
--------
-----------------------------
git config credential.helper 'cache [options]'
git config credential.helper 'cache [<options>]'
-----------------------------
DESCRIPTION

View File

@ -8,7 +8,7 @@ git-credential-store - Helper to store credentials on disk
SYNOPSIS
--------
-------------------
git config credential.helper 'store [options]'
git config credential.helper 'store [<options>]'
-------------------
DESCRIPTION

View File

@ -22,7 +22,7 @@ cvspserver stream tcp nowait nobody /usr/bin/git-cvsserver git-cvsserver pserver
Usage:
[verse]
'git-cvsserver' [options] [pserver|server] [<directory> ...]
'git-cvsserver' [<options>] [pserver|server] [<directory> ...]
OPTIONS
-------

View File

@ -9,11 +9,11 @@ git-diff - Show changes between commits, commit and working tree, etc
SYNOPSIS
--------
[verse]
'git diff' [options] [<commit>] [--] [<path>...]
'git diff' [options] --cached [<commit>] [--] [<path>...]
'git diff' [options] <commit> <commit> [--] [<path>...]
'git diff' [options] <blob> <blob>
'git diff' [options] --no-index [--] <path> <path>
'git diff' [<options>] [<commit>] [--] [<path>...]
'git diff' [<options>] --cached [<commit>] [--] [<path>...]
'git diff' [<options>] <commit> <commit> [--] [<path>...]
'git diff' [<options>] <blob> <blob>
'git diff' [<options>] --no-index [--] <path> <path>
DESCRIPTION
-----------
@ -21,7 +21,7 @@ Show changes between the working tree and the index or a tree, changes
between the index and a tree, changes between two trees, changes between
two blob objects, or changes between two files on disk.
'git diff' [options] [--] [<path>...]::
'git diff' [<options>] [--] [<path>...]::
This form is to view the changes you made relative to
the index (staging area for the next commit). In other
@ -29,7 +29,7 @@ two blob objects, or changes between two files on disk.
further add to the index but you still haven't. You can
stage these changes by using linkgit:git-add[1].
'git diff' [options] --no-index [--] <path> <path>::
'git diff' [<options>] --no-index [--] <path> <path>::
This form is to compare the given two paths on the
filesystem. You can omit the `--no-index` option when
@ -38,7 +38,7 @@ two blob objects, or changes between two files on disk.
or when running the command outside a working tree
controlled by Git.
'git diff' [options] --cached [<commit>] [--] [<path>...]::
'git diff' [<options>] --cached [<commit>] [--] [<path>...]::
This form is to view the changes you staged for the next
commit relative to the named <commit>. Typically you
@ -48,7 +48,7 @@ two blob objects, or changes between two files on disk.
<commit> is not given, it shows all staged changes.
--staged is a synonym of --cached.
'git diff' [options] <commit> [--] [<path>...]::
'git diff' [<options>] <commit> [--] [<path>...]::
This form is to view the changes you have in your
working tree relative to the named <commit>. You can
@ -56,18 +56,18 @@ two blob objects, or changes between two files on disk.
branch name to compare with the tip of a different
branch.
'git diff' [options] <commit> <commit> [--] [<path>...]::
'git diff' [<options>] <commit> <commit> [--] [<path>...]::
This is to view the changes between two arbitrary
<commit>.
'git diff' [options] <commit>..<commit> [--] [<path>...]::
'git diff' [<options>] <commit>..<commit> [--] [<path>...]::
This is synonymous to the previous form. If <commit> on
one side is omitted, it will have the same effect as
using HEAD instead.
'git diff' [options] <commit>\...<commit> [--] [<path>...]::
'git diff' [<options>] <commit>\...<commit> [--] [<path>...]::
This form is to view the changes on the branch containing
and up to the second <commit>, starting at a common ancestor
@ -87,7 +87,7 @@ and the range notations ("<commit>..<commit>" and
"<commit>\...<commit>") do not mean a range as defined in the
"SPECIFYING RANGES" section in linkgit:gitrevisions[7].
'git diff' [options] <blob> <blob>::
'git diff' [<options>] <blob> <blob>::
This form is to view the differences between the raw
contents of two blob objects.

View File

@ -9,7 +9,7 @@ git-fast-export - Git data exporter
SYNOPSIS
--------
[verse]
'git fast-export [options]' | 'git fast-import'
'git fast-export [<options>]' | 'git fast-import'
DESCRIPTION
-----------

View File

@ -9,7 +9,7 @@ git-fast-import - Backend for fast Git data importers
SYNOPSIS
--------
[verse]
frontend | 'git fast-import' [options]
frontend | 'git fast-import' [<options>]
DESCRIPTION
-----------

View File

@ -8,7 +8,7 @@ git-help - Display help information about Git
SYNOPSIS
--------
[verse]
'git help' [-a|--all] [-g|--guide]
'git help' [-a|--all [--verbose]] [-g|--guide]
[-i|--info|-m|--man|-w|--web] [COMMAND|GUIDE]
DESCRIPTION
@ -42,6 +42,8 @@ OPTIONS
--all::
Prints all the available commands on the standard output. This
option overrides any given command or guide name.
When used with `--verbose` print description for all recognized
commands.
-g::
--guides::

View File

@ -8,8 +8,8 @@ git-interpret-trailers - add or parse structured information in commit messages
SYNOPSIS
--------
[verse]
'git interpret-trailers' [options] [(--trailer <token>[(=|:)<value>])...] [<file>...]
'git interpret-trailers' [options] [--parse] [<file>...]
'git interpret-trailers' [<options>] [(--trailer <token>[(=|:)<value>])...] [<file>...]
'git interpret-trailers' [<options>] [--parse] [<file>...]
DESCRIPTION
-----------

View File

@ -164,6 +164,31 @@ $ git p4 submit --shelve
$ git p4 submit --update-shelve 1234 --update-shelve 2345
----
Unshelve
~~~~~~~~
Unshelving will take a shelved P4 changelist, and produce the equivalent git commit
in the branch refs/remotes/p4/unshelved/<changelist>.
The git commit is created relative to the current origin revision (HEAD by default).
If the shelved changelist's parent revisions differ, git-p4 will refuse to unshelve;
you need to be unshelving onto an equivalent tree.
The origin revision can be changed with the "--origin" option.
If the target branch in refs/remotes/p4/unshelved already exists, the old one will
be renamed.
----
$ git p4 sync
$ git p4 unshelve 12345
$ git show refs/remotes/p4/unshelved/12345
<submit more changes via p4 to the same files>
$ git p4 unshelve 12345
<refuses to unshelve until git is in sync with p4 again>
----
OPTIONS
-------
@ -337,6 +362,13 @@ These options can be used to modify 'git p4 rebase' behavior.
--import-labels::
Import p4 labels.
Unshelve options
~~~~~~~~~~~~~~~~
--origin::
Sets the git refspec against which the shelved P4 changelist is compared.
Defaults to p4/master.
DEPOT PATH SYNTAX
-----------------
The p4 depot path argument to 'git p4 sync' and 'git p4 clone' can
@ -392,7 +424,7 @@ dedicating a client spec just for 'git p4'.
The name of the client can be given to 'git p4' in multiple ways. The
variable 'git-p4.client' takes precedence if it exists. Otherwise,
normal p4 mechanisms of determining the client are used: environment
variable P4CLIENT, a file referenced by P4CONFIG, or the local host name.
variable `P4CLIENT`, a file referenced by `P4CONFIG`, or the local host name.
BRANCH DETECTION
@ -461,22 +493,22 @@ General variables
~~~~~~~~~~~~~~~~~
git-p4.user::
User specified as an option to all p4 commands, with '-u <user>'.
The environment variable 'P4USER' can be used instead.
The environment variable `P4USER` can be used instead.
git-p4.password::
Password specified as an option to all p4 commands, with
'-P <password>'.
The environment variable 'P4PASS' can be used instead.
The environment variable `P4PASS` can be used instead.
git-p4.port::
Port specified as an option to all p4 commands, with
'-p <port>'.
The environment variable 'P4PORT' can be used instead.
The environment variable `P4PORT` can be used instead.
git-p4.host::
Host specified as an option to all p4 commands, with
'-h <host>'.
The environment variable 'P4HOST' can be used instead.
The environment variable `P4HOST` can be used instead.
git-p4.client::
Client specified as an option to all p4 commands, with

View File

@ -9,7 +9,7 @@ git-pull - Fetch from and integrate with another repository or a local branch
SYNOPSIS
--------
[verse]
'git pull' [options] [<repository> [<refspec>...]]
'git pull' [<options>] [<repository> [<refspec>...]]
DESCRIPTION

View File

@ -8,9 +8,9 @@ git-rebase - Reapply commits on top of another base tip
SYNOPSIS
--------
[verse]
'git rebase' [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>]
'git rebase' [-i | --interactive] [<options>] [--exec <cmd>] [--onto <newbase>]
[<upstream> [<branch>]]
'git rebase' [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>]
'git rebase' [-i | --interactive] [<options>] [--exec <cmd>] [--onto <newbase>]
--root [<branch>]
'git rebase' --continue | --skip | --abort | --quit | --edit-todo | --show-current-patch

View File

@ -186,8 +186,8 @@ actually prune them.
'update'::
Fetch updates for a named set of remotes in the repository as defined by
remotes.<group>. If a named group is not specified on the command line,
Fetch updates for remotes or remote groups in the repository as defined by
remotes.<group>. If neither group nor remote is specified on the command line,
the configuration parameter remotes.default will be used; if
remotes.default is not defined, all remotes which do not have the
configuration parameter remote.<name>.skipDefaultUpdate set to true will

View File

@ -9,7 +9,7 @@ git-rev-parse - Pick out and massage parameters
SYNOPSIS
--------
[verse]
'git rev-parse' [ --option ] <args>...
'git rev-parse' [<options>] <args>...
DESCRIPTION
-----------
@ -360,7 +360,7 @@ Example
------------
OPTS_SPEC="\
some-command [options] <args>...
some-command [<options>] <args>...
some-command does foo and bar!
--
@ -385,7 +385,7 @@ When `"$@"` is `-h` or `--help` in the above example, the following
usage text would be shown:
------------
usage: some-command [options] <args>...
usage: some-command [<options>] <args>...
some-command does foo and bar!

View File

@ -9,7 +9,7 @@ git-send-email - Send a collection of patches as emails
SYNOPSIS
--------
[verse]
'git send-email' [options] <file|directory|rev-list options>...
'git send-email' [<options>] <file|directory|rev-list options>...
'git send-email' --dump-aliases

View File

@ -9,7 +9,7 @@ git-show - Show various types of objects
SYNOPSIS
--------
[verse]
'git show' [options] [<object>...]
'git show' [<options>] [<object>...]
DESCRIPTION
-----------

View File

@ -8,7 +8,7 @@ git-svn - Bidirectional operation between a Subversion repository and Git
SYNOPSIS
--------
[verse]
'git svn' <command> [options] [arguments]
'git svn' <command> [<options>] [<arguments>]
DESCRIPTION
-----------

View File

@ -34,8 +34,8 @@ in the tag message.
If `-m <msg>` or `-F <file>` is given and `-a`, `-s`, and `-u <keyid>`
are absent, `-a` is implied.
Otherwise just a tag reference for the SHA-1 object name of the commit object is
created (i.e. a lightweight tag).
Otherwise, a tag reference that points directly at the given object
(i.e., a lightweight tag) is created.
A GnuPG signed tag object will be created when `-s` or `-u
<keyid>` is used. When `-u <keyid>` is not used, the

View File

@ -8,7 +8,7 @@ git-web--browse - Git helper script to launch a web browser
SYNOPSIS
--------
[verse]
'git web{litdd}browse' [OPTIONS] URL/FILE ...
'git web{litdd}browse' [<options>] <url|file>...
DESCRIPTION
-----------

View File

@ -164,6 +164,16 @@ foo.bar= ...`) sets `foo.bar` to the empty string which `git config
Do not perform optional operations that require locks. This is
equivalent to setting the `GIT_OPTIONAL_LOCKS` to `0`.
--list-cmds=group[,group...]::
List commands by group. This is an internal/experimental
option and may change or be removed in the future. Supported
groups are: builtins, parseopt (builtin commands that use
parse-options), main (all commands in libexec directory),
others (all other commands in `$PATH` that have git- prefix),
list-<category> (see categories in command-list.txt),
nohelpers (exclude helper commands), alias and config
(retrieve command list from config variable completion.commands)
GIT COMMANDS
------------

View File

@ -3,7 +3,7 @@ gitattributes(5)
NAME
----
gitattributes - defining attributes per path
gitattributes - Defining attributes per path
SYNOPSIS
--------

View File

@ -110,8 +110,8 @@ couple of magic command-line options:
+
---------------------------------------------
$ git describe -h
usage: git describe [options] <commit-ish>*
or: git describe [options] --dirty
usage: git describe [<options>] <commit-ish>*
or: git describe [<options>] --dirty
--contains find the tag that comes after the commit
--debug debug search strategy on stderr

View File

@ -3,7 +3,7 @@ gitmodules(5)
NAME
----
gitmodules - defining submodule properties
gitmodules - Defining submodule properties
SYNOPSIS
--------

View File

@ -3,7 +3,7 @@ gitrevisions(7)
NAME
----
gitrevisions - specifying revisions and ranges for Git
gitrevisions - Specifying revisions and ranges for Git
SYNOPSIS
--------

View File

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

View File

@ -795,7 +795,7 @@ LIB_FILE = libgit.a
XDIFF_LIB = xdiff/lib.a
VCSSVN_LIB = vcs-svn/lib.a
GENERATED_H += common-cmds.h
GENERATED_H += command-list.h
LIB_H = $(shell $(FIND) . \
-name .git -prune -o \
@ -2006,9 +2006,9 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
$(filter %.o,$^) $(LIBS)
help.sp help.s help.o: common-cmds.h
help.sp help.s help.o: command-list.h
builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h GIT-PREFIX
builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX
builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \
'-DGIT_HTML_PATH="$(htmldir_relative_SQ)"' \
'-DGIT_MAN_PATH="$(mandir_relative_SQ)"' \
@ -2027,9 +2027,9 @@ $(BUILT_INS): git$X
ln -s $< $@ 2>/dev/null || \
cp $< $@
common-cmds.h: generate-cmdlist.sh command-list.txt
command-list.h: generate-cmdlist.sh command-list.txt
common-cmds.h: $(wildcard Documentation/git-*.txt)
command-list.h: $(wildcard Documentation/git*.txt)
$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt >$@+ && mv $@+ $@
SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\
@ -2273,7 +2273,7 @@ else
# Dependencies on header files, for platforms that do not support
# the gcc -MMD option.
#
# Dependencies on automatically generated headers such as common-cmds.h
# Dependencies on automatically generated headers such as command-list.h
# should _not_ be included here, since they are necessary even when
# building an object for the first time.
@ -2653,7 +2653,7 @@ sparse: $(SP_OBJ)
style:
git clang-format --style file --diff --extensions c,h
check: common-cmds.h
check: command-list.h
@if sparse; \
then \
echo >&2 "Use 'make sparse' instead"; \
@ -2901,7 +2901,7 @@ clean: profile-clean coverage-clean
$(RM) $(TEST_PROGRAMS) $(NO_INSTALL)
$(RM) -r bin-wrappers $(dep_dirs)
$(RM) -r po/build/
$(RM) *.pyc *.pyo */*.pyc */*.pyo common-cmds.h $(ETAGS_TARGET) tags cscope*
$(RM) *.pyc *.pyo */*.pyc */*.pyo command-list.h $(ETAGS_TARGET) tags cscope*
$(RM) -r $(GIT_TARNAME) .doc-tmp-dir
$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
$(RM) $(htmldocs).tar.gz $(manpages).tar.gz

View File

@ -36,6 +36,9 @@ the body to majordomo@vger.kernel.org. The mailing list archives are
available at <https://public-inbox.org/git/>,
<http://marc.info/?l=git> and other archival sites.
Issues which are security relevant should be disclosed privately to
the Git Security mailing list <git-security@googlegroups.com>.
The maintainer frequently sends the "What's cooking" reports that
list the current status of various development topics to the mailing
list. The discussion following them give a good reference for

22
alias.c
View File

@ -1,9 +1,12 @@
#include "cache.h"
#include "alias.h"
#include "config.h"
#include "string-list.h"
struct config_alias_data {
const char *alias;
char *v;
struct string_list *list;
};
static int config_alias_cb(const char *key, const char *value, void *d)
@ -11,8 +14,16 @@ static int config_alias_cb(const char *key, const char *value, void *d)
struct config_alias_data *data = d;
const char *p;
if (skip_prefix(key, "alias.", &p) && !strcasecmp(p, data->alias))
return git_config_string((const char **)&data->v, key, value);
if (!skip_prefix(key, "alias.", &p))
return 0;
if (data->alias) {
if (!strcasecmp(p, data->alias))
return git_config_string((const char **)&data->v,
key, value);
} else if (data->list) {
string_list_append(data->list, p);
}
return 0;
}
@ -26,6 +37,13 @@ char *alias_lookup(const char *alias)
return data.v;
}
void list_aliases(struct string_list *list)
{
struct config_alias_data data = { NULL, NULL, list };
read_early_config(config_alias_cb, &data);
}
#define SPLIT_CMDLINE_BAD_ENDING 1
#define SPLIT_CMDLINE_UNCLOSED_QUOTE 2
static const char *split_cmdline_errors[] = {

12
alias.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef __ALIAS_H__
#define __ALIAS_H__
struct string_list;
char *alias_lookup(const char *alias);
int split_cmdline(char *cmdline, const char ***argv);
/* Takes a negative value returned by split_cmdline */
const char *split_cmdline_strerror(int cmdline_errno);
void list_aliases(struct string_list *list);
#endif

View File

@ -411,11 +411,9 @@ static void parse_treeish_arg(const char **argv,
}
#define OPT__COMPR(s, v, h, p) \
{ OPTION_SET_INT, (s), NULL, (v), NULL, (h), \
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, (p) }
OPT_SET_INT_F(s, NULL, v, h, p, PARSE_OPT_NONEG)
#define OPT__COMPR_HIDDEN(s, v, p) \
{ OPTION_SET_INT, (s), NULL, (v), NULL, "", \
PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_HIDDEN, NULL, (p) }
OPT_SET_INT_F(s, NULL, v, "", p, PARSE_OPT_NONEG | PARSE_OPT_HIDDEN)
static int parse_archive_args(int argc, const char **argv,
const struct archiver **ar, struct archiver_args *args,

View File

@ -2231,12 +2231,12 @@ int cmd_am(int argc, const char **argv, const char *prefix)
N_("pass -b flag to git-mailinfo"), KEEP_NON_PATCH),
OPT_BOOL('m', "message-id", &state.message_id,
N_("pass -m flag to git-mailinfo")),
{ OPTION_SET_INT, 0, "keep-cr", &keep_cr, NULL,
N_("pass --keep-cr flag to git-mailsplit for mbox format"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1},
{ OPTION_SET_INT, 0, "no-keep-cr", &keep_cr, NULL,
N_("do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 0},
OPT_SET_INT_F(0, "keep-cr", &keep_cr,
N_("pass --keep-cr flag to git-mailsplit for mbox format"),
1, PARSE_OPT_NONEG),
OPT_SET_INT_F(0, "no-keep-cr", &keep_cr,
N_("do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"),
0, PARSE_OPT_NONEG),
OPT_BOOL('c', "scissors", &state.scissors,
N_("strip everything before a scissors line")),
OPT_PASSTHRU_ARGV(0, "whitespace", &state.git_apply_opts, N_("action"),

View File

@ -592,8 +592,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT__QUIET(&quiet, N_("suppress informational messages")),
OPT_SET_INT('t', "track", &track, N_("set up tracking mode (see git-pull(1))"),
BRANCH_TRACK_EXPLICIT),
{ OPTION_SET_INT, 0, "set-upstream", &track, NULL, N_("do not use"),
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, BRANCH_TRACK_OVERRIDE },
OPT_SET_INT_F(0, "set-upstream", &track, N_("do not use"),
BRANCH_TRACK_OVERRIDE, PARSE_OPT_HIDDEN),
OPT_STRING('u', "set-upstream-to", &new_upstream, N_("upstream"), N_("change the upstream info")),
OPT_BOOL(0, "unset-upstream", &unset_upstream, N_("Unset the upstream info")),
OPT__COLOR(&branch_use_color, N_("use colored output")),

View File

@ -695,12 +695,11 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
N_("use `diff.guitool` instead of `diff.tool`")),
OPT_BOOL('d', "dir-diff", &dir_diff,
N_("perform a full-directory diff")),
{ OPTION_SET_INT, 'y', "no-prompt", &prompt, NULL,
OPT_SET_INT_F('y', "no-prompt", &prompt,
N_("do not prompt before launching a diff tool"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 0},
{ OPTION_SET_INT, 0, "prompt", &prompt, NULL, NULL,
PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_HIDDEN,
NULL, 1 },
0, PARSE_OPT_NONEG),
OPT_SET_INT_F(0, "prompt", &prompt, NULL,
1, PARSE_OPT_NONEG | PARSE_OPT_HIDDEN),
OPT_BOOL(0, "symlinks", &symlinks,
N_("use symlinks in dir-diff mode")),
OPT_STRING('t', "tool", &difftool_cmd, N_("<tool>"),

View File

@ -155,9 +155,9 @@ static struct option builtin_fetch_options[] = {
N_("deepen history of shallow clone, excluding rev")),
OPT_INTEGER(0, "deepen", &deepen_relative,
N_("deepen history of shallow clone")),
{ OPTION_SET_INT, 0, "unshallow", &unshallow, NULL,
N_("convert to a complete repository"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1 },
OPT_SET_INT_F(0, "unshallow", &unshallow,
N_("convert to a complete repository"),
1, PARSE_OPT_NONEG),
{ OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
{ OPTION_CALLBACK, 0, "recurse-submodules-default",

View File

@ -886,9 +886,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
N_("indicate hit with exit status without output")),
OPT_BOOL(0, "all-match", &opt.all_match,
N_("show only matches from files that match all patterns")),
{ OPTION_SET_INT, 0, "debug", &opt.debug, NULL,
N_("show parse tree for grep expression"),
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1 },
OPT_SET_INT_F(0, "debug", &opt.debug,
N_("show parse tree for grep expression"),
1, PARSE_OPT_HIDDEN),
OPT_GROUP(""),
{ OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager,
N_("pager"), N_("show matching files in the pager"),

View File

@ -9,6 +9,7 @@
#include "run-command.h"
#include "column.h"
#include "help.h"
#include "alias.h"
#ifndef DEFAULT_HELP_FORMAT
#define DEFAULT_HELP_FORMAT "man"
@ -36,6 +37,7 @@ static const char *html_path;
static int show_all = 0;
static int show_guides = 0;
static int verbose;
static unsigned int colopts;
static enum help_format help_format = HELP_FORMAT_NONE;
static int exclude_guides;
@ -48,6 +50,7 @@ static struct option builtin_help_options[] = {
HELP_FORMAT_WEB),
OPT_SET_INT('i', "info", &help_format, N_("show info page"),
HELP_FORMAT_INFO),
OPT__VERBOSE(&verbose, N_("print command description")),
OPT_END(),
};
@ -400,38 +403,6 @@ static void show_html_page(const char *git_cmd)
open_html(page_path.buf);
}
static struct {
const char *name;
const char *help;
} common_guides[] = {
{ "attributes", N_("Defining attributes per path") },
{ "everyday", N_("Everyday Git With 20 Commands Or So") },
{ "glossary", N_("A Git glossary") },
{ "ignore", N_("Specifies intentionally untracked files to ignore") },
{ "modules", N_("Defining submodule properties") },
{ "revisions", N_("Specifying revisions and ranges for Git") },
{ "tutorial", N_("A tutorial introduction to Git (for version 1.5.1 or newer)") },
{ "workflows", N_("An overview of recommended workflows with Git") },
};
static void list_common_guides_help(void)
{
int i, longest = 0;
for (i = 0; i < ARRAY_SIZE(common_guides); i++) {
if (longest < strlen(common_guides[i].name))
longest = strlen(common_guides[i].name);
}
puts(_("The common Git guides are:\n"));
for (i = 0; i < ARRAY_SIZE(common_guides); i++) {
printf(" %s ", common_guides[i].name);
mput_char(' ', longest - strlen(common_guides[i].name));
puts(_(common_guides[i].help));
}
putchar('\n');
}
static const char *check_git_cmd(const char* cmd)
{
char *alias;
@ -463,6 +434,11 @@ int cmd_help(int argc, const char **argv, const char *prefix)
if (show_all) {
git_config(git_help_config, NULL);
if (verbose) {
setup_pager();
list_all_cmds_help();
return 0;
}
printf(_("usage: %s%s"), _(git_usage_string), "\n\n");
load_command_list("git-", &main_cmds, &other_cmds);
list_commands(colopts, &main_cmds, &other_cmds);

View File

@ -1482,8 +1482,12 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
} else
chmod(final_index_name, 0444);
if (do_fsck_object)
add_packed_git(final_index_name, strlen(final_index_name), 0);
if (do_fsck_object) {
struct packed_git *p;
p = add_packed_git(final_index_name, strlen(final_index_name), 0);
if (p)
install_packed_git(the_repository, p);
}
if (!from_stdin) {
printf("%s\n", sha1_to_hex(hash));

View File

@ -117,7 +117,7 @@ static void copy_templates(const char *template_dir)
dir = opendir(template_path.buf);
if (!dir) {
warning(_("templates not found %s"), template_dir);
warning(_("templates not found in %s"), template_dir);
goto free_return;
}

View File

@ -1474,9 +1474,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
N_("output all-zero hash in From header")),
OPT_BOOL(0, "ignore-if-in-upstream", &ignore_if_in_upstream,
N_("don't include a patch matching a commit upstream")),
{ OPTION_SET_INT, 'p', "no-stat", &use_patch_format, NULL,
N_("show patch format instead of default (patch + stat)"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1},
OPT_SET_INT_F('p', "no-stat", &use_patch_format,
N_("show patch format instead of default (patch + stat)"),
1, PARSE_OPT_NONEG),
OPT_GROUP(N_("Messaging")),
{ OPTION_CALLBACK, 0, "add-header", NULL, N_("header"),
N_("add email header"), 0, header_callback },

View File

@ -556,9 +556,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
{ OPTION_CALLBACK, 0, "exclude-standard", &dir, NULL,
N_("add the standard git exclusions"),
PARSE_OPT_NOARG, option_parse_exclude_standard },
{ OPTION_SET_INT, 0, "full-name", &prefix_len, NULL,
N_("make the output relative to the project top directory"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL },
OPT_SET_INT_F(0, "full-name", &prefix_len,
N_("make the output relative to the project top directory"),
0, PARSE_OPT_NONEG),
OPT_BOOL(0, "recurse-submodules", &recurse_submodules,
N_("recurse through submodules")),
OPT_BOOL(0, "error-unmatch", &error_unmatch,

View File

@ -35,6 +35,7 @@
#include "string-list.h"
#include "packfile.h"
#include "tag.h"
#include "alias.h"
#define DEFAULT_TWOHEAD (1<<0)
#define DEFAULT_OCTOPUS (1<<1)
@ -214,9 +215,9 @@ static struct option builtin_merge_options[] = {
OPT_BOOL('e', "edit", &option_edit,
N_("edit message before committing")),
OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
{ OPTION_SET_INT, 0, "ff-only", &fast_forward, NULL,
N_("abort if fast-forward is not possible"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, FF_ONLY },
OPT_SET_INT_F(0, "ff-only", &fast_forward,
N_("abort if fast-forward is not possible"),
FF_ONLY, PARSE_OPT_NONEG),
OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
OPT_BOOL(0, "verify-signatures", &verify_signatures,
N_("verify that the named commit has a valid GPG signature")),

View File

@ -778,13 +778,13 @@ static int merge(int argc, const char **argv, const char *prefix)
N_("resolve notes conflicts using the given strategy "
"(manual/ours/theirs/union/cat_sort_uniq)")),
OPT_GROUP(N_("Committing unmerged notes")),
{ OPTION_SET_INT, 0, "commit", &do_commit, NULL,
N_("finalize notes merge by committing unmerged notes"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1},
OPT_SET_INT_F(0, "commit", &do_commit,
N_("finalize notes merge by committing unmerged notes"),
1, PARSE_OPT_NONEG),
OPT_GROUP(N_("Aborting notes merge resolution")),
{ OPTION_SET_INT, 0, "abort", &do_abort, NULL,
N_("abort notes merge"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1},
OPT_SET_INT_F(0, "abort", &do_abort,
N_("abort notes merge"),
1, PARSE_OPT_NONEG),
OPT_END()
};

View File

@ -3134,18 +3134,18 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
N_("do not create an empty pack output")),
OPT_BOOL(0, "revs", &use_internal_rev_list,
N_("read revision arguments from standard input")),
{ OPTION_SET_INT, 0, "unpacked", &rev_list_unpacked, NULL,
N_("limit the objects to those that are not yet packed"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
{ OPTION_SET_INT, 0, "all", &rev_list_all, NULL,
N_("include objects reachable from any reference"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
{ OPTION_SET_INT, 0, "reflog", &rev_list_reflog, NULL,
N_("include objects referred by reflog entries"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
{ OPTION_SET_INT, 0, "indexed-objects", &rev_list_index, NULL,
N_("include objects referred to by the index"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
OPT_SET_INT_F(0, "unpacked", &rev_list_unpacked,
N_("limit the objects to those that are not yet packed"),
1, PARSE_OPT_NONEG),
OPT_SET_INT_F(0, "all", &rev_list_all,
N_("include objects reachable from any reference"),
1, PARSE_OPT_NONEG),
OPT_SET_INT_F(0, "reflog", &rev_list_reflog,
N_("include objects referred by reflog entries"),
1, PARSE_OPT_NONEG),
OPT_SET_INT_F(0, "indexed-objects", &rev_list_index,
N_("include objects referred to by the index"),
1, PARSE_OPT_NONEG),
OPT_BOOL(0, "stdout", &pack_to_stdout,
N_("output pack to stdout")),
OPT_BOOL(0, "include-tag", &include_tag,

View File

@ -282,6 +282,10 @@ static int try_difference(const char *arg)
struct commit *a, *b;
a = lookup_commit_reference(&start_oid);
b = lookup_commit_reference(&end_oid);
if (!a || !b) {
*dotdot = '.';
return 0;
}
exclude = get_merge_bases(a, b);
while (exclude) {
struct commit *commit = pop_commit(&exclude);
@ -328,12 +332,12 @@ static int try_parent_shorthands(const char *arg)
return 0;
*dotdot = 0;
if (get_oid_committish(arg, &oid)) {
if (get_oid_committish(arg, &oid) ||
!(commit = lookup_commit_reference(&oid))) {
*dotdot = '^';
return 0;
}
commit = lookup_commit_reference(&oid);
if (exclude_parent &&
exclude_parent > commit_list_count(commit->parents)) {
*dotdot = '^';

View File

@ -1826,11 +1826,6 @@ extern int ws_blank_line(const char *line, int len, unsigned ws_rule);
void overlay_tree_on_index(struct index_state *istate,
const char *tree_name, const char *prefix);
char *alias_lookup(const char *alias);
int split_cmdline(char *cmdline, const char ***argv);
/* Takes a negative value returned by split_cmdline */
const char *split_cmdline_strerror(int cmdline_errno);
/* setup.c */
struct startup_info {
int have_repository;

View File

@ -1,23 +1,58 @@
# common commands are grouped by themes
# these groups are output by 'git help' in the order declared here.
# map each common command in the command list to one of these groups.
### common groups (do not change this line)
init start a working area (see also: git help tutorial)
worktree work on the current change (see also: git help everyday)
info examine the history and state (see also: git help revisions)
history grow, mark and tweak your common history
remote collaborate (see also: git help workflows)
### command list (do not change this line)
# command name category [deprecated] [common]
# Command classification list
# ---------------------------
# All supported commands, builtin or external, must be described in
# here. This info is used to list commands in various places. Each
# command is on one line followed by one or more attributes.
#
# The first attribute group is mandatory and indicates the command
# type. This group includes:
#
# mainporcelain
# ancillarymanipulators
# ancillaryinterrogators
# foreignscminterface
# plumbingmanipulators
# plumbinginterrogators
# synchingrepositories
# synchelpers
# purehelpers
#
# The type names are self explanatory. But if you want to see what
# command belongs to what group to get a better picture, have a look
# at "git" man page, "GIT COMMANDS" section.
#
# Commands of type mainporcelain can also optionally have one of these
# attributes:
#
# init
# worktree
# info
# history
# remote
#
# These commands are considered "common" and will show up in "git
# help" output in groups. Uncommon porcelain commands must not
# specify any of these attributes.
#
# "complete" attribute is used to mark that the command should be
# completable by git-completion.bash. Note that by default,
# mainporcelain commands are completable so you don't need this
# attribute.
#
# As part of the Git man page list, the man(5/7) guides are also
# specified here, which can only have "guide" attribute and nothing
# else.
#
### command list (do not change this line, also do not change alignment)
# command name category [category] [category]
git-add mainporcelain worktree
git-am mainporcelain
git-annotate ancillaryinterrogators
git-apply plumbingmanipulators
git-apply plumbingmanipulators complete
git-archimport foreignscminterface
git-archive mainporcelain
git-bisect mainporcelain info
git-blame ancillaryinterrogators
git-blame ancillaryinterrogators complete
git-branch mainporcelain history
git-bundle mainporcelain
git-cat-file plumbinginterrogators
@ -27,7 +62,7 @@ git-check-mailmap purehelpers
git-checkout mainporcelain history
git-checkout-index plumbingmanipulators
git-check-ref-format purehelpers
git-cherry ancillaryinterrogators
git-cherry ancillaryinterrogators complete
git-cherry-pick mainporcelain
git-citool mainporcelain
git-clean mainporcelain
@ -36,7 +71,7 @@ git-column purehelpers
git-commit mainporcelain history
git-commit-graph plumbingmanipulators
git-commit-tree plumbingmanipulators
git-config ancillarymanipulators
git-config ancillarymanipulators complete
git-count-objects ancillaryinterrogators
git-credential purehelpers
git-credential-cache purehelpers
@ -50,7 +85,7 @@ git-diff mainporcelain history
git-diff-files plumbinginterrogators
git-diff-index plumbinginterrogators
git-diff-tree plumbinginterrogators
git-difftool ancillaryinterrogators
git-difftool ancillaryinterrogators complete
git-fast-export ancillarymanipulators
git-fast-import ancillarymanipulators
git-fetch mainporcelain remote
@ -59,20 +94,20 @@ git-filter-branch ancillarymanipulators
git-fmt-merge-msg purehelpers
git-for-each-ref plumbinginterrogators
git-format-patch mainporcelain
git-fsck ancillaryinterrogators
git-fsck ancillaryinterrogators complete
git-gc mainporcelain
git-get-tar-commit-id ancillaryinterrogators
git-grep mainporcelain info
git-gui mainporcelain
git-hash-object plumbingmanipulators
git-help ancillaryinterrogators
git-help ancillaryinterrogators complete
git-http-backend synchingrepositories
git-http-fetch synchelpers
git-http-push synchelpers
git-imap-send foreignscminterface
git-index-pack plumbingmanipulators
git-init mainporcelain init
git-instaweb ancillaryinterrogators
git-instaweb ancillaryinterrogators complete
git-interpret-trailers purehelpers
gitk mainporcelain
git-log mainporcelain info
@ -86,7 +121,7 @@ git-merge-base plumbinginterrogators
git-merge-file plumbingmanipulators
git-merge-index plumbingmanipulators
git-merge-one-file purehelpers
git-mergetool ancillarymanipulators
git-mergetool ancillarymanipulators complete
git-merge-tree ancillaryinterrogators
git-mktag plumbingmanipulators
git-mktree plumbingmanipulators
@ -107,28 +142,29 @@ git-quiltimport foreignscminterface
git-read-tree plumbingmanipulators
git-rebase mainporcelain history
git-receive-pack synchelpers
git-reflog ancillarymanipulators
git-remote ancillarymanipulators
git-repack ancillarymanipulators
git-replace ancillarymanipulators
git-request-pull foreignscminterface
git-reflog ancillarymanipulators complete
git-remote ancillarymanipulators complete
git-repack ancillarymanipulators complete
git-replace ancillarymanipulators complete
git-request-pull foreignscminterface complete
git-rerere ancillaryinterrogators
git-reset mainporcelain worktree
git-revert mainporcelain
git-rev-list plumbinginterrogators
git-rev-parse ancillaryinterrogators
git-rm mainporcelain worktree
git-send-email foreignscminterface
git-send-email foreignscminterface complete
git-send-pack synchingrepositories
git-shell synchelpers
git-shortlog mainporcelain
git-show mainporcelain info
git-show-branch ancillaryinterrogators
git-show-branch ancillaryinterrogators complete
git-show-index plumbinginterrogators
git-show-ref plumbinginterrogators
git-sh-i18n purehelpers
git-sh-setup purehelpers
git-stash mainporcelain
git-stage complete
git-status mainporcelain info
git-stripspace purehelpers
git-submodule mainporcelain
@ -147,6 +183,22 @@ git-verify-commit ancillaryinterrogators
git-verify-pack plumbinginterrogators
git-verify-tag ancillaryinterrogators
gitweb ancillaryinterrogators
git-whatchanged ancillaryinterrogators
git-whatchanged ancillaryinterrogators complete
git-worktree mainporcelain
git-write-tree plumbingmanipulators
gitattributes guide
gitcli guide
gitcore-tutorial guide
gitcvs-migration guide
gitdiffcore guide
giteveryday guide
gitglossary guide
githooks guide
gitignore guide
gitmodules guide
gitnamespaces guide
gitrepository-layout guide
gitrevisions guide
gittutorial-2 guide
gittutorial guide
gitworkflows guide

View File

@ -207,6 +207,9 @@ static void prepare_commit_graft(void)
if (commit_graft_prepared)
return;
if (!startup_info->have_repository)
return;
graft_file = get_graft_file();
read_graft_file(graft_file);
/* make sure shallows are read */

View File

@ -14,6 +14,7 @@
#include "strbuf.h"
#include "version.h"
#include "protocol.h"
#include "alias.h"
static char *server_capabilities_v1;
static struct argv_array server_capabilities_v2 = ARGV_ARRAY_INIT;

View File

@ -989,127 +989,11 @@ __git_complete_strategy ()
return 1
}
__git_commands () {
if test -n "${GIT_TESTING_COMMAND_COMPLETION:-}"
then
printf "%s" "${GIT_TESTING_COMMAND_COMPLETION}"
else
git help -a|egrep '^ [a-zA-Z0-9]'
fi
}
__git_list_all_commands ()
{
local i IFS=" "$'\n'
for i in $(__git_commands)
do
case $i in
*--*) : helper pattern;;
*) echo $i;;
esac
done
}
__git_all_commands=
__git_compute_all_commands ()
{
test -n "$__git_all_commands" ||
__git_all_commands=$(__git_list_all_commands)
}
__git_list_porcelain_commands ()
{
local i IFS=" "$'\n'
__git_compute_all_commands
for i in $__git_all_commands
do
case $i in
*--*) : helper pattern;;
applymbox) : ask gittus;;
applypatch) : ask gittus;;
archimport) : import;;
cat-file) : plumbing;;
check-attr) : plumbing;;
check-ignore) : plumbing;;
check-mailmap) : plumbing;;
check-ref-format) : plumbing;;
checkout-index) : plumbing;;
column) : internal helper;;
commit-graph) : plumbing;;
commit-tree) : plumbing;;
count-objects) : infrequent;;
credential) : credentials;;
credential-*) : credentials helper;;
cvsexportcommit) : export;;
cvsimport) : import;;
cvsserver) : daemon;;
daemon) : daemon;;
diff-files) : plumbing;;
diff-index) : plumbing;;
diff-tree) : plumbing;;
fast-import) : import;;
fast-export) : export;;
fsck-objects) : plumbing;;
fetch-pack) : plumbing;;
fmt-merge-msg) : plumbing;;
for-each-ref) : plumbing;;
hash-object) : plumbing;;
http-*) : transport;;
index-pack) : plumbing;;
init-db) : deprecated;;
local-fetch) : plumbing;;
ls-files) : plumbing;;
ls-remote) : plumbing;;
ls-tree) : plumbing;;
mailinfo) : plumbing;;
mailsplit) : plumbing;;
merge-*) : plumbing;;
mktree) : plumbing;;
mktag) : plumbing;;
pack-objects) : plumbing;;
pack-redundant) : plumbing;;
pack-refs) : plumbing;;
parse-remote) : plumbing;;
patch-id) : plumbing;;
prune) : plumbing;;
prune-packed) : plumbing;;
quiltimport) : import;;
read-tree) : plumbing;;
receive-pack) : plumbing;;
remote-*) : transport;;
rerere) : plumbing;;
rev-list) : plumbing;;
rev-parse) : plumbing;;
runstatus) : plumbing;;
sh-setup) : internal;;
shell) : daemon;;
show-ref) : plumbing;;
send-pack) : plumbing;;
show-index) : plumbing;;
ssh-*) : transport;;
stripspace) : plumbing;;
symbolic-ref) : plumbing;;
unpack-file) : plumbing;;
unpack-objects) : plumbing;;
update-index) : plumbing;;
update-ref) : plumbing;;
update-server-info) : daemon;;
upload-archive) : plumbing;;
upload-pack) : plumbing;;
write-tree) : plumbing;;
var) : infrequent;;
verify-pack) : infrequent;;
verify-tag) : plumbing;;
*) echo $i;;
esac
done
}
__git_porcelain_commands=
__git_compute_porcelain_commands ()
{
test -n "$__git_porcelain_commands" ||
__git_porcelain_commands=$(__git_list_porcelain_commands)
__git_all_commands=$(git --list-cmds=main,others,alias,nohelpers)
}
# Lists all set config variables starting with the given section prefix,
@ -1127,11 +1011,6 @@ __git_pretty_aliases ()
__git_get_config_variables "pretty"
}
__git_aliases ()
{
__git_get_config_variables "alias"
}
# __git_aliased_command requires 1 argument
__git_aliased_command ()
{
@ -1739,13 +1618,12 @@ _git_help ()
return
;;
esac
__git_compute_all_commands
__gitcomp "$__git_all_commands $(__git_aliases)
attributes cli core-tutorial cvs-migration
diffcore everyday gitk glossary hooks ignore modules
namespaces repository-layout revisions tutorial tutorial-2
workflows
"
if test -n "$GIT_TESTING_ALL_COMMAND_LIST"
then
__gitcomp "$GIT_TESTING_ALL_COMMAND_LIST $(git --list-cmds=alias,list-guide) gitk"
else
__gitcomp "$(git --list-cmds=main,nohelpers,alias,list-guide) gitk"
fi
}
_git_init ()
@ -3214,7 +3092,7 @@ __git_complete_common () {
__git_cmds_with_parseopt_helper=
__git_support_parseopt_helper () {
test -n "$__git_cmds_with_parseopt_helper" ||
__git_cmds_with_parseopt_helper="$(__git --list-parseopt-builtins)"
__git_cmds_with_parseopt_helper="$(__git --list-cmds=parseopt)"
case " $__git_cmds_with_parseopt_helper " in
*" $1 "*)
@ -3300,8 +3178,14 @@ __git_main ()
--help
"
;;
*) __git_compute_porcelain_commands
__gitcomp "$__git_porcelain_commands $(__git_aliases)" ;;
*)
if test -n "$GIT_TESTING_PORCELAIN_COMMAND_LIST"
then
__gitcomp "$GIT_TESTING_PORCELAIN_COMMAND_LIST"
else
__gitcomp "$(git --list-cmds=list-mainporcelain,others,nohelpers,alias,list-complete,config)"
fi
;;
esac
return
fi
@ -3339,7 +3223,10 @@ __gitk_main ()
__git_complete_revlist
}
if [[ -n ${ZSH_VERSION-} ]]; then
if [[ -n ${ZSH_VERSION-} ]] &&
# Don't define these functions when sourced from 'git-completion.zsh',
# it has its own implementations.
[[ -z ${GIT_SOURCING_ZSH_COMPLETION-} ]]; then
echo "WARNING: this script is deprecated, please see git-completion.zsh" 1>&2
autoload -U +X compinit && compinit

View File

@ -39,7 +39,7 @@ if [ -z "$script" ]; then
test -f $e && script="$e" && break
done
fi
ZSH_VERSION='' . "$script"
GIT_SOURCING_ZSH_COMPLETION=y . "$script"
__gitcomp ()
{

View File

@ -63,6 +63,8 @@ foreach my $tar_file (@ARGV)
my $have_top_dir = 1;
my ($top_dir, %files);
my $next_path = '';
while (read(I, $_, 512) == 512) {
my ($name, $mode, $uid, $gid, $size, $mtime,
$chksum, $typeflag, $linkname, $magic,
@ -70,6 +72,13 @@ foreach my $tar_file (@ARGV)
$prefix) = unpack 'Z100 Z8 Z8 Z8 Z12 Z12
Z8 Z1 Z100 Z6
Z2 Z32 Z32 Z8 Z8 Z*', $_;
unless ($next_path eq '') {
# Recover name from previous extended header
$name = $next_path;
$next_path = '';
}
last unless length($name);
if ($name eq '././@LongLink') {
# GNU tar extension
@ -90,13 +99,31 @@ foreach my $tar_file (@ARGV)
Z8 Z1 Z100 Z6
Z2 Z32 Z32 Z8 Z8 Z*', $_;
}
next if $name =~ m{/\z};
$mode = oct $mode;
$size = oct $size;
$mtime = oct $mtime;
next if $typeflag == 5; # directory
if ($typeflag != 1) { # handle hard links later
if ($typeflag eq 'x') { # extended header
# If extended header, check for path
my $pax_header = '';
while ($size > 0 && read(I, $_, 512) == 512) {
$pax_header = $pax_header . substr($_, 0, $size);
$size -= 512;
}
my @lines = split /\n/, $pax_header;
foreach my $line (@lines) {
my ($len, $entry) = split / /, $line;
my ($key, $value) = split /=/, $entry;
if ($key eq 'path') {
$next_path = $value;
}
}
next;
} elsif ($name =~ m{/\z}) { # directory
next;
} elsif ($typeflag != 1) { # handle hard links later
print FI "blob\n", "mark :$next_mark\n";
if ($typeflag == 2) { # symbolic link
print FI "data ", length($linkname), "\n",

3
fsck.c
View File

@ -1036,7 +1036,8 @@ int fsck_finish(struct fsck_options *options)
blob = lookup_blob(oid);
if (!blob) {
ret |= report(options, &blob->object,
struct object *obj = lookup_unknown_object(oid->hash);
ret |= report(options, obj,
FSCK_MSG_GITMODULES_BLOB,
"non-blob found at .gitmodules");
continue;

View File

@ -1,50 +1,90 @@
#!/bin/sh
die () {
echo "$@" >&2
exit 1
}
command_list () {
grep -v '^#' "$1"
}
get_categories () {
tr ' ' '\n'|
grep -v '^$' |
sort |
uniq
}
category_list () {
command_list "$1" |
cut -c 40- |
get_categories
}
get_synopsis () {
sed -n '
/^NAME/,/'"$1"'/H
${
x
s/.*'"$1"' - \(.*\)/N_("\1")/
p
}' "Documentation/$1.txt"
}
define_categories () {
echo
echo "/* Command categories */"
bit=0
category_list "$1" |
while read cat
do
echo "#define CAT_$cat (1UL << $bit)"
bit=$(($bit+1))
done
test "$bit" -gt 32 && die "Urgh.. too many categories?"
}
define_category_names () {
echo
echo "/* Category names */"
echo "static const char *category_names[] = {"
bit=0
category_list "$1" |
while read cat
do
echo " \"$cat\", /* (1UL << $bit) */"
bit=$(($bit+1))
done
echo " NULL"
echo "};"
}
print_command_list () {
echo "static struct cmdname_help command_list[] = {"
command_list "$1" |
while read cmd rest
do
printf " { \"$cmd\", $(get_synopsis $cmd), 0"
for cat in $(echo "$rest" | get_categories)
do
printf " | CAT_$cat"
done
echo " },"
done
echo "};"
}
echo "/* Automatically generated by generate-cmdlist.sh */
struct cmdname_help {
char name[16];
char help[80];
unsigned char group;
const char *name;
const char *help;
uint32_t category;
};
static const char *common_cmd_groups[] = {"
grps=grps$$.tmp
match=match$$.tmp
trap "rm -f '$grps' '$match'" 0 1 2 3 15
sed -n '
1,/^### common groups/b
/^### command list/q
/^#/b
/^[ ]*$/b
h;s/^[^ ][^ ]*[ ][ ]*\(.*\)/ N_("\1"),/p
g;s/^\([^ ][^ ]*\)[ ].*/\1/w '$grps'
' "$1"
printf '};\n\n'
n=0
substnum=
while read grp
do
echo "^git-..*[ ]$grp"
substnum="$substnum${substnum:+;}s/[ ]$grp/$n/"
n=$(($n+1))
done <"$grps" >"$match"
printf 'static struct cmdname_help common_cmds[] = {\n'
grep -f "$match" "$1" |
sed 's/^git-//' |
sort |
while read cmd tags
do
tag=$(echo "$tags" | sed "$substnum; s/[^0-9]//g")
sed -n '
/^NAME/,/git-'"$cmd"'/H
${
x
s/.*git-'"$cmd"' - \(.*\)/ {"'"$cmd"'", N_("\1"), '$tag'},/
p
}' "Documentation/git-$cmd.txt"
done
echo "};"
"
define_categories "$1"
echo
define_category_names "$1"
echo
print_command_list "$1"

213
git-p4.py
View File

@ -316,12 +316,17 @@ def p4_last_change():
results = p4CmdList(["changes", "-m", "1"], skip_info=True)
return int(results[0]['change'])
def p4_describe(change):
def p4_describe(change, shelved=False):
"""Make sure it returns a valid result by checking for
the presence of field "time". Return a dict of the
results."""
ds = p4CmdList(["describe", "-s", str(change)], skip_info=True)
cmd = ["describe", "-s"]
if shelved:
cmd += ["-S"]
cmd += [str(change)]
ds = p4CmdList(cmd, skip_info=True)
if len(ds) != 1:
die("p4 describe -s %d did not return 1 result: %s" % (change, str(ds)))
@ -662,6 +667,12 @@ def gitBranchExists(branch):
stderr=subprocess.PIPE, stdout=subprocess.PIPE);
return proc.wait() == 0;
def gitUpdateRef(ref, newvalue):
subprocess.check_call(["git", "update-ref", ref, newvalue])
def gitDeleteRef(ref):
subprocess.check_call(["git", "update-ref", "-d", ref])
_gitConfig = {}
def gitConfig(key, typeSpecifier=None):
@ -2411,6 +2422,7 @@ class P4Sync(Command, P4UserMap):
self.tempBranches = []
self.tempBranchLocation = "refs/git-p4-tmp"
self.largeFileSystem = None
self.suppress_meta_comment = False
if gitConfig('git-p4.largeFileSystem'):
largeFileSystemConstructor = globals()[gitConfig('git-p4.largeFileSystem')]
@ -2421,6 +2433,18 @@ class P4Sync(Command, P4UserMap):
if gitConfig("git-p4.syncFromOrigin") == "false":
self.syncWithOrigin = False
self.depotPaths = []
self.changeRange = ""
self.previousDepotPaths = []
self.hasOrigin = False
# map from branch depot path to parent branch
self.knownBranches = {}
self.initialParents = {}
self.tz = "%+03d%02d" % (- time.timezone / 3600, ((- time.timezone % 3600) / 60))
self.labels = {}
# Force a checkpoint in fast-import and wait for it to finish
def checkpoint(self):
self.gitStream.write("checkpoint\n\n")
@ -2429,7 +2453,20 @@ class P4Sync(Command, P4UserMap):
if self.verbose:
print "checkpoint finished: " + out
def extractFilesFromCommit(self, commit):
def cmp_shelved(self, path, filerev, revision):
""" Determine if a path at revision #filerev is the same as the file
at revision @revision for a shelved changelist. If they don't match,
unshelving won't be safe (we will get other changes mixed in).
This is comparing the revision that the shelved changelist is *based* on, not
the shelved changelist itself.
"""
ret = p4Cmd(["diff2", "{0}#{1}".format(path, filerev), "{0}@{1}".format(path, revision)])
if verbose:
print("p4 diff2 path %s filerev %s revision %s => %s" % (path, filerev, revision, ret))
return ret["status"] == "identical"
def extractFilesFromCommit(self, commit, shelved=False, shelved_cl = 0, origin_revision = 0):
self.cloneExclude = [re.sub(r"\.\.\.$", "", path)
for path in self.cloneExclude]
files = []
@ -2452,6 +2489,19 @@ class P4Sync(Command, P4UserMap):
file["rev"] = commit["rev%s" % fnum]
file["action"] = commit["action%s" % fnum]
file["type"] = commit["type%s" % fnum]
if shelved:
file["shelved_cl"] = int(shelved_cl)
# For shelved changelists, check that the revision of each file that the
# shelve was based on matches the revision that we are using for the
# starting point for git-fast-import (self.initialParent). Otherwise
# the resulting diff will contain deltas from multiple commits.
if file["action"] != "add" and \
not self.cmp_shelved(path, file["rev"], origin_revision):
sys.exit("change {0} not based on {1} for {2}, cannot unshelve".format(
commit["change"], self.initialParent, path))
files.append(file)
fnum = fnum + 1
return files
@ -2743,7 +2793,16 @@ class P4Sync(Command, P4UserMap):
def streamP4FilesCbSelf(entry):
self.streamP4FilesCb(entry)
fileArgs = ['%s#%s' % (f['path'], f['rev']) for f in filesToRead]
fileArgs = []
for f in filesToRead:
if 'shelved_cl' in f:
# Handle shelved CLs using the "p4 print file@=N" syntax to print
# the contents
fileArg = '%s@=%d' % (f['path'], f['shelved_cl'])
else:
fileArg = '%s#%s' % (f['path'], f['rev'])
fileArgs.append(fileArg)
p4CmdList(["-x", "-", "print"],
stdin=fileArgs,
@ -2844,11 +2903,15 @@ class P4Sync(Command, P4UserMap):
self.gitStream.write(details["desc"])
if len(jobs) > 0:
self.gitStream.write("\nJobs: %s" % (' '.join(jobs)))
self.gitStream.write("\n[git-p4: depot-paths = \"%s\": change = %s" %
(','.join(self.branchPrefixes), details["change"]))
if len(details['options']) > 0:
self.gitStream.write(": options = %s" % details['options'])
self.gitStream.write("]\nEOT\n\n")
if not self.suppress_meta_comment:
self.gitStream.write("\n[git-p4: depot-paths = \"%s\": change = %s" %
(','.join(self.branchPrefixes), details["change"]))
if len(details['options']) > 0:
self.gitStream.write(": options = %s" % details['options'])
self.gitStream.write("]\n")
self.gitStream.write("EOT\n\n")
if len(parent) > 0:
if self.verbose:
@ -3162,10 +3225,10 @@ class P4Sync(Command, P4UserMap):
else:
return None
def importChanges(self, changes):
def importChanges(self, changes, shelved=False, origin_revision=0):
cnt = 1
for change in changes:
description = p4_describe(change)
description = p4_describe(change, shelved)
self.updateOptionDict(description)
if not self.silent:
@ -3235,7 +3298,7 @@ class P4Sync(Command, P4UserMap):
print "Parent of %s not found. Committing into head of %s" % (branch, parent)
self.commit(description, filesForCommit, branch, parent)
else:
files = self.extractFilesFromCommit(description)
files = self.extractFilesFromCommit(description, shelved, change, origin_revision)
self.commit(description, files, self.branch,
self.initialParent)
# only needed once, to connect to the previous commit
@ -3300,17 +3363,23 @@ class P4Sync(Command, P4UserMap):
print "IO error with git fast-import. Is your git version recent enough?"
print self.gitError.read()
def openStreams(self):
self.importProcess = subprocess.Popen(["git", "fast-import"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE);
self.gitOutput = self.importProcess.stdout
self.gitStream = self.importProcess.stdin
self.gitError = self.importProcess.stderr
def closeStreams(self):
self.gitStream.close()
if self.importProcess.wait() != 0:
die("fast-import failed: %s" % self.gitError.read())
self.gitOutput.close()
self.gitError.close()
def run(self, args):
self.depotPaths = []
self.changeRange = ""
self.previousDepotPaths = []
self.hasOrigin = False
# map from branch depot path to parent branch
self.knownBranches = {}
self.initialParents = {}
if self.importIntoRemotes:
self.refPrefix = "refs/remotes/p4/"
else:
@ -3497,15 +3566,7 @@ class P4Sync(Command, P4UserMap):
b = b[len(self.projectName):]
self.createdBranches.add(b)
self.tz = "%+03d%02d" % (- time.timezone / 3600, ((- time.timezone % 3600) / 60))
self.importProcess = subprocess.Popen(["git", "fast-import"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE);
self.gitOutput = self.importProcess.stdout
self.gitStream = self.importProcess.stdin
self.gitError = self.importProcess.stderr
self.openStreams()
if revision:
self.importHeadRevision(revision)
@ -3585,11 +3646,7 @@ class P4Sync(Command, P4UserMap):
missingP4Labels = p4Labels - gitTags
self.importP4Labels(self.gitStream, missingP4Labels)
self.gitStream.close()
if self.importProcess.wait() != 0:
die("fast-import failed: %s" % self.gitError.read())
self.gitOutput.close()
self.gitError.close()
self.closeStreams()
# Cleanup temporary branches created during import
if self.tempBranches != []:
@ -3721,6 +3778,89 @@ class P4Clone(P4Sync):
return True
class P4Unshelve(Command):
def __init__(self):
Command.__init__(self)
self.options = []
self.origin = "HEAD"
self.description = "Unshelve a P4 changelist into a git commit"
self.usage = "usage: %prog [options] changelist"
self.options += [
optparse.make_option("--origin", dest="origin",
help="Use this base revision instead of the default (%s)" % self.origin),
]
self.verbose = False
self.noCommit = False
self.destbranch = "refs/remotes/p4/unshelved"
def renameBranch(self, branch_name):
""" Rename the existing branch to branch_name.N
"""
found = True
for i in range(0,1000):
backup_branch_name = "{0}.{1}".format(branch_name, i)
if not gitBranchExists(backup_branch_name):
gitUpdateRef(backup_branch_name, branch_name) # copy ref to backup
gitDeleteRef(branch_name)
found = True
print("renamed old unshelve branch to {0}".format(backup_branch_name))
break
if not found:
sys.exit("gave up trying to rename existing branch {0}".format(sync.branch))
def findLastP4Revision(self, starting_point):
""" Look back from starting_point for the first commit created by git-p4
to find the P4 commit we are based on, and the depot-paths.
"""
for parent in (range(65535)):
log = extractLogMessageFromGitCommit("{0}^{1}".format(starting_point, parent))
settings = extractSettingsGitLog(log)
if settings.has_key('change'):
return settings
sys.exit("could not find git-p4 commits in {0}".format(self.origin))
def run(self, args):
if len(args) != 1:
return False
if not gitBranchExists(self.origin):
sys.exit("origin branch {0} does not exist".format(self.origin))
sync = P4Sync()
changes = args
sync.initialParent = self.origin
# use the first change in the list to construct the branch to unshelve into
change = changes[0]
# if the target branch already exists, rename it
branch_name = "{0}/{1}".format(self.destbranch, change)
if gitBranchExists(branch_name):
self.renameBranch(branch_name)
sync.branch = branch_name
sync.verbose = self.verbose
sync.suppress_meta_comment = True
settings = self.findLastP4Revision(self.origin)
origin_revision = settings['change']
sync.depotPaths = settings['depot-paths']
sync.branchPrefixes = sync.depotPaths
sync.openStreams()
sync.loadUserMapFromCache()
sync.silent = True
sync.importChanges(changes, shelved=True, origin_revision=origin_revision)
sync.closeStreams()
print("unshelved changelist {0} into {1}".format(change, branch_name))
return True
class P4Branches(Command):
def __init__(self):
Command.__init__(self)
@ -3775,7 +3915,8 @@ commands = {
"rebase" : P4Rebase,
"clone" : P4Clone,
"rollback" : P4RollBack,
"branches" : P4Branches
"branches" : P4Branches,
"unshelve" : P4Unshelve,
}

View File

@ -162,7 +162,7 @@ r, reword <commit> = use commit, but edit the commit message
e, edit <commit> = use commit, but stop for amending
s, squash <commit> = use commit, but meld into previous commit
f, fixup <commit> = like \"squash\", but discard this commit's log message
x, exec <commit> = run command (the rest of the line) using shell
x, exec <command> = run command (the rest of the line) using shell
d, drop <commit> = remove commit
l, label <label> = label current HEAD with a name
t, reset <label> = reset HEAD to a label

85
git.c
View File

@ -3,6 +3,7 @@
#include "exec-cmd.h"
#include "help.h"
#include "run-command.h"
#include "alias.h"
#define RUN_SETUP (1<<0)
#define RUN_SETUP_GENTLY (1<<1)
@ -36,7 +37,66 @@ const char git_more_info_string[] =
static int use_pager = -1;
static void list_builtins(unsigned int exclude_option, char sep);
static void list_builtins(struct string_list *list, unsigned int exclude_option);
static void exclude_helpers_from_list(struct string_list *list)
{
int i = 0;
while (i < list->nr) {
if (strstr(list->items[i].string, "--"))
unsorted_string_list_delete_item(list, i, 0);
else
i++;
}
}
static int match_token(const char *spec, int len, const char *token)
{
int token_len = strlen(token);
return len == token_len && !strncmp(spec, token, token_len);
}
static int list_cmds(const char *spec)
{
struct string_list list = STRING_LIST_INIT_DUP;
int i;
while (*spec) {
const char *sep = strchrnul(spec, ',');
int len = sep - spec;
if (match_token(spec, len, "builtins"))
list_builtins(&list, 0);
else if (match_token(spec, len, "main"))
list_all_main_cmds(&list);
else if (match_token(spec, len, "others"))
list_all_other_cmds(&list);
else if (match_token(spec, len, "nohelpers"))
exclude_helpers_from_list(&list);
else if (match_token(spec, len, "alias"))
list_aliases(&list);
else if (match_token(spec, len, "config"))
list_cmds_by_config(&list);
else if (len > 5 && !strncmp(spec, "list-", 5)) {
struct strbuf sb = STRBUF_INIT;
strbuf_add(&sb, spec + 5, len - 5);
list_cmds_by_category(&list, sb.buf);
strbuf_release(&sb);
}
else
die(_("unsupported command listing type '%s'"), spec);
spec += len;
if (*spec == ',')
spec++;
}
for (i = 0; i < list.nr; i++)
puts(list.items[i].string);
string_list_clear(&list, 0);
return 0;
}
static void commit_pager_choice(void) {
switch (use_pager) {
@ -223,12 +283,19 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
}
(*argv)++;
(*argc)--;
} else if (!strcmp(cmd, "--list-builtins")) {
list_builtins(0, '\n');
exit(0);
} else if (!strcmp(cmd, "--list-parseopt-builtins")) {
list_builtins(NO_PARSEOPT, ' ');
exit(0);
} else if (skip_prefix(cmd, "--list-cmds=", &cmd)) {
if (!strcmp(cmd, "parseopt")) {
struct string_list list = STRING_LIST_INIT_DUP;
int i;
list_builtins(&list, NO_PARSEOPT);
for (i = 0; i < list.nr; i++)
printf("%s ", list.items[i].string);
string_list_clear(&list, 0);
exit(0);
} else {
exit(list_cmds(cmd));
}
} else {
fprintf(stderr, _("unknown option: %s\n"), cmd);
usage(git_usage_string);
@ -511,14 +578,14 @@ int is_builtin(const char *s)
return !!get_builtin(s);
}
static void list_builtins(unsigned int exclude_option, char sep)
static void list_builtins(struct string_list *out, unsigned int exclude_option)
{
int i;
for (i = 0; i < ARRAY_SIZE(commands); i++) {
if (exclude_option &&
(commands[i].option & exclude_option))
continue;
printf("%s%c", commands[i].cmd, sep);
string_list_append(out, commands[i].cmd);
}
}

256
help.c
View File

@ -5,13 +5,127 @@
#include "run-command.h"
#include "levenshtein.h"
#include "help.h"
#include "common-cmds.h"
#include "command-list.h"
#include "string-list.h"
#include "column.h"
#include "version.h"
#include "refs.h"
#include "parse-options.h"
struct category_description {
uint32_t category;
const char *desc;
};
static uint32_t common_mask =
CAT_init | CAT_worktree | CAT_info |
CAT_history | CAT_remote;
static struct category_description common_categories[] = {
{ CAT_init, N_("start a working area (see also: git help tutorial)") },
{ CAT_worktree, N_("work on the current change (see also: git help everyday)") },
{ CAT_info, N_("examine the history and state (see also: git help revisions)") },
{ CAT_history, N_("grow, mark and tweak your common history") },
{ CAT_remote, N_("collaborate (see also: git help workflows)") },
{ 0, NULL }
};
static struct category_description main_categories[] = {
{ CAT_mainporcelain, N_("Main Porcelain Commands") },
{ CAT_ancillarymanipulators, N_("Ancillary Commands / Manipulators") },
{ CAT_ancillaryinterrogators, N_("Ancillary Commands / Interrogators") },
{ CAT_foreignscminterface, N_("Interacting with Others") },
{ CAT_plumbingmanipulators, N_("Low-level Commands / Manipulators") },
{ CAT_plumbinginterrogators, N_("Low-level Commands / Interrogators") },
{ CAT_synchingrepositories, N_("Low-level Commands / Synching Repositories") },
{ CAT_purehelpers, N_("Low-level Commands / Internal Helpers") },
{ 0, NULL }
};
static const char *drop_prefix(const char *name, uint32_t category)
{
const char *new_name;
if (skip_prefix(name, "git-", &new_name))
return new_name;
if (category == CAT_guide && skip_prefix(name, "git", &new_name))
return new_name;
return name;
}
static void extract_cmds(struct cmdname_help **p_cmds, uint32_t mask)
{
int i, nr = 0;
struct cmdname_help *cmds;
if (ARRAY_SIZE(command_list) == 0)
BUG("empty command_list[] is a sign of broken generate-cmdlist.sh");
ALLOC_ARRAY(cmds, ARRAY_SIZE(command_list) + 1);
for (i = 0; i < ARRAY_SIZE(command_list); i++) {
const struct cmdname_help *cmd = command_list + i;
if (!(cmd->category & mask))
continue;
cmds[nr] = *cmd;
cmds[nr].name = drop_prefix(cmd->name, cmd->category);
nr++;
}
cmds[nr].name = NULL;
*p_cmds = cmds;
}
static void print_command_list(const struct cmdname_help *cmds,
uint32_t mask, int longest)
{
int i;
for (i = 0; cmds[i].name; i++) {
if (cmds[i].category & mask) {
printf(" %s ", cmds[i].name);
mput_char(' ', longest - strlen(cmds[i].name));
puts(_(cmds[i].help));
}
}
}
static int cmd_name_cmp(const void *elem1, const void *elem2)
{
const struct cmdname_help *e1 = elem1;
const struct cmdname_help *e2 = elem2;
return strcmp(e1->name, e2->name);
}
static void print_cmd_by_category(const struct category_description *catdesc)
{
struct cmdname_help *cmds;
int longest = 0;
int i, nr = 0;
uint32_t mask = 0;
for (i = 0; catdesc[i].desc; i++)
mask |= catdesc[i].category;
extract_cmds(&cmds, mask);
for (i = 0; cmds[i].name; i++, nr++) {
if (longest < strlen(cmds[i].name))
longest = strlen(cmds[i].name);
}
QSORT(cmds, nr, cmd_name_cmp);
for (i = 0; catdesc[i].desc; i++) {
uint32_t mask = catdesc[i].category;
const char *desc = catdesc[i].desc;
printf("\n%s\n", _(desc));
print_command_list(cmds, mask, longest);
}
free(cmds);
}
void add_cmdname(struct cmdnames *cmds, const char *name, int len)
{
struct cmdname *ent;
@ -190,42 +304,114 @@ void list_commands(unsigned int colopts,
}
}
static int cmd_group_cmp(const void *elem1, const void *elem2)
{
const struct cmdname_help *e1 = elem1;
const struct cmdname_help *e2 = elem2;
if (e1->group < e2->group)
return -1;
if (e1->group > e2->group)
return 1;
return strcmp(e1->name, e2->name);
}
void list_common_cmds_help(void)
{
int i, longest = 0;
int current_grp = -1;
for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
if (longest < strlen(common_cmds[i].name))
longest = strlen(common_cmds[i].name);
}
QSORT(common_cmds, ARRAY_SIZE(common_cmds), cmd_group_cmp);
puts(_("These are common Git commands used in various situations:"));
print_cmd_by_category(common_categories);
}
for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
if (common_cmds[i].group != current_grp) {
printf("\n%s\n", _(common_cmd_groups[common_cmds[i].group]));
current_grp = common_cmds[i].group;
void list_all_main_cmds(struct string_list *list)
{
struct cmdnames main_cmds, other_cmds;
int i;
memset(&main_cmds, 0, sizeof(main_cmds));
memset(&other_cmds, 0, sizeof(other_cmds));
load_command_list("git-", &main_cmds, &other_cmds);
for (i = 0; i < main_cmds.cnt; i++)
string_list_append(list, main_cmds.names[i]->name);
clean_cmdnames(&main_cmds);
clean_cmdnames(&other_cmds);
}
void list_all_other_cmds(struct string_list *list)
{
struct cmdnames main_cmds, other_cmds;
int i;
memset(&main_cmds, 0, sizeof(main_cmds));
memset(&other_cmds, 0, sizeof(other_cmds));
load_command_list("git-", &main_cmds, &other_cmds);
for (i = 0; i < other_cmds.cnt; i++)
string_list_append(list, other_cmds.names[i]->name);
clean_cmdnames(&main_cmds);
clean_cmdnames(&other_cmds);
}
void list_cmds_by_category(struct string_list *list,
const char *cat)
{
int i, n = ARRAY_SIZE(command_list);
uint32_t cat_id = 0;
for (i = 0; category_names[i]; i++) {
if (!strcmp(cat, category_names[i])) {
cat_id = 1UL << i;
break;
}
printf(" %s ", common_cmds[i].name);
mput_char(' ', longest - strlen(common_cmds[i].name));
puts(_(common_cmds[i].help));
}
if (!cat_id)
die(_("unsupported command listing type '%s'"), cat);
for (i = 0; i < n; i++) {
struct cmdname_help *cmd = command_list + i;
if (!(cmd->category & cat_id))
continue;
string_list_append(list, drop_prefix(cmd->name, cmd->category));
}
}
void list_cmds_by_config(struct string_list *list)
{
const char *cmd_list;
/*
* There's no actual repository setup at this point (and even
* if there is, we don't really care; only global config
* matters). If we accidentally set up a repository, it's ok
* too since the caller (git --list-cmds=) should exit shortly
* anyway.
*/
if (git_config_get_string_const("completion.commands", &cmd_list))
return;
string_list_sort(list);
string_list_remove_duplicates(list, 0);
while (*cmd_list) {
struct strbuf sb = STRBUF_INIT;
const char *p = strchrnul(cmd_list, ' ');
strbuf_add(&sb, cmd_list, p - cmd_list);
if (*cmd_list == '-')
string_list_remove(list, cmd_list + 1, 0);
else
string_list_insert(list, sb.buf);
strbuf_release(&sb);
while (*p == ' ')
p++;
cmd_list = p;
}
}
void list_common_guides_help(void)
{
struct category_description catdesc[] = {
{ CAT_guide, N_("The common Git guides are:") },
{ 0, NULL }
};
print_cmd_by_category(catdesc);
putchar('\n');
}
void list_all_cmds_help(void)
{
print_cmd_by_category(main_categories);
}
int is_in_cmdlist(struct cmdnames *c, const char *s)
@ -285,6 +471,7 @@ const char *help_unknown_cmd(const char *cmd)
{
int i, n, best_similarity = 0;
struct cmdnames main_cmds, other_cmds;
struct cmdname_help *common_cmds;
memset(&main_cmds, 0, sizeof(main_cmds));
memset(&other_cmds, 0, sizeof(other_cmds));
@ -299,6 +486,8 @@ const char *help_unknown_cmd(const char *cmd)
QSORT(main_cmds.names, main_cmds.cnt, cmdname_compare);
uniq(&main_cmds);
extract_cmds(&common_cmds, common_mask);
/* This abuses cmdname->len for levenshtein distance */
for (i = 0, n = 0; i < main_cmds.cnt; i++) {
int cmp = 0; /* avoid compiler stupidity */
@ -313,10 +502,10 @@ const char *help_unknown_cmd(const char *cmd)
die(_(bad_interpreter_advice), cmd, cmd);
/* Does the candidate appear in common_cmds list? */
while (n < ARRAY_SIZE(common_cmds) &&
while (common_cmds[n].name &&
(cmp = strcmp(common_cmds[n].name, candidate)) < 0)
n++;
if ((n < ARRAY_SIZE(common_cmds)) && !cmp) {
if (common_cmds[n].name && !cmp) {
/* Yes, this is one of the common commands */
n++; /* use the entry from common_cmds[] */
if (starts_with(candidate, cmd)) {
@ -329,6 +518,7 @@ const char *help_unknown_cmd(const char *cmd)
main_cmds.names[i]->len =
levenshtein(cmd, candidate, 0, 2, 1, 3) + 1;
}
FREE_AND_NULL(common_cmds);
QSORT(main_cmds.names, main_cmds.cnt, levenshtein_compare);

10
help.h
View File

@ -1,6 +1,8 @@
#ifndef HELP_H
#define HELP_H
struct string_list;
struct cmdnames {
int alloc;
int cnt;
@ -17,6 +19,14 @@ static inline void mput_char(char c, unsigned int num)
}
extern void list_common_cmds_help(void);
extern void list_all_cmds_help(void);
extern void list_common_guides_help(void);
extern void list_all_main_cmds(struct string_list *list);
extern void list_all_other_cmds(struct string_list *list);
extern void list_cmds_by_category(struct string_list *list,
const char *category);
extern void list_cmds_by_config(struct string_list *list);
extern const char *help_unknown_cmd(const char *cmd);
extern void load_command_list(const char *prefix,
struct cmdnames *main_cmds,

View File

@ -1208,7 +1208,7 @@ static int merge_submodule(struct merge_options *o,
output(o, 3, _("Fast-forwarding submodule %s to the following commit:"), path);
output_commit_title(o, commit_b);
} else if (show(o, 2))
output(o, 2, _("Fast-forwarding submodule %s to %s"), path, oid_to_hex(b));
output(o, 2, _("Fast-forwarding submodule %s"), path);
else
; /* no output */
@ -1220,7 +1220,7 @@ static int merge_submodule(struct merge_options *o,
output(o, 3, _("Fast-forwarding submodule %s to the following commit:"), path);
output_commit_title(o, commit_a);
} else if (show(o, 2))
output(o, 2, _("Fast-forwarding submodule %s to %s"), path, oid_to_hex(a));
output(o, 2, _("Fast-forwarding submodule %s"), path);
else
; /* no output */

View File

@ -2,6 +2,7 @@
#include "config.h"
#include "run-command.h"
#include "sigchain.h"
#include "alias.h"
#ifndef DEFAULT_PAGER
#define DEFAULT_PAGER "less"

View File

@ -49,6 +49,8 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet
size_t rlen = strlen(++rhs);
is_glob = (1 <= rlen && strchr(rhs, '*'));
item->dst = xstrndup(rhs, rlen);
} else {
item->dst = NULL;
}
llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
@ -202,6 +204,8 @@ void refspec_ref_prefixes(const struct refspec *rs,
const struct refspec_item *item = &rs->items[i];
const char *prefix = NULL;
if (item->exact_sha1)
continue;
if (rs->fetch == REFSPEC_FETCH)
prefix = item->src;
else if (item->dst)

View File

@ -42,6 +42,10 @@ void refspec_clear(struct refspec *rs);
int valid_fetch_refspec(const char *refspec);
struct argv_array;
/*
* Determine what <prefix> values to pass to the peer in ref-prefix lines
* (see Documentation/technical/protocol-v2.txt).
*/
void refspec_ref_prefixes(const struct refspec *rs,
struct argv_array *ref_prefixes);

View File

@ -27,6 +27,7 @@
#include "worktree.h"
#include "oidmap.h"
#include "oidset.h"
#include "alias.h"
#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
@ -3791,7 +3792,7 @@ static const char *label_oid(struct object_id *oid, const char *label,
p[i] = save;
}
}
} else if (((len = strlen(label)) == GIT_SHA1_RAWSZ &&
} else if (((len = strlen(label)) == the_hash_algo->hexsz &&
!get_oid_hex(label, &dummy)) ||
(len == 1 && *label == '#') ||
hashmap_get_from_hash(&state->labels,

View File

@ -3,6 +3,7 @@
#include "exec-cmd.h"
#include "strbuf.h"
#include "run-command.h"
#include "alias.h"
#define COMMAND_DIR "git-shell-commands"
#define HELP_COMMAND COMMAND_DIR "/help"

View File

@ -1169,8 +1169,10 @@ int submodule_touches_in_range(struct object_id *excl_oid,
argv_array_push(&args, "--"); /* args[0] program name */
argv_array_push(&args, oid_to_hex(incl_oid));
argv_array_push(&args, "--not");
argv_array_push(&args, oid_to_hex(excl_oid));
if (!is_null_oid(excl_oid)) {
argv_array_push(&args, "--not");
argv_array_push(&args, oid_to_hex(excl_oid));
}
collect_changed_submodules(&subs, &args);
ret = subs.nr;

View File

@ -92,7 +92,10 @@ extern int bad_to_remove_submodule(const char *path, unsigned flags);
int add_submodule_odb(const char *path);
/* Checks if there are submodule changes in a..b. */
/*
* Checks if there are submodule changes in a..b. If a is the null OID,
* checks b and all its ancestors instead.
*/
extern int submodule_touches_in_range(struct object_id *a,
struct object_id *b);
extern int find_unpushed_submodules(struct oid_array *commits,

View File

@ -4,11 +4,11 @@ mkdir -p .git/refs/tags
>sed.script
# Answer the sha1 has associated with the tag. The tag must exist in .git/refs/tags
# Answer the sha1 has associated with the tag. The tag must exist under refs/tags
tag () {
_tag=$1
test -f ".git/refs/tags/$_tag" || error "tag: \"$_tag\" does not exist"
cat ".git/refs/tags/$_tag"
git rev-parse --verify "refs/tags/$_tag" ||
error "tag: \"$_tag\" does not exist"
}
# Generate a commit using the text specified to make it unique and the tree

View File

@ -25,6 +25,15 @@ test_expect_success "setup" '
EOF
'
# make sure to exercise these code paths, the output is a bit tricky
# to verify
test_expect_success 'basic help commands' '
git help >/dev/null &&
git help -a >/dev/null &&
git help -g >/dev/null &&
git help -av >/dev/null
'
test_expect_success "works for commands and guides by default" '
configure_help &&
git help status &&
@ -49,8 +58,23 @@ test_expect_success "--help does not work for guides" "
test_i18ncmp expect actual
"
test_expect_success 'git help' '
git help >help.output &&
test_i18ngrep "^ clone " help.output &&
test_i18ngrep "^ add " help.output &&
test_i18ngrep "^ log " help.output &&
test_i18ngrep "^ commit " help.output &&
test_i18ngrep "^ fetch " help.output
'
test_expect_success 'git help -g' '
git help -g >help.output &&
test_i18ngrep "^ attributes " help.output &&
test_i18ngrep "^ everyday " help.output &&
test_i18ngrep "^ tutorial " help.output
'
test_expect_success 'generate builtin list' '
git --list-builtins >builtins
git --list-cmds=builtins >builtins
'
while read builtin

View File

@ -65,7 +65,7 @@ reset_to_sane
test_expect_success 'symbolic-ref fails to delete real ref' '
echo "fatal: Cannot delete refs/heads/foo, not a symbolic ref" >expect &&
test_must_fail git symbolic-ref -d refs/heads/foo >actual 2>&1 &&
test_path_is_file .git/refs/heads/foo &&
git rev-parse --verify refs/heads/foo &&
test_cmp expect actual
'
reset_to_sane

View File

@ -234,34 +234,34 @@ test_expect_success 'git branch -M master2 master2 should work when master is ch
test_expect_success 'git branch -v -d t should work' '
git branch t &&
test_path_is_file .git/refs/heads/t &&
git rev-parse --verify refs/heads/t &&
git branch -v -d t &&
test_path_is_missing .git/refs/heads/t
test_must_fail git rev-parse --verify refs/heads/t
'
test_expect_success 'git branch -v -m t s should work' '
git branch t &&
test_path_is_file .git/refs/heads/t &&
git rev-parse --verify refs/heads/t &&
git branch -v -m t s &&
test_path_is_missing .git/refs/heads/t &&
test_path_is_file .git/refs/heads/s &&
test_must_fail git rev-parse --verify refs/heads/t &&
git rev-parse --verify refs/heads/s &&
git branch -d s
'
test_expect_success 'git branch -m -d t s should fail' '
git branch t &&
test_path_is_file .git/refs/heads/t &&
git rev-parse refs/heads/t &&
test_must_fail git branch -m -d t s &&
git branch -d t &&
test_path_is_missing .git/refs/heads/t
test_must_fail git rev-parse refs/heads/t
'
test_expect_success 'git branch --list -d t should fail' '
git branch t &&
test_path_is_file .git/refs/heads/t &&
git rev-parse refs/heads/t &&
test_must_fail git branch --list -d t &&
git branch -d t &&
test_path_is_missing .git/refs/heads/t
test_must_fail git rev-parse refs/heads/t
'
test_expect_success 'git branch --list -v with --abbrev' '

View File

@ -313,4 +313,20 @@ test_expect_success 'A root commit can be a cousin, treat it that way' '
EOF
'
test_expect_success 'labels that are object IDs are rewritten' '
git checkout -b third B &&
test_commit I &&
third=$(git rev-parse HEAD) &&
git checkout -b labels master &&
git merge --no-commit third &&
test_tick &&
git commit -m "Merge commit '\''$third'\'' into labels" &&
echo noop >script-from-scratch &&
test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
test_tick &&
git rebase -i -r A &&
grep "^label $third-" .git/ORIGINAL-TODO &&
! grep "^label $third$" .git/ORIGINAL-TODO
'
test_done

View File

@ -726,7 +726,7 @@ test_expect_success 'store updates stash ref and reflog' '
git reset --hard &&
! grep quux bazzy &&
git stash store -m quuxery $STASH_ID &&
test $(cat .git/refs/stash) = $STASH_ID &&
test $(git rev-parse stash) = $STASH_ID &&
git reflog --format=%H stash| grep $STASH_ID &&
git stash pop &&
grep quux bazzy

View File

@ -421,6 +421,12 @@ test_expect_success 'index-pack <pack> works in non-repo' '
test_path_is_file foo.idx
'
test_expect_success 'index-pack --strict <pack> works in non-repo' '
rm -f foo.idx &&
nongit git index-pack --strict ../foo.pack &&
test_path_is_file foo.idx
'
test_expect_success !PTHREADS,C_LOCALE_OUTPUT 'index-pack --threads=N or pack.threads=N warns when no pthreads' '
test_must_fail git index-pack --threads=2 2>err &&
grep ^warning: err >warnings &&

View File

@ -30,7 +30,7 @@ add () {
test_tick &&
commit=$(echo "$text" | git commit-tree $tree $parents) &&
eval "$name=$commit; export $name" &&
echo $commit > .git/refs/heads/$branch &&
git update-ref "refs/heads/$branch" "$commit" &&
eval ${branch}TIP=$commit
}
@ -45,10 +45,10 @@ pull_to_client () {
case "$heads" in
*A*)
echo $ATIP > .git/refs/heads/A;;
git update-ref refs/heads/A "$ATIP";;
esac &&
case "$heads" in *B*)
echo $BTIP > .git/refs/heads/B;;
git update-ref refs/heads/B "$BTIP";;
esac &&
git symbolic-ref HEAD refs/heads/$(echo $heads \
| sed -e "s/^\(.\).*$/\1/") &&
@ -92,8 +92,8 @@ test_expect_success 'setup' '
cur=$(($cur+1))
done &&
add B1 $A1 &&
echo $ATIP > .git/refs/heads/A &&
echo $BTIP > .git/refs/heads/B &&
git update-ref refs/heads/A "$ATIP" &&
git update-ref refs/heads/B "$BTIP" &&
git symbolic-ref HEAD refs/heads/B
'

View File

@ -63,7 +63,7 @@ test_expect_success "fetch test" '
git commit -a -m "updated by origin" &&
cd two &&
git fetch &&
test -f .git/refs/heads/one &&
git rev-parse --verify refs/heads/one &&
mine=$(git rev-parse refs/heads/one) &&
his=$(cd ../one && git rev-parse refs/heads/master) &&
test "z$mine" = "z$his"
@ -73,8 +73,8 @@ test_expect_success "fetch test for-merge" '
cd "$D" &&
cd three &&
git fetch &&
test -f .git/refs/heads/two &&
test -f .git/refs/heads/one &&
git rev-parse --verify refs/heads/two &&
git rev-parse --verify refs/heads/one &&
master_in_two=$(cd ../two && git rev-parse master) &&
one_in_two=$(cd ../two && git rev-parse one) &&
{

View File

@ -1121,6 +1121,25 @@ test_expect_success 'fetch exact SHA1' '
)
'
test_expect_success 'fetch exact SHA1 in protocol v2' '
mk_test testrepo heads/master hidden/one &&
git push testrepo master:refs/hidden/one &&
git -C testrepo config transfer.hiderefs refs/hidden &&
check_push_result testrepo $the_commit hidden/one &&
mk_child testrepo child &&
git -C child config protocol.version 2 &&
# make sure $the_commit does not exist here
git -C child repack -a -d &&
git -C child prune &&
test_must_fail git -C child cat-file -t $the_commit &&
# fetching the hidden object succeeds by default
# NEEDSWORK: should this match the v0 behavior instead?
git -C child fetch -v ../testrepo $the_commit:refs/heads/copy
'
for configallowtipsha1inwant in true false
do
test_expect_success "shallow fetch reachable SHA1 (but not a ref), allowtipsha1inwant=$configallowtipsha1inwant" '

View File

@ -132,4 +132,25 @@ test_expect_success 'pull rebase recursing fails with conflicts' '
test_i18ngrep "locally recorded submodule modifications" err
'
test_expect_success 'branch has no merge base with remote-tracking counterpart' '
rm -rf parent child &&
test_create_repo a-submodule &&
test_commit -C a-submodule foo &&
test_create_repo parent &&
git -C parent submodule add "$(pwd)/a-submodule" &&
git -C parent commit -m foo &&
git clone parent child &&
# Reset master so that it has no merge base with
# refs/remotes/origin/master.
OTHER=$(git -C child commit-tree -m bar \
$(git -C child rev-parse HEAD^{tree})) &&
git -C child reset --hard "$OTHER" &&
git -C child pull --recurse-submodules --rebase
'
test_done

View File

@ -34,7 +34,7 @@ doit () {
commit=$(echo $NAME | git commit-tree $T $PARENTS) &&
echo $commit >.git/refs/tags/$NAME &&
git update-ref "refs/tags/$NAME" "$commit" &&
echo $commit
}

View File

@ -214,4 +214,12 @@ test_expect_success 'rev-list merge^-1x (garbage after ^-1)' '
test_must_fail git rev-list merge^-1x
'
test_expect_success 'rev-parse $garbage^@ does not segfault' '
test_must_fail git rev-parse $EMPTY_TREE^@
'
test_expect_success 'rev-parse $garbage...$garbage does not segfault' '
test_must_fail git rev-parse $EMPTY_TREE...$EMPTY_BLOB
'
test_done

View File

@ -65,7 +65,7 @@ test_expect_success setup '
test_expect_success "checkout from non-existing branch" '
git checkout -b delete-me master &&
rm .git/refs/heads/delete-me &&
git update-ref -d --no-deref refs/heads/delete-me &&
test refs/heads/delete-me = "$(git symbolic-ref HEAD)" &&
git checkout master &&
test refs/heads/master = "$(git symbolic-ref HEAD)"

View File

@ -122,6 +122,16 @@ test_expect_success 'transfer.fsckObjects handles odd pack (index)' '
test_must_fail git -C dst.git index-pack --strict --stdin <odd.pack
'
test_expect_success 'index-pack --strict works for non-repo pack' '
rm -rf dst.git &&
git init --bare dst.git &&
cp odd.pack dst.git &&
test_must_fail git -C dst.git index-pack --strict odd.pack 2>output &&
# Make sure we fail due to bad gitmodules content, not because we
# could not read the blob in the first place.
grep gitmodulesName output
'
test_expect_success 'fsck detects symlinked .gitmodules file' '
git init symlink &&
(
@ -135,13 +145,10 @@ test_expect_success 'fsck detects symlinked .gitmodules file' '
tricky="[foo]bar=true" &&
content=$(git hash-object -w ../.gitmodules) &&
target=$(printf "$tricky" | git hash-object -w --stdin) &&
tree=$(
{
printf "100644 blob $content\t$tricky\n" &&
printf "120000 blob $target\t.gitmodules\n"
} | git mktree
) &&
commit=$(git commit-tree $tree) &&
{
printf "100644 blob $content\t$tricky\n" &&
printf "120000 blob $target\t.gitmodules\n"
} | git mktree &&
# Check not only that we fail, but that it is due to the
# symlink detector; this grep string comes from the config
@ -151,4 +158,22 @@ test_expect_success 'fsck detects symlinked .gitmodules file' '
)
'
test_expect_success 'fsck detects non-blob .gitmodules' '
git init non-blob &&
(
cd non-blob &&
# As above, make the funny tree directly to avoid index
# restrictions.
mkdir subdir &&
cp ../.gitmodules subdir/file &&
git add subdir/file &&
git commit -m ok &&
git ls-tree HEAD | sed s/subdir/.gitmodules/ | git mktree &&
test_must_fail git fsck 2>output &&
grep gitmodulesBlob output
)
'
test_done

View File

@ -215,7 +215,8 @@ test_expect_success "multi-fetch continues to work" "
"
test_expect_success "multi-fetch works off a 'clean' repository" '
rm -r "$GIT_DIR/svn" "$GIT_DIR/refs/remotes" "$GIT_DIR/logs" &&
rm -rf "$GIT_DIR/svn" "$GIT_DIR/refs/remotes" &&
git reflog expire --all --expire=all &&
mkdir "$GIT_DIR/svn" &&
git svn multi-fetch
'

138
t/t9832-unshelve.sh Executable file
View File

@ -0,0 +1,138 @@
#!/bin/sh
last_shelved_change () {
p4 changes -s shelved -m1 | cut -d " " -f 2
}
test_description='git p4 unshelve'
. ./lib-git-p4.sh
test_expect_success 'start p4d' '
start_p4d
'
test_expect_success 'init depot' '
(
cd "$cli" &&
echo file1 >file1 &&
p4 add file1 &&
p4 submit -d "change 1" &&
: >file_to_delete &&
p4 add file_to_delete &&
p4 submit -d "file to delete"
)
'
test_expect_success 'initial clone' '
git p4 clone --dest="$git" //depot/@all
'
test_expect_success 'create shelved changelist' '
(
cd "$cli" &&
p4 edit file1 &&
echo "a change" >>file1 &&
echo "new file" >file2 &&
p4 add file2 &&
p4 delete file_to_delete &&
p4 opened &&
p4 shelve -i <<EOF
Change: new
Description:
Test commit
Further description
Files:
//depot/file1
//depot/file2
//depot/file_to_delete
EOF
) &&
(
cd "$git" &&
change=$(last_shelved_change) &&
git p4 unshelve $change &&
git show refs/remotes/p4/unshelved/$change | grep -q "Further description" &&
git cherry-pick refs/remotes/p4/unshelved/$change &&
test_path_is_file file2 &&
test_cmp file1 "$cli"/file1 &&
test_cmp file2 "$cli"/file2 &&
test_path_is_missing file_to_delete
)
'
test_expect_success 'update shelved changelist and re-unshelve' '
test_when_finished cleanup_git &&
(
cd "$cli" &&
change=$(last_shelved_change) &&
echo "file3" >file3 &&
p4 add -c $change file3 &&
p4 shelve -i -r <<EOF &&
Change: $change
Description:
Test commit
Further description
Files:
//depot/file1
//depot/file2
//depot/file3
//depot/file_to_delete
EOF
p4 describe $change
) &&
(
cd "$git" &&
change=$(last_shelved_change) &&
git p4 unshelve $change &&
git diff refs/remotes/p4/unshelved/$change.0 refs/remotes/p4/unshelved/$change | grep -q file3
)
'
# This is the tricky case where the shelved changelist base revision doesn't
# match git-p4's idea of the base revision
#
# We will attempt to unshelve a change that is based on a change one commit
# ahead of p4/master
test_expect_success 'create shelved changelist based on p4 change ahead of p4/master' '
git p4 clone --dest="$git" //depot/@all &&
(
cd "$cli" &&
p4 revert ... &&
p4 edit file1 &&
echo "foo" >>file1 &&
p4 submit -d "change:foo" &&
p4 edit file1 &&
echo "bar" >>file1 &&
p4 shelve -i <<EOF &&
Change: new
Description:
Change to be unshelved
Files:
//depot/file1
EOF
change=$(last_shelved_change) &&
p4 describe -S $change | grep -q "Change to be unshelved"
)
'
# Now try to unshelve it. git-p4 should refuse to do so.
test_expect_success 'try to unshelve the change' '
test_when_finished cleanup_git &&
(
change=$(last_shelved_change) &&
cd "$git" &&
test_must_fail git p4 unshelve $change 2>out.txt &&
grep -q "cannot unshelve" out.txt
)
'
test_expect_success 'kill p4d' '
kill_p4d
'
test_done

View File

@ -13,7 +13,7 @@ complete ()
return 0
}
# Be careful when updating this list:
# Be careful when updating these lists:
#
# (1) The build tree may have build artifact from different branch, or
# the user's $PATH may have a random executable that may begin
@ -30,7 +30,8 @@ complete ()
# completion for "git <TAB>", and a plumbing is excluded. "add",
# "filter-branch" and "ls-files" are listed for this.
GIT_TESTING_COMMAND_COMPLETION='add checkout check-attr filter-branch ls-files'
GIT_TESTING_ALL_COMMAND_LIST='add checkout check-attr filter-branch ls-files'
GIT_TESTING_PORCELAIN_COMMAND_LIST='add checkout filter-branch'
. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash"
@ -180,7 +181,7 @@ test_expect_success '__git_find_repo_path - cwd is a .git directory' '
test_expect_success '__git_find_repo_path - parent is a .git directory' '
echo "$ROOT/.git" >expected &&
(
cd .git/refs/heads &&
cd .git/objects &&
__git_find_repo_path &&
echo "$__git_repo_path" >"$actual"
) &&
@ -1350,17 +1351,6 @@ test_expect_success '__git_pretty_aliases' '
test_cmp expect actual
'
test_expect_success '__git_aliases' '
cat >expect <<-EOF &&
ci
co
EOF
test_config alias.ci commit &&
test_config alias.co checkout &&
__git_aliases >actual &&
test_cmp expect actual
'
test_expect_success 'basic' '
run_completion "git " &&
# built-in
@ -1670,13 +1660,6 @@ test_expect_success 'sourcing the completion script clears cached commands' '
verbose test -z "$__git_all_commands"
'
test_expect_success 'sourcing the completion script clears cached porcelain commands' '
__git_compute_porcelain_commands &&
verbose test -n "$__git_porcelain_commands" &&
. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
verbose test -z "$__git_porcelain_commands"
'
test_expect_success !GETTEXT_POISON 'sourcing the completion script clears cached merge strategies' '
__git_compute_merge_strategies &&
verbose test -n "$__git_merge_strategies" &&

View File

@ -148,7 +148,7 @@ test_expect_success 'prompt - inside .git directory' '
test_expect_success 'prompt - deep inside .git directory' '
printf " (GIT_DIR!)" >expected &&
(
cd .git/refs/heads &&
cd .git/objects &&
__git_ps1 >"$actual"
) &&
test_cmp expected "$actual"