mirror of
https://github.com/git/git.git
synced 2026-04-02 04:50:12 +02:00
Merge branch 'master' of git://repo.or.cz/alt-git
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -11,6 +11,7 @@ git-apply
|
||||
git-archimport
|
||||
git-archive
|
||||
git-bisect
|
||||
git-bisect--helper
|
||||
git-blame
|
||||
git-branch
|
||||
git-bundle
|
||||
@@ -35,6 +36,8 @@ git-diff
|
||||
git-diff-files
|
||||
git-diff-index
|
||||
git-diff-tree
|
||||
git-difftool
|
||||
git-difftool--helper
|
||||
git-describe
|
||||
git-fast-export
|
||||
git-fast-import
|
||||
@@ -78,6 +81,7 @@ git-merge-recursive
|
||||
git-merge-resolve
|
||||
git-merge-subtree
|
||||
git-mergetool
|
||||
git-mergetool--lib
|
||||
git-mktag
|
||||
git-mktree
|
||||
git-name-rev
|
||||
|
||||
31
Documentation/RelNotes-1.6.2.4.txt
Normal file
31
Documentation/RelNotes-1.6.2.4.txt
Normal file
@@ -0,0 +1,31 @@
|
||||
GIT v1.6.2.4 Release Notes
|
||||
==========================
|
||||
|
||||
Fixes since v1.6.2.3
|
||||
--------------------
|
||||
|
||||
* The configuration parser had a buffer overflow while parsing an overlong
|
||||
value.
|
||||
|
||||
* "git-checkout <tree-ish> <submodule>" did not update the index entry at
|
||||
the named path; it now does.
|
||||
|
||||
* "git init" segfaulted when given an overlong template location via
|
||||
the --template= option.
|
||||
|
||||
* "git-ls-tree" and "git-diff-tree" used a pathspec correctly when
|
||||
deciding to descend into a subdirectory but they did not match the
|
||||
individual paths correctly. This caused pathspecs "abc/d ab" to match
|
||||
"abc/0" ("abc/d" made them decide to descend into the directory "abc/",
|
||||
and then "ab" incorrectly matched "abc/0" when it shouldn't).
|
||||
|
||||
* "git-merge-recursive" was broken when a submodule entry was involved in
|
||||
a criss-cross merge situation.
|
||||
|
||||
Many small documentation updates are included as well.
|
||||
|
||||
---
|
||||
exec >/var/tmp/1
|
||||
echo O=$(git describe maint)
|
||||
O=v1.6.2.3-21-ga51609a
|
||||
git shortlog --no-merges $O..maint
|
||||
@@ -47,6 +47,8 @@ Updates since v1.6.2
|
||||
|
||||
(usability, bells and whistles)
|
||||
|
||||
* Boolean configuration variable yes/no can be written as on/off.
|
||||
|
||||
* rsync:/path/to/repo can be used to run git over rsync for local
|
||||
repositories. It may not be useful in practice; meant primarily for
|
||||
testing.
|
||||
@@ -63,6 +65,9 @@ Updates since v1.6.2
|
||||
|
||||
* "--oneline" is a synonym for "--pretty=oneline --abbrev-commit".
|
||||
|
||||
* "--graph" to the "git log" family can draw the commit ancestry graph
|
||||
in colors.
|
||||
|
||||
* If you realize that you botched the patch when you are editing hunks
|
||||
with the 'edit' action in git-add -i/-p, you can abort the editor to
|
||||
tell git not to apply it.
|
||||
@@ -75,8 +80,16 @@ Updates since v1.6.2
|
||||
1.6.2, but the initial implementation did not teach this to a few
|
||||
commands. Now the syntax works with "branch -m @{-1} newname".
|
||||
|
||||
* "git-add -p" now supports "q"uit action.
|
||||
|
||||
* git-archive learned --output=<file> option.
|
||||
|
||||
* git-archive takes attributes from the tree being archived; strictly
|
||||
speaking, this is an incompatible behaviour change, but is a good one.
|
||||
Use --worktree-attributes option to allow it to read attributes from
|
||||
the work tree as before (deprecated git-tar tree command always reads
|
||||
attributes from the work tree).
|
||||
|
||||
* git-bisect shows not just the number of remaining commits whose goodness
|
||||
is unknown, but also shows the estimated number of remaining rounds.
|
||||
|
||||
@@ -93,6 +106,9 @@ Updates since v1.6.2
|
||||
|
||||
* git-clone runs post-checkout hook when run without --no-checkout.
|
||||
|
||||
* git-difftool is now part of the officially supported command, primarily
|
||||
maintained by David Aguilar.
|
||||
|
||||
* git-fast-export choked when seeing a tag that does not point at commit.
|
||||
|
||||
* git-for-each-ref learned a new "upstream" token.
|
||||
@@ -156,26 +172,18 @@ release, unless otherwise noted.
|
||||
Here are fixes that this release has, but have not been backported to
|
||||
v1.6.2.X series.
|
||||
|
||||
* "git-apply" rejected a patch that swaps two files (i.e. renames A to B
|
||||
and B to A at the same time). May need to be backported by cherry
|
||||
picking d8c81df and then 7fac0ee).
|
||||
|
||||
* The initial checkout did not read the attributes from the .gitattribute
|
||||
file that is being checked out.
|
||||
|
||||
* "git-checkout <tree-ish> <submodule>" did not update the index entry at
|
||||
the named path; it now does.
|
||||
|
||||
* git-gc spent excessive amount of time to decide if an object appears
|
||||
in a locally existing pack (if needed, backport by merging 69e020a).
|
||||
|
||||
* "git-ls-tree" and "git-diff-tree" used a pathspec correctly when
|
||||
deciding to descend into a subdirectory but they did not match the
|
||||
individual paths correctly. This caused pathspecs "abc/d ab" to match
|
||||
"abc/0" ("abc/d" made them decide to descend into the directory "abc/",
|
||||
and then "ab" incorrectly matched "abc/0" when it shouldn't).
|
||||
|
||||
* "git-merge-recursive" was broken when a submodule entry was involved in
|
||||
a criss-cross merge situation.
|
||||
|
||||
---
|
||||
exec >/var/tmp/1
|
||||
O=v1.6.2.3-497-g54a4749
|
||||
O=v1.6.3-rc0-74-g9824a38
|
||||
echo O=$(git describe master)
|
||||
git shortlog --no-merges $O..master ^maint
|
||||
|
||||
@@ -61,7 +61,7 @@ Internal whitespace within a variable value is retained verbatim.
|
||||
|
||||
The values following the equals sign in variable assign are all either
|
||||
a string, an integer, or a boolean. Boolean values may be given as yes/no,
|
||||
0/1 or true/false. Case is not significant in boolean values, when
|
||||
0/1, true/false or on/off. Case is not significant in boolean values, when
|
||||
converting value to the canonical form using '--bool' type specifier;
|
||||
'git-config' will ensure that the output is "true" or "false".
|
||||
|
||||
@@ -667,6 +667,27 @@ diff.suppressBlankEmpty::
|
||||
A boolean to inhibit the standard behavior of printing a space
|
||||
before each empty output line. Defaults to false.
|
||||
|
||||
diff.tool::
|
||||
Controls which diff tool is used. `diff.tool` overrides
|
||||
`merge.tool` when used by linkgit:git-difftool[1] and has
|
||||
the same valid values as `merge.tool` minus "tortoisemerge"
|
||||
and plus "kompare".
|
||||
|
||||
difftool.<tool>.path::
|
||||
Override the path for the given tool. This is useful in case
|
||||
your tool is not in the PATH.
|
||||
|
||||
difftool.<tool>.cmd::
|
||||
Specify the command to invoke the specified diff tool.
|
||||
The specified command is evaluated in shell with the following
|
||||
variables available: 'LOCAL' is set to the name of the temporary
|
||||
file containing the contents of the diff pre-image and 'REMOTE'
|
||||
is set to the name of the temporary file containing the contents
|
||||
of the diff post-image.
|
||||
|
||||
difftool.prompt::
|
||||
Prompt before each invocation of the diff tool.
|
||||
|
||||
diff.wordRegex::
|
||||
A POSIX Extended Regular Expression used to determine what is a "word"
|
||||
when performing word-by-word difference calculations. Character
|
||||
|
||||
@@ -245,8 +245,11 @@ patch::
|
||||
|
||||
y - stage this hunk
|
||||
n - do not stage this hunk
|
||||
q - quit, do not stage this hunk nor any of the remaining ones
|
||||
a - stage this and all the remaining hunks in the file
|
||||
d - do not stage this hunk nor any of the remaining hunks in the file
|
||||
g - select a hunk to go to
|
||||
/ - search for a hunk matching the given regex
|
||||
j - leave this hunk undecided, see next undecided hunk
|
||||
J - leave this hunk undecided, see next hunk
|
||||
k - leave this hunk undecided, see previous undecided hunk
|
||||
|
||||
@@ -10,7 +10,7 @@ SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git archive' --format=<fmt> [--list] [--prefix=<prefix>/] [<extra>]
|
||||
[--output=<file>]
|
||||
[--output=<file>] [--worktree-attributes]
|
||||
[--remote=<repo> [--exec=<git-upload-archive>]] <tree-ish>
|
||||
[path...]
|
||||
|
||||
@@ -51,6 +51,9 @@ OPTIONS
|
||||
--output=<file>::
|
||||
Write the archive to <file> instead of stdout.
|
||||
|
||||
--worktree-attributes::
|
||||
Look for attributes in .gitattributes in working directory too.
|
||||
|
||||
<extra>::
|
||||
This can be any options that the archiver backend understands.
|
||||
See next section.
|
||||
|
||||
@@ -112,19 +112,22 @@ OPTIONS
|
||||
Display the full sha1s in the output listing rather than abbreviating them.
|
||||
|
||||
--track::
|
||||
When creating a new branch, set up the configuration so that 'git-pull'
|
||||
will automatically retrieve data from the start point, which must be
|
||||
a branch. Use this if you always pull from the same upstream branch
|
||||
into the new branch, and if you do not want to use "git pull
|
||||
<repository> <refspec>" explicitly. This behavior is the default
|
||||
when the start point is a remote branch. Set the
|
||||
branch.autosetupmerge configuration variable to `false` if you want
|
||||
'git-checkout' and 'git-branch' to always behave as if '--no-track' were
|
||||
given. Set it to `always` if you want this behavior when the
|
||||
start-point is either a local or remote branch.
|
||||
When creating a new branch, set up configuration to mark the
|
||||
start-point branch as "upstream" from the new branch. This
|
||||
configuration will tell git to show the relationship between the
|
||||
two branches in `git status` and `git branch -v`. Furthermore,
|
||||
it directs `git pull` without arguments to pull from the
|
||||
upstream when the new branch is checked out.
|
||||
+
|
||||
This behavior is the default when the start point is a remote branch.
|
||||
Set the branch.autosetupmerge configuration variable to `false` if you
|
||||
want `git checkout` and `git branch` to always behave as if '--no-track'
|
||||
were given. Set it to `always` if you want this behavior when the
|
||||
start-point is either a local or remote branch.
|
||||
|
||||
--no-track::
|
||||
Ignore the branch.autosetupmerge configuration variable.
|
||||
Do not set up "upstream" configuration, even if the
|
||||
branch.autosetupmerge configuration variable is true.
|
||||
|
||||
--contains <commit>::
|
||||
Only list branches which contain the specified commit.
|
||||
|
||||
@@ -8,22 +8,22 @@ git-checkout - Checkout a branch or paths to the working tree
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git checkout' [-q] [-f] [-t | --track | --no-track] [-b <new_branch> [-l]] [-m] [<branch>]
|
||||
'git checkout' [-q] [-f] [-m] [<branch>]
|
||||
'git checkout' [-q] [-f] [-m] [-b <new_branch>] [<start_point>]
|
||||
'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
When <paths> are not given, this command switches branches by
|
||||
updating the index and working tree to reflect the specified
|
||||
branch, <branch>, and updating HEAD to be <branch> or, if
|
||||
specified, <new_branch>. Using -b will cause <new_branch> to
|
||||
be created; in this case you can use the --track or --no-track
|
||||
options, which will be passed to `git branch`.
|
||||
updating the index, working tree, and HEAD to reflect the specified
|
||||
branch.
|
||||
|
||||
As a convenience, --track will default to creating a branch whose
|
||||
name is constructed from the specified branch name by stripping
|
||||
the first namespace level.
|
||||
If `-b` is given, a new branch is created and checked out, as if
|
||||
linkgit:git-branch[1] were called; in this case you can
|
||||
use the --track or --no-track options, which will be passed to `git
|
||||
branch`. As a convenience, --track without `-b` implies branch
|
||||
creation; see the description of --track below.
|
||||
|
||||
When <paths> are given, this command does *not* switch
|
||||
branches. It updates the named paths in the working tree from
|
||||
@@ -62,22 +62,12 @@ entries; instead, unmerged entries are ignored.
|
||||
|
||||
-b::
|
||||
Create a new branch named <new_branch> and start it at
|
||||
<branch>. The new branch name must pass all checks defined
|
||||
by linkgit:git-check-ref-format[1]. Some of these checks
|
||||
may restrict the characters allowed in a branch name.
|
||||
<start_point>; see linkgit:git-branch[1] for details.
|
||||
|
||||
-t::
|
||||
--track::
|
||||
When creating a new branch, set up configuration so that 'git-pull'
|
||||
will automatically retrieve data from the start point, which must be
|
||||
a branch. Use this if you always pull from the same upstream branch
|
||||
into the new branch, and if you don't want to use "git pull
|
||||
<repository> <refspec>" explicitly. This behavior is the default
|
||||
when the start point is a remote branch. Set the
|
||||
branch.autosetupmerge configuration variable to `false` if you want
|
||||
'git checkout' and 'git branch' to always behave as if '--no-track' were
|
||||
given. Set it to `always` if you want this behavior when the
|
||||
start point is either a local or remote branch.
|
||||
When creating a new branch, set up "upstream" configuration. See
|
||||
"--track" in linkgit:git-branch[1] for details.
|
||||
+
|
||||
If no '-b' option is given, the name of the new branch will be
|
||||
derived from the remote branch. If "remotes/" or "refs/remotes/"
|
||||
@@ -90,12 +80,12 @@ guessing results in an empty name, the guessing is aborted. You can
|
||||
explicitly give a name with '-b' in such a case.
|
||||
|
||||
--no-track::
|
||||
Ignore the branch.autosetupmerge configuration variable.
|
||||
Do not set up "upstream" configuration, even if the
|
||||
branch.autosetupmerge configuration variable is true.
|
||||
|
||||
-l::
|
||||
Create the new branch's reflog. This activates recording of
|
||||
all changes made to the branch ref, enabling use of date
|
||||
based sha1 expressions such as "<branchname>@\{yesterday}".
|
||||
Create the new branch's reflog; see linkgit:git-branch[1] for
|
||||
details.
|
||||
|
||||
-m::
|
||||
--merge::
|
||||
@@ -123,23 +113,28 @@ the conflicted merge in the specified paths.
|
||||
"merge" (default) and "diff3" (in addition to what is shown by
|
||||
"merge" style, shows the original contents).
|
||||
|
||||
<branch>::
|
||||
Branch to checkout; if it refers to a branch (i.e., a name that,
|
||||
when prepended with "refs/heads/", is a valid ref), then that
|
||||
branch is checked out. Otherwise, if it refers to a valid
|
||||
commit, your HEAD becomes "detached" and you are no longer on
|
||||
any branch (see below for details).
|
||||
+
|
||||
As a special case, the `"@\{-N\}"` syntax for the N-th last branch
|
||||
checks out the branch (instead of detaching). You may also specify
|
||||
`-` which is synonymous with `"@\{-1\}"`.
|
||||
|
||||
<new_branch>::
|
||||
Name for the new branch.
|
||||
|
||||
<start_point>::
|
||||
The name of a commit at which to start the new branch; see
|
||||
linkgit:git-branch[1] for details. Defaults to HEAD.
|
||||
|
||||
<tree-ish>::
|
||||
Tree to checkout from (when paths are given). If not specified,
|
||||
the index will be used.
|
||||
|
||||
<branch>::
|
||||
Branch to checkout (when no paths are given); may be any object
|
||||
ID that resolves to a commit. Defaults to HEAD.
|
||||
+
|
||||
When this parameter names a non-branch (but still a valid commit object),
|
||||
your HEAD becomes 'detached'.
|
||||
+
|
||||
As a special case, the `"@\{-N\}"` syntax for the N-th last branch
|
||||
checks out the branch (instead of detaching). You may also specify
|
||||
`-` which is synonymous with `"@\{-1\}"`.
|
||||
|
||||
|
||||
Detached HEAD
|
||||
|
||||
@@ -48,7 +48,7 @@ OPTIONS
|
||||
'git-daemon' will refuse to start when this option is enabled and no
|
||||
whitelist is specified.
|
||||
|
||||
--base-path::
|
||||
--base-path=path::
|
||||
Remap all the path requests as relative to the given path.
|
||||
This is sort of "GIT root" - if you run 'git-daemon' with
|
||||
'--base-path=/srv/git' on example.com, then if you later try to pull
|
||||
@@ -81,8 +81,8 @@ OPTIONS
|
||||
Incompatible with --port, --listen, --user and --group options.
|
||||
|
||||
--listen=host_or_ipaddr::
|
||||
Listen on an a specific IP address or hostname. IP addresses can
|
||||
be either an IPv4 address or an IPV6 address if supported. If IPv6
|
||||
Listen on a specific IP address or hostname. IP addresses can
|
||||
be either an IPv4 address or an IPv6 address if supported. If IPv6
|
||||
is not supported, then --listen=hostname is also not supported and
|
||||
--listen must be given an IPv4 address.
|
||||
Incompatible with '--inetd' option.
|
||||
@@ -90,17 +90,17 @@ OPTIONS
|
||||
--port=n::
|
||||
Listen on an alternative port. Incompatible with '--inetd' option.
|
||||
|
||||
--init-timeout::
|
||||
--init-timeout=n::
|
||||
Timeout between the moment the connection is established and the
|
||||
client request is received (typically a rather low value, since
|
||||
that should be basically immediate).
|
||||
|
||||
--timeout::
|
||||
--timeout=n::
|
||||
Timeout for specific client sub-requests. This includes the time
|
||||
it takes for the server to process the sub-request and time spent
|
||||
waiting for next client's request.
|
||||
it takes for the server to process the sub-request and the time spent
|
||||
waiting for the next client's request.
|
||||
|
||||
--max-connections::
|
||||
--max-connections=n::
|
||||
Maximum number of concurrent clients, defaults to 32. Set it to
|
||||
zero for no limit.
|
||||
|
||||
@@ -150,7 +150,7 @@ the facility of inet daemon to achieve the same before spawning
|
||||
Enable/disable the service site-wide per default. Note
|
||||
that a service disabled site-wide can still be enabled
|
||||
per repository if it is marked overridable and the
|
||||
repository enables the service with an configuration
|
||||
repository enables the service with a configuration
|
||||
item.
|
||||
|
||||
--allow-override=service::
|
||||
|
||||
@@ -3,35 +3,37 @@ git-difftool(1)
|
||||
|
||||
NAME
|
||||
----
|
||||
git-difftool - compare changes using common merge tools
|
||||
git-difftool - Show changes using common diff tools
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git difftool' [--tool=<tool>] [--no-prompt] ['git diff' options]
|
||||
'git difftool' [--tool=<tool>] [-y|--no-prompt|--prompt] [<'git diff' options>]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
'git-difftool' is a git command that allows you to compare and edit files
|
||||
between revisions using common merge tools. At its most basic level,
|
||||
'git-difftool' does what 'git-mergetool' does but its use is for non-merge
|
||||
situations such as when preparing commits or comparing changes against
|
||||
the index.
|
||||
|
||||
'git difftool' is a frontend to 'git diff' and accepts the same
|
||||
arguments and options.
|
||||
|
||||
See linkgit:git-diff[1] for the full list of supported options.
|
||||
between revisions using common diff tools. 'git difftool' is a frontend
|
||||
to 'git-diff' and accepts the same options and arguments.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
-y::
|
||||
--no-prompt::
|
||||
Do not prompt before launching a diff tool.
|
||||
|
||||
--prompt::
|
||||
Prompt before each invocation of the diff tool.
|
||||
This is the default behaviour; the option is provided to
|
||||
override any configuration settings.
|
||||
|
||||
-t <tool>::
|
||||
--tool=<tool>::
|
||||
Use the merge resolution program specified by <tool>.
|
||||
Use the diff tool specified by <tool>.
|
||||
Valid merge tools are:
|
||||
kdiff3, kompare, tkdiff, meld, xxdiff, emerge,
|
||||
vimdiff, gvimdiff, ecmerge, and opendiff
|
||||
kdiff3, kompare, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff,
|
||||
ecmerge, diffuse and opendiff
|
||||
+
|
||||
If a merge resolution program is not specified, 'git-difftool'
|
||||
If a diff tool is not specified, 'git-difftool'
|
||||
will use the configuration variable `diff.tool`. If the
|
||||
configuration variable `diff.tool` is not set, 'git-difftool'
|
||||
will pick a suitable default.
|
||||
@@ -42,7 +44,7 @@ can configure the absolute path to kdiff3 by setting
|
||||
`difftool.kdiff3.path`. Otherwise, 'git-difftool' assumes the
|
||||
tool is available in PATH.
|
||||
+
|
||||
Instead of running one of the known merge tool programs,
|
||||
Instead of running one of the known diff tools,
|
||||
'git-difftool' can be customized to run an alternative program
|
||||
by specifying the command line to invoke in a configuration
|
||||
variable `difftool.<tool>.cmd`.
|
||||
@@ -56,8 +58,7 @@ is set to the name of the temporary file containing the contents
|
||||
of the diff post-image. `$BASE` is provided for compatibility
|
||||
with custom merge tool commands and has the same value as `$LOCAL`.
|
||||
|
||||
--no-prompt::
|
||||
Do not prompt before launching a diff tool.
|
||||
See linkgit:git-diff[1] for the full list of supported options.
|
||||
|
||||
CONFIG VARIABLES
|
||||
----------------
|
||||
@@ -65,20 +66,19 @@ CONFIG VARIABLES
|
||||
difftool equivalents have not been defined.
|
||||
|
||||
diff.tool::
|
||||
The default merge tool to use.
|
||||
The default diff tool to use.
|
||||
|
||||
difftool.<tool>.path::
|
||||
Override the path for the given tool. This is useful in case
|
||||
your tool is not in the PATH.
|
||||
|
||||
difftool.<tool>.cmd::
|
||||
Specify the command to invoke the specified merge tool.
|
||||
Specify the command to invoke the specified diff tool.
|
||||
+
|
||||
See the `--tool=<tool>` option above for more details.
|
||||
|
||||
merge.keepBackup::
|
||||
The original, unedited file content can be saved to a file with
|
||||
a `.orig` extension. Defaults to `true` (i.e. keep the backup files).
|
||||
difftool.prompt::
|
||||
Prompt before each invocation of the diff tool.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
@@ -75,6 +75,8 @@ For all objects, the following names can be used:
|
||||
refname::
|
||||
The name of the ref (the part after $GIT_DIR/).
|
||||
For a non-ambiguous short name of the ref append `:short`.
|
||||
The option core.warnAmbiguousRefs is used to select the strict
|
||||
abbreviation mode.
|
||||
|
||||
objecttype::
|
||||
The type of the object (`blob`, `tree`, `commit`, `tag`).
|
||||
|
||||
@@ -51,7 +51,7 @@ imap.host::
|
||||
imap.user::
|
||||
The username to use when logging in to the server.
|
||||
|
||||
imap.password::
|
||||
imap.pass::
|
||||
The password to use when logging in to the server.
|
||||
|
||||
imap.port::
|
||||
|
||||
54
Documentation/git-mergetool--lib.txt
Normal file
54
Documentation/git-mergetool--lib.txt
Normal file
@@ -0,0 +1,54 @@
|
||||
git-mergetool--lib(1)
|
||||
=====================
|
||||
|
||||
NAME
|
||||
----
|
||||
git-mergetool--lib - Common git merge tool shell scriptlets
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'TOOL_MODE=(diff|merge) . "$(git --exec-path)/git-mergetool--lib"'
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
This is not a command the end user would want to run. Ever.
|
||||
This documentation is meant for people who are studying the
|
||||
Porcelain-ish scripts and/or are writing new ones.
|
||||
|
||||
The 'git-mergetool--lib' scriptlet is designed to be sourced (using
|
||||
`.`) by other shell scripts to set up functions for working
|
||||
with git merge tools.
|
||||
|
||||
Before sourcing 'git-mergetool--lib', your script must set `TOOL_MODE`
|
||||
to define the operation mode for the functions listed below.
|
||||
'diff' and 'merge' are valid values.
|
||||
|
||||
FUNCTIONS
|
||||
---------
|
||||
get_merge_tool::
|
||||
returns a merge tool.
|
||||
|
||||
get_merge_tool_cmd::
|
||||
returns the custom command for a merge tool.
|
||||
|
||||
get_merge_tool_path::
|
||||
returns the custom path for a merge tool.
|
||||
|
||||
run_merge_tool::
|
||||
launches a merge tool given the tool name and a true/false
|
||||
flag to indicate whether a merge base is present.
|
||||
'$MERGED', '$LOCAL', '$REMOTE', and '$BASE' must be defined
|
||||
for use by the merge tool.
|
||||
|
||||
Author
|
||||
------
|
||||
Written by David Aguilar <davvid@gmail.com>
|
||||
|
||||
Documentation
|
||||
--------------
|
||||
Documentation by David Aguilar and the git-list <git@vger.kernel.org>.
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the linkgit:git[1] suite
|
||||
@@ -26,7 +26,8 @@ OPTIONS
|
||||
--tool=<tool>::
|
||||
Use the merge resolution program specified by <tool>.
|
||||
Valid merge tools are:
|
||||
kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, and opendiff
|
||||
kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge,
|
||||
diffuse, tortoisemerge and opendiff
|
||||
+
|
||||
If a merge resolution program is not specified, 'git-mergetool'
|
||||
will use the configuration variable `merge.tool`. If the
|
||||
|
||||
@@ -84,6 +84,11 @@ OPTIONS
|
||||
unfortunately named tag "master"), and show them as full
|
||||
refnames (e.g. "refs/heads/master").
|
||||
|
||||
--abbrev-ref[={strict|loose}]::
|
||||
A non-ambiguous short name of the objects name.
|
||||
The option core.warnAmbiguousRefs is used to select the strict
|
||||
abbreviation mode.
|
||||
|
||||
--all::
|
||||
Show all refs found in `$GIT_DIR/refs`.
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@ of server-side GIT commands implementing the pull/push functionality.
|
||||
The commands can be executed only by the '-c' option; the shell is not
|
||||
interactive.
|
||||
|
||||
Currently, only three commands are permitted to be called, 'git-receive-pack'
|
||||
'git-upload-pack' with a single required argument or 'cvs server' (to invoke
|
||||
'git-cvsserver').
|
||||
Currently, only four commands are permitted to be called, 'git-receive-pack'
|
||||
'git-upload-pack' and 'git-upload-archive' with a single required argument, or
|
||||
'cvs server' (to invoke 'git-cvsserver').
|
||||
|
||||
Author
|
||||
------
|
||||
|
||||
@@ -297,7 +297,8 @@ for paths.
|
||||
|
||||
Then, you would define a "diff.tex.xfuncname" configuration to
|
||||
specify a regular expression that matches a line that you would
|
||||
want to appear as the hunk header "TEXT", like this:
|
||||
want to appear as the hunk header "TEXT". Add a section to your
|
||||
`$GIT_DIR/config` file (or `$HOME/.gitconfig` file) like this:
|
||||
|
||||
------------------------
|
||||
[diff "tex"]
|
||||
@@ -345,7 +346,8 @@ split words in a line, by specifying an appropriate regular expression
|
||||
in the "diff.*.wordRegex" configuration variable. For example, in TeX
|
||||
a backslash followed by a sequence of letters forms a command, but
|
||||
several such commands can be run together without intervening
|
||||
whitespace. To separate them, use a regular expression such as
|
||||
whitespace. To separate them, use a regular expression in your
|
||||
`$GIT_DIR/config` file (or `$HOME/.gitconfig` file) like this:
|
||||
|
||||
------------------------
|
||||
[diff "tex"]
|
||||
@@ -373,7 +375,8 @@ resulting text on stdout.
|
||||
|
||||
For example, to show the diff of the exif information of a
|
||||
file instead of the binary information (assuming you have the
|
||||
exif tool installed):
|
||||
exif tool installed), add the following section to your
|
||||
`$GIT_DIR/config` file (or `$HOME/.gitconfig` file):
|
||||
|
||||
------------------------
|
||||
[diff "jpg"]
|
||||
|
||||
@@ -22,7 +22,8 @@ merge.stat::
|
||||
merge.tool::
|
||||
Controls which merge resolution program is used by
|
||||
linkgit:git-mergetool[1]. Valid built-in values are: "kdiff3",
|
||||
"tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", and
|
||||
"tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff",
|
||||
"diffuse", "ecmerge", "tortoisemerge", and
|
||||
"opendiff". Any other value is treated is custom merge tool
|
||||
and there must be a corresponding mergetool.<tool>.cmd option.
|
||||
|
||||
|
||||
3
Makefile
3
Makefile
@@ -280,12 +280,14 @@ TEST_PROGRAMS =
|
||||
|
||||
SCRIPT_SH += git-am.sh
|
||||
SCRIPT_SH += git-bisect.sh
|
||||
SCRIPT_SH += git-difftool--helper.sh
|
||||
SCRIPT_SH += git-filter-branch.sh
|
||||
SCRIPT_SH += git-lost-found.sh
|
||||
SCRIPT_SH += git-merge-octopus.sh
|
||||
SCRIPT_SH += git-merge-one-file.sh
|
||||
SCRIPT_SH += git-merge-resolve.sh
|
||||
SCRIPT_SH += git-mergetool.sh
|
||||
SCRIPT_SH += git-mergetool--lib.sh
|
||||
SCRIPT_SH += git-parse-remote.sh
|
||||
SCRIPT_SH += git-pull.sh
|
||||
SCRIPT_SH += git-quiltimport.sh
|
||||
@@ -299,6 +301,7 @@ SCRIPT_SH += git-submodule.sh
|
||||
SCRIPT_SH += git-web--browse.sh
|
||||
|
||||
SCRIPT_PERL += git-add--interactive.perl
|
||||
SCRIPT_PERL += git-difftool.perl
|
||||
SCRIPT_PERL += git-archimport.perl
|
||||
SCRIPT_PERL += git-cvsexportcommit.perl
|
||||
SCRIPT_PERL += git-cvsimport.perl
|
||||
|
||||
23
archive.c
23
archive.c
@@ -4,6 +4,7 @@
|
||||
#include "attr.h"
|
||||
#include "archive.h"
|
||||
#include "parse-options.h"
|
||||
#include "unpack-trees.h"
|
||||
|
||||
static char const * const archive_usage[] = {
|
||||
"git archive [options] <tree-ish> [path...]",
|
||||
@@ -150,6 +151,8 @@ int write_archive_entries(struct archiver_args *args,
|
||||
write_archive_entry_fn_t write_entry)
|
||||
{
|
||||
struct archiver_context context;
|
||||
struct unpack_trees_options opts;
|
||||
struct tree_desc t;
|
||||
int err;
|
||||
|
||||
if (args->baselen > 0 && args->base[args->baselen - 1] == '/') {
|
||||
@@ -168,6 +171,22 @@ int write_archive_entries(struct archiver_args *args,
|
||||
context.args = args;
|
||||
context.write_entry = write_entry;
|
||||
|
||||
/*
|
||||
* Setup index and instruct attr to read index only
|
||||
*/
|
||||
if (!args->worktree_attributes) {
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
opts.index_only = 1;
|
||||
opts.head_idx = -1;
|
||||
opts.src_index = &the_index;
|
||||
opts.dst_index = &the_index;
|
||||
opts.fn = oneway_merge;
|
||||
init_tree_desc(&t, args->tree->buffer, args->tree->size);
|
||||
if (unpack_trees(1, &t, &opts))
|
||||
return -1;
|
||||
git_attr_set_direction(GIT_ATTR_INDEX, &the_index);
|
||||
}
|
||||
|
||||
err = read_tree_recursive(args->tree, args->base, args->baselen, 0,
|
||||
args->pathspec, write_archive_entry, &context);
|
||||
if (err == READ_TREE_RECURSIVE)
|
||||
@@ -258,6 +277,7 @@ static int parse_archive_args(int argc, const char **argv,
|
||||
int verbose = 0;
|
||||
int i;
|
||||
int list = 0;
|
||||
int worktree_attributes = 0;
|
||||
struct option opts[] = {
|
||||
OPT_GROUP(""),
|
||||
OPT_STRING(0, "format", &format, "fmt", "archive format"),
|
||||
@@ -265,6 +285,8 @@ static int parse_archive_args(int argc, const char **argv,
|
||||
"prepend prefix to each pathname in the archive"),
|
||||
OPT_STRING(0, "output", &output, "file",
|
||||
"write the archive to this file"),
|
||||
OPT_BOOLEAN(0, "worktree-attributes", &worktree_attributes,
|
||||
"read .gitattributes in working directory"),
|
||||
OPT__VERBOSE(&verbose),
|
||||
OPT__COMPR('0', &compression_level, "store only", 0),
|
||||
OPT__COMPR('1', &compression_level, "compress faster", 1),
|
||||
@@ -324,6 +346,7 @@ static int parse_archive_args(int argc, const char **argv,
|
||||
args->verbose = verbose;
|
||||
args->base = base;
|
||||
args->baselen = strlen(base);
|
||||
args->worktree_attributes = worktree_attributes;
|
||||
|
||||
return argc;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ struct archiver_args {
|
||||
time_t time;
|
||||
const char **pathspec;
|
||||
unsigned int verbose : 1;
|
||||
unsigned int worktree_attributes : 1;
|
||||
int compression_level;
|
||||
};
|
||||
|
||||
|
||||
12
attr.c
12
attr.c
@@ -405,7 +405,7 @@ static struct attr_stack *read_attr(const char *path, int macro_ok)
|
||||
if (!res)
|
||||
res = read_attr_from_file(path, macro_ok);
|
||||
}
|
||||
else {
|
||||
else if (direction == GIT_ATTR_CHECKIN) {
|
||||
res = read_attr_from_file(path, macro_ok);
|
||||
if (!res)
|
||||
/*
|
||||
@@ -415,6 +415,8 @@ static struct attr_stack *read_attr(const char *path, int macro_ok)
|
||||
*/
|
||||
res = read_attr_from_index(path, macro_ok);
|
||||
}
|
||||
else
|
||||
res = read_attr_from_index(path, macro_ok);
|
||||
if (!res)
|
||||
res = xcalloc(1, sizeof(*res));
|
||||
return res;
|
||||
@@ -466,7 +468,7 @@ static void bootstrap_attr_stack(void)
|
||||
elem->prev = attr_stack;
|
||||
attr_stack = elem;
|
||||
|
||||
if (!is_bare_repository()) {
|
||||
if (!is_bare_repository() || direction == GIT_ATTR_INDEX) {
|
||||
elem = read_attr(GITATTRIBUTES_FILE, 1);
|
||||
elem->origin = strdup("");
|
||||
elem->prev = attr_stack;
|
||||
@@ -533,7 +535,7 @@ static void prepare_attr_stack(const char *path, int dirlen)
|
||||
/*
|
||||
* Read from parent directories and push them down
|
||||
*/
|
||||
if (!is_bare_repository()) {
|
||||
if (!is_bare_repository() || direction == GIT_ATTR_INDEX) {
|
||||
while (1) {
|
||||
char *cp;
|
||||
|
||||
@@ -674,6 +676,10 @@ int git_checkattr(const char *path, int num, struct git_attr_check *check)
|
||||
void git_attr_set_direction(enum git_attr_direction new, struct index_state *istate)
|
||||
{
|
||||
enum git_attr_direction old = direction;
|
||||
|
||||
if (is_bare_repository() && new != GIT_ATTR_INDEX)
|
||||
die("BUG: non-INDEX attr direction in a bare repo");
|
||||
|
||||
direction = new;
|
||||
if (new != old)
|
||||
drop_attr_stack();
|
||||
|
||||
3
attr.h
3
attr.h
@@ -33,7 +33,8 @@ int git_checkattr(const char *path, int, struct git_attr_check *);
|
||||
|
||||
enum git_attr_direction {
|
||||
GIT_ATTR_CHECKIN,
|
||||
GIT_ATTR_CHECKOUT
|
||||
GIT_ATTR_CHECKOUT,
|
||||
GIT_ATTR_INDEX,
|
||||
};
|
||||
void git_attr_set_direction(enum git_attr_direction, struct index_state *);
|
||||
|
||||
|
||||
@@ -2271,6 +2271,25 @@ static struct patch *in_fn_table(const char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* item->util in the filename table records the status of the path.
|
||||
* Usually it points at a patch (whose result records the contents
|
||||
* of it after applying it), but it could be PATH_WAS_DELETED for a
|
||||
* path that a previously applied patch has already removed.
|
||||
*/
|
||||
#define PATH_TO_BE_DELETED ((struct patch *) -2)
|
||||
#define PATH_WAS_DELETED ((struct patch *) -1)
|
||||
|
||||
static int to_be_deleted(struct patch *patch)
|
||||
{
|
||||
return patch == PATH_TO_BE_DELETED;
|
||||
}
|
||||
|
||||
static int was_deleted(struct patch *patch)
|
||||
{
|
||||
return patch == PATH_WAS_DELETED;
|
||||
}
|
||||
|
||||
static void add_to_fn_table(struct patch *patch)
|
||||
{
|
||||
struct string_list_item *item;
|
||||
@@ -2291,7 +2310,22 @@ static void add_to_fn_table(struct patch *patch)
|
||||
*/
|
||||
if ((patch->new_name == NULL) || (patch->is_rename)) {
|
||||
item = string_list_insert(patch->old_name, &fn_table);
|
||||
item->util = (struct patch *) -1;
|
||||
item->util = PATH_WAS_DELETED;
|
||||
}
|
||||
}
|
||||
|
||||
static void prepare_fn_table(struct patch *patch)
|
||||
{
|
||||
/*
|
||||
* store information about incoming file deletion
|
||||
*/
|
||||
while (patch) {
|
||||
if ((patch->new_name == NULL) || (patch->is_rename)) {
|
||||
struct string_list_item *item;
|
||||
item = string_list_insert(patch->old_name, &fn_table);
|
||||
item->util = PATH_TO_BE_DELETED;
|
||||
}
|
||||
patch = patch->next;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2304,8 +2338,8 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
|
||||
struct patch *tpatch;
|
||||
|
||||
if (!(patch->is_copy || patch->is_rename) &&
|
||||
((tpatch = in_fn_table(patch->old_name)) != NULL)) {
|
||||
if (tpatch == (struct patch *) -1) {
|
||||
(tpatch = in_fn_table(patch->old_name)) != NULL && !to_be_deleted(tpatch)) {
|
||||
if (was_deleted(tpatch)) {
|
||||
return error("patch %s has been renamed/deleted",
|
||||
patch->old_name);
|
||||
}
|
||||
@@ -2399,10 +2433,9 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
|
||||
assert(patch->is_new <= 0);
|
||||
|
||||
if (!(patch->is_copy || patch->is_rename) &&
|
||||
(tpatch = in_fn_table(old_name)) != NULL) {
|
||||
if (tpatch == (struct patch *) -1) {
|
||||
(tpatch = in_fn_table(old_name)) != NULL && !to_be_deleted(tpatch)) {
|
||||
if (was_deleted(tpatch))
|
||||
return error("%s: has been deleted/renamed", old_name);
|
||||
}
|
||||
st_mode = tpatch->new_mode;
|
||||
} else if (!cached) {
|
||||
stat_ret = lstat(old_name, st);
|
||||
@@ -2410,6 +2443,9 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
|
||||
return error("%s: %s", old_name, strerror(errno));
|
||||
}
|
||||
|
||||
if (to_be_deleted(tpatch))
|
||||
tpatch = NULL;
|
||||
|
||||
if (check_index && !tpatch) {
|
||||
int pos = cache_name_pos(old_name, strlen(old_name));
|
||||
if (pos < 0) {
|
||||
@@ -2471,6 +2507,7 @@ static int check_patch(struct patch *patch)
|
||||
const char *new_name = patch->new_name;
|
||||
const char *name = old_name ? old_name : new_name;
|
||||
struct cache_entry *ce = NULL;
|
||||
struct patch *tpatch;
|
||||
int ok_if_exists;
|
||||
int status;
|
||||
|
||||
@@ -2481,7 +2518,8 @@ static int check_patch(struct patch *patch)
|
||||
return status;
|
||||
old_name = patch->old_name;
|
||||
|
||||
if (in_fn_table(new_name) == (struct patch *) -1)
|
||||
if ((tpatch = in_fn_table(new_name)) &&
|
||||
(was_deleted(tpatch) || to_be_deleted(tpatch)))
|
||||
/*
|
||||
* A type-change diff is always split into a patch to
|
||||
* delete old, immediately followed by a patch to
|
||||
@@ -2533,6 +2571,7 @@ static int check_patch_list(struct patch *patch)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
prepare_fn_table(patch);
|
||||
while (patch) {
|
||||
if (apply_verbosely)
|
||||
say_patch_name(stderr,
|
||||
|
||||
@@ -311,14 +311,14 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
|
||||
if (branch && branch->merge && branch->merge[0]->dst &&
|
||||
show_upstream_ref)
|
||||
strbuf_addf(stat, "[%s] ",
|
||||
shorten_unambiguous_ref(branch->merge[0]->dst));
|
||||
shorten_unambiguous_ref(branch->merge[0]->dst, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
strbuf_addch(stat, '[');
|
||||
if (show_upstream_ref)
|
||||
strbuf_addf(stat, "%s: ",
|
||||
shorten_unambiguous_ref(branch->merge[0]->dst));
|
||||
shorten_unambiguous_ref(branch->merge[0]->dst, 0));
|
||||
if (!ours)
|
||||
strbuf_addf(stat, "behind %d] ", theirs);
|
||||
else if (!theirs)
|
||||
|
||||
@@ -601,7 +601,8 @@ static void populate_value(struct refinfo *ref)
|
||||
if (formatp) {
|
||||
formatp++;
|
||||
if (!strcmp(formatp, "short"))
|
||||
refname = shorten_unambiguous_ref(refname);
|
||||
refname = shorten_unambiguous_ref(refname,
|
||||
warn_ambiguous_refs);
|
||||
else
|
||||
die("unknown %.*s format %s",
|
||||
(int)(formatp - name), name, formatp);
|
||||
@@ -917,6 +918,9 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
|
||||
sort = default_sort();
|
||||
sort_atom_limit = used_atom_cnt;
|
||||
|
||||
/* for warn_ambiguous_refs */
|
||||
git_config(git_default_config, NULL);
|
||||
|
||||
memset(&cbdata, 0, sizeof(cbdata));
|
||||
cbdata.grab_pattern = argv;
|
||||
for_each_ref(grab_single_ref, &cbdata);
|
||||
|
||||
@@ -122,8 +122,10 @@ static void copy_templates(const char *template_dir)
|
||||
template_dir = system_path(DEFAULT_GIT_TEMPLATE_DIR);
|
||||
if (!template_dir[0])
|
||||
return;
|
||||
template_len = strlen(template_dir);
|
||||
if (PATH_MAX <= (template_len+strlen("/config")))
|
||||
die("insanely long template path %s", template_dir);
|
||||
strcpy(template_path, template_dir);
|
||||
template_len = strlen(template_path);
|
||||
if (template_path[template_len-1] != '/') {
|
||||
template_path[template_len++] = '/';
|
||||
template_path[template_len] = 0;
|
||||
|
||||
@@ -1907,13 +1907,19 @@ static void show_commit(struct commit *commit, void *data)
|
||||
commit->object.flags |= OBJECT_ADDED;
|
||||
}
|
||||
|
||||
static void show_object(struct object_array_entry *p, void *data)
|
||||
static void show_object(struct object *obj, const struct name_path *path, const char *last)
|
||||
{
|
||||
add_preferred_base_object(p->name);
|
||||
add_object_entry(p->item->sha1, p->item->type, p->name, 0);
|
||||
p->item->flags |= OBJECT_ADDED;
|
||||
free((char *)p->name);
|
||||
p->name = NULL;
|
||||
char *name = path_name(path, last);
|
||||
|
||||
add_preferred_base_object(name);
|
||||
add_object_entry(obj->sha1, obj->type, name, 0);
|
||||
obj->flags |= OBJECT_ADDED;
|
||||
|
||||
/*
|
||||
* We will have generated the hash from the name,
|
||||
* but not saved a pointer to it - we can free it
|
||||
*/
|
||||
free((char *)name);
|
||||
}
|
||||
|
||||
static void show_edge(struct commit *commit)
|
||||
|
||||
@@ -156,27 +156,29 @@ static void finish_commit(struct commit *commit, void *data)
|
||||
commit->buffer = NULL;
|
||||
}
|
||||
|
||||
static void finish_object(struct object_array_entry *p, void *data)
|
||||
static void finish_object(struct object *obj, const struct name_path *path, const char *name)
|
||||
{
|
||||
if (p->item->type == OBJ_BLOB && !has_sha1_file(p->item->sha1))
|
||||
die("missing blob object '%s'", sha1_to_hex(p->item->sha1));
|
||||
if (obj->type == OBJ_BLOB && !has_sha1_file(obj->sha1))
|
||||
die("missing blob object '%s'", sha1_to_hex(obj->sha1));
|
||||
}
|
||||
|
||||
static void show_object(struct object_array_entry *p, void *data)
|
||||
static void show_object(struct object *obj, const struct name_path *path, const char *component)
|
||||
{
|
||||
char *name = path_name(path, component);
|
||||
/* An object with name "foo\n0000000..." can be used to
|
||||
* confuse downstream "git pack-objects" very badly.
|
||||
*/
|
||||
const char *ep = strchr(p->name, '\n');
|
||||
const char *ep = strchr(name, '\n');
|
||||
|
||||
finish_object(p, data);
|
||||
finish_object(obj, path, name);
|
||||
if (ep) {
|
||||
printf("%s %.*s\n", sha1_to_hex(p->item->sha1),
|
||||
(int) (ep - p->name),
|
||||
p->name);
|
||||
printf("%s %.*s\n", sha1_to_hex(obj->sha1),
|
||||
(int) (ep - name),
|
||||
name);
|
||||
}
|
||||
else
|
||||
printf("%s %s\n", sha1_to_hex(p->item->sha1), p->name);
|
||||
printf("%s %s\n", sha1_to_hex(obj->sha1), name);
|
||||
free(name);
|
||||
}
|
||||
|
||||
static void show_edge(struct commit *commit)
|
||||
|
||||
@@ -26,6 +26,8 @@ static int show_type = NORMAL;
|
||||
#define SHOW_SYMBOLIC_FULL 2
|
||||
static int symbolic;
|
||||
static int abbrev;
|
||||
static int abbrev_ref;
|
||||
static int abbrev_ref_strict;
|
||||
static int output_sq;
|
||||
|
||||
/*
|
||||
@@ -109,8 +111,8 @@ static void show_rev(int type, const unsigned char *sha1, const char *name)
|
||||
return;
|
||||
def = NULL;
|
||||
|
||||
if (symbolic && name) {
|
||||
if (symbolic == SHOW_SYMBOLIC_FULL) {
|
||||
if ((symbolic || abbrev_ref) && name) {
|
||||
if (symbolic == SHOW_SYMBOLIC_FULL || abbrev_ref) {
|
||||
unsigned char discard[20];
|
||||
char *full;
|
||||
|
||||
@@ -125,6 +127,9 @@ static void show_rev(int type, const unsigned char *sha1, const char *name)
|
||||
*/
|
||||
break;
|
||||
case 1: /* happy */
|
||||
if (abbrev_ref)
|
||||
full = shorten_unambiguous_ref(full,
|
||||
abbrev_ref_strict);
|
||||
show_with_type(type, full);
|
||||
break;
|
||||
default: /* ambiguous */
|
||||
@@ -506,6 +511,20 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
||||
symbolic = SHOW_SYMBOLIC_FULL;
|
||||
continue;
|
||||
}
|
||||
if (!prefixcmp(arg, "--abbrev-ref") &&
|
||||
(!arg[12] || arg[12] == '=')) {
|
||||
abbrev_ref = 1;
|
||||
abbrev_ref_strict = warn_ambiguous_refs;
|
||||
if (arg[12] == '=') {
|
||||
if (!strcmp(arg + 13, "strict"))
|
||||
abbrev_ref_strict = 1;
|
||||
else if (!strcmp(arg + 13, "loose"))
|
||||
abbrev_ref_strict = 0;
|
||||
else
|
||||
die("unknown mode for %s", arg);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--all")) {
|
||||
for_each_ref(show_reference, NULL);
|
||||
continue;
|
||||
|
||||
@@ -24,7 +24,7 @@ int cmd_tar_tree(int argc, const char **argv, const char *prefix)
|
||||
* git archive --format-tar --prefix=basedir tree-ish
|
||||
*/
|
||||
int i;
|
||||
const char **nargv = xcalloc(sizeof(*nargv), argc + 2);
|
||||
const char **nargv = xcalloc(sizeof(*nargv), argc + 3);
|
||||
char *basedir_arg;
|
||||
int nargc = 0;
|
||||
|
||||
@@ -36,6 +36,13 @@ int cmd_tar_tree(int argc, const char **argv, const char *prefix)
|
||||
argv++;
|
||||
argc--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Because it's just a compatibility wrapper, tar-tree supports only
|
||||
* the old behaviour of reading attributes from the work tree.
|
||||
*/
|
||||
nargv[nargc++] = "--worktree-attributes";
|
||||
|
||||
switch (argc) {
|
||||
default:
|
||||
usage(tar_tree_usage);
|
||||
|
||||
1
color.h
1
color.h
@@ -11,6 +11,7 @@
|
||||
#define GIT_COLOR_GREEN "\033[32m"
|
||||
#define GIT_COLOR_YELLOW "\033[33m"
|
||||
#define GIT_COLOR_BLUE "\033[34m"
|
||||
#define GIT_COLOR_MAGENTA "\033[35m"
|
||||
#define GIT_COLOR_CYAN "\033[36m"
|
||||
#define GIT_COLOR_BG_RED "\033[41m"
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ git-diff mainporcelain common
|
||||
git-diff-files plumbinginterrogators
|
||||
git-diff-index plumbinginterrogators
|
||||
git-diff-tree plumbinginterrogators
|
||||
git-difftool ancillaryinterrogators
|
||||
git-fast-export ancillarymanipulators
|
||||
git-fast-import ancillarymanipulators
|
||||
git-fetch mainporcelain common
|
||||
|
||||
6
config.c
6
config.c
@@ -51,7 +51,7 @@ static char *parse_value(void)
|
||||
|
||||
for (;;) {
|
||||
int c = get_next_char();
|
||||
if (len >= sizeof(value))
|
||||
if (len >= sizeof(value) - 1)
|
||||
return NULL;
|
||||
if (c == '\n') {
|
||||
if (quote)
|
||||
@@ -331,9 +331,9 @@ int git_config_bool_or_int(const char *name, const char *value, int *is_bool)
|
||||
return 1;
|
||||
if (!*value)
|
||||
return 0;
|
||||
if (!strcasecmp(value, "true") || !strcasecmp(value, "yes"))
|
||||
if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on"))
|
||||
return 1;
|
||||
if (!strcasecmp(value, "false") || !strcasecmp(value, "no"))
|
||||
if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off"))
|
||||
return 0;
|
||||
*is_bool = 0;
|
||||
return git_config_int(name, value);
|
||||
|
||||
@@ -910,6 +910,26 @@ _git_diff ()
|
||||
__git_complete_file
|
||||
}
|
||||
|
||||
__git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff
|
||||
tkdiff vimdiff gvimdiff xxdiff
|
||||
"
|
||||
|
||||
_git_difftool ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
case "$cur" in
|
||||
--tool=*)
|
||||
__gitcomp "$__git_mergetools_common kompare" "" "${cur##--tool=}"
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
__gitcomp "--tool="
|
||||
return
|
||||
;;
|
||||
esac
|
||||
COMPREPLY=()
|
||||
}
|
||||
|
||||
__git_fetch_options="
|
||||
--quiet --verbose --append --upload-pack --force --keep --depth=
|
||||
--tags --no-tags
|
||||
@@ -1172,10 +1192,7 @@ _git_mergetool ()
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
case "$cur" in
|
||||
--tool=*)
|
||||
__gitcomp "
|
||||
kdiff3 tkdiff meld xxdiff emerge
|
||||
vimdiff gvimdiff ecmerge opendiff
|
||||
" "" "${cur##--tool=}"
|
||||
__gitcomp "$__git_mergetools_common tortoisemerge" "" "${cur##--tool=}"
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
@@ -1901,6 +1918,7 @@ _git ()
|
||||
config) _git_config ;;
|
||||
describe) _git_describe ;;
|
||||
diff) _git_diff ;;
|
||||
difftool) _git_difftool ;;
|
||||
fetch) _git_fetch ;;
|
||||
format-patch) _git_format_patch ;;
|
||||
fsck) _git_fsck ;;
|
||||
|
||||
@@ -1,249 +0,0 @@
|
||||
#!/bin/sh
|
||||
# git-difftool-helper is a GIT_EXTERNAL_DIFF-compatible diff tool launcher.
|
||||
# It supports kdiff3, kompare, tkdiff, xxdiff, meld, opendiff,
|
||||
# emerge, ecmerge, vimdiff, gvimdiff, and custom user-configurable tools.
|
||||
# This script is typically launched by using the 'git difftool'
|
||||
# convenience command.
|
||||
#
|
||||
# Copyright (c) 2009 David Aguilar
|
||||
|
||||
# Set GIT_DIFFTOOL_NO_PROMPT to bypass the per-file prompt.
|
||||
should_prompt () {
|
||||
! test -n "$GIT_DIFFTOOL_NO_PROMPT"
|
||||
}
|
||||
|
||||
# Should we keep the backup .orig file?
|
||||
keep_backup_mode="$(git config --bool merge.keepBackup || echo true)"
|
||||
keep_backup () {
|
||||
test "$keep_backup_mode" = "true"
|
||||
}
|
||||
|
||||
# This function manages the backup .orig file.
|
||||
# A backup $MERGED.orig file is created if changes are detected.
|
||||
cleanup_temp_files () {
|
||||
if test -n "$MERGED"; then
|
||||
if keep_backup && test "$MERGED" -nt "$BACKUP"; then
|
||||
test -f "$BACKUP" && mv -- "$BACKUP" "$MERGED.orig"
|
||||
else
|
||||
rm -f -- "$BACKUP"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# This is called when users Ctrl-C out of git-difftool-helper
|
||||
sigint_handler () {
|
||||
cleanup_temp_files
|
||||
exit 1
|
||||
}
|
||||
|
||||
# This function prepares temporary files and launches the appropriate
|
||||
# merge tool.
|
||||
launch_merge_tool () {
|
||||
# Merged is the filename as it appears in the work tree
|
||||
# Local is the contents of a/filename
|
||||
# Remote is the contents of b/filename
|
||||
# Custom merge tool commands might use $BASE so we provide it
|
||||
MERGED="$1"
|
||||
LOCAL="$2"
|
||||
REMOTE="$3"
|
||||
BASE="$1"
|
||||
ext="$$$(expr "$MERGED" : '.*\(\.[^/]*\)$')"
|
||||
BACKUP="$MERGED.BACKUP.$ext"
|
||||
|
||||
# Create and ensure that we clean up $BACKUP
|
||||
test -f "$MERGED" && cp -- "$MERGED" "$BACKUP"
|
||||
trap sigint_handler INT
|
||||
|
||||
# $LOCAL and $REMOTE are temporary files so prompt
|
||||
# the user with the real $MERGED name before launching $merge_tool.
|
||||
if should_prompt; then
|
||||
printf "\nViewing: '$MERGED'\n"
|
||||
printf "Hit return to launch '%s': " "$merge_tool"
|
||||
read ans
|
||||
fi
|
||||
|
||||
# Run the appropriate merge tool command
|
||||
case "$merge_tool" in
|
||||
kdiff3)
|
||||
basename=$(basename "$MERGED")
|
||||
"$merge_tool_path" --auto \
|
||||
--L1 "$basename (A)" \
|
||||
--L2 "$basename (B)" \
|
||||
-o "$MERGED" "$LOCAL" "$REMOTE" \
|
||||
> /dev/null 2>&1
|
||||
;;
|
||||
|
||||
kompare)
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE"
|
||||
;;
|
||||
|
||||
tkdiff)
|
||||
"$merge_tool_path" -o "$MERGED" "$LOCAL" "$REMOTE"
|
||||
;;
|
||||
|
||||
meld)
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE"
|
||||
;;
|
||||
|
||||
vimdiff)
|
||||
"$merge_tool_path" -c "wincmd l" "$LOCAL" "$REMOTE"
|
||||
;;
|
||||
|
||||
gvimdiff)
|
||||
"$merge_tool_path" -c "wincmd l" -f "$LOCAL" "$REMOTE"
|
||||
;;
|
||||
|
||||
xxdiff)
|
||||
"$merge_tool_path" \
|
||||
-X \
|
||||
-R 'Accel.SaveAsMerged: "Ctrl-S"' \
|
||||
-R 'Accel.Search: "Ctrl+F"' \
|
||||
-R 'Accel.SearchForward: "Ctrl-G"' \
|
||||
--merged-file "$MERGED" \
|
||||
"$LOCAL" "$REMOTE"
|
||||
;;
|
||||
|
||||
opendiff)
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE" \
|
||||
-merge "$MERGED" | cat
|
||||
;;
|
||||
|
||||
ecmerge)
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE" \
|
||||
--default --mode=merge2 --to="$MERGED"
|
||||
;;
|
||||
|
||||
emerge)
|
||||
"$merge_tool_path" -f emerge-files-command \
|
||||
"$LOCAL" "$REMOTE" "$(basename "$MERGED")"
|
||||
;;
|
||||
|
||||
*)
|
||||
if test -n "$merge_tool_cmd"; then
|
||||
( eval $merge_tool_cmd )
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
cleanup_temp_files
|
||||
}
|
||||
|
||||
# Verifies that (difftool|mergetool).<tool>.cmd exists
|
||||
valid_custom_tool() {
|
||||
merge_tool_cmd="$(git config difftool.$1.cmd)"
|
||||
test -z "$merge_tool_cmd" &&
|
||||
merge_tool_cmd="$(git config mergetool.$1.cmd)"
|
||||
test -n "$merge_tool_cmd"
|
||||
}
|
||||
|
||||
# Verifies that the chosen merge tool is properly setup.
|
||||
# Built-in merge tools are always valid.
|
||||
valid_tool() {
|
||||
case "$1" in
|
||||
kdiff3 | kompare | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge)
|
||||
;; # happy
|
||||
*)
|
||||
if ! valid_custom_tool "$1"
|
||||
then
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Sets up the merge_tool_path variable.
|
||||
# This handles the difftool.<tool>.path configuration.
|
||||
# This also falls back to mergetool defaults.
|
||||
init_merge_tool_path() {
|
||||
merge_tool_path=$(git config difftool."$1".path)
|
||||
test -z "$merge_tool_path" &&
|
||||
merge_tool_path=$(git config mergetool."$1".path)
|
||||
if test -z "$merge_tool_path"; then
|
||||
case "$1" in
|
||||
emerge)
|
||||
merge_tool_path=emacs
|
||||
;;
|
||||
*)
|
||||
merge_tool_path="$1"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
# Allow GIT_DIFF_TOOL and GIT_MERGE_TOOL to provide default values
|
||||
test -n "$GIT_MERGE_TOOL" && merge_tool="$GIT_MERGE_TOOL"
|
||||
test -n "$GIT_DIFF_TOOL" && merge_tool="$GIT_DIFF_TOOL"
|
||||
|
||||
# If merge tool was not specified then use the diff.tool
|
||||
# configuration variable. If that's invalid then reset merge_tool.
|
||||
# Fallback to merge.tool.
|
||||
if test -z "$merge_tool"; then
|
||||
merge_tool=$(git config diff.tool)
|
||||
test -z "$merge_tool" &&
|
||||
merge_tool=$(git config merge.tool)
|
||||
if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then
|
||||
echo >&2 "git config option diff.tool set to unknown tool: $merge_tool"
|
||||
echo >&2 "Resetting to default..."
|
||||
unset merge_tool
|
||||
fi
|
||||
fi
|
||||
|
||||
# Try to guess an appropriate merge tool if no tool has been set.
|
||||
if test -z "$merge_tool"; then
|
||||
# We have a $DISPLAY so try some common UNIX merge tools
|
||||
if test -n "$DISPLAY"; then
|
||||
# If gnome then prefer meld, otherwise, prefer kdiff3 or kompare
|
||||
if test -n "$GNOME_DESKTOP_SESSION_ID" ; then
|
||||
merge_tool_candidates="meld kdiff3 kompare tkdiff xxdiff gvimdiff"
|
||||
else
|
||||
merge_tool_candidates="kdiff3 kompare tkdiff xxdiff meld gvimdiff"
|
||||
fi
|
||||
fi
|
||||
if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then
|
||||
# $EDITOR is emacs so add emerge as a candidate
|
||||
merge_tool_candidates="$merge_tool_candidates emerge opendiff vimdiff"
|
||||
elif echo "${VISUAL:-$EDITOR}" | grep 'vim' > /dev/null 2>&1; then
|
||||
# $EDITOR is vim so add vimdiff as a candidate
|
||||
merge_tool_candidates="$merge_tool_candidates vimdiff opendiff emerge"
|
||||
else
|
||||
merge_tool_candidates="$merge_tool_candidates opendiff emerge vimdiff"
|
||||
fi
|
||||
echo "merge tool candidates: $merge_tool_candidates"
|
||||
|
||||
# Loop over each candidate and stop when a valid merge tool is found.
|
||||
for i in $merge_tool_candidates
|
||||
do
|
||||
init_merge_tool_path $i
|
||||
if type "$merge_tool_path" > /dev/null 2>&1; then
|
||||
merge_tool=$i
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if test -z "$merge_tool" ; then
|
||||
echo "No known merge resolution program available."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
else
|
||||
# A merge tool has been set, so verify that it's valid.
|
||||
if ! valid_tool "$merge_tool"; then
|
||||
echo >&2 "Unknown merge tool $merge_tool"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
init_merge_tool_path "$merge_tool"
|
||||
|
||||
if test -z "$merge_tool_cmd" && ! type "$merge_tool_path" > /dev/null 2>&1; then
|
||||
echo "The merge tool $merge_tool is not available as '$merge_tool_path'"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# Launch the merge tool on each path provided by 'git diff'
|
||||
while test $# -gt 6
|
||||
do
|
||||
launch_merge_tool "$1" "$2" "$5"
|
||||
shift 7
|
||||
done
|
||||
@@ -620,11 +620,12 @@ sub parse_diff {
|
||||
if ($diff_use_color) {
|
||||
@colored = run_cmd_pipe(qw(git diff-files -p --color --), $path);
|
||||
}
|
||||
my (@hunk) = { TEXT => [], DISPLAY => [] };
|
||||
my (@hunk) = { TEXT => [], DISPLAY => [], TYPE => 'header' };
|
||||
|
||||
for (my $i = 0; $i < @diff; $i++) {
|
||||
if ($diff[$i] =~ /^@@ /) {
|
||||
push @hunk, { TEXT => [], DISPLAY => [] };
|
||||
push @hunk, { TEXT => [], DISPLAY => [],
|
||||
TYPE => 'hunk' };
|
||||
}
|
||||
push @{$hunk[-1]{TEXT}}, $diff[$i];
|
||||
push @{$hunk[-1]{DISPLAY}},
|
||||
@@ -636,8 +637,8 @@ sub parse_diff {
|
||||
sub parse_diff_header {
|
||||
my $src = shift;
|
||||
|
||||
my $head = { TEXT => [], DISPLAY => [] };
|
||||
my $mode = { TEXT => [], DISPLAY => [] };
|
||||
my $head = { TEXT => [], DISPLAY => [], TYPE => 'header' };
|
||||
my $mode = { TEXT => [], DISPLAY => [], TYPE => 'mode' };
|
||||
|
||||
for (my $i = 0; $i < @{$src->{TEXT}}; $i++) {
|
||||
my $dest = $src->{TEXT}->[$i] =~ /^(old|new) mode (\d+)$/ ?
|
||||
@@ -684,6 +685,7 @@ sub split_hunk {
|
||||
my $this = +{
|
||||
TEXT => [],
|
||||
DISPLAY => [],
|
||||
TYPE => 'hunk',
|
||||
OLD => $o_ofs,
|
||||
NEW => $n_ofs,
|
||||
OCNT => 0,
|
||||
@@ -873,7 +875,11 @@ sub edit_hunk_loop {
|
||||
if (!defined $text) {
|
||||
return undef;
|
||||
}
|
||||
my $newhunk = { TEXT => $text, USE => 1 };
|
||||
my $newhunk = {
|
||||
TEXT => $text,
|
||||
TYPE => $hunk->[$ix]->{TYPE},
|
||||
USE => 1
|
||||
};
|
||||
if (diff_applies($head,
|
||||
@{$hunk}[0..$ix-1],
|
||||
$newhunk,
|
||||
@@ -894,6 +900,7 @@ sub help_patch_cmd {
|
||||
print colored $help_color, <<\EOF ;
|
||||
y - stage this hunk
|
||||
n - do not stage this hunk
|
||||
q - quit, do not stage this hunk nor any of the remaining ones
|
||||
a - stage this and all the remaining hunks in the file
|
||||
d - do not stage this hunk nor any of the remaining hunks in the file
|
||||
g - select a hunk to go to
|
||||
@@ -930,7 +937,7 @@ sub patch_update_cmd {
|
||||
@mods);
|
||||
}
|
||||
for (@them) {
|
||||
patch_update_file($_->{VALUE});
|
||||
return 0 if patch_update_file($_->{VALUE});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -976,6 +983,7 @@ sub display_hunks {
|
||||
}
|
||||
|
||||
sub patch_update_file {
|
||||
my $quit = 0;
|
||||
my ($ix, $num);
|
||||
my $path = shift;
|
||||
my ($head, @hunk) = parse_diff($path);
|
||||
@@ -985,32 +993,7 @@ sub patch_update_file {
|
||||
}
|
||||
|
||||
if (@{$mode->{TEXT}}) {
|
||||
while (1) {
|
||||
print @{$mode->{DISPLAY}};
|
||||
print colored $prompt_color,
|
||||
"Stage mode change [y/n/a/d/?]? ";
|
||||
my $line = prompt_single_character;
|
||||
if ($line =~ /^y/i) {
|
||||
$mode->{USE} = 1;
|
||||
last;
|
||||
}
|
||||
elsif ($line =~ /^n/i) {
|
||||
$mode->{USE} = 0;
|
||||
last;
|
||||
}
|
||||
elsif ($line =~ /^a/i) {
|
||||
$_->{USE} = 1 foreach ($mode, @hunk);
|
||||
last;
|
||||
}
|
||||
elsif ($line =~ /^d/i) {
|
||||
$_->{USE} = 0 foreach ($mode, @hunk);
|
||||
last;
|
||||
}
|
||||
else {
|
||||
help_patch_cmd('');
|
||||
next;
|
||||
}
|
||||
}
|
||||
unshift @hunk, $mode;
|
||||
}
|
||||
|
||||
$num = scalar @hunk;
|
||||
@@ -1054,14 +1037,19 @@ sub patch_update_file {
|
||||
}
|
||||
last if (!$undecided);
|
||||
|
||||
if (hunk_splittable($hunk[$ix]{TEXT})) {
|
||||
if ($hunk[$ix]{TYPE} eq 'hunk' &&
|
||||
hunk_splittable($hunk[$ix]{TEXT})) {
|
||||
$other .= ',s';
|
||||
}
|
||||
$other .= ',e';
|
||||
if ($hunk[$ix]{TYPE} eq 'hunk') {
|
||||
$other .= ',e';
|
||||
}
|
||||
for (@{$hunk[$ix]{DISPLAY}}) {
|
||||
print;
|
||||
}
|
||||
print colored $prompt_color, "Stage this hunk [y,n,a,d,/$other,?]? ";
|
||||
print colored $prompt_color, 'Stage ',
|
||||
($hunk[$ix]{TYPE} eq 'mode' ? 'mode change' : 'this hunk'),
|
||||
" [y,n,a,d,/$other,?]? ";
|
||||
my $line = prompt_single_character;
|
||||
if ($line) {
|
||||
if ($line =~ /^y/i) {
|
||||
@@ -1113,6 +1101,16 @@ sub patch_update_file {
|
||||
}
|
||||
next;
|
||||
}
|
||||
elsif ($line =~ /^q/i) {
|
||||
while ($ix < $num) {
|
||||
if (!defined $hunk[$ix]{USE}) {
|
||||
$hunk[$ix]{USE} = 0;
|
||||
}
|
||||
$ix++;
|
||||
}
|
||||
$quit = 1;
|
||||
next;
|
||||
}
|
||||
elsif ($line =~ m|^/(.*)|) {
|
||||
my $regex = $1;
|
||||
if ($1 eq "") {
|
||||
@@ -1193,7 +1191,7 @@ sub patch_update_file {
|
||||
$num = scalar @hunk;
|
||||
next;
|
||||
}
|
||||
elsif ($line =~ /^e/) {
|
||||
elsif ($other =~ /e/ && $line =~ /^e/) {
|
||||
my $newhunk = edit_hunk_loop($head, \@hunk, $ix);
|
||||
if (defined $newhunk) {
|
||||
splice @hunk, $ix, 1, $newhunk;
|
||||
@@ -1214,9 +1212,6 @@ sub patch_update_file {
|
||||
|
||||
my $n_lofs = 0;
|
||||
my @result = ();
|
||||
if ($mode->{USE}) {
|
||||
push @result, @{$mode->{TEXT}};
|
||||
}
|
||||
for (@hunk) {
|
||||
if ($_->{USE}) {
|
||||
push @result, @{$_->{TEXT}};
|
||||
@@ -1239,6 +1234,7 @@ sub patch_update_file {
|
||||
}
|
||||
|
||||
print "\n";
|
||||
return $quit;
|
||||
}
|
||||
|
||||
sub diff_cmd {
|
||||
|
||||
29
git-am.sh
29
git-am.sh
@@ -36,6 +36,13 @@ cd_to_toplevel
|
||||
git var GIT_COMMITTER_IDENT >/dev/null ||
|
||||
die "You need to set your committer info first"
|
||||
|
||||
if git rev-parse --verify -q HEAD >/dev/null
|
||||
then
|
||||
HAS_HEAD=yes
|
||||
else
|
||||
HAS_HEAD=
|
||||
fi
|
||||
|
||||
sq () {
|
||||
for sqarg
|
||||
do
|
||||
@@ -290,16 +297,26 @@ else
|
||||
: >"$dotest/rebasing"
|
||||
else
|
||||
: >"$dotest/applying"
|
||||
git update-ref ORIG_HEAD HEAD
|
||||
if test -n "$HAS_HEAD"
|
||||
then
|
||||
git update-ref ORIG_HEAD HEAD
|
||||
else
|
||||
git update-ref -d ORIG_HEAD >/dev/null 2>&1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
case "$resolved" in
|
||||
'')
|
||||
files=$(git diff-index --cached --name-only HEAD --) || exit
|
||||
case "$HAS_HEAD" in
|
||||
'')
|
||||
files=$(git ls-files) ;;
|
||||
?*)
|
||||
files=$(git diff-index --cached --name-only HEAD --) ;;
|
||||
esac || exit
|
||||
if test "$files"
|
||||
then
|
||||
: >"$dotest/dirtyindex"
|
||||
test -n "$HAS_HEAD" && : >"$dotest/dirtyindex"
|
||||
die "Dirty index: cannot apply patches (dirty: $files)"
|
||||
fi
|
||||
esac
|
||||
@@ -541,18 +558,20 @@ do
|
||||
fi
|
||||
|
||||
tree=$(git write-tree) &&
|
||||
parent=$(git rev-parse --verify HEAD) &&
|
||||
commit=$(
|
||||
if test -n "$ignore_date"
|
||||
then
|
||||
GIT_AUTHOR_DATE=
|
||||
fi
|
||||
parent=$(git rev-parse --verify -q HEAD) ||
|
||||
echo >&2 "applying to an empty history"
|
||||
|
||||
if test -n "$committer_date_is_author_date"
|
||||
then
|
||||
GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
|
||||
export GIT_COMMITTER_DATE
|
||||
fi &&
|
||||
git commit-tree $tree -p $parent <"$dotest/final-commit"
|
||||
git commit-tree $tree ${parent:+-p $parent} <"$dotest/final-commit"
|
||||
) &&
|
||||
git update-ref -m "$GIT_REFLOG_ACTION: $FIRSTLINE" HEAD $commit $parent ||
|
||||
stop_here $this
|
||||
|
||||
59
git-difftool--helper.sh
Executable file
59
git-difftool--helper.sh
Executable file
@@ -0,0 +1,59 @@
|
||||
#!/bin/sh
|
||||
# git-difftool--helper is a GIT_EXTERNAL_DIFF-compatible diff tool launcher.
|
||||
# This script is typically launched by using the 'git difftool'
|
||||
# convenience command.
|
||||
#
|
||||
# Copyright (c) 2009 David Aguilar
|
||||
|
||||
# Load common functions from git-mergetool--lib
|
||||
TOOL_MODE=diff
|
||||
. git-mergetool--lib
|
||||
|
||||
# difftool.prompt controls the default prompt/no-prompt behavior
|
||||
# and is overridden with $GIT_DIFFTOOL*_PROMPT.
|
||||
should_prompt () {
|
||||
prompt=$(git config --bool difftool.prompt || echo true)
|
||||
if test "$prompt" = true; then
|
||||
test -z "$GIT_DIFFTOOL_NO_PROMPT"
|
||||
else
|
||||
test -n "$GIT_DIFFTOOL_PROMPT"
|
||||
fi
|
||||
}
|
||||
|
||||
# Sets up shell variables and runs a merge tool
|
||||
launch_merge_tool () {
|
||||
# Merged is the filename as it appears in the work tree
|
||||
# Local is the contents of a/filename
|
||||
# Remote is the contents of b/filename
|
||||
# Custom merge tool commands might use $BASE so we provide it
|
||||
MERGED="$1"
|
||||
LOCAL="$2"
|
||||
REMOTE="$3"
|
||||
BASE="$1"
|
||||
|
||||
# $LOCAL and $REMOTE are temporary files so prompt
|
||||
# the user with the real $MERGED name before launching $merge_tool.
|
||||
if should_prompt; then
|
||||
printf "\nViewing: '$MERGED'\n"
|
||||
printf "Hit return to launch '%s': " "$merge_tool"
|
||||
read ans
|
||||
fi
|
||||
|
||||
# Run the appropriate merge tool command
|
||||
run_merge_tool "$merge_tool"
|
||||
}
|
||||
|
||||
# Allow GIT_DIFF_TOOL and GIT_MERGE_TOOL to provide default values
|
||||
test -n "$GIT_MERGE_TOOL" && merge_tool="$GIT_MERGE_TOOL"
|
||||
test -n "$GIT_DIFF_TOOL" && merge_tool="$GIT_DIFF_TOOL"
|
||||
|
||||
if test -z "$merge_tool"; then
|
||||
merge_tool="$(get_merge_tool)" || exit
|
||||
fi
|
||||
|
||||
# Launch the merge tool on each path provided by 'git diff'
|
||||
while test $# -gt 6
|
||||
do
|
||||
launch_merge_tool "$1" "$2" "$5"
|
||||
shift 7
|
||||
done
|
||||
@@ -2,9 +2,12 @@
|
||||
# Copyright (c) 2009 David Aguilar
|
||||
#
|
||||
# This is a wrapper around the GIT_EXTERNAL_DIFF-compatible
|
||||
# git-difftool-helper script. This script exports
|
||||
# GIT_EXTERNAL_DIFF and GIT_PAGER for use by git, and
|
||||
# GIT_DIFFTOOL_NO_PROMPT and GIT_DIFF_TOOL for use by git-difftool-helper.
|
||||
# git-difftool--helper script.
|
||||
#
|
||||
# This script exports GIT_EXTERNAL_DIFF and GIT_PAGER for use by git.
|
||||
# GIT_DIFFTOOL_NO_PROMPT, GIT_DIFFTOOL_PROMPT, and GIT_DIFF_TOOL
|
||||
# are exported for use by git-difftool--helper.
|
||||
#
|
||||
# Any arguments that are unknown to this script are forwarded to 'git diff'.
|
||||
|
||||
use strict;
|
||||
@@ -18,7 +21,7 @@ my $DIR = abs_path(dirname($0));
|
||||
sub usage
|
||||
{
|
||||
print << 'USAGE';
|
||||
usage: git difftool [--tool=<tool>] [--no-prompt] ["git diff" options]
|
||||
usage: git difftool [--tool=<tool>] [-y|--no-prompt] ["git diff" options]
|
||||
USAGE
|
||||
exit 1;
|
||||
}
|
||||
@@ -27,13 +30,16 @@ sub setup_environment
|
||||
{
|
||||
$ENV{PATH} = "$DIR:$ENV{PATH}";
|
||||
$ENV{GIT_PAGER} = '';
|
||||
$ENV{GIT_EXTERNAL_DIFF} = 'git-difftool-helper';
|
||||
$ENV{GIT_EXTERNAL_DIFF} = 'git-difftool--helper';
|
||||
}
|
||||
|
||||
sub exe
|
||||
{
|
||||
my $exe = shift;
|
||||
return defined $ENV{COMSPEC} ? "$exe.exe" : $exe;
|
||||
if ($^O eq 'MSWin32' || $^O eq 'msys') {
|
||||
return "$exe.exe";
|
||||
}
|
||||
return $exe;
|
||||
}
|
||||
|
||||
sub generate_command
|
||||
@@ -47,7 +53,7 @@ sub generate_command
|
||||
$skip_next = 0;
|
||||
next;
|
||||
}
|
||||
if ($arg eq '-t' or $arg eq '--tool') {
|
||||
if ($arg eq '-t' || $arg eq '--tool') {
|
||||
usage() if $#ARGV <= $idx;
|
||||
$ENV{GIT_DIFF_TOOL} = $ARGV[$idx + 1];
|
||||
$skip_next = 1;
|
||||
@@ -57,11 +63,17 @@ sub generate_command
|
||||
$ENV{GIT_DIFF_TOOL} = substr($arg, 7);
|
||||
next;
|
||||
}
|
||||
if ($arg eq '--no-prompt') {
|
||||
if ($arg eq '-y' || $arg eq '--no-prompt') {
|
||||
$ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true';
|
||||
delete $ENV{GIT_DIFFTOOL_PROMPT};
|
||||
next;
|
||||
}
|
||||
if ($arg eq '-h' or $arg eq '--help') {
|
||||
if ($arg eq '--prompt') {
|
||||
$ENV{GIT_DIFFTOOL_PROMPT} = 'true';
|
||||
delete $ENV{GIT_DIFFTOOL_NO_PROMPT};
|
||||
next;
|
||||
}
|
||||
if ($arg eq '-h' || $arg eq '--help') {
|
||||
usage();
|
||||
}
|
||||
push @command, $arg;
|
||||
385
git-mergetool--lib.sh
Normal file
385
git-mergetool--lib.sh
Normal file
@@ -0,0 +1,385 @@
|
||||
# git-mergetool--lib is a library for common merge tool functions
|
||||
diff_mode() {
|
||||
test "$TOOL_MODE" = diff
|
||||
}
|
||||
|
||||
merge_mode() {
|
||||
test "$TOOL_MODE" = merge
|
||||
}
|
||||
|
||||
translate_merge_tool_path () {
|
||||
case "$1" in
|
||||
vimdiff)
|
||||
echo vim
|
||||
;;
|
||||
gvimdiff)
|
||||
echo gvim
|
||||
;;
|
||||
emerge)
|
||||
echo emacs
|
||||
;;
|
||||
*)
|
||||
echo "$1"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
check_unchanged () {
|
||||
if test "$MERGED" -nt "$BACKUP"; then
|
||||
status=0
|
||||
else
|
||||
while true; do
|
||||
echo "$MERGED seems unchanged."
|
||||
printf "Was the merge successful? [y/n] "
|
||||
read answer < /dev/tty
|
||||
case "$answer" in
|
||||
y*|Y*) status=0; break ;;
|
||||
n*|N*) status=1; break ;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
valid_tool () {
|
||||
case "$1" in
|
||||
kdiff3 | tkdiff | xxdiff | meld | opendiff | \
|
||||
emerge | vimdiff | gvimdiff | ecmerge | diffuse)
|
||||
;; # happy
|
||||
tortoisemerge)
|
||||
if ! merge_mode; then
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
kompare)
|
||||
if ! diff_mode; then
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
if test -z "$(get_merge_tool_cmd "$1")"; then
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
get_merge_tool_cmd () {
|
||||
# Prints the custom command for a merge tool
|
||||
if test -n "$1"; then
|
||||
merge_tool="$1"
|
||||
else
|
||||
merge_tool="$(get_merge_tool)"
|
||||
fi
|
||||
if diff_mode; then
|
||||
echo "$(git config difftool.$merge_tool.cmd ||
|
||||
git config mergetool.$merge_tool.cmd)"
|
||||
else
|
||||
echo "$(git config mergetool.$merge_tool.cmd)"
|
||||
fi
|
||||
}
|
||||
|
||||
run_merge_tool () {
|
||||
merge_tool_path="$(get_merge_tool_path "$1")" || exit
|
||||
base_present="$2"
|
||||
status=0
|
||||
|
||||
case "$1" in
|
||||
kdiff3)
|
||||
if merge_mode; then
|
||||
if $base_present; then
|
||||
("$merge_tool_path" --auto \
|
||||
--L1 "$MERGED (Base)" \
|
||||
--L2 "$MERGED (Local)" \
|
||||
--L3 "$MERGED (Remote)" \
|
||||
-o "$MERGED" \
|
||||
"$BASE" "$LOCAL" "$REMOTE" \
|
||||
> /dev/null 2>&1)
|
||||
else
|
||||
("$merge_tool_path" --auto \
|
||||
--L1 "$MERGED (Local)" \
|
||||
--L2 "$MERGED (Remote)" \
|
||||
-o "$MERGED" \
|
||||
"$LOCAL" "$REMOTE" \
|
||||
> /dev/null 2>&1)
|
||||
fi
|
||||
status=$?
|
||||
else
|
||||
("$merge_tool_path" --auto \
|
||||
--L1 "$MERGED (A)" \
|
||||
--L2 "$MERGED (B)" "$LOCAL" "$REMOTE" \
|
||||
> /dev/null 2>&1)
|
||||
fi
|
||||
;;
|
||||
kompare)
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE"
|
||||
;;
|
||||
tkdiff)
|
||||
if merge_mode; then
|
||||
if $base_present; then
|
||||
"$merge_tool_path" -a "$BASE" \
|
||||
-o "$MERGED" "$LOCAL" "$REMOTE"
|
||||
else
|
||||
"$merge_tool_path" \
|
||||
-o "$MERGED" "$LOCAL" "$REMOTE"
|
||||
fi
|
||||
status=$?
|
||||
else
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE"
|
||||
fi
|
||||
;;
|
||||
meld)
|
||||
if merge_mode; then
|
||||
touch "$BACKUP"
|
||||
"$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE"
|
||||
check_unchanged
|
||||
else
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE"
|
||||
fi
|
||||
;;
|
||||
diffuse)
|
||||
if merge_mode; then
|
||||
touch "$BACKUP"
|
||||
if $base_present; then
|
||||
"$merge_tool_path" \
|
||||
"$LOCAL" "$MERGED" "$REMOTE" \
|
||||
"$BASE" | cat
|
||||
else
|
||||
"$merge_tool_path" \
|
||||
"$LOCAL" "$MERGED" "$REMOTE" | cat
|
||||
fi
|
||||
check_unchanged
|
||||
else
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE" | cat
|
||||
fi
|
||||
;;
|
||||
vimdiff)
|
||||
if merge_mode; then
|
||||
touch "$BACKUP"
|
||||
"$merge_tool_path" -d -c "wincmd l" \
|
||||
"$LOCAL" "$MERGED" "$REMOTE"
|
||||
check_unchanged
|
||||
else
|
||||
"$merge_tool_path" -d -c "wincmd l" \
|
||||
"$LOCAL" "$REMOTE"
|
||||
fi
|
||||
;;
|
||||
gvimdiff)
|
||||
if merge_mode; then
|
||||
touch "$BACKUP"
|
||||
"$merge_tool_path" -d -c "wincmd l" -f \
|
||||
"$LOCAL" "$MERGED" "$REMOTE"
|
||||
check_unchanged
|
||||
else
|
||||
"$merge_tool_path" -d -c "wincmd l" -f \
|
||||
"$LOCAL" "$REMOTE"
|
||||
fi
|
||||
;;
|
||||
xxdiff)
|
||||
if merge_mode; then
|
||||
touch "$BACKUP"
|
||||
if $base_present; then
|
||||
"$merge_tool_path" -X --show-merged-pane \
|
||||
-R 'Accel.SaveAsMerged: "Ctrl-S"' \
|
||||
-R 'Accel.Search: "Ctrl+F"' \
|
||||
-R 'Accel.SearchForward: "Ctrl-G"' \
|
||||
--merged-file "$MERGED" \
|
||||
"$LOCAL" "$BASE" "$REMOTE"
|
||||
else
|
||||
"$merge_tool_path" -X $extra \
|
||||
-R 'Accel.SaveAsMerged: "Ctrl-S"' \
|
||||
-R 'Accel.Search: "Ctrl+F"' \
|
||||
-R 'Accel.SearchForward: "Ctrl-G"' \
|
||||
--merged-file "$MERGED" \
|
||||
"$LOCAL" "$REMOTE"
|
||||
fi
|
||||
check_unchanged
|
||||
else
|
||||
"$merge_tool_path" \
|
||||
-R 'Accel.Search: "Ctrl+F"' \
|
||||
-R 'Accel.SearchForward: "Ctrl-G"' \
|
||||
"$LOCAL" "$REMOTE"
|
||||
fi
|
||||
;;
|
||||
opendiff)
|
||||
if merge_mode; then
|
||||
touch "$BACKUP"
|
||||
if $base_present; then
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE" \
|
||||
-ancestor "$BASE" \
|
||||
-merge "$MERGED" | cat
|
||||
else
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE" \
|
||||
-merge "$MERGED" | cat
|
||||
fi
|
||||
check_unchanged
|
||||
else
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE" | cat
|
||||
fi
|
||||
;;
|
||||
ecmerge)
|
||||
if merge_mode; then
|
||||
touch "$BACKUP"
|
||||
if $base_present; then
|
||||
"$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" \
|
||||
--default --mode=merge3 --to="$MERGED"
|
||||
else
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE" \
|
||||
--default --mode=merge2 --to="$MERGED"
|
||||
fi
|
||||
check_unchanged
|
||||
else
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE" \
|
||||
--default --mode=merge2 --to="$MERGED"
|
||||
fi
|
||||
;;
|
||||
emerge)
|
||||
if merge_mode; then
|
||||
if $base_present; then
|
||||
"$merge_tool_path" \
|
||||
-f emerge-files-with-ancestor-command \
|
||||
"$LOCAL" "$REMOTE" "$BASE" \
|
||||
"$(basename "$MERGED")"
|
||||
else
|
||||
"$merge_tool_path" \
|
||||
-f emerge-files-command \
|
||||
"$LOCAL" "$REMOTE" \
|
||||
"$(basename "$MERGED")"
|
||||
fi
|
||||
status=$?
|
||||
else
|
||||
"$merge_tool_path" -f emerge-files-command \
|
||||
"$LOCAL" "$REMOTE" "$(basename "$MERGED")"
|
||||
fi
|
||||
;;
|
||||
tortoisemerge)
|
||||
if $base_present; then
|
||||
touch "$BACKUP"
|
||||
"$merge_tool_path" \
|
||||
-base:"$BASE" -mine:"$LOCAL" \
|
||||
-theirs:"$REMOTE" -merged:"$MERGED"
|
||||
check_unchanged
|
||||
else
|
||||
echo "TortoiseMerge cannot be used without a base" 1>&2
|
||||
status=1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
merge_tool_cmd="$(get_merge_tool_cmd "$1")"
|
||||
if test -z "$merge_tool_cmd"; then
|
||||
if merge_mode; then
|
||||
status=1
|
||||
fi
|
||||
break
|
||||
fi
|
||||
if merge_mode; then
|
||||
trust_exit_code="$(git config --bool \
|
||||
mergetool."$1".trustExitCode || echo false)"
|
||||
if test "$trust_exit_code" = "false"; then
|
||||
touch "$BACKUP"
|
||||
( eval $merge_tool_cmd )
|
||||
check_unchanged
|
||||
else
|
||||
( eval $merge_tool_cmd )
|
||||
status=$?
|
||||
fi
|
||||
else
|
||||
( eval $merge_tool_cmd )
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
return $status
|
||||
}
|
||||
|
||||
guess_merge_tool () {
|
||||
if merge_mode; then
|
||||
tools="tortoisemerge"
|
||||
else
|
||||
tools="kompare"
|
||||
fi
|
||||
if test -n "$DISPLAY"; then
|
||||
if test -n "$GNOME_DESKTOP_SESSION_ID" ; then
|
||||
tools="meld opendiff kdiff3 tkdiff xxdiff $tools"
|
||||
else
|
||||
tools="opendiff kdiff3 tkdiff xxdiff meld $tools"
|
||||
fi
|
||||
tools="$tools gvimdiff diffuse ecmerge"
|
||||
fi
|
||||
if echo "${VISUAL:-$EDITOR}" | grep emacs > /dev/null 2>&1; then
|
||||
# $EDITOR is emacs so add emerge as a candidate
|
||||
tools="$tools emerge vimdiff"
|
||||
elif echo "${VISUAL:-$EDITOR}" | grep vim > /dev/null 2>&1; then
|
||||
# $EDITOR is vim so add vimdiff as a candidate
|
||||
tools="$tools vimdiff emerge"
|
||||
else
|
||||
tools="$tools emerge vimdiff"
|
||||
fi
|
||||
echo >&2 "merge tool candidates: $tools"
|
||||
|
||||
# Loop over each candidate and stop when a valid merge tool is found.
|
||||
for i in $tools
|
||||
do
|
||||
merge_tool_path="$(translate_merge_tool_path "$i")"
|
||||
if type "$merge_tool_path" > /dev/null 2>&1; then
|
||||
echo "$i"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
echo >&2 "No known merge resolution program available."
|
||||
return 1
|
||||
}
|
||||
|
||||
get_configured_merge_tool () {
|
||||
# Diff mode first tries diff.tool and falls back to merge.tool.
|
||||
# Merge mode only checks merge.tool
|
||||
if diff_mode; then
|
||||
merge_tool=$(git config diff.tool || git config merge.tool)
|
||||
else
|
||||
merge_tool=$(git config merge.tool)
|
||||
fi
|
||||
if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then
|
||||
echo >&2 "git config option $TOOL_MODE.tool set to unknown tool: $merge_tool"
|
||||
echo >&2 "Resetting to default..."
|
||||
return 1
|
||||
fi
|
||||
echo "$merge_tool"
|
||||
}
|
||||
|
||||
get_merge_tool_path () {
|
||||
# A merge tool has been set, so verify that it's valid.
|
||||
if test -n "$1"; then
|
||||
merge_tool="$1"
|
||||
else
|
||||
merge_tool="$(get_merge_tool)"
|
||||
fi
|
||||
if ! valid_tool "$merge_tool"; then
|
||||
echo >&2 "Unknown merge tool $merge_tool"
|
||||
exit 1
|
||||
fi
|
||||
if diff_mode; then
|
||||
merge_tool_path=$(git config difftool."$merge_tool".path ||
|
||||
git config mergetool."$merge_tool".path)
|
||||
else
|
||||
merge_tool_path=$(git config mergetool."$merge_tool".path)
|
||||
fi
|
||||
if test -z "$merge_tool_path"; then
|
||||
merge_tool_path="$(translate_merge_tool_path "$merge_tool")"
|
||||
fi
|
||||
if test -z "$(get_merge_tool_cmd "$merge_tool")" &&
|
||||
! type "$merge_tool_path" > /dev/null 2>&1; then
|
||||
echo >&2 "The $TOOL_MODE tool $merge_tool is not available as"\
|
||||
"'$merge_tool_path'"
|
||||
exit 1
|
||||
fi
|
||||
echo "$merge_tool_path"
|
||||
}
|
||||
|
||||
get_merge_tool () {
|
||||
# Check if a merge tool has been configured
|
||||
merge_tool=$(get_configured_merge_tool)
|
||||
# Try to guess an appropriate merge tool if no tool has been set.
|
||||
if test -z "$merge_tool"; then
|
||||
merge_tool="$(guess_merge_tool)" || exit
|
||||
fi
|
||||
echo "$merge_tool"
|
||||
}
|
||||
217
git-mergetool.sh
217
git-mergetool.sh
@@ -11,7 +11,9 @@
|
||||
USAGE='[--tool=tool] [-y|--no-prompt|--prompt] [file to merge] ...'
|
||||
SUBDIRECTORY_OK=Yes
|
||||
OPTIONS_SPEC=
|
||||
TOOL_MODE=merge
|
||||
. git-sh-setup
|
||||
. git-mergetool--lib
|
||||
require_work_tree
|
||||
|
||||
# Returns true if the mode reflects a symlink
|
||||
@@ -110,22 +112,6 @@ resolve_deleted_merge () {
|
||||
done
|
||||
}
|
||||
|
||||
check_unchanged () {
|
||||
if test "$MERGED" -nt "$BACKUP" ; then
|
||||
status=0;
|
||||
else
|
||||
while true; do
|
||||
echo "$MERGED seems unchanged."
|
||||
printf "Was the merge successful? [y/n] "
|
||||
read answer < /dev/tty
|
||||
case "$answer" in
|
||||
y*|Y*) status=0; break ;;
|
||||
n*|N*) status=1; break ;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
checkout_staged_file () {
|
||||
tmpfile=$(expr "$(git checkout-index --temp --stage="$1" "$2")" : '\([^ ]*\) ')
|
||||
|
||||
@@ -137,7 +123,7 @@ checkout_staged_file () {
|
||||
merge_file () {
|
||||
MERGED="$1"
|
||||
|
||||
f=`git ls-files -u -- "$MERGED"`
|
||||
f=$(git ls-files -u -- "$MERGED")
|
||||
if test -z "$f" ; then
|
||||
if test ! -f "$MERGED" ; then
|
||||
echo "$MERGED: file not found"
|
||||
@@ -156,9 +142,9 @@ merge_file () {
|
||||
mv -- "$MERGED" "$BACKUP"
|
||||
cp -- "$BACKUP" "$MERGED"
|
||||
|
||||
base_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==1) print $1;}'`
|
||||
local_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $1;}'`
|
||||
remote_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $1;}'`
|
||||
base_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==1) print $1;}')
|
||||
local_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $1;}')
|
||||
remote_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $1;}')
|
||||
|
||||
base_present && checkout_staged_file 1 "$MERGED" "$BASE"
|
||||
local_present && checkout_staged_file 2 "$MERGED" "$LOCAL"
|
||||
@@ -188,97 +174,13 @@ merge_file () {
|
||||
read ans
|
||||
fi
|
||||
|
||||
case "$merge_tool" in
|
||||
kdiff3)
|
||||
if base_present ; then
|
||||
("$merge_tool_path" --auto --L1 "$MERGED (Base)" --L2 "$MERGED (Local)" --L3 "$MERGED (Remote)" \
|
||||
-o "$MERGED" "$BASE" "$LOCAL" "$REMOTE" > /dev/null 2>&1)
|
||||
else
|
||||
("$merge_tool_path" --auto --L1 "$MERGED (Local)" --L2 "$MERGED (Remote)" \
|
||||
-o "$MERGED" "$LOCAL" "$REMOTE" > /dev/null 2>&1)
|
||||
fi
|
||||
status=$?
|
||||
;;
|
||||
tkdiff)
|
||||
if base_present ; then
|
||||
"$merge_tool_path" -a "$BASE" -o "$MERGED" "$LOCAL" "$REMOTE"
|
||||
else
|
||||
"$merge_tool_path" -o "$MERGED" "$LOCAL" "$REMOTE"
|
||||
fi
|
||||
status=$?
|
||||
;;
|
||||
meld)
|
||||
touch "$BACKUP"
|
||||
"$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE"
|
||||
check_unchanged
|
||||
;;
|
||||
vimdiff)
|
||||
touch "$BACKUP"
|
||||
"$merge_tool_path" -c "wincmd l" "$LOCAL" "$MERGED" "$REMOTE"
|
||||
check_unchanged
|
||||
;;
|
||||
gvimdiff)
|
||||
touch "$BACKUP"
|
||||
"$merge_tool_path" -c "wincmd l" -f "$LOCAL" "$MERGED" "$REMOTE"
|
||||
check_unchanged
|
||||
;;
|
||||
xxdiff)
|
||||
touch "$BACKUP"
|
||||
if base_present ; then
|
||||
"$merge_tool_path" -X --show-merged-pane \
|
||||
-R 'Accel.SaveAsMerged: "Ctrl-S"' \
|
||||
-R 'Accel.Search: "Ctrl+F"' \
|
||||
-R 'Accel.SearchForward: "Ctrl-G"' \
|
||||
--merged-file "$MERGED" "$LOCAL" "$BASE" "$REMOTE"
|
||||
else
|
||||
"$merge_tool_path" -X --show-merged-pane \
|
||||
-R 'Accel.SaveAsMerged: "Ctrl-S"' \
|
||||
-R 'Accel.Search: "Ctrl+F"' \
|
||||
-R 'Accel.SearchForward: "Ctrl-G"' \
|
||||
--merged-file "$MERGED" "$LOCAL" "$REMOTE"
|
||||
fi
|
||||
check_unchanged
|
||||
;;
|
||||
opendiff)
|
||||
touch "$BACKUP"
|
||||
if base_present; then
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE" -ancestor "$BASE" -merge "$MERGED" | cat
|
||||
else
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE" -merge "$MERGED" | cat
|
||||
fi
|
||||
check_unchanged
|
||||
;;
|
||||
ecmerge)
|
||||
touch "$BACKUP"
|
||||
if base_present; then
|
||||
"$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" --default --mode=merge3 --to="$MERGED"
|
||||
else
|
||||
"$merge_tool_path" "$LOCAL" "$REMOTE" --default --mode=merge2 --to="$MERGED"
|
||||
fi
|
||||
check_unchanged
|
||||
;;
|
||||
emerge)
|
||||
if base_present ; then
|
||||
"$merge_tool_path" -f emerge-files-with-ancestor-command "$LOCAL" "$REMOTE" "$BASE" "$(basename "$MERGED")"
|
||||
else
|
||||
"$merge_tool_path" -f emerge-files-command "$LOCAL" "$REMOTE" "$(basename "$MERGED")"
|
||||
fi
|
||||
status=$?
|
||||
;;
|
||||
*)
|
||||
if test -n "$merge_tool_cmd"; then
|
||||
if test "$merge_tool_trust_exit_code" = "false"; then
|
||||
touch "$BACKUP"
|
||||
( eval $merge_tool_cmd )
|
||||
check_unchanged
|
||||
else
|
||||
( eval $merge_tool_cmd )
|
||||
status=$?
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
if test "$status" -ne 0; then
|
||||
if base_present; then
|
||||
present=true
|
||||
else
|
||||
present=false
|
||||
fi
|
||||
|
||||
if ! run_merge_tool "$merge_tool" "$present"; then
|
||||
echo "merge of $MERGED failed" 1>&2
|
||||
mv -- "$BACKUP" "$MERGED"
|
||||
|
||||
@@ -308,7 +210,7 @@ do
|
||||
-t|--tool*)
|
||||
case "$#,$1" in
|
||||
*,*=*)
|
||||
merge_tool=`expr "z$1" : 'z-[^=]*=\(.*\)'`
|
||||
merge_tool=$(expr "z$1" : 'z-[^=]*=\(.*\)')
|
||||
;;
|
||||
1,*)
|
||||
usage ;;
|
||||
@@ -337,38 +239,6 @@ do
|
||||
shift
|
||||
done
|
||||
|
||||
valid_custom_tool()
|
||||
{
|
||||
merge_tool_cmd="$(git config mergetool.$1.cmd)"
|
||||
test -n "$merge_tool_cmd"
|
||||
}
|
||||
|
||||
valid_tool() {
|
||||
case "$1" in
|
||||
kdiff3 | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge)
|
||||
;; # happy
|
||||
*)
|
||||
if ! valid_custom_tool "$1"; then
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
init_merge_tool_path() {
|
||||
merge_tool_path=`git config mergetool.$1.path`
|
||||
if test -z "$merge_tool_path" ; then
|
||||
case "$1" in
|
||||
emerge)
|
||||
merge_tool_path=emacs
|
||||
;;
|
||||
*)
|
||||
merge_tool_path=$1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
prompt_after_failed_merge() {
|
||||
while true; do
|
||||
printf "Continue merging other unresolved paths (y/n) ? "
|
||||
@@ -387,67 +257,16 @@ prompt_after_failed_merge() {
|
||||
}
|
||||
|
||||
if test -z "$merge_tool"; then
|
||||
merge_tool=`git config merge.tool`
|
||||
if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then
|
||||
echo >&2 "git config option merge.tool set to unknown tool: $merge_tool"
|
||||
echo >&2 "Resetting to default..."
|
||||
unset merge_tool
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$merge_tool" ; then
|
||||
if test -n "$DISPLAY"; then
|
||||
if test -n "$GNOME_DESKTOP_SESSION_ID" ; then
|
||||
merge_tool_candidates="meld kdiff3 tkdiff xxdiff gvimdiff"
|
||||
else
|
||||
merge_tool_candidates="kdiff3 tkdiff xxdiff meld gvimdiff"
|
||||
fi
|
||||
fi
|
||||
if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then
|
||||
merge_tool_candidates="$merge_tool_candidates emerge opendiff vimdiff"
|
||||
elif echo "${VISUAL:-$EDITOR}" | grep 'vim' > /dev/null 2>&1; then
|
||||
merge_tool_candidates="$merge_tool_candidates vimdiff opendiff emerge"
|
||||
else
|
||||
merge_tool_candidates="$merge_tool_candidates opendiff emerge vimdiff"
|
||||
fi
|
||||
echo "merge tool candidates: $merge_tool_candidates"
|
||||
for i in $merge_tool_candidates; do
|
||||
init_merge_tool_path $i
|
||||
if type "$merge_tool_path" > /dev/null 2>&1; then
|
||||
merge_tool=$i
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -z "$merge_tool" ; then
|
||||
echo "No known merge resolution program available."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
if ! valid_tool "$merge_tool"; then
|
||||
echo >&2 "Unknown merge_tool $merge_tool"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
init_merge_tool_path "$merge_tool"
|
||||
|
||||
merge_keep_backup="$(git config --bool merge.keepBackup || echo true)"
|
||||
merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo false)"
|
||||
|
||||
if test -z "$merge_tool_cmd" && ! type "$merge_tool_path" > /dev/null 2>&1; then
|
||||
echo "The merge tool $merge_tool is not available as '$merge_tool_path'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! test -z "$merge_tool_cmd"; then
|
||||
merge_tool_trust_exit_code="$(git config --bool mergetool.$merge_tool.trustExitCode || echo false)"
|
||||
fi
|
||||
merge_tool=$(get_merge_tool "$merge_tool") || exit
|
||||
fi
|
||||
merge_keep_backup="$(git config --bool mergetool.keepBackup || echo true)"
|
||||
merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo false)"
|
||||
|
||||
last_status=0
|
||||
rollup_status=0
|
||||
|
||||
if test $# -eq 0 ; then
|
||||
files=`git ls-files -u | sed -e 's/^[^ ]* //' | sort -u`
|
||||
files=$(git ls-files -u | sed -e 's/^[^ ]* //' | sort -u)
|
||||
if test -z "$files" ; then
|
||||
echo "No files need merging"
|
||||
exit 0
|
||||
|
||||
246
graph.c
246
graph.c
@@ -1,5 +1,6 @@
|
||||
#include "cache.h"
|
||||
#include "commit.h"
|
||||
#include "color.h"
|
||||
#include "graph.h"
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
@@ -43,10 +44,6 @@ static void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb);
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* - Add colors to the graph.
|
||||
* Pick a color for each column, and print all characters
|
||||
* in that column with the specified color.
|
||||
*
|
||||
* - Limit the number of columns, similar to the way gitk does.
|
||||
* If we reach more than a specified number of columns, omit
|
||||
* sections of some columns.
|
||||
@@ -72,9 +69,10 @@ struct column {
|
||||
*/
|
||||
struct commit *commit;
|
||||
/*
|
||||
* XXX: Once we add support for colors, struct column could also
|
||||
* contain the color of its branch line.
|
||||
* The color to (optionally) print this column in. This is an
|
||||
* index into column_colors.
|
||||
*/
|
||||
unsigned short color;
|
||||
};
|
||||
|
||||
enum graph_state {
|
||||
@@ -86,6 +84,41 @@ enum graph_state {
|
||||
GRAPH_COLLAPSING
|
||||
};
|
||||
|
||||
/*
|
||||
* The list of available column colors.
|
||||
*/
|
||||
static char column_colors[][COLOR_MAXLEN] = {
|
||||
GIT_COLOR_RED,
|
||||
GIT_COLOR_GREEN,
|
||||
GIT_COLOR_YELLOW,
|
||||
GIT_COLOR_BLUE,
|
||||
GIT_COLOR_MAGENTA,
|
||||
GIT_COLOR_CYAN,
|
||||
GIT_COLOR_BOLD GIT_COLOR_RED,
|
||||
GIT_COLOR_BOLD GIT_COLOR_GREEN,
|
||||
GIT_COLOR_BOLD GIT_COLOR_YELLOW,
|
||||
GIT_COLOR_BOLD GIT_COLOR_BLUE,
|
||||
GIT_COLOR_BOLD GIT_COLOR_MAGENTA,
|
||||
GIT_COLOR_BOLD GIT_COLOR_CYAN,
|
||||
};
|
||||
|
||||
#define COLUMN_COLORS_MAX (ARRAY_SIZE(column_colors))
|
||||
|
||||
static const char *column_get_color_code(const struct column *c)
|
||||
{
|
||||
return column_colors[c->color];
|
||||
}
|
||||
|
||||
static void strbuf_write_column(struct strbuf *sb, const struct column *c,
|
||||
char col_char)
|
||||
{
|
||||
if (c->color < COLUMN_COLORS_MAX)
|
||||
strbuf_addstr(sb, column_get_color_code(c));
|
||||
strbuf_addch(sb, col_char);
|
||||
if (c->color < COLUMN_COLORS_MAX)
|
||||
strbuf_addstr(sb, GIT_COLOR_RESET);
|
||||
}
|
||||
|
||||
struct git_graph {
|
||||
/*
|
||||
* The commit currently being processed
|
||||
@@ -185,6 +218,11 @@ struct git_graph {
|
||||
* temporary array each time we have to output a collapsing line.
|
||||
*/
|
||||
int *new_mapping;
|
||||
/*
|
||||
* The current default column color being used. This is
|
||||
* stored as an index into the array column_colors.
|
||||
*/
|
||||
unsigned short default_column_color;
|
||||
};
|
||||
|
||||
struct git_graph *graph_init(struct rev_info *opt)
|
||||
@@ -201,6 +239,7 @@ struct git_graph *graph_init(struct rev_info *opt)
|
||||
graph->num_columns = 0;
|
||||
graph->num_new_columns = 0;
|
||||
graph->mapping_size = 0;
|
||||
graph->default_column_color = 0;
|
||||
|
||||
/*
|
||||
* Allocate a reasonably large default number of columns
|
||||
@@ -312,6 +351,33 @@ static struct commit_list *first_interesting_parent(struct git_graph *graph)
|
||||
return next_interesting_parent(graph, parents);
|
||||
}
|
||||
|
||||
static unsigned short graph_get_current_column_color(const struct git_graph *graph)
|
||||
{
|
||||
if (!DIFF_OPT_TST(&graph->revs->diffopt, COLOR_DIFF))
|
||||
return COLUMN_COLORS_MAX;
|
||||
return graph->default_column_color;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the graph's default column color.
|
||||
*/
|
||||
static void graph_increment_column_color(struct git_graph *graph)
|
||||
{
|
||||
graph->default_column_color = (graph->default_column_color + 1) %
|
||||
COLUMN_COLORS_MAX;
|
||||
}
|
||||
|
||||
static unsigned short graph_find_commit_color(const struct git_graph *graph,
|
||||
const struct commit *commit)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < graph->num_columns; i++) {
|
||||
if (graph->columns[i].commit == commit)
|
||||
return graph->columns[i].color;
|
||||
}
|
||||
return graph_get_current_column_color(graph);
|
||||
}
|
||||
|
||||
static void graph_insert_into_new_columns(struct git_graph *graph,
|
||||
struct commit *commit,
|
||||
int *mapping_index)
|
||||
@@ -334,6 +400,7 @@ static void graph_insert_into_new_columns(struct git_graph *graph,
|
||||
* This commit isn't already in new_columns. Add it.
|
||||
*/
|
||||
graph->new_columns[graph->num_new_columns].commit = commit;
|
||||
graph->new_columns[graph->num_new_columns].color = graph_find_commit_color(graph, commit);
|
||||
graph->mapping[*mapping_index] = graph->num_new_columns;
|
||||
*mapping_index += 2;
|
||||
graph->num_new_columns++;
|
||||
@@ -445,6 +512,12 @@ static void graph_update_columns(struct git_graph *graph)
|
||||
for (parent = first_interesting_parent(graph);
|
||||
parent;
|
||||
parent = next_interesting_parent(graph, parent)) {
|
||||
/*
|
||||
* If this is a merge increment the current
|
||||
* color.
|
||||
*/
|
||||
if (graph->num_parents > 1)
|
||||
graph_increment_column_color(graph);
|
||||
graph_insert_into_new_columns(graph,
|
||||
parent->item,
|
||||
&mapping_idx);
|
||||
@@ -560,7 +633,8 @@ static int graph_is_mapping_correct(struct git_graph *graph)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void graph_pad_horizontally(struct git_graph *graph, struct strbuf *sb)
|
||||
static void graph_pad_horizontally(struct git_graph *graph, struct strbuf *sb,
|
||||
int chars_written)
|
||||
{
|
||||
/*
|
||||
* Add additional spaces to the end of the strbuf, so that all
|
||||
@@ -570,10 +644,10 @@ static void graph_pad_horizontally(struct git_graph *graph, struct strbuf *sb)
|
||||
* aligned for the entire commit.
|
||||
*/
|
||||
int extra;
|
||||
if (sb->len >= graph->width)
|
||||
if (chars_written >= graph->width)
|
||||
return;
|
||||
|
||||
extra = graph->width - sb->len;
|
||||
extra = graph->width - chars_written;
|
||||
strbuf_addf(sb, "%*s", (int) extra, "");
|
||||
}
|
||||
|
||||
@@ -596,10 +670,11 @@ static void graph_output_padding_line(struct git_graph *graph,
|
||||
* Output a padding row, that leaves all branch lines unchanged
|
||||
*/
|
||||
for (i = 0; i < graph->num_new_columns; i++) {
|
||||
strbuf_addstr(sb, "| ");
|
||||
strbuf_write_column(sb, &graph->new_columns[i], '|');
|
||||
strbuf_addch(sb, ' ');
|
||||
}
|
||||
|
||||
graph_pad_horizontally(graph, sb);
|
||||
graph_pad_horizontally(graph, sb, graph->num_new_columns * 2);
|
||||
}
|
||||
|
||||
static void graph_output_skip_line(struct git_graph *graph, struct strbuf *sb)
|
||||
@@ -609,7 +684,7 @@ static void graph_output_skip_line(struct git_graph *graph, struct strbuf *sb)
|
||||
* of the graph is missing.
|
||||
*/
|
||||
strbuf_addstr(sb, "...");
|
||||
graph_pad_horizontally(graph, sb);
|
||||
graph_pad_horizontally(graph, sb, 3);
|
||||
|
||||
if (graph->num_parents >= 3 &&
|
||||
graph->commit_index < (graph->num_columns - 1))
|
||||
@@ -623,6 +698,7 @@ static void graph_output_pre_commit_line(struct git_graph *graph,
|
||||
{
|
||||
int num_expansion_rows;
|
||||
int i, seen_this;
|
||||
int chars_written;
|
||||
|
||||
/*
|
||||
* This function formats a row that increases the space around a commit
|
||||
@@ -645,11 +721,14 @@ static void graph_output_pre_commit_line(struct git_graph *graph,
|
||||
* Output the row
|
||||
*/
|
||||
seen_this = 0;
|
||||
chars_written = 0;
|
||||
for (i = 0; i < graph->num_columns; i++) {
|
||||
struct column *col = &graph->columns[i];
|
||||
if (col->commit == graph->commit) {
|
||||
seen_this = 1;
|
||||
strbuf_addf(sb, "| %*s", graph->expansion_row, "");
|
||||
strbuf_write_column(sb, col, '|');
|
||||
strbuf_addf(sb, " %*s", graph->expansion_row, "");
|
||||
chars_written += 2 + graph->expansion_row;
|
||||
} else if (seen_this && (graph->expansion_row == 0)) {
|
||||
/*
|
||||
* This is the first line of the pre-commit output.
|
||||
@@ -662,17 +741,22 @@ static void graph_output_pre_commit_line(struct git_graph *graph,
|
||||
*/
|
||||
if (graph->prev_state == GRAPH_POST_MERGE &&
|
||||
graph->prev_commit_index < i)
|
||||
strbuf_addstr(sb, "\\ ");
|
||||
strbuf_write_column(sb, col, '\\');
|
||||
else
|
||||
strbuf_addstr(sb, "| ");
|
||||
strbuf_write_column(sb, col, '|');
|
||||
chars_written++;
|
||||
} else if (seen_this && (graph->expansion_row > 0)) {
|
||||
strbuf_addstr(sb, "\\ ");
|
||||
strbuf_write_column(sb, col, '\\');
|
||||
chars_written++;
|
||||
} else {
|
||||
strbuf_addstr(sb, "| ");
|
||||
strbuf_write_column(sb, col, '|');
|
||||
chars_written++;
|
||||
}
|
||||
strbuf_addch(sb, ' ');
|
||||
chars_written++;
|
||||
}
|
||||
|
||||
graph_pad_horizontally(graph, sb);
|
||||
graph_pad_horizontally(graph, sb, chars_written);
|
||||
|
||||
/*
|
||||
* Increment graph->expansion_row,
|
||||
@@ -714,10 +798,34 @@ static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb)
|
||||
strbuf_addch(sb, '*');
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw an octopus merge and return the number of characters written.
|
||||
*/
|
||||
static int graph_draw_octopus_merge(struct git_graph *graph,
|
||||
struct strbuf *sb)
|
||||
{
|
||||
/*
|
||||
* Here dashless_commits represents the number of parents
|
||||
* which don't need to have dashes (because their edges fit
|
||||
* neatly under the commit).
|
||||
*/
|
||||
const int dashless_commits = 2;
|
||||
int col_num, i;
|
||||
int num_dashes =
|
||||
((graph->num_parents - dashless_commits) * 2) - 1;
|
||||
for (i = 0; i < num_dashes; i++) {
|
||||
col_num = (i / 2) + dashless_commits;
|
||||
strbuf_write_column(sb, &graph->new_columns[col_num], '-');
|
||||
}
|
||||
col_num = (i / 2) + dashless_commits;
|
||||
strbuf_write_column(sb, &graph->new_columns[col_num], '.');
|
||||
return num_dashes + 1;
|
||||
}
|
||||
|
||||
static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
|
||||
{
|
||||
int seen_this = 0;
|
||||
int i, j;
|
||||
int i, chars_written;
|
||||
|
||||
/*
|
||||
* Output the row containing this commit
|
||||
@@ -727,7 +835,9 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
|
||||
* children that we have already processed.)
|
||||
*/
|
||||
seen_this = 0;
|
||||
chars_written = 0;
|
||||
for (i = 0; i <= graph->num_columns; i++) {
|
||||
struct column *col = &graph->columns[i];
|
||||
struct commit *col_commit;
|
||||
if (i == graph->num_columns) {
|
||||
if (seen_this)
|
||||
@@ -740,18 +850,14 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
|
||||
if (col_commit == graph->commit) {
|
||||
seen_this = 1;
|
||||
graph_output_commit_char(graph, sb);
|
||||
chars_written++;
|
||||
|
||||
if (graph->num_parents < 3)
|
||||
strbuf_addch(sb, ' ');
|
||||
else {
|
||||
int num_dashes =
|
||||
((graph->num_parents - 2) * 2) - 1;
|
||||
for (j = 0; j < num_dashes; j++)
|
||||
strbuf_addch(sb, '-');
|
||||
strbuf_addstr(sb, ". ");
|
||||
}
|
||||
if (graph->num_parents > 3)
|
||||
chars_written += graph_draw_octopus_merge(graph,
|
||||
sb);
|
||||
} else if (seen_this && (graph->num_parents > 2)) {
|
||||
strbuf_addstr(sb, "\\ ");
|
||||
strbuf_write_column(sb, col, '\\');
|
||||
chars_written++;
|
||||
} else if (seen_this && (graph->num_parents == 2)) {
|
||||
/*
|
||||
* This is a 2-way merge commit.
|
||||
@@ -768,15 +874,19 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
|
||||
*/
|
||||
if (graph->prev_state == GRAPH_POST_MERGE &&
|
||||
graph->prev_commit_index < i)
|
||||
strbuf_addstr(sb, "\\ ");
|
||||
strbuf_write_column(sb, col, '\\');
|
||||
else
|
||||
strbuf_addstr(sb, "| ");
|
||||
strbuf_write_column(sb, col, '|');
|
||||
chars_written++;
|
||||
} else {
|
||||
strbuf_addstr(sb, "| ");
|
||||
strbuf_write_column(sb, col, '|');
|
||||
chars_written++;
|
||||
}
|
||||
strbuf_addch(sb, ' ');
|
||||
chars_written++;
|
||||
}
|
||||
|
||||
graph_pad_horizontally(graph, sb);
|
||||
graph_pad_horizontally(graph, sb, chars_written);
|
||||
|
||||
/*
|
||||
* Update graph->state
|
||||
@@ -789,37 +899,75 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
|
||||
graph_update_state(graph, GRAPH_COLLAPSING);
|
||||
}
|
||||
|
||||
static struct column *find_new_column_by_commit(struct git_graph *graph,
|
||||
struct commit *commit)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < graph->num_new_columns; i++) {
|
||||
if (graph->new_columns[i].commit == commit)
|
||||
return &graph->new_columns[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void graph_output_post_merge_line(struct git_graph *graph, struct strbuf *sb)
|
||||
{
|
||||
int seen_this = 0;
|
||||
int i, j;
|
||||
int i, j, chars_written;
|
||||
|
||||
/*
|
||||
* Output the post-merge row
|
||||
*/
|
||||
chars_written = 0;
|
||||
for (i = 0; i <= graph->num_columns; i++) {
|
||||
struct column *col = &graph->columns[i];
|
||||
struct commit *col_commit;
|
||||
if (i == graph->num_columns) {
|
||||
if (seen_this)
|
||||
break;
|
||||
col_commit = graph->commit;
|
||||
} else {
|
||||
col_commit = graph->columns[i].commit;
|
||||
col_commit = col->commit;
|
||||
}
|
||||
|
||||
if (col_commit == graph->commit) {
|
||||
/*
|
||||
* Since the current commit is a merge find
|
||||
* the columns for the parent commits in
|
||||
* new_columns and use those to format the
|
||||
* edges.
|
||||
*/
|
||||
struct commit_list *parents = NULL;
|
||||
struct column *par_column;
|
||||
seen_this = 1;
|
||||
strbuf_addch(sb, '|');
|
||||
for (j = 0; j < graph->num_parents - 1; j++)
|
||||
strbuf_addstr(sb, "\\ ");
|
||||
parents = first_interesting_parent(graph);
|
||||
assert(parents);
|
||||
par_column = find_new_column_by_commit(graph, parents->item);
|
||||
assert(par_column);
|
||||
|
||||
strbuf_write_column(sb, par_column, '|');
|
||||
chars_written++;
|
||||
for (j = 0; j < graph->num_parents - 1; j++) {
|
||||
parents = next_interesting_parent(graph, parents);
|
||||
assert(parents);
|
||||
par_column = find_new_column_by_commit(graph, parents->item);
|
||||
assert(par_column);
|
||||
strbuf_write_column(sb, par_column, '\\');
|
||||
strbuf_addch(sb, ' ');
|
||||
}
|
||||
chars_written += j * 2;
|
||||
} else if (seen_this) {
|
||||
strbuf_addstr(sb, "\\ ");
|
||||
strbuf_write_column(sb, col, '\\');
|
||||
strbuf_addch(sb, ' ');
|
||||
chars_written += 2;
|
||||
} else {
|
||||
strbuf_addstr(sb, "| ");
|
||||
strbuf_write_column(sb, col, '|');
|
||||
strbuf_addch(sb, ' ');
|
||||
chars_written += 2;
|
||||
}
|
||||
}
|
||||
|
||||
graph_pad_horizontally(graph, sb);
|
||||
graph_pad_horizontally(graph, sb, chars_written);
|
||||
|
||||
/*
|
||||
* Update graph->state
|
||||
@@ -912,12 +1060,12 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
|
||||
if (target < 0)
|
||||
strbuf_addch(sb, ' ');
|
||||
else if (target * 2 == i)
|
||||
strbuf_addch(sb, '|');
|
||||
strbuf_write_column(sb, &graph->new_columns[target], '|');
|
||||
else
|
||||
strbuf_addch(sb, '/');
|
||||
strbuf_write_column(sb, &graph->new_columns[target], '/');
|
||||
}
|
||||
|
||||
graph_pad_horizontally(graph, sb);
|
||||
graph_pad_horizontally(graph, sb, graph->mapping_size);
|
||||
|
||||
/*
|
||||
* Swap mapping and new_mapping
|
||||
@@ -979,9 +1127,10 @@ static void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
|
||||
* children that we have already processed.)
|
||||
*/
|
||||
for (i = 0; i < graph->num_columns; i++) {
|
||||
struct commit *col_commit = graph->columns[i].commit;
|
||||
struct column *col = &graph->columns[i];
|
||||
struct commit *col_commit = col->commit;
|
||||
if (col_commit == graph->commit) {
|
||||
strbuf_addch(sb, '|');
|
||||
strbuf_write_column(sb, col, '|');
|
||||
|
||||
if (graph->num_parents < 3)
|
||||
strbuf_addch(sb, ' ');
|
||||
@@ -991,11 +1140,12 @@ static void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
|
||||
strbuf_addch(sb, ' ');
|
||||
}
|
||||
} else {
|
||||
strbuf_addstr(sb, "| ");
|
||||
strbuf_write_column(sb, col, '|');
|
||||
strbuf_addch(sb, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
graph_pad_horizontally(graph, sb);
|
||||
graph_pad_horizontally(graph, sb, graph->num_columns);
|
||||
|
||||
/*
|
||||
* Update graph->prev_state since we have output a padding line
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
static void process_blob(struct rev_info *revs,
|
||||
struct blob *blob,
|
||||
struct object_array *p,
|
||||
show_object_fn show,
|
||||
struct name_path *path,
|
||||
const char *name)
|
||||
{
|
||||
@@ -23,7 +23,7 @@ static void process_blob(struct rev_info *revs,
|
||||
if (obj->flags & (UNINTERESTING | SEEN))
|
||||
return;
|
||||
obj->flags |= SEEN;
|
||||
add_object(obj, p, path, name);
|
||||
show(obj, path, name);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -50,7 +50,7 @@ static void process_blob(struct rev_info *revs,
|
||||
*/
|
||||
static void process_gitlink(struct rev_info *revs,
|
||||
const unsigned char *sha1,
|
||||
struct object_array *p,
|
||||
show_object_fn show,
|
||||
struct name_path *path,
|
||||
const char *name)
|
||||
{
|
||||
@@ -59,7 +59,7 @@ static void process_gitlink(struct rev_info *revs,
|
||||
|
||||
static void process_tree(struct rev_info *revs,
|
||||
struct tree *tree,
|
||||
struct object_array *p,
|
||||
show_object_fn show,
|
||||
struct name_path *path,
|
||||
const char *name)
|
||||
{
|
||||
@@ -77,7 +77,7 @@ static void process_tree(struct rev_info *revs,
|
||||
if (parse_tree(tree) < 0)
|
||||
die("bad tree object %s", sha1_to_hex(obj->sha1));
|
||||
obj->flags |= SEEN;
|
||||
add_object(obj, p, path, name);
|
||||
show(obj, path, name);
|
||||
me.up = path;
|
||||
me.elem = name;
|
||||
me.elem_len = strlen(name);
|
||||
@@ -88,14 +88,14 @@ static void process_tree(struct rev_info *revs,
|
||||
if (S_ISDIR(entry.mode))
|
||||
process_tree(revs,
|
||||
lookup_tree(entry.sha1),
|
||||
p, &me, entry.path);
|
||||
show, &me, entry.path);
|
||||
else if (S_ISGITLINK(entry.mode))
|
||||
process_gitlink(revs, entry.sha1,
|
||||
p, &me, entry.path);
|
||||
show, &me, entry.path);
|
||||
else
|
||||
process_blob(revs,
|
||||
lookup_blob(entry.sha1),
|
||||
p, &me, entry.path);
|
||||
show, &me, entry.path);
|
||||
}
|
||||
free(tree->buffer);
|
||||
tree->buffer = NULL;
|
||||
@@ -134,6 +134,11 @@ void mark_edges_uninteresting(struct commit_list *list,
|
||||
}
|
||||
}
|
||||
|
||||
static void add_pending_tree(struct rev_info *revs, struct tree *tree)
|
||||
{
|
||||
add_pending_object(revs, &tree->object, "");
|
||||
}
|
||||
|
||||
void traverse_commit_list(struct rev_info *revs,
|
||||
show_commit_fn show_commit,
|
||||
show_object_fn show_object,
|
||||
@@ -141,10 +146,9 @@ void traverse_commit_list(struct rev_info *revs,
|
||||
{
|
||||
int i;
|
||||
struct commit *commit;
|
||||
struct object_array objects = { 0, 0, NULL };
|
||||
|
||||
while ((commit = get_revision(revs)) != NULL) {
|
||||
process_tree(revs, commit->tree, &objects, NULL, "");
|
||||
add_pending_tree(revs, commit->tree);
|
||||
show_commit(commit, data);
|
||||
}
|
||||
for (i = 0; i < revs->pending.nr; i++) {
|
||||
@@ -155,25 +159,22 @@ void traverse_commit_list(struct rev_info *revs,
|
||||
continue;
|
||||
if (obj->type == OBJ_TAG) {
|
||||
obj->flags |= SEEN;
|
||||
add_object_array(obj, name, &objects);
|
||||
show_object(obj, NULL, name);
|
||||
continue;
|
||||
}
|
||||
if (obj->type == OBJ_TREE) {
|
||||
process_tree(revs, (struct tree *)obj, &objects,
|
||||
process_tree(revs, (struct tree *)obj, show_object,
|
||||
NULL, name);
|
||||
continue;
|
||||
}
|
||||
if (obj->type == OBJ_BLOB) {
|
||||
process_blob(revs, (struct blob *)obj, &objects,
|
||||
process_blob(revs, (struct blob *)obj, show_object,
|
||||
NULL, name);
|
||||
continue;
|
||||
}
|
||||
die("unknown pending object %s (%s)",
|
||||
sha1_to_hex(obj->sha1), name);
|
||||
}
|
||||
for (i = 0; i < objects.nr; i++)
|
||||
show_object(&objects.objects[i], data);
|
||||
free(objects.objects);
|
||||
if (revs->pending.nr) {
|
||||
free(revs->pending.objects);
|
||||
revs->pending.nr = 0;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define LIST_OBJECTS_H
|
||||
|
||||
typedef void (*show_commit_fn)(struct commit *, void *);
|
||||
typedef void (*show_object_fn)(struct object_array_entry *, void *);
|
||||
typedef void (*show_object_fn)(struct object *, const struct name_path *, const char *);
|
||||
typedef void (*show_edge_fn)(struct commit *);
|
||||
|
||||
void traverse_commit_list(struct rev_info *, show_commit_fn, show_object_fn, void *);
|
||||
|
||||
18
refs.c
18
refs.c
@@ -1681,7 +1681,7 @@ static void gen_scanf_fmt(char *scanf_fmt, const char *rule)
|
||||
return;
|
||||
}
|
||||
|
||||
char *shorten_unambiguous_ref(const char *ref)
|
||||
char *shorten_unambiguous_ref(const char *ref, int strict)
|
||||
{
|
||||
int i;
|
||||
static char **scanf_fmts;
|
||||
@@ -1718,6 +1718,7 @@ char *shorten_unambiguous_ref(const char *ref)
|
||||
/* skip first rule, it will always match */
|
||||
for (i = nr_rules - 1; i > 0 ; --i) {
|
||||
int j;
|
||||
int rules_to_fail = i;
|
||||
int short_name_len;
|
||||
|
||||
if (1 != sscanf(ref, scanf_fmts[i], short_name))
|
||||
@@ -1725,15 +1726,26 @@ char *shorten_unambiguous_ref(const char *ref)
|
||||
|
||||
short_name_len = strlen(short_name);
|
||||
|
||||
/*
|
||||
* in strict mode, all (except the matched one) rules
|
||||
* must fail to resolve to a valid non-ambiguous ref
|
||||
*/
|
||||
if (strict)
|
||||
rules_to_fail = nr_rules;
|
||||
|
||||
/*
|
||||
* check if the short name resolves to a valid ref,
|
||||
* but use only rules prior to the matched one
|
||||
*/
|
||||
for (j = 0; j < i; j++) {
|
||||
for (j = 0; j < rules_to_fail; j++) {
|
||||
const char *rule = ref_rev_parse_rules[j];
|
||||
unsigned char short_objectname[20];
|
||||
char refname[PATH_MAX];
|
||||
|
||||
/* skip matched rule */
|
||||
if (i == j)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* the short name is ambiguous, if it resolves
|
||||
* (with this previous rule) to a valid ref
|
||||
@@ -1749,7 +1761,7 @@ char *shorten_unambiguous_ref(const char *ref)
|
||||
* short name is non-ambiguous if all previous rules
|
||||
* haven't resolved to a valid ref
|
||||
*/
|
||||
if (j == i)
|
||||
if (j == rules_to_fail)
|
||||
return short_name;
|
||||
}
|
||||
|
||||
|
||||
2
refs.h
2
refs.h
@@ -81,7 +81,7 @@ extern int for_each_reflog(each_ref_fn, void *);
|
||||
extern int check_ref_format(const char *target);
|
||||
|
||||
extern const char *prettify_ref(const struct ref *ref);
|
||||
extern char *shorten_unambiguous_ref(const char *ref);
|
||||
extern char *shorten_unambiguous_ref(const char *ref, int strict);
|
||||
|
||||
/** rename ref, return 0 on success **/
|
||||
extern int rename_ref(const char *oldref, const char *newref, const char *logmsg);
|
||||
|
||||
8
remote.c
8
remote.c
@@ -1461,11 +1461,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
|
||||
return 0;
|
||||
|
||||
base = branch->merge[0]->dst;
|
||||
if (!prefixcmp(base, "refs/remotes/")) {
|
||||
base += strlen("refs/remotes/");
|
||||
} else if (!prefixcmp(base, "refs/heads/")) {
|
||||
base += strlen("refs/heads/");
|
||||
}
|
||||
base = shorten_unambiguous_ref(base, 0);
|
||||
if (!num_theirs)
|
||||
strbuf_addf(sb, "Your branch is ahead of '%s' "
|
||||
"by %d commit%s.\n",
|
||||
@@ -1504,7 +1500,7 @@ static int one_local_ref(const char *refname, const unsigned char *sha1, int fla
|
||||
|
||||
struct ref *get_local_heads(void)
|
||||
{
|
||||
struct ref *local_refs, **local_tail = &local_refs;
|
||||
struct ref *local_refs = NULL, **local_tail = &local_refs;
|
||||
for_each_ref(one_local_ref, &local_tail);
|
||||
return local_refs;
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
|
||||
volatile show_early_output_fn_t show_early_output;
|
||||
|
||||
static char *path_name(struct name_path *path, const char *name)
|
||||
char *path_name(const struct name_path *path, const char *name)
|
||||
{
|
||||
struct name_path *p;
|
||||
const struct name_path *p;
|
||||
char *n, *m;
|
||||
int nlen = strlen(name);
|
||||
int len = nlen + 1;
|
||||
|
||||
@@ -146,6 +146,8 @@ struct name_path {
|
||||
const char *elem;
|
||||
};
|
||||
|
||||
char *path_name(const struct name_path *path, const char *name);
|
||||
|
||||
extern void add_object(struct object *obj,
|
||||
struct object_array *p,
|
||||
struct name_path *path,
|
||||
|
||||
1
shell.c
1
shell.c
@@ -40,6 +40,7 @@ static struct commands {
|
||||
} cmd_list[] = {
|
||||
{ "git-receive-pack", do_generic_cmd },
|
||||
{ "git-upload-pack", do_generic_cmd },
|
||||
{ "git-upload-archive", do_generic_cmd },
|
||||
{ "cvs", do_cvs_cmd },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
@@ -199,4 +199,13 @@ test_expect_success 'init honors global core.sharedRepository' '
|
||||
x`git config -f shared-honor-global/.git/config core.sharedRepository`
|
||||
'
|
||||
|
||||
test_expect_success 'init rejects insanely long --template' '
|
||||
(
|
||||
insane=$(printf "x%09999dx" 1) &&
|
||||
mkdir test &&
|
||||
cd test &&
|
||||
test_must_fail git init --template=$insane
|
||||
)
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -10,7 +10,7 @@ setup() {
|
||||
|
||||
check() {
|
||||
echo "$2" >expected
|
||||
git config --get "$1" >actual
|
||||
git config --get "$1" >actual 2>&1
|
||||
test_cmp actual expected
|
||||
}
|
||||
|
||||
@@ -40,4 +40,11 @@ test_expect_success 'make sure git config escapes section names properly' '
|
||||
check "$SECTION" bar
|
||||
'
|
||||
|
||||
LONG_VALUE=$(printf "x%01021dx a" 7)
|
||||
test_expect_success 'do not crash on special long config line' '
|
||||
setup &&
|
||||
git config section.key "$LONG_VALUE" &&
|
||||
check section.key "fatal: bad config file line 2 in .git/config"
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
38
t/t4130-apply-criss-cross-rename.sh
Executable file
38
t/t4130-apply-criss-cross-rename.sh
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='git apply handling criss-cross rename patch.'
|
||||
. ./test-lib.sh
|
||||
|
||||
create_file() {
|
||||
cnt=0
|
||||
while test $cnt -le 100
|
||||
do
|
||||
cnt=$(($cnt + 1))
|
||||
echo "$2" >> "$1"
|
||||
done
|
||||
}
|
||||
|
||||
test_expect_success 'setup' '
|
||||
create_file file1 "File1 contents" &&
|
||||
create_file file2 "File2 contents" &&
|
||||
git add file1 file2 &&
|
||||
git commit -m 1
|
||||
'
|
||||
|
||||
test_expect_success 'criss-cross rename' '
|
||||
mv file1 tmp &&
|
||||
mv file2 file1 &&
|
||||
mv tmp file2
|
||||
'
|
||||
|
||||
test_expect_success 'diff -M -B' '
|
||||
git diff -M -B > diff &&
|
||||
git reset --hard
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'apply' '
|
||||
git apply diff
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -294,4 +294,19 @@ test_expect_success 'am --ignore-date' '
|
||||
echo "$at" | grep "+0000"
|
||||
'
|
||||
|
||||
test_expect_success 'am into an unborn branch' '
|
||||
rm -fr subdir &&
|
||||
mkdir -p subdir &&
|
||||
git format-patch --numbered-files -o subdir -1 first &&
|
||||
(
|
||||
cd subdir &&
|
||||
git init &&
|
||||
git am 1
|
||||
) &&
|
||||
result=$(
|
||||
cd subdir && git rev-parse HEAD^{tree}
|
||||
) &&
|
||||
test "z$result" = "z$(git rev-parse first^{tree})"
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -50,7 +50,7 @@ test_expect_success \
|
||||
test_expect_success \
|
||||
'add ignored file' \
|
||||
'echo ignore me >a/ignored &&
|
||||
echo ignored export-ignore >.gitattributes'
|
||||
echo ignored export-ignore >.git/info/attributes'
|
||||
|
||||
test_expect_success \
|
||||
'add files to repository' \
|
||||
@@ -64,7 +64,7 @@ test_expect_success \
|
||||
test_expect_success \
|
||||
'create bare clone' \
|
||||
'git clone --bare . bare.git &&
|
||||
cp .gitattributes bare.git/info/attributes'
|
||||
cp .git/info/attributes bare.git/info/attributes'
|
||||
|
||||
test_expect_success \
|
||||
'remove ignored file' \
|
||||
@@ -139,10 +139,11 @@ test_expect_success \
|
||||
|
||||
test_expect_success \
|
||||
'create archives with substfiles' \
|
||||
'echo "substfile?" export-subst >a/.gitattributes &&
|
||||
'cp .git/info/attributes .git/info/attributes.before &&
|
||||
echo "substfile?" export-subst >>.git/info/attributes &&
|
||||
git archive HEAD >f.tar &&
|
||||
git archive --prefix=prefix/ HEAD >g.tar &&
|
||||
rm a/.gitattributes'
|
||||
mv .git/info/attributes.before .git/info/attributes'
|
||||
|
||||
test_expect_success \
|
||||
'extract substfiles' \
|
||||
|
||||
91
t/t5001-archive-attr.sh
Executable file
91
t/t5001-archive-attr.sh
Executable file
@@ -0,0 +1,91 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='git archive attribute tests'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
SUBSTFORMAT=%H%n
|
||||
|
||||
test_expect_exists() {
|
||||
test_expect_success " $1 exists" "test -e $1"
|
||||
}
|
||||
|
||||
test_expect_missing() {
|
||||
test_expect_success " $1 does not exist" "test ! -e $1"
|
||||
}
|
||||
|
||||
test_expect_success 'setup' '
|
||||
echo ignored >ignored &&
|
||||
echo ignored export-ignore >>.git/info/attributes &&
|
||||
git add ignored &&
|
||||
|
||||
echo ignored by tree >ignored-by-tree &&
|
||||
echo ignored-by-tree export-ignore >.gitattributes &&
|
||||
git add ignored-by-tree .gitattributes &&
|
||||
|
||||
echo ignored by worktree >ignored-by-worktree &&
|
||||
echo ignored-by-worktree export-ignore >.gitattributes &&
|
||||
git add ignored-by-worktree &&
|
||||
|
||||
printf "A\$Format:%s\$O" "$SUBSTFORMAT" >nosubstfile &&
|
||||
printf "A\$Format:%s\$O" "$SUBSTFORMAT" >substfile1 &&
|
||||
printf "A not substituted O" >substfile2 &&
|
||||
echo "substfile?" export-subst >>.git/info/attributes &&
|
||||
git add nosubstfile substfile1 substfile2 &&
|
||||
|
||||
git commit -m. &&
|
||||
|
||||
git clone --bare . bare &&
|
||||
cp .git/info/attributes bare/info/attributes
|
||||
'
|
||||
|
||||
test_expect_success 'git archive' '
|
||||
git archive HEAD >archive.tar &&
|
||||
(mkdir archive && cd archive && "$TAR" xf -) <archive.tar
|
||||
'
|
||||
|
||||
test_expect_missing archive/ignored
|
||||
test_expect_missing archive/ignored-by-tree
|
||||
test_expect_exists archive/ignored-by-worktree
|
||||
|
||||
test_expect_success 'git archive with worktree attributes' '
|
||||
git archive --worktree-attributes HEAD >worktree.tar &&
|
||||
(mkdir worktree && cd worktree && "$TAR" xf -) <worktree.tar
|
||||
'
|
||||
|
||||
test_expect_missing worktree/ignored
|
||||
test_expect_exists worktree/ignored-by-tree
|
||||
test_expect_missing worktree/ignored-by-worktree
|
||||
|
||||
test_expect_success 'git archive vs. bare' '
|
||||
(cd bare && git archive HEAD) >bare-archive.tar &&
|
||||
test_cmp archive.tar bare-archive.tar
|
||||
'
|
||||
|
||||
test_expect_success 'git archive with worktree attributes, bare' '
|
||||
(cd bare && git archive --worktree-attributes HEAD) >bare-worktree.tar &&
|
||||
(mkdir bare-worktree && cd bare-worktree && "$TAR" xf -) <bare-worktree.tar
|
||||
'
|
||||
|
||||
test_expect_missing bare-worktree/ignored
|
||||
test_expect_exists bare-worktree/ignored-by-tree
|
||||
test_expect_exists bare-worktree/ignored-by-worktree
|
||||
|
||||
test_expect_success 'export-subst' '
|
||||
git log "--pretty=format:A${SUBSTFORMAT}O" HEAD >substfile1.expected &&
|
||||
test_cmp nosubstfile archive/nosubstfile &&
|
||||
test_cmp substfile1.expected archive/substfile1 &&
|
||||
test_cmp substfile2 archive/substfile2
|
||||
'
|
||||
|
||||
test_expect_success 'git tar-tree vs. git archive with worktree attributes' '
|
||||
git tar-tree HEAD >tar-tree.tar &&
|
||||
test_cmp worktree.tar tar-tree.tar
|
||||
'
|
||||
|
||||
test_expect_success 'git tar-tree vs. git archive with worktree attrs, bare' '
|
||||
(cd bare && git tar-tree HEAD) >bare-tar-tree.tar &&
|
||||
test_cmp bare-worktree.tar bare-tar-tree.tar
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -301,10 +301,11 @@ test_expect_success 'Check for invalid refname format' '
|
||||
|
||||
cat >expected <<\EOF
|
||||
heads/master
|
||||
master
|
||||
tags/master
|
||||
EOF
|
||||
|
||||
test_expect_success 'Check ambiguous head and tag refs' '
|
||||
test_expect_success 'Check ambiguous head and tag refs (strict)' '
|
||||
git config --bool core.warnambiguousrefs true &&
|
||||
git checkout -b newtag &&
|
||||
echo "Using $datestamp" > one &&
|
||||
git add one &&
|
||||
@@ -315,12 +316,23 @@ test_expect_success 'Check ambiguous head and tag refs' '
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
cat >expected <<\EOF
|
||||
heads/master
|
||||
master
|
||||
EOF
|
||||
|
||||
test_expect_success 'Check ambiguous head and tag refs (loose)' '
|
||||
git config --bool core.warnambiguousrefs false &&
|
||||
git for-each-ref --format "%(refname:short)" refs/heads/master refs/tags/master >actual &&
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
cat >expected <<\EOF
|
||||
heads/ambiguous
|
||||
ambiguous
|
||||
EOF
|
||||
|
||||
test_expect_success 'Check ambiguous head and tag refs II' '
|
||||
test_expect_success 'Check ambiguous head and tag refs II (loose)' '
|
||||
git checkout master &&
|
||||
git tag ambiguous testtag^0 &&
|
||||
git branch ambiguous testtag^0 &&
|
||||
|
||||
211
t/t7800-difftool.sh
Executable file
211
t/t7800-difftool.sh
Executable file
@@ -0,0 +1,211 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2009 David Aguilar
|
||||
#
|
||||
|
||||
test_description='git-difftool
|
||||
|
||||
Testing basic diff tool invocation
|
||||
'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
remove_config_vars()
|
||||
{
|
||||
# Unset all config variables used by git-difftool
|
||||
git config --unset diff.tool
|
||||
git config --unset difftool.test-tool.cmd
|
||||
git config --unset difftool.prompt
|
||||
git config --unset merge.tool
|
||||
git config --unset mergetool.test-tool.cmd
|
||||
return 0
|
||||
}
|
||||
|
||||
restore_test_defaults()
|
||||
{
|
||||
# Restores the test defaults used by several tests
|
||||
remove_config_vars
|
||||
unset GIT_DIFF_TOOL
|
||||
unset GIT_MERGE_TOOL
|
||||
unset GIT_DIFFTOOL_PROMPT
|
||||
unset GIT_DIFFTOOL_NO_PROMPT
|
||||
git config diff.tool test-tool &&
|
||||
git config difftool.test-tool.cmd 'cat $LOCAL'
|
||||
}
|
||||
|
||||
prompt_given()
|
||||
{
|
||||
prompt="$1"
|
||||
test "$prompt" = "Hit return to launch 'test-tool': branch"
|
||||
}
|
||||
|
||||
# Create a file on master and change it on branch
|
||||
test_expect_success 'setup' '
|
||||
echo master >file &&
|
||||
git add file &&
|
||||
git commit -m "added file" &&
|
||||
|
||||
git checkout -b branch master &&
|
||||
echo branch >file &&
|
||||
git commit -a -m "branch changed file" &&
|
||||
git checkout master
|
||||
'
|
||||
|
||||
# Configure a custom difftool.<tool>.cmd and use it
|
||||
test_expect_success 'custom commands' '
|
||||
restore_test_defaults &&
|
||||
git config difftool.test-tool.cmd "cat \$REMOTE" &&
|
||||
|
||||
diff=$(git difftool --no-prompt branch) &&
|
||||
test "$diff" = "master" &&
|
||||
|
||||
restore_test_defaults &&
|
||||
diff=$(git difftool --no-prompt branch) &&
|
||||
test "$diff" = "branch"
|
||||
'
|
||||
|
||||
# Ensures that git-difftool ignores bogus --tool values
|
||||
test_expect_success 'difftool ignores bad --tool values' '
|
||||
diff=$(git difftool --no-prompt --tool=bogus-tool branch)
|
||||
test "$?" = 1 &&
|
||||
test "$diff" = ""
|
||||
'
|
||||
|
||||
# Specify the diff tool using $GIT_DIFF_TOOL
|
||||
test_expect_success 'GIT_DIFF_TOOL variable' '
|
||||
git config --unset diff.tool
|
||||
GIT_DIFF_TOOL=test-tool &&
|
||||
export GIT_DIFF_TOOL &&
|
||||
|
||||
diff=$(git difftool --no-prompt branch) &&
|
||||
test "$diff" = "branch" &&
|
||||
|
||||
restore_test_defaults
|
||||
'
|
||||
|
||||
# Test the $GIT_*_TOOL variables and ensure
|
||||
# that $GIT_DIFF_TOOL always wins unless --tool is specified
|
||||
test_expect_success 'GIT_DIFF_TOOL overrides' '
|
||||
git config diff.tool bogus-tool &&
|
||||
git config merge.tool bogus-tool &&
|
||||
|
||||
GIT_MERGE_TOOL=test-tool &&
|
||||
export GIT_MERGE_TOOL &&
|
||||
diff=$(git difftool --no-prompt branch) &&
|
||||
test "$diff" = "branch" &&
|
||||
unset GIT_MERGE_TOOL &&
|
||||
|
||||
GIT_MERGE_TOOL=bogus-tool &&
|
||||
GIT_DIFF_TOOL=test-tool &&
|
||||
export GIT_MERGE_TOOL &&
|
||||
export GIT_DIFF_TOOL &&
|
||||
|
||||
diff=$(git difftool --no-prompt branch) &&
|
||||
test "$diff" = "branch" &&
|
||||
|
||||
GIT_DIFF_TOOL=bogus-tool &&
|
||||
export GIT_DIFF_TOOL &&
|
||||
|
||||
diff=$(git difftool --no-prompt --tool=test-tool branch) &&
|
||||
test "$diff" = "branch" &&
|
||||
|
||||
restore_test_defaults
|
||||
'
|
||||
|
||||
# Test that we don't have to pass --no-prompt to difftool
|
||||
# when $GIT_DIFFTOOL_NO_PROMPT is true
|
||||
test_expect_success 'GIT_DIFFTOOL_NO_PROMPT variable' '
|
||||
GIT_DIFFTOOL_NO_PROMPT=true &&
|
||||
export GIT_DIFFTOOL_NO_PROMPT &&
|
||||
|
||||
diff=$(git difftool branch) &&
|
||||
test "$diff" = "branch" &&
|
||||
|
||||
restore_test_defaults
|
||||
'
|
||||
|
||||
# git-difftool supports the difftool.prompt variable.
|
||||
# Test that GIT_DIFFTOOL_PROMPT can override difftool.prompt = false
|
||||
test_expect_success 'GIT_DIFFTOOL_PROMPT variable' '
|
||||
git config difftool.prompt false &&
|
||||
GIT_DIFFTOOL_PROMPT=true &&
|
||||
export GIT_DIFFTOOL_PROMPT &&
|
||||
|
||||
prompt=$(echo | git difftool --prompt branch | tail -1) &&
|
||||
prompt_given "$prompt" &&
|
||||
|
||||
restore_test_defaults
|
||||
'
|
||||
|
||||
# Test that we don't have to pass --no-prompt when difftool.prompt is false
|
||||
test_expect_success 'difftool.prompt config variable is false' '
|
||||
git config difftool.prompt false &&
|
||||
|
||||
diff=$(git difftool branch) &&
|
||||
test "$diff" = "branch" &&
|
||||
|
||||
restore_test_defaults
|
||||
'
|
||||
|
||||
# Test that the -y flag can override difftool.prompt = true
|
||||
test_expect_success 'difftool.prompt can overridden with -y' '
|
||||
git config difftool.prompt true &&
|
||||
|
||||
diff=$(git difftool -y branch) &&
|
||||
test "$diff" = "branch" &&
|
||||
|
||||
restore_test_defaults
|
||||
'
|
||||
|
||||
# Test that the --prompt flag can override difftool.prompt = false
|
||||
test_expect_success 'difftool.prompt can overridden with --prompt' '
|
||||
git config difftool.prompt false &&
|
||||
|
||||
prompt=$(echo | git difftool --prompt branch | tail -1) &&
|
||||
prompt_given "$prompt" &&
|
||||
|
||||
restore_test_defaults
|
||||
'
|
||||
|
||||
# Test that the last flag passed on the command-line wins
|
||||
test_expect_success 'difftool last flag wins' '
|
||||
diff=$(git difftool --prompt --no-prompt branch) &&
|
||||
test "$diff" = "branch" &&
|
||||
|
||||
restore_test_defaults &&
|
||||
|
||||
prompt=$(echo | git difftool --no-prompt --prompt branch | tail -1) &&
|
||||
prompt_given "$prompt" &&
|
||||
|
||||
restore_test_defaults
|
||||
'
|
||||
|
||||
# git-difftool falls back to git-mergetool config variables
|
||||
# so test that behavior here
|
||||
test_expect_success 'difftool + mergetool config variables' '
|
||||
remove_config_vars
|
||||
git config merge.tool test-tool &&
|
||||
git config mergetool.test-tool.cmd "cat \$LOCAL" &&
|
||||
|
||||
diff=$(git difftool --no-prompt branch) &&
|
||||
test "$diff" = "branch" &&
|
||||
|
||||
# set merge.tool to something bogus, diff.tool to test-tool
|
||||
git config merge.tool bogus-tool &&
|
||||
git config diff.tool test-tool &&
|
||||
|
||||
diff=$(git difftool --no-prompt branch) &&
|
||||
test "$diff" = "branch" &&
|
||||
|
||||
restore_test_defaults
|
||||
'
|
||||
|
||||
test_expect_success 'difftool.<tool>.path' '
|
||||
git config difftool.tkdiff.path echo &&
|
||||
diff=$(git difftool --tool=tkdiff --no-prompt branch) &&
|
||||
git config --unset difftool.tkdiff.path &&
|
||||
lines=$(echo "$diff" | grep file | wc -l) &&
|
||||
test "$lines" -eq 1
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -16,6 +16,9 @@
|
||||
# hooks.allowdeletebranch
|
||||
# This boolean sets whether deleting branches will be allowed in the
|
||||
# repository. By default they won't be.
|
||||
# hooks.denycreatebranch
|
||||
# This boolean sets whether remotely creating branches will be denied
|
||||
# in the repository. By default this is allowed.
|
||||
#
|
||||
|
||||
# --- Command line
|
||||
@@ -39,6 +42,7 @@ fi
|
||||
# --- Config
|
||||
allowunannotated=$(git config --bool hooks.allowunannotated)
|
||||
allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
|
||||
denycreatebranch=$(git config --bool hooks.denycreatebranch)
|
||||
allowdeletetag=$(git config --bool hooks.allowdeletetag)
|
||||
|
||||
# check for no description
|
||||
@@ -52,7 +56,8 @@ esac
|
||||
|
||||
# --- Check types
|
||||
# if $newrev is 0000...0000, it's a commit to delete a ref.
|
||||
if [ "$newrev" = "0000000000000000000000000000000000000000" ]; then
|
||||
zero="0000000000000000000000000000000000000000"
|
||||
if [ "$newrev" = "$zero" ]; then
|
||||
newrev_type=delete
|
||||
else
|
||||
newrev_type=$(git-cat-file -t $newrev)
|
||||
@@ -80,6 +85,10 @@ case "$refname","$newrev_type" in
|
||||
;;
|
||||
refs/heads/*,commit)
|
||||
# branch
|
||||
if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
|
||||
echo "*** Creating a branch is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/heads/*,delete)
|
||||
# delete branch
|
||||
|
||||
@@ -87,7 +87,8 @@ static int check_updates(struct unpack_trees_options *o)
|
||||
cnt = 0;
|
||||
}
|
||||
|
||||
git_attr_set_direction(GIT_ATTR_CHECKOUT, &o->result);
|
||||
if (o->update)
|
||||
git_attr_set_direction(GIT_ATTR_CHECKOUT, &o->result);
|
||||
for (i = 0; i < index->cache_nr; i++) {
|
||||
struct cache_entry *ce = index->cache[i];
|
||||
|
||||
@@ -112,7 +113,8 @@ static int check_updates(struct unpack_trees_options *o)
|
||||
}
|
||||
}
|
||||
stop_progress(&progress);
|
||||
git_attr_set_direction(GIT_ATTR_CHECKIN, NULL);
|
||||
if (o->update)
|
||||
git_attr_set_direction(GIT_ATTR_CHECKIN, NULL);
|
||||
return errs != 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,20 +78,22 @@ static void show_commit(struct commit *commit, void *data)
|
||||
commit->buffer = NULL;
|
||||
}
|
||||
|
||||
static void show_object(struct object_array_entry *p, void *data)
|
||||
static void show_object(struct object *obj, const struct name_path *path, const char *component)
|
||||
{
|
||||
/* An object with name "foo\n0000000..." can be used to
|
||||
* confuse downstream git-pack-objects very badly.
|
||||
*/
|
||||
const char *ep = strchr(p->name, '\n');
|
||||
const char *name = path_name(path, component);
|
||||
const char *ep = strchr(name, '\n');
|
||||
if (ep) {
|
||||
fprintf(pack_pipe, "%s %.*s\n", sha1_to_hex(p->item->sha1),
|
||||
(int) (ep - p->name),
|
||||
p->name);
|
||||
fprintf(pack_pipe, "%s %.*s\n", sha1_to_hex(obj->sha1),
|
||||
(int) (ep - name),
|
||||
name);
|
||||
}
|
||||
else
|
||||
fprintf(pack_pipe, "%s %s\n",
|
||||
sha1_to_hex(p->item->sha1), p->name);
|
||||
sha1_to_hex(obj->sha1), name);
|
||||
free((char *)name);
|
||||
}
|
||||
|
||||
static void show_edge(struct commit *commit)
|
||||
|
||||
Reference in New Issue
Block a user