pax_global_header00006660000000000000000000000064135674326450014531gustar00rootroot0000000000000052 comment=f363095be67a04b48542f6518bbc3dfd99c77a00 git-cola-3.6/000077500000000000000000000000001356743264500131005ustar00rootroot00000000000000git-cola-3.6/.gitignore000066400000000000000000000004171356743264500150720ustar00rootroot00000000000000/.cache /.coverage /.idea /build /config.mak /cola/_build_version.py /dist /env* /git-cola.app /git_cola.egg-info /local /Meta /pynsist_pkgs /.pytest_cache /README.html /share/locale /test/tmp /tags /.tox __pycache__ .DS_Store .noseids *.gz *.py[cod] *.qm *.swp *.zip *~ git-cola-3.6/.mailmap000066400000000000000000000014411356743264500145210ustar00rootroot00000000000000AJ Bagwell 林博仁(Buo-ren Lin) David Martínez Martí David Aguilar Javier Rodriguez Cuevas Javier Rodriguez Cuevas Mickael Albertus Minarto Margoliono Minarto Margoliono Pilar Molina Lopez Szymon Judasz Szymon Judasz V字龍(Vdragon) Vitor Lobo Vitor Lobo Zhang Han git-cola-3.6/.pylintrc000066400000000000000000000261041356743264500147500ustar00rootroot00000000000000[MASTER] # Specify a configuration file. #rcfile= # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). #init-hook= # Add files or directories to the blacklist. They should be base names, not # paths. ignore=.git,sphinxtogithub # Pickle collected data for later comparisons. persistent=yes # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. load-plugins= # Use multiple processes to speed up Pylint. jobs=2 # Allow loading of arbitrary C extensions. Extensions are imported into the # active Python interpreter and may run arbitrary code. unsafe-load-any-extension=no # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code extension-pkg-whitelist=PyQt5,PyQt4,PySide,PySide2 # Allow optimization of some AST trees. This will activate a peephole AST # optimizer, which will apply various small optimizations. For instance, it can # be used to obtain the result of joining multiple strings with the addition # operator. Joining a lot of strings can lead to a maximum recursion error in # Pylint and this flag can prevent that. It has one side effect, the resulting # AST will be different than the one from reality. optimize-ast=no [MESSAGES CONTROL] # Only show warnings with the listed confidence levels. Leave empty to show # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED confidence= # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option # multiple time. See also the "--disable" option for examples. #enable= # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifiers separated by comma (,) or put this # option multiple times (only on the command line, not in the configuration # file where it should appear only once).You can also use "--disable=all" to # disable everything first and then reenable specific checks. For example, if # you want to run only the similarities checker, you can use "--disable=all # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" disable=assignment-from-none,bad-continuation,consider-using-dict-comprehension,consider-using-set-comprehension,fixme,wrong-import-position,invalid-name,missing-docstring,no-else-return,too-many-instance-attributes,useless-object-inheritance [REPORTS] # Set the output format. Available formats are text, parseable, colorized, msvs # (visual studio) and html. You can also give a reporter class, eg # mypackage.mymodule.MyReporterClass. output-format=text # Put messages in a separate file for each module / package specified on the # command line instead of printing them on stdout. Reports (if any) will be # written in a file name "pylint_global.[txt|html]". files-output=no # Tells whether to display a full report or only the messages reports=no # Python expression which should return a note less than 10 (10 is the highest # note). You have access to the variables errors warning, statement which # respectively contain the number of errors / warnings messages and the total # number of statements analyzed. This is used by the global evaluation report # (RP0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) # Template used to display messages. This is a python new-style format string # used to format the message information. See doc for all details msg-template={path}:{line}:{column}: {msg} ({symbol}) [BASIC] # List of builtins function names that should not be used, separated by a comma bad-functions=map,filter,input # Good variable names which should always be accepted, separated by a comma good-names=i,j,k,ex,Run,_ # Bad variable names which should always be refused, separated by a comma bad-names=foo,bar,baz,toto,tutu,tata # Colon-delimited sets of names that determine each other's naming style when # the name regexes allow several styles. name-group= # Include a hint for the correct naming format with invalid-name include-naming-hint=yes # Regular expression matching correct function names function-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for function names function-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct variable names variable-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for variable names variable-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct constant names const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ # Naming hint for constant names const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ # Regular expression matching correct attribute names attr-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for attribute names attr-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct argument names argument-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for argument names argument-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct class attribute names class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ # Naming hint for class attribute names class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ # Regular expression matching correct inline iteration names inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ # Naming hint for inline iteration names inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ # Regular expression matching correct class names class-rgx=[A-Z_][a-zA-Z0-9]+$ # Naming hint for class names class-name-hint=[A-Z_][a-zA-Z0-9]+$ # Regular expression matching correct module names module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ # Naming hint for module names module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ # Regular expression matching correct method names method-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for method names method-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match function or class names that do # not require a docstring. no-docstring-rgx=__.*__ # Minimum line length for functions/classes that require docstrings, shorter # ones are exempt. docstring-min-length=-1 [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME,XXX,TODO [FORMAT] # Maximum number of characters on a single line. max-line-length=80 # Regexp for a line that is allowed to be longer than the limit. ignore-long-lines=^\s*(# )??$ # Allow the body of an if to be on the same line as the test if there is no # else. single-line-if-stmt=no # List of optional constructs for which whitespace checking is disabled no-space-check= # Maximum number of lines in a module max-module-lines=3000 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). indent-string=' ' # Number of spaces of indent required inside a hanging or continued line. indent-after-paren=4 # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. expected-line-ending-format=LF [TYPECHECK] # Tells whether missing members accessed in mixin class should be ignored. A # mixin class is detected if its name ends with "mixin" (case insensitive). ignore-mixin-members=yes # List of module names for which member attributes should not be checked # (useful for modules/projects where namespaces are manipulated during runtime # and thus existing member attributes cannot be deduced by static analysis ignored-modules= # List of classes names for which member attributes should not be checked # (useful for classes with attributes dynamically set). ignored-classes= # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E0201 when accessed. Python regular # expressions are accepted. generated-members= [SIMILARITIES] # Minimum lines number of a similarity. min-similarity-lines=4 # Ignore comments when computing similarities. ignore-comments=yes # Ignore docstrings when computing similarities. ignore-docstrings=yes # Ignore imports when computing similarities. ignore-imports=no [SPELLING] # Spelling dictionary name. Available dictionaries: none. To make it working # install python-enchant package. spelling-dict= # List of comma separated words that should not be checked. spelling-ignore-words= # A path to a file that contains private dictionary; one word per line. spelling-private-dict-file= # Tells whether to store unknown words to indicated private dictionary in # --spelling-private-dict-file option instead of raising a message. spelling-store-unknown-words=no [LOGGING] # Logging modules to check that the string format arguments are in logging # function parameter format logging-modules=logging [VARIABLES] # Tells whether we should check for unused import in __init__ files. init-import=no # A regular expression matching the name of dummy variables (i.e. expectedly # not used). dummy-variables-rgx=_$|dummy # List of additional names supposed to be defined in builtins. Remember that # you should avoid to define new builtins when possible. additional-builtins= # List of strings which can identify a callback function by name. A callback # name must start or end with one of those strings. callbacks=cb_,_cb [CLASSES] # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__,__new__,setUp # List of valid names for the first argument in a class method. valid-classmethod-first-arg=cls # List of valid names for the first argument in a metaclass class method. valid-metaclass-classmethod-first-arg=mcs # List of member names, which should be excluded from the protected access # warning. exclude-protected=_asdict,_fields,_replace,_source,_make [DESIGN] # Maximum number of arguments for function / method max-args=12 # Argument names that match this expression will be ignored. Default to name # with leading underscore ignored-argument-names=_.* # Maximum number of locals for function / method body max-locals=32 # Maximum number of return / yield for function / method body max-returns=6 # Maximum number of branch for function / method body max-branches=24 # Maximum number of statements in function / method body max-statements=300 # Maximum number of parents for a class (see R0901). max-parents=10 # Maximum number of attributes for a class (see R0902). max-attributes=7 # Minimum number of public methods for a class (see R0903). min-public-methods=0 # Maximum number of public methods for a class (see R0904). max-public-methods=40 [IMPORTS] # Deprecated modules which should not be used, separated by a comma deprecated-modules= # Create a graph of every (i.e. internal and external) dependencies in the # given file (report RP0402 must not be disabled) import-graph= # Create a graph of external dependencies in the given file (report RP0402 must # not be disabled) ext-import-graph= # Create a graph of internal dependencies in the given file (report RP0402 must # not be disabled) int-import-graph= [EXCEPTIONS] # Exceptions that will emit a warning when being caught. Defaults to # "Exception" overgeneral-exceptions=Exception git-cola-3.6/.travis.yml000066400000000000000000000014541356743264500152150ustar00rootroot00000000000000# Travis CI(http://travis-ci.org) configuration file # https://docs.travis-ci.com/user/languages/python/ language: python dist: bionic sudo: required python: - "2.7" - "3.6" virtualenv: system_site_packages: true before_install: # Git test setup - git config --global user.name "Git Cola" - git config --global user.email git-cola@localhost.localdomain - sudo apt update # Build dependencies - sudo apt install -y gettext - sudo apt install -y rsync - sudo apt install -y python-sphinx - sudo apt install -y python3-sphinx # Runtime dependencies - sudo apt install -y python-pyqt5 - sudo apt install -y python3-pyqt5 install: # Test dependencies - make requirements-dev # Build translations - make all script: # Run tests and static analysis checks - make check V=2 git-cola-3.6/CHANGELOG000077700000000000000000000000001356743264500222402share/doc/git-cola/relnotes.rstustar00rootroot00000000000000git-cola-3.6/CONTRIBUTING.md000066400000000000000000000153701356743264500153370ustar00rootroot00000000000000# CONTRIBUTING GUIDELINES Here are some guidelines for people who want to contribute their code to this software. ## Make separate commits for logically separate changes. ## Run the pre-commit checks before committing * `make check` ## Be picky about whitespace This project is very picky about code style. The style here is the standard Python PEP-8 style: http://www.python.org/dev/peps/pep-0008/ * Follow the same style as the existing code. * Use 4-space indents. * Use `variable_names_with_underscores`, AKA "snake case" naming. No camelCase. The only exception is when overriding Qt functions. * Do not introduce trailing whitespace. The "Diff" viewer displays trailing whitespace in red, or you can use "git diff --check". * If you use SublimeText, configure `newline_at_eof_on_save` to true. https://robots.thoughtbot.com/no-newline-at-end-of-file ## Describe your changes well. The first line of the commit message should be a short description (50 characters is the soft limit, see DISCUSSION in git-commit(1)), and should skip the full stop. It is also conventional in most cases to prefix the first line with "area: " where the area is a filename or identifier for the general area of the code being modified, e.g. * push: allow pushing to multiple remotes * grep: allow passing in command-line arguments If in doubt which identifier to use, run "git log --no-merges" on the files you are modifying to see the current conventions. The body should provide a meaningful commit message, which: * explains the problem the change tries to solve, iow, what is wrong with the current code without the change. * justifies the way the change solves the problem, iow, why the result with the change is better. * alternate solutions considered but discarded, if any. Describe your changes in imperative mood, e.g. "make xyzzy do frotz" instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy to do frotz", as if you are giving orders to the codebase to change its behaviour. Try to make sure your explanation can be understood without external resources. Instead of giving a URL to a mailing list archive, summarize the relevant points of the discussion. If you like, you can put extra tags at the end: * "Reported-by:" is used to credit someone who found the bug that the patch attempts to fix. * "Acked-by:" says that the person who is more familiar with the area the patch attempts to modify liked the patch. * "Reviewed-by:", unlike the other tags, can only be offered by the reviewer and means that she is completely satisfied that the patch is ready for application. It is usually offered only after a detailed review. * "Tested-by:" is used to indicate that the person applied the patch and found it to have the desired effect. You can also create your own tag or use one that's in common usage such as "Thanks-to:", "Based-on-patch-by:", or "Helped-by:". ## Sign your work To improve tracking of who did what, we've borrowed the "sign-off" procedure from the Linux kernel project on patches that are being emailed around. Although core Git is a lot smaller project it is a good discipline to follow it. The sign-off is a simple line at the end of the explanation for the patch, which certifies that you wrote it or otherwise have the right to pass it on as an open-source patch. The rules are pretty simple: if you can certify the below: Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. then you just add a line saying Signed-off-by: Random J Developer This line can be automatically added by Git if you run the git-commit command with the -s option, or using the `Ctrl+i` hotkey in git-cola's commit message editor. Notice that you can place your own Signed-off-by: line when forwarding somebody else's patch with the above rules for D-C-O. Indeed you are encouraged to do so. Do not forget to place an in-body "From: " line at the beginning to properly attribute the change to its true author (see (2) above). Also notice that a real name is used in the Signed-off-by: line. Please don't hide your real name. ## Reporting Bugs Please read [How to Report Bugs Effectively](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html) for some general tips on bug reporting. ## Internationalization and Localization git-cola is translated to several languages. When strings are presented to the user they must use the `N_('')` function so that `` is translated into a localized string. The translation message files are the `*.po` files in the `po/` directory. Adding a new translation entails creating a new language-specific `.po` file and building the translation files using "make". The `share/locale/` directory tree is generated by "make" from the `po/*` source files. When new (untranslated) strings are added to the project, the `git-cola.pot` base template and the language-specific message files need to be updated with the new strings. To regenerate `git-cola.pot` and update `.po` files with new strings run: make pot This will update `.po` files with untranslated strings which translators can use to translate `git-cola`. Untranslatted strings are denoted by an empty "" string. The `.mo` files have to be regenerated after each change by running: make mo Alternate translations can be tested by setting `$LANG` when running, e.g. env LANG=zh_TW ./bin/git-cola The [Gettext Language Code](https://www.gnu.org/software/gettext/manual/gettext.html#Language-Codes) corresponds to the `.po` filename. Country-specific suffixes use the [Gettext country code](https://www.gnu.org/software/gettext/manual/gettext.html#Country-Codes). We happily welcome pull requests with improvements to `git-cola`'s translations. ## Fork the repo on Github and create a pull request. git-cola-3.6/COPYING000066400000000000000000000431031356743264500141340ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. git-cola-3.6/COPYRIGHT000066400000000000000000000000671356743264500143760ustar00rootroot00000000000000Copyright (C) 2007-2017 David Aguilar and contributors git-cola-3.6/Makefile000066400000000000000000000204541356743264500145450ustar00rootroot00000000000000# The default target of this Makefile is... all:: # Development # ----------- # make V=1 # generate files; V=1 increases verbosity # make test [flags=...] # run tests; flags=-x fails fast # make test V=2 # V=2 increases test verbosity # make doc # build docs # make flake8 # python style checks # make pylint [color=1] # run pylint; color=1 colorizes output # make pylint3k [color=1] # run python2+3 compatibility checks # make format file= # run the yapf python formatter on # make check [color=1] # run test, doc, flake8, pylint3k, and pylint # make check file= # run checks on # # Release Prep # ------------ # make pot # update main translation template # make po # merge translations # make mo # generate message files # make i18n # all three of the above # # Installation # ------------ # make prefix= install # DESTDIR is also supported. # # To disable distutil's replacement of "#!/usr/bin/env python" with # the path to the build environment's python, pass USE_ENV_PYTHON=1 # when invoking make. # # The external commands used by this Makefile are... CTAGS = ctags CP = cp FIND = find FLAKE8 = flake8 GIT = git GZIP = gzip LN = ln LN_S = $(LN) -s -f MARKDOWN = markdown MKDIR_P = mkdir -p PIP = pip PYLINT = pylint PYTHON = python PYTEST ?= $(PYTHON) -m pytest RM = rm -f RM_R = rm -fr RMDIR = rmdir TAR = tar TOX ?= tox YAPF = yapf # Flags # ----- ifdef V VERBOSE = --verbose ifeq ($(V),2) TEST_VERBOSE = --verbose VERBOSE_SHORT = -vv else VERBOSE_SHORT = -v endif else QUIET = --quiet endif FLAKE8_FLAGS = $(VERBOSE) FLAKE8_FLAGS += --max-line-length=80 FLAKE8_FLAGS += --format=pylint FLAKE8_FLAGS += --doctests PYTEST_FLAGS = $(QUIET) $(TEST_VERBOSE) PYTEST_FLAGS += --doctest-modules uname_S := $(shell uname -s) ifneq ($(uname_S),Linux) PYTEST_FLAGS += --ignore=cola/inotify.py endif TOX_FLAGS = $(VERBOSE_SHORT) --develop --skip-missing-interpreters PYLINT_FLAGS = --rcfile=.pylintrc PYLINT_FLAGS += --score=no ifdef color PYLINT_FLAGS += --output-format=colorized endif # These values can be overridden on the command-line or via config.mak prefix = $(HOME) bindir = $(prefix)/bin datadir = $(prefix)/share/git-cola coladir = $(datadir)/lib hicolordir = $(prefix)/share/icons/hicolor/scalable/apps # DESTDIR = cola_base := git-cola cola_app_base= $(cola_base).app cola_app = $(CURDIR)/$(cola_app_base) cola_version = $(shell $(PYTHON) bin/git-cola version --brief) cola_dist := $(cola_base)-$(cola_version) SETUP ?= $(PYTHON) setup.py build_args += build ifdef USE_ENV_PYTHON build_args += --use-env-python endif install_args += install install_args += --prefix="$(prefix)" install_args += --force install_args += --install-scripts="$(bindir)" install_args += --record=build/MANIFEST install_args += --install-lib="$(coladir)" ifdef DESTDIR install_args += --root="$(DESTDIR)" export DESTDIR endif export prefix # If NO_VENDOR_LIBS is specified on the command line then pass it to setup.py ifdef NO_VENDOR_LIBS install_args += --no-vendor-libs endif PYTHON_DIRS = cola PYTHON_DIRS += test ALL_PYTHON_DIRS = $(PYTHON_DIRS) ALL_PYTHON_DIRS += extras PYTHON_SOURCES = bin/git-cola PYTHON_SOURCES += bin/git-dag PYTHON_SOURCES += share/git-cola/bin/git-xbase PYTHON_SOURCES += setup.py # User customizations -include config.mak all:: build .PHONY: all build_version: @GIT=$(GIT) ./extras/generate-build-version.sh 2>/dev/null || true .PHONY: build_version build: build_version $(SETUP) $(QUIET) $(VERBOSE) $(build_args) .PHONY: build install: all $(SETUP) $(QUIET) $(VERBOSE) $(install_args) $(MKDIR_P) "$(DESTDIR)$(hicolordir)" $(LN_S) "$(datadir)/icons/git-cola.svg" \ "$(DESTDIR)$(hicolordir)/git-cola.svg" $(LN_S) git-cola "$(DESTDIR)$(bindir)/cola" $(RM_R) "$(DESTDIR)$(coladir)/git_cola"* $(RM_R) git_cola.egg-info .PHONY: install # Maintainer's dist target dist: $(GIT) archive --format=tar --prefix=$(cola_dist)/ HEAD^{tree} | \ $(GZIP) -f -9 - >$(cola_dist).tar.gz .PHONY: dist doc: $(MAKE) -C share/doc/git-cola all .PHONY: doc html: $(MAKE) -C share/doc/git-cola html .PHONY: html man: $(MAKE) -C share/doc/git-cola man .PHONY: man install-doc: $(MAKE) -C share/doc/git-cola install .PHONY: install-doc install-html: $(MAKE) -C share/doc/git-cola install-html .PHONY: install-html install-man: $(MAKE) -C share/doc/git-cola install-man .PHONY: install-man uninstall: $(RM) "$(DESTDIR)$(prefix)"/bin/git-cola $(RM) "$(DESTDIR)$(prefix)"/bin/git-dag $(RM) "$(DESTDIR)$(prefix)"/bin/cola $(RM) "$(DESTDIR)$(prefix)"/share/applications/git-cola.desktop $(RM) "$(DESTDIR)$(prefix)"/share/applications/git-cola-folder-handler.desktop $(RM) "$(DESTDIR)$(prefix)"/share/applications/git-dag.desktop $(RM) "$(DESTDIR)$(prefix)"/share/appdata/git-dag.appdata.xml $(RM) "$(DESTDIR)$(prefix)"/share/appdata/git-cola.appdata.xml $(RM) "$(DESTDIR)$(prefix)"/share/icons/hicolor/scalable/apps/git-cola.svg $(RM_R) "$(DESTDIR)$(prefix)"/share/doc/git-cola $(RM_R) "$(DESTDIR)$(prefix)"/share/git-cola $(RM) "$(DESTDIR)$(prefix)"/share/locale/*/LC_MESSAGES/git-cola.mo -$(RMDIR) "$(DESTDIR)$(prefix)"/share/applications 2>/dev/null -$(RMDIR) "$(DESTDIR)$(prefix)"/share/appdata 2>/dev/null -$(RMDIR) "$(DESTDIR)$(prefix)"/share/doc 2>/dev/null -$(RMDIR) "$(DESTDIR)$(prefix)"/share/locale/*/LC_MESSAGES 2>/dev/null -$(RMDIR) "$(DESTDIR)$(prefix)"/share/locale/* 2>/dev/null -$(RMDIR) "$(DESTDIR)$(prefix)"/share/locale 2>/dev/null -$(RMDIR) "$(DESTDIR)$(prefix)"/share/icons/hicolor/scalable/apps 2>/dev/null -$(RMDIR) "$(DESTDIR)$(prefix)"/share/icons/hicolor/scalable 2>/dev/null -$(RMDIR) "$(DESTDIR)$(prefix)"/share/icons/hicolor 2>/dev/null -$(RMDIR) "$(DESTDIR)$(prefix)"/share/icons 2>/dev/null -$(RMDIR) "$(DESTDIR)$(prefix)"/share 2>/dev/null -$(RMDIR) "$(DESTDIR)$(prefix)"/bin 2>/dev/null -$(RMDIR) "$(DESTDIR)$(prefix)" 2>/dev/null .PHONY: uninstall test: all $(PYTEST) $(PYTEST_FLAGS) $(flags) $(PYTHON_DIRS) .PHONY: test coverage: $(PYTEST) $(PYTEST_FLAGS) --cov=cola $(flags) $(PYTHON_DIRS) .PHONY: coverage clean: $(FIND) $(ALL_PYTHON_DIRS) -name '*.py[cod]' -print0 | xargs -0 rm -f $(FIND) $(ALL_PYTHON_DIRS) -name __pycache__ -print0 | xargs -0 rm -rf $(RM_R) build dist tags git-cola.app $(RM_R) share/locale $(MAKE) -C share/doc/git-cola clean .PHONY: clean tags: $(FIND) $(ALL_PYTHON_DIRS) -name '*.py' -print0 | xargs -0 $(CTAGS) -f tags .PHONY: tags # Update i18n files i18n:: pot i18n:: po i18n:: mo .PHONY: i18n pot: $(SETUP) build_pot --build-dir=po --no-lang .PHONY: pot po: $(SETUP) build_pot --build-dir=po .PHONY: po mo: $(SETUP) build_mo --force .PHONY: mo git-cola.app: $(MKDIR_P) $(cola_app)/Contents/MacOS $(MKDIR_P) $(cola_app)/Contents/Resources $(CP) contrib/darwin/Info.plist contrib/darwin/PkgInfo \ $(cola_app)/Contents $(CP) contrib/darwin/git-cola $(cola_app)/Contents/MacOS $(CP) contrib/darwin/git-cola.icns $(cola_app)/Contents/Resources $(MAKE) prefix=$(cola_app)/Contents/Resources install install-doc .PHONY: git-cola.app app-tarball: git-cola.app $(TAR) czf $(cola_dist).app.tar.gz $(cola_app_base) .PHONY: app-tarball # Preview the markdown using "make README.html" %.html: %.md $(MARKDOWN) $< >$@ flake8: $(FLAKE8) --version $(FLAKE8) $(FLAKE8_FLAGS) $(flags) \ $(PYTHON_SOURCES) $(ALL_PYTHON_DIRS) contrib .PHONY: flake8 pylint-version: $(PYLINT) --version .PHONY: pylint-version pylint3k: pylint-version $(PYLINT) $(PYLINT_FLAGS) --py3k $(flags) \ $(PYTHON_SOURCES) $(ALL_PYTHON_DIRS) .PHONY: pylint3k pylint: pylint-version $(PYLINT) $(PYLINT_FLAGS) $(flags) \ $(PYTHON_SOURCES) $(ALL_PYTHON_DIRS) .PHONY: pylint # Pre-commit checks ifdef file check: $(FLAKE8) $(FLAKE8_FLAGS) $(flags) $(file) $(PYLINT) $(PYLINT_FLAGS) --output-format=colorized $(flags) $(file) $(PYLINT) $(PYLINT_FLAGS) --output-format=colorized --py3k $(flags) $(file) else check:: all check:: test check:: doc check:: flake8 check:: pylint3k check:: pylint endif .PHONY: check format: $(YAPF) --in-place $(flags) $(file) .PHONY: format requirements: $(PIP) install --requirement requirements/requirements.txt .PHONY: requirements requirements-dev: $(PIP) install --requirement requirements/requirements-dev.txt .PHONY: requirements-dev tox: $(TOX) $(TOX_FLAGS) $(flags) .PHONY: tox git-cola-3.6/README.md000066400000000000000000000324271356743264500143670ustar00rootroot00000000000000# git-cola: The highly caffeinated Git GUI git-cola is a powerful Git GUI with a slick and intuitive user interface. Copyright (C) 2007-2018, David Aguilar and contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ## SCREENSHOTS Screenshots are available on the [git-cola screenshots page](https://git-cola.github.io/screenshots.html). ## DOWNLOAD apt install git-cola New releases are available on the [git-cola download page](https://git-cola.github.io/downloads.html). ## FORK git clone git://github.com/git-cola/git-cola.git [![git-cola build status](https://api.travis-ci.org/git-cola/git-cola.svg?branch=master)](https://travis-ci.org/git-cola/git-cola) [git-cola on github](https://github.com/git-cola/git-cola) [git-cola google group](https://groups.google.com/group/git-cola/) # NUTRITIONAL FACTS ## ACTIVE INGREDIENTS * [git](https://git-scm.com/) 1.6.3 or newer. * [Python](https://python.org/) 2.6 or newer (Python 2+3 compatible). * [QtPy](https://github.com/spyder-ide/qtpy) 1.1.0 or newer. * [argparse](https://pypi.python.org/pypi/argparse) 1.1 or newer. argparse is part of the stdlib in Python 2.7; install argparse separately if you are running on Python 2.6. * [Sphinx](http://sphinx-doc.org/) for building the documentation. *git-cola* uses *QtPy*, so you can choose between *PyQt4*, *PyQt5*, and *PySide* by setting the `QT_API` environment variable to `pyqt4`, `pyqt5` or `pyside` as desired. `qtpy` defaults to `pyqt5` and falls back to `pyqt4` if `pyqt5` is not installed. Any of the following Python Qt libraries must be installed: * [PyQt4](https://www.riverbankcomputing.com/software/pyqt/download) 4.6 or newer * [PyQt5](https://www.riverbankcomputing.com/software/pyqt/download5) 5.2 or newer * [PySide](https://github.com/PySide/PySide) 1.1.0 or newer Set `QT_API=pyqt4` in your environment if you have both versions of *PyQt* installed and want to ensure that PyQt4 is used. *NOTE*: *git-cola* includes a vendored copy of its *QtPy* dependency. We provide a copy of the `qtpy` module when installing *git-cola* so that you are not required to install *QtPy* separately. If you'd like to provide your own `qtpy` module, for example from the `python-qtpy` Debian package, then use `make NO_VENDOR_LIBS=1 ...` when invoking `make`, or export `GIT_COLA_NO_VENDOR_LIBS=1` into the build environment. Python3 users on debian will need to install `python3-distutils` in order to run the Makefile's installation steps. `distutils` is a Python build requirement, but not needed at runtime. ## ADDITIVES *git-cola* enables additional features when the following Python modules are installed. [send2trash](https://github.com/hsoft/send2trash) enables cross-platform "Send to Trash" functionality. # BREWING INSTRUCTIONS ## RUN FROM SOURCE You don't need to install *git-cola* to run it. Running *git-cola* from its source tree is the easiest way to try the latest version. git clone git://github.com/git-cola/git-cola.git cd git-cola ./bin/git-cola ./bin/git-dag Having *git-cola*'s *bin/* directory in your path allows you to run *git cola* like a regular built-in Git command: # Replace "$PWD/bin" with the path to git-cola's bin/ directory PATH="$PWD/bin":"$PATH" export PATH git cola git dag The instructions below assume that you have *git-cola* present in your `$PATH`. Replace "git cola" with "./bin/git-cola" as needed if you'd like to just run it in-place. # DOCUMENTATION * [HTML documentation](https://git-cola.readthedocs.io/en/latest/) * [git-cola manual](share/doc/git-cola/git-cola.rst) * [git-dag manual](share/doc/git-cola/git-dag.rst) * [Keyboard shortcuts](https://git-cola.github.io/share/doc/git-cola/hotkeys.html) * [Contributing guidelines](CONTRIBUTING.md) # INSTALLATION Normally you can just do "make install" to install *git-cola* in your `$HOME` directory (`$HOME/bin`, `$HOME/share`, etc). If you want to do a global install you can do make prefix=/usr install The platform-specific installation methods below use the native package manager. You should use one of these so that all of *git-cola*'s dependencies are installed. Distutils is used by the `Makefile` via `setup.py` to install *git-cola* and its launcher scripts. distutils replaces the `#!/usr/bin/env python` lines in scripts with the full path to python at build time, which can be undesirable when the runtime python is not the same as the build-time python. To disable the replacement of the `#!/usr/bin/env python` lines, pass `USE_ENV_PYTHON=1` to `make`. ## LINUX Linux is it! Your distro has probably already packaged git-cola. If not, please file a bug against your distribution ;-) ### arch Available in the [AUR](https://aur.archlinux.org/packages/git-cola/). ### debian, ubuntu apt install git-cola ### fedora dnf install git-cola ### gentoo emerge git-cola ### opensuse, sle zypper install git-cola ### slackware Available in [SlackBuilds.org](http://slackbuilds.org/result/?search=git-cola). ## Ubuntu The default version on 18.04 is older and is missing features and enhancements. Use this [PPA](https://launchpad.net/~pavreh/+archive/ubuntu/git-cola) maintained by @pavreh to get a newer version. ## MAC OS X [Homebrew](https://brew.sh/) is the easiest way to install git-cola's *Qt4* and *PyQt4* dependencies. We will use Homebrew to install the git-cola recipe, but build our own .app bundle from source. [Sphinx](http://sphinx-doc.org/latest/install.html) is used to build the documentation. brew install sphinx-doc brew install git-cola Once brew has installed git-cola you can: 1. Clone git-cola `git clone git://github.com/git-cola/git-cola.git && cd git-cola` 2. Build the git-cola.app application bundle ``` make \ PYTHON=$(brew --prefix python3)/bin/python3 \ PYTHON_CONFIG=$(brew --prefix python3)/bin/python3-config \ SPHINXBUILD=$(brew --prefix sphinx-doc)/bin/sphinx-build \ git-cola.app ``` 3. Copy it to _/Applications_ `rm -fr /Applications/git-cola.app && cp -r git-cola.app /Applications` Newer versions of Homebrew install their own `python3` installation and provide the `PyQt5` modules for `python3` only. You have to use `python3 ./bin/git-cola` when running from the source tree. ### UPGRADING USING HOMEBREW If you upgrade using `brew` then it is recommended that you re-install *git-cola*'s dependencies when upgrading. Re-installing ensures that the Python modules provided by Homebrew will be properly setup. This is required when upgrading to a modern (post-10.11 El Capitan) Mac OS X. Homebrew now bundles its own Python3 installation instead of using the system-provided default Python. # update homebrew brew update # uninstall git-cola and its dependencies brew uninstall git-cola brew uninstall pyqt5 brew uninstall sip # re-install git-cola and its dependencies brew install git-cola ## WINDOWS INSTALLATION **IMPORTANT** If you have a 64-bit machine, install the 64-bit versions only. Do not mix 32-bit and 64-bit versions. Download and install the following: * [Git for Windows](https://git-for-windows.github.io/) * [Git Cola](https://github.com/git-cola/git-cola/releases) Once these are installed you can run *git cola* from the Start menu. See "WINDOWS (continued)" below for more details. # GOODIES *git cola* ships with an interactive rebase editor called *git-xbase*. *git-xbase* is used to reorder and choose commits when rebasing. Start an interactive rebase through the "Rebase" menu, or through the *git cola rebase* sub-command to start the *git-xbase* editor: git cola rebase origin/master *git-xbase* can be launched independently of *git cola* by telling `git rebase` to use it as its editor through the `GIT_SEQUENCE_EDITOR` enviironment variable: env GIT_SEQUENCE_EDITOR="$PWD/share/git-cola/bin/git-xbase" \ git rebase -i origin/master # COMMAND-LINE TOOLS The *git-cola* command exposes various sub-commands that allow you to quickly launch tools that are available from within the *git-cola* interface. For example, `./bin/git-cola find` launches the file finder, and `./bin/git-cola grep` launches the grep tool. See `git cola --help-commands` for the full list of commands. $ git cola --help-commands usage: git-cola [-h] {cola,am,archive,branch,browse,config, dag,diff,fetch,find,grep,merge,pull,push, rebase,remote,search,stash,tag,version} ... valid commands: {cola,am,archive,branch,browse,config, dag,diff,fetch,find,grep,merge,pull,push, rebase,remote,search,stash,tag,version} cola start git-cola am apply patches using "git am" archive save an archive branch create a branch browse browse repository config edit configuration dag start git-dag diff view diffs fetch fetch remotes find find files grep grep source merge merge branches pull pull remote branches push push remote branches rebase interactive rebase remote edit remotes search search commits stash stash and unstash changes tag create tags version print the version ## HACKING The following commands should be run during development: # Run the unit tests $ make test # Run tests and longer-running pylint and flake8 checks $ make check # Run tests against multiple python interpreters using tox $ make tox The test suite can be found in the [test](test) directory. The tests are setup to run automatically when code is pushed using [Travis CI](https://travis-ci.org/git-cola/git-cola). Checkout the [Travis config file](.travis.yml) for more details. Auto-format `po/*.po` files before committing when updating translations: $ make po When submitting patches, consult the [contributing guidelines](CONTRIBUTING.md). ## SOURCE INSTALL For Linux/Unix-like environments with symlinks, an easy way to use the latest `git cola` is to keep a clone of the repository and symlink it into your `~/bin` directory. If `$HOME/bin` is not already in your `$PATH` you can add these two lines to the bottom of your `~/.bashrc` to make the linked tools available. PATH="$HOME/bin":"$PATH" export PATH Then, install git-cola by linking it into your `~/bin`: mkdir -p ~/src ~/bin git clone git://github.com/git-cola/git-cola.git ~/src/git-cola (cd ~/bin && ln -s ../src/git-cola/bin/git-cola && ln -s ../src/git-cola/bin/git-dag) You should then get the latest `git cola` in your shell. # WINDOWS (continued) ## Development In order to develop *git cola* on Windows you will need to install Python3 and pip. Install PyQt5 using `pip install PyQt5` to make the PyQt5 bindings available to Python. Once these are installed you can use `python.exe` to run directly from the source tree. For example, from a Git Bash terminal: /c/Python36/python.exe ./bin/git-cola ## Multiple Python versions If you have multiple versions of Python installed, the `contrib/win32/cola` launcher script might choose the newer version instead of the python that has PyQt installed. In order to resolve this, you can set the `cola.pythonlocation` git configuration variable to tell cola where to find python. For example: git config --global cola.pythonlocation /c/Python36 ## BUILDING WINDOWS INSTALLERS Windows installers are built using * [Pynsist](https://pynsist.readthedocs.io/en/latest/). * [NSIS](http://nsis.sourceforge.net/Main_Page) is also needed. To build the installer using *Pynsist* run: ./contrib/win32/run-pynsist.sh This will generate an installer in `build/nsis/`. ## WINDOWS HISTORY BROWSER CONFIGURATION UPGRADE You may need to configure your history browser if you are upgrading from an older version of *git-cola*. `gitk` was originally the default history browser, but `gitk` cannot be launched as-is on Windows because `gitk` is a shell script. If you are configured to use `gitk`, then change your configuration to go through Git's `sh.exe` on Windows. Similarly,we must go through `python.exe` if we want to use `git-dag`. If you want to use *gitk* as your history browser open the *Preferences* screen and change the history browser command to: "C:/Program Files/Git/bin/sh.exe" --login -i C:/Git/bin/gitk *git-dag* became the default history browser on Windows in `v2.3`, so new users should not need to configure anything. git-cola-3.6/bin/000077500000000000000000000000001356743264500136505ustar00rootroot00000000000000git-cola-3.6/bin/git-cola000077500000000000000000000031511356743264500152750ustar00rootroot00000000000000#!/usr/bin/env python """git-cola: The highly caffeinated Git GUI """ from __future__ import division, absolute_import, unicode_literals import os from os.path import abspath, dirname, join, realpath import sys __copyright__ = """ Copyright (C) 2007-2018 David Aguilar and contributors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. """ def setup_environment(): """Provides access to the cola modules""" # Try to detect where it is run from and set prefix and the search path. # It is assumed that the user installed Cola using the --prefix= option python2 = sys.version_info[0] == 2 prefix = dirname(dirname(realpath(abspath(__file__)))) # Look for modules in the source or install trees if python2: cola_mod = join(prefix, str('cola'), str('__init__.py')) install_lib = join(prefix, str('share'), str('git-cola'), str('lib')) else: cola_mod = join(prefix, 'cola', '__init__.py') install_lib = join(prefix, 'share', 'git-cola', 'lib') if os.path.exists(cola_mod): # Source tree sys.path.insert(1, prefix) else: # Install tree sys.path.insert(1, install_lib) setup_environment() if __name__ == '__main__': from cola.main import main sys.exit(main()) git-cola-3.6/bin/git-dag000077500000000000000000000031731356743264500151160ustar00rootroot00000000000000#!/usr/bin/env python """git-dag: An advanced git DAG visualizer """ from __future__ import division, absolute_import, unicode_literals import os from os.path import abspath, dirname, join, realpath import sys __copyright__ = """ Copyright (C) 2007-2018 David Aguilar and contributors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. """ def setup_environment(): """Provides access to the cola modules""" # Try to detect where it is run from and set prefix and the search path. # It is assumed that the user installed Cola using the --prefix= option python2 = sys.version_info[0] == 2 prefix = dirname(dirname(realpath(abspath(__file__)))) if python2: cola_mod = join(prefix, str('cola'), str('__init__.py')) install_lib = join(prefix, str('share'), str('git-cola'), str('lib')) else: # Look for modules in the source or install trees cola_mod = os.path.join(prefix, 'cola', '__init__.py') install_lib = os.path.join(prefix, 'share', 'git-cola', 'lib') if os.path.exists(cola_mod): # Source tree sys.path.insert(1, prefix) else: # Install tree sys.path.insert(1, install_lib) setup_environment() if __name__ == '__main__': from cola import dag sys.exit(dag.main()) git-cola-3.6/cola/000077500000000000000000000000001356743264500140165ustar00rootroot00000000000000git-cola-3.6/cola/__init__.py000066400000000000000000000000001356743264500161150ustar00rootroot00000000000000git-cola-3.6/cola/_version.py000066400000000000000000000000201356743264500162040ustar00rootroot00000000000000VERSION = '3.6' git-cola-3.6/cola/actions.py000066400000000000000000000036141356743264500160340ustar00rootroot00000000000000"""QAction creator functions""" from __future__ import absolute_import, division, unicode_literals from . import cmds from . import hotkeys from . import icons from . import qtutils from .i18n import N_ def cmd_action(widget, cmd, context, icon, *shortcuts): """Wrap a generic ContextCommand in a QAction""" action = qtutils.add_action(widget, cmd.name(), cmds.run(cmd, context), *shortcuts) action.setIcon(icon) return action def launch_editor(context, widget, *shortcuts): """Create a QAction to launch an editor""" icon = icons.edit() return cmd_action(widget, cmds.LaunchEditor, context, icon, hotkeys.EDIT, *shortcuts) def launch_editor_at_line(context, widget, *shortcuts): """Create a QAction to launch an editor""" icon = icons.edit() return cmd_action(widget, cmds.LaunchEditorAtLine, context, icon, hotkeys.EDIT, *shortcuts) def launch_difftool(context, widget): """Create a QAction to launch git-difftool(1)""" icon = icons.diff() cmd = cmds.LaunchDifftool action = qtutils.add_action(widget, cmd.name(), cmds.run(cmd, context), hotkeys.DIFF) action.setIcon(icon) return action def stage_or_unstage(context, widget): """Create a QAction to stage or unstage the selection""" icon = icons.add() return cmd_action(widget, cmds.StageOrUnstage, context, icon, hotkeys.STAGE_SELECTION) def move_down(widget): """Create a QAction to select the next item""" return qtutils.add_action(widget, N_('Next File'), widget.down.emit, hotkeys.MOVE_DOWN_SECONDARY) def move_up(widget): """Create a QAction to select the previous/above item""" return qtutils.add_action(widget, N_('Previous File'), widget.up.emit, hotkeys.MOVE_UP_SECONDARY) git-cola-3.6/cola/app.py000066400000000000000000000460121356743264500151530ustar00rootroot00000000000000"""Provides the main() routine and ColaApplication""" # pylint: disable=unused-import from __future__ import division, absolute_import, unicode_literals from functools import partial import argparse import os import signal import sys import time __copyright__ = """ Copyright (C) 2007-2017 David Aguilar and contributors """ try: from qtpy import QtCore except ImportError: sys.stderr.write(""" You do not seem to have PyQt5, PySide, or PyQt4 installed. Please install it before using git-cola, e.g. on a Debian/Ubutnu system: sudo apt-get install python-pyqt5 python-pyqt5.qtwebkit """) sys.exit(1) from qtpy import QtWidgets from qtpy.QtCore import Qt try: # Qt 5.12 / PyQt 5.13 is unable to use QtWebEngineWidgets unless it is # imported before QApplication is constructed. from qtpy import QtWebEngineWidgets # noqa except ImportError: # QtWebEngineWidgets / QtWebKit is not available -- no big deal. pass # Import cola modules from .i18n import N_ from .interaction import Interaction from .models import main from .models import selection from .widgets import cfgactions from .widgets import standard from .widgets import startup from .settings import Session from . import cmds from . import core from . import compat from . import fsmonitor from . import git from . import gitcfg from . import guicmds from . import hidpi from . import icons from . import i18n from . import qtcompat from . import qtutils from . import resources from . import themes from . import utils from . import version def setup_environment(): """Set environment variables to control git's behavior""" # Allow Ctrl-C to exit signal.signal(signal.SIGINT, signal.SIG_DFL) # Session management wants an absolute path when restarting sys.argv[0] = sys_argv0 = os.path.abspath(sys.argv[0]) # Spoof an X11 display for SSH os.environ.setdefault('DISPLAY', ':0') if not core.getenv('SHELL', ''): for shell in ('/bin/zsh', '/bin/bash', '/bin/sh'): if os.path.exists(shell): compat.setenv('SHELL', shell) break # Setup the path so that git finds us when we run 'git cola' path_entries = core.getenv('PATH', '').split(os.pathsep) bindir = core.decode(os.path.dirname(sys_argv0)) path_entries.append(bindir) path = os.pathsep.join(path_entries) compat.setenv('PATH', path) # We don't ever want a pager compat.setenv('GIT_PAGER', '') # Setup *SSH_ASKPASS git_askpass = core.getenv('GIT_ASKPASS') ssh_askpass = core.getenv('SSH_ASKPASS') if git_askpass: askpass = git_askpass elif ssh_askpass: askpass = ssh_askpass elif sys.platform == 'darwin': askpass = resources.share('bin', 'ssh-askpass-darwin') else: askpass = resources.share('bin', 'ssh-askpass') compat.setenv('GIT_ASKPASS', askpass) compat.setenv('SSH_ASKPASS', askpass) # --- >8 --- >8 --- # Git v1.7.10 Release Notes # ========================= # # Compatibility Notes # ------------------- # # * From this release on, the "git merge" command in an interactive # session will start an editor when it automatically resolves the # merge for the user to explain the resulting commit, just like the # "git commit" command does when it wasn't given a commit message. # # If you have a script that runs "git merge" and keeps its standard # input and output attached to the user's terminal, and if you do not # want the user to explain the resulting merge commits, you can # export GIT_MERGE_AUTOEDIT environment variable set to "no", like # this: # # #!/bin/sh # GIT_MERGE_AUTOEDIT=no # export GIT_MERGE_AUTOEDIT # # to disable this behavior (if you want your users to explain their # merge commits, you do not have to do anything). Alternatively, you # can give the "--no-edit" option to individual invocations of the # "git merge" command if you know everybody who uses your script has # Git v1.7.8 or newer. # --- >8 --- >8 --- # Longer-term: Use `git merge --no-commit` so that we always # have a chance to explain our merges. compat.setenv('GIT_MERGE_AUTOEDIT', 'no') # Gnome3 on Debian has XDG_SESSION_TYPE=wayland and # XDG_CURRENT_DESKTOP=GNOME, which Qt warns about at startup: # # Warning: Ignoring XDG_SESSION_TYPE=wayland on Gnome. # Use QT_QPA_PLATFORM=wayland to run on Wayland anyway. # # This annoying, so we silence the warning. # We'll need to keep this hack here until a future version of Qt provides # Qt Wayland widgets that are usable in gnome-shell. # Cf. https://bugreports.qt.io/browse/QTBUG-68619 if (core.getenv('XDG_CURRENT_DESKTOP', '') == 'GNOME' and core.getenv('XDG_SESSION_TYPE', '') == 'wayland'): compat.unsetenv('XDG_SESSION_TYPE') def get_icon_themes(context): """Return the default icon theme names""" result = [] icon_themes_env = core.getenv('GIT_COLA_ICON_THEME') if icon_themes_env: result.extend([x for x in icon_themes_env.split(':') if x]) icon_themes_cfg = context.cfg.get_all('cola.icontheme') if icon_themes_cfg: result.extend(icon_themes_cfg) if not result: result.append('light') return result # style note: we use camelCase here since we're masquerading a Qt class class ColaApplication(object): """The main cola application ColaApplication handles i18n of user-visible data """ def __init__(self, context, argv, locale=None, icon_themes=None, gui_theme=None): cfgactions.install() i18n.install(locale) qtcompat.install() guicmds.install() standard.install() icons.install(icon_themes or get_icon_themes(context)) self.context = context self._install_hidpi_config() self._app = ColaQApplication(context, list(argv)) self._app.setWindowIcon(icons.cola()) self._install_style(gui_theme) def _install_style(self, theme_str): """Generate and apply a stylesheet to the app""" if theme_str is None: theme_str = self.context.cfg.get('cola.theme', default='default') theme = themes.find_theme(theme_str) self._app.setStyleSheet(theme.build_style_sheet(self._app.palette())) if theme_str != 'default': self._app.setPalette(theme.build_palette(self._app.palette())) def _install_hidpi_config(self): """Sets QT HIDPI scalling (requires Qt 5.6)""" value = self.context.cfg.get('cola.hidpi', default=hidpi.Option.AUTO) hidpi.apply_choice(value) def activeWindow(self): """QApplication::activeWindow() pass-through""" return self._app.activeWindow() def desktop(self): """QApplication::desktop() pass-through""" return self._app.desktop() def start(self): """Wrap exec_() and start the application""" # Defer connection so that local cola.inotify is honored context = self.context monitor = context.fsmonitor monitor.files_changed.connect( cmds.run(cmds.Refresh, context), type=Qt.QueuedConnection) monitor.config_changed.connect( cmds.run(cmds.RefreshConfig, context), type=Qt.QueuedConnection) # Start the filesystem monitor thread monitor.start() return self._app.exec_() def stop(self): """Finalize the application""" self.context.fsmonitor.stop() # Workaround QTBUG-52988 by deleting the app manually to prevent a # crash during app shutdown. # https://bugreports.qt.io/browse/QTBUG-52988 try: del self._app except (AttributeError, RuntimeError): pass self._app = None def exit(self, status): """QApplication::exit(status) pass-through""" return self._app.exit(status) class ColaQApplication(QtWidgets.QApplication): """QApplication implementation for handling custom events""" def __init__(self, context, argv): super(ColaQApplication, self).__init__(argv) self.context = context # Make icons sharp in HiDPI screen if hasattr(Qt, 'AA_UseHighDpiPixmaps'): self.setAttribute(Qt.AA_UseHighDpiPixmaps, True) def event(self, e): """Respond to focus events for the cola.refreshonfocus feature""" if e.type() == QtCore.QEvent.ApplicationActivate: context = self.context if context: cfg = context.cfg if (context.git.is_valid() and cfg.get('cola.refreshonfocus', default=False)): cmds.do(cmds.Refresh, context) return super(ColaQApplication, self).event(e) def commitData(self, session_mgr): """Save session data""" if not self.context or not self.context.view: return view = self.context.view if not hasattr(view, 'save_state'): return sid = session_mgr.sessionId() skey = session_mgr.sessionKey() session_id = '%s_%s' % (sid, skey) session = Session(session_id, repo=core.getcwd()) view.save_state(settings=session) def process_args(args): """Process and verify command-line arguments""" if args.version: # Accept 'git cola --version' or 'git cola version' version.print_version() sys.exit(core.EXIT_SUCCESS) # Handle session management restore_session(args) # Bail out if --repo is not a directory repo = core.decode(args.repo) if repo.startswith('file:'): repo = repo[len('file:'):] repo = core.realpath(repo) if not core.isdir(repo): errmsg = N_('fatal: "%s" is not a directory. ' 'Please specify a correct --repo .') % repo core.print_stderr(errmsg) sys.exit(core.EXIT_USAGE) def restore_session(args): """Load a session based on the window-manager provided arguments""" # args.settings is provided when restoring from a session. args.settings = None if args.session is None: return session = Session(args.session) if session.load(): args.settings = session args.repo = session.repo def application_init(args, update=False): """Parses the command-line arguments and starts git-cola """ # Ensure that we're working in a valid git repository. # If not, try to find one. When found, chdir there. setup_environment() process_args(args) context = new_context(args) timer = context.timer timer.start('init') new_worktree(context, args.repo, args.prompt, args.settings) if update: context.model.update_status() timer.stop('init') if args.perf: timer.display('init') return context def new_context(args): """Create top-level ApplicationContext objects""" context = ApplicationContext(args) context.git = git.create() context.cfg = gitcfg.create(context) context.fsmonitor = fsmonitor.create(context) context.selection = selection.create() context.model = main.create(context) context.app = new_application(context, args) context.timer = Timer() return context def application_run(context, view, start=None, stop=None): """Run the application main loop""" context.set_view(view) view.show() # Startup callbacks if start: start(context, view) # Start the event loop result = context.app.start() # Finish if stop: stop(context, view) context.app.stop() return result def application_start(context, view): """Show the GUI and start the main event loop""" # Store the view for session management return application_run(context, view, start=default_start, stop=default_stop) def default_start(context, _view): """Scan for the first time""" QtCore.QTimer.singleShot(0, startup_message) QtCore.QTimer.singleShot(0, lambda: async_update(context)) def default_stop(_context, _view): """All done, cleanup""" QtCore.QThreadPool.globalInstance().waitForDone() def add_common_arguments(parser): """Add command arguments to the ArgumentParser""" # We also accept 'git cola version' parser.add_argument('--version', default=False, action='store_true', help='print version number') # Specifies a git repository to open parser.add_argument('-r', '--repo', metavar='', default=core.getcwd(), help='open the specified git repository') # Specifies that we should prompt for a repository at startup parser.add_argument('--prompt', action='store_true', default=False, help='prompt for a repository') # Specify the icon theme parser.add_argument('--icon-theme', metavar='', dest='icon_themes', action='append', default=[], help='specify an icon theme (name or directory)') # Resume an X Session Management session parser.add_argument('-session', metavar='', default=None, help=argparse.SUPPRESS) # Enable timing information parser.add_argument('--perf', action='store_true', default=False, help=argparse.SUPPRESS) # Specify the GUI theme parser.add_argument('--theme', metavar='', default=None, help='specify an GUI theme name') def new_application(context, args): """Create a new ColaApplication""" return ColaApplication(context, sys.argv, icon_themes=args.icon_themes, gui_theme=args.theme ) def new_worktree(context, repo, prompt, settings): """Find a Git repository, or prompt for one when not found""" model = context.model cfg = context.cfg parent = qtutils.active_window() valid = False if not prompt: valid = model.set_worktree(repo) if not valid: # We are not currently in a git repository so we need to find one. # Before prompting the user for a repository, check if they've # configured a default repository and attempt to use it. default_repo = cfg.get('cola.defaultrepo') if default_repo: valid = model.set_worktree(default_repo) while not valid: # If we've gotten into this loop then that means that neither the # current directory nor the default repository were available. # Prompt the user for a repository. startup_dlg = startup.StartupDialog(context, parent, settings=settings) gitdir = startup_dlg.find_git_repo() if not gitdir: sys.exit(core.EXIT_NOINPUT) valid = model.set_worktree(gitdir) def async_update(context): """Update the model in the background git-cola should startup as quickly as possible. """ update_status = partial(context.model.update_status, update_index=True) task = qtutils.SimpleTask(context.view, update_status) context.runtask.start(task) def startup_message(): """Print debug startup messages""" trace = git.GIT_COLA_TRACE if trace in ('2', 'trace'): msg1 = 'info: debug level 2: trace mode enabled' msg2 = 'info: set GIT_COLA_TRACE=1 for less-verbose output' Interaction.log(msg1) Interaction.log(msg2) elif trace: msg1 = 'info: debug level 1' msg2 = 'info: set GIT_COLA_TRACE=2 for trace mode' Interaction.log(msg1) Interaction.log(msg2) def initialize(): """System-level initialization""" # The current directory may have been deleted while we are still # in that directory. We rectify this situation by walking up the # directory tree and retrying. # # This is needed because because Python throws exceptions in lots of # stdlib functions when in this situation, e.g. os.path.abspath() and # os.path.realpath(), so it's simpler to mitigate the damage by changing # the current directory to one that actually exists. while True: try: return core.getcwd() except OSError: os.chdir('..') class Timer(object): """Simple performance timer""" def __init__(self): self._data = {} def start(self, key): """Start a timer""" now = time.time() self._data[key] = [now, now] def stop(self, key): """Stop a timer and return its elapsed time""" entry = self._data[key] entry[1] = time.time() return self.elapsed(key) def elapsed(self, key): """Return the elapsed time for a timer""" entry = self._data[key] return entry[1] - entry[0] def display(self, key): """Display a timer""" elapsed = self.elapsed(key) sys.stdout.write('%s: %.5fs\n' % (key, elapsed)) class ApplicationContext(object): """Context for performing operations on Git and related data models""" def __init__(self, args): self.args = args self.app = None # ColaApplication self.git = None # git.Git self.cfg = None # gitcfg.GitConfig self.model = None # main.MainModel self.timer = None # Timer self.runtask = None # qtutils.RunTask self.selection = None # selection.SelectionModel self.fsmonitor = None # fsmonitor self.view = None # QWidget def set_view(self, view): """Initialize view-specific members""" self.view = view self.runtask = qtutils.RunTask(parent=view) def winmain(main_fn, *argv): """Find Git and launch main(argv)""" git_path = find_git() if git_path: prepend_path(git_path) return main_fn(*argv) def find_git(): """Return the path of git.exe, or None if we can't find it.""" if not utils.is_win32(): return None # UNIX systems have git in their $PATH # If the user wants to use a Git/bin/ directory from a non-standard # directory then they can write its location into # ~/.config/git-cola/git-bindir git_bindir = os.path.expanduser(os.path.join('~', '.config', 'git-cola', 'git-bindir')) if core.exists(git_bindir): custom_path = core.read(git_bindir).strip() if custom_path and core.exists(custom_path): return custom_path # Try to find Git's bin/ directory in one of the typical locations pf = os.environ.get('ProgramFiles', 'C:\\Program Files') pf32 = os.environ.get('ProgramFiles(x86)', 'C:\\Program Files (x86)') pf64 = os.environ.get('ProgramW6432', 'C:\\Program Files') for p in [pf64, pf32, pf, 'C:\\']: candidate = os.path.join(p, 'Git\\bin') if os.path.isdir(candidate): return candidate return None def prepend_path(path): """Adds git to the PATH. This is needed on Windows.""" path = core.decode(path) path_entries = core.getenv('PATH', '').split(os.pathsep) if path not in path_entries: path_entries.insert(0, path) compat.setenv('PATH', os.pathsep.join(path_entries)) git-cola-3.6/cola/cmd.py000066400000000000000000000016431356743264500151370ustar00rootroot00000000000000"""Base Command class""" from __future__ import division, absolute_import, unicode_literals class Command(object): """Mixin interface for commands""" UNDOABLE = False @staticmethod def name(): """Return the command's name""" return '(undefined)' @classmethod def is_undoable(cls): """Can this be undone?""" return cls.UNDOABLE # pylint: disable=no-self-use def do(self): """Execute the command""" return # pylint: disable=no-self-use def undo(self): """Undo the command""" return class ContextCommand(Command): """Base class for commands that operate on a context""" def __init__(self, context): self.context = context self.model = context.model self.cfg = context.cfg self.git = context.git self.selection = context.selection self.fsmonitor = context.fsmonitor git-cola-3.6/cola/cmds.py000066400000000000000000002423201356743264500153210ustar00rootroot00000000000000"""Editor commands""" from __future__ import division, absolute_import, unicode_literals import os import re import sys from fnmatch import fnmatch from io import StringIO try: from send2trash import send2trash except ImportError: send2trash = None from . import compat from . import core from . import gitcmds from . import icons from . import resources from . import textwrap from . import utils from . import version from .cmd import ContextCommand from .diffparse import DiffParser from .git import STDOUT from .git import EMPTY_TREE_OID from .git import MISSING_BLOB_OID from .i18n import N_ from .interaction import Interaction from .models import prefs from .settings import Settings class UsageError(Exception): """Exception class for usage errors.""" def __init__(self, title, message): Exception.__init__(self, message) self.title = title self.msg = message class EditModel(ContextCommand): """Commands that mutate the main model diff data""" UNDOABLE = True def __init__(self, context): """Common edit operations on the main model""" super(EditModel, self).__init__(context) self.old_diff_text = self.model.diff_text self.old_filename = self.model.filename self.old_mode = self.model.mode self.old_diff_type = self.model.diff_type self.new_diff_text = self.old_diff_text self.new_filename = self.old_filename self.new_mode = self.old_mode self.new_diff_type = self.old_diff_type def do(self): """Perform the operation.""" self.model.set_filename(self.new_filename) self.model.set_mode(self.new_mode) self.model.set_diff_text(self.new_diff_text) self.model.set_diff_type(self.new_diff_type) def undo(self): """Undo the operation.""" self.model.set_filename(self.old_filename) self.model.set_mode(self.old_mode) self.model.set_diff_text(self.old_diff_text) self.model.set_diff_type(self.old_diff_type) class ConfirmAction(ContextCommand): """Confirm an action before running it""" # pylint: disable=no-self-use def ok_to_run(self): """Return True when the command is ok to run""" return True # pylint: disable=no-self-use def confirm(self): """Prompt for confirmation""" return True # pylint: disable=no-self-use def action(self): """Run the command and return (status, out, err)""" return (-1, '', '') # pylint: disable=no-self-use def success(self): """Callback run on success""" return # pylint: disable=no-self-use def command(self): """Command name, for error messages""" return 'git' # pylint: disable=no-self-use def error_message(self): """Command error message""" return '' def do(self): """Prompt for confirmation before running a command""" status = -1 out = err = '' ok = self.ok_to_run() and self.confirm() if ok: status, out, err = self.action() if status == 0: self.success() title = self.error_message() cmd = self.command() Interaction.command(title, cmd, status, out, err) return ok, status, out, err class AbortMerge(ConfirmAction): """Reset an in-progress merge back to HEAD""" def confirm(self): title = N_('Abort Merge...') question = N_('Aborting the current merge?') info = N_('Aborting the current merge will cause ' '*ALL* uncommitted changes to be lost.\n' 'Recovering uncommitted changes is not possible.') ok_txt = N_('Abort Merge') return Interaction.confirm(title, question, info, ok_txt, default=False, icon=icons.undo()) def action(self): status, out, err = gitcmds.abort_merge(self.context) self.model.update_file_status() return status, out, err def success(self): self.model.set_commitmsg('') def error_message(self): return N_('Error') def command(self): return 'git merge' class AmendMode(EditModel): """Try to amend a commit.""" UNDOABLE = True LAST_MESSAGE = None @staticmethod def name(): return N_('Amend') def __init__(self, context, amend=True): super(AmendMode, self).__init__(context) self.skip = False self.amending = amend self.old_commitmsg = self.model.commitmsg self.old_mode = self.model.mode if self.amending: self.new_mode = self.model.mode_amend self.new_commitmsg = gitcmds.prev_commitmsg(context) AmendMode.LAST_MESSAGE = self.model.commitmsg return # else, amend unchecked, regular commit self.new_mode = self.model.mode_none self.new_diff_text = '' self.new_commitmsg = self.model.commitmsg # If we're going back into new-commit-mode then search the # undo stack for a previous amend-commit-mode and grab the # commit message at that point in time. if AmendMode.LAST_MESSAGE is not None: self.new_commitmsg = AmendMode.LAST_MESSAGE AmendMode.LAST_MESSAGE = None def do(self): """Leave/enter amend mode.""" # Attempt to enter amend mode. Do not allow this when merging. if self.amending: if self.model.is_merging: self.skip = True self.model.set_mode(self.old_mode) Interaction.information( N_('Cannot Amend'), N_('You are in the middle of a merge.\n' 'Cannot amend while merging.')) return self.skip = False super(AmendMode, self).do() self.model.set_commitmsg(self.new_commitmsg) self.model.update_file_status() def undo(self): if self.skip: return self.model.set_commitmsg(self.old_commitmsg) super(AmendMode, self).undo() self.model.update_file_status() class AnnexAdd(ContextCommand): """Add to Git Annex""" def __init__(self, context): super(AnnexAdd, self).__init__(context) self.filename = self.selection.filename() def do(self): status, out, err = self.git.annex('add', self.filename) Interaction.command(N_('Error'), 'git annex add', status, out, err) self.model.update_status() class AnnexInit(ContextCommand): """Initialize Git Annex""" def do(self): status, out, err = self.git.annex('init') Interaction.command(N_('Error'), 'git annex init', status, out, err) self.model.cfg.reset() self.model.emit_updated() class LFSTrack(ContextCommand): """Add a file to git lfs""" def __init__(self, context): super(LFSTrack, self).__init__(context) self.filename = self.selection.filename() self.stage_cmd = Stage(context, [self.filename]) def do(self): status, out, err = self.git.lfs('track', self.filename) Interaction.command( N_('Error'), 'git lfs track', status, out, err) if status == 0: self.stage_cmd.do() class LFSInstall(ContextCommand): """Initialize git lfs""" def do(self): status, out, err = self.git.lfs('install') Interaction.command( N_('Error'), 'git lfs install', status, out, err) self.model.update_config(reset=True, emit=True) class ApplyDiffSelection(ContextCommand): """Apply the selected diff to the worktree or index""" def __init__(self, context, first_line_idx, last_line_idx, has_selection, reverse, apply_to_worktree): super(ApplyDiffSelection, self).__init__(context) self.first_line_idx = first_line_idx self.last_line_idx = last_line_idx self.has_selection = has_selection self.reverse = reverse self.apply_to_worktree = apply_to_worktree def do(self): context = self.context cfg = self.context.cfg diff_text = self.model.diff_text parser = DiffParser(self.model.filename, diff_text) if self.has_selection: patch = parser.generate_patch( self.first_line_idx, self.last_line_idx, reverse=self.reverse) else: patch = parser.generate_hunk_patch( self.first_line_idx, reverse=self.reverse) if patch is None: return if isinstance(diff_text, core.UStr): # original encoding must prevail encoding = diff_text.encoding else: encoding = cfg.file_encoding(self.model.filename) tmp_file = utils.tmp_filename('patch') try: core.write(tmp_file, patch, encoding=encoding) if self.apply_to_worktree: status, out, err = gitcmds.apply_diff_to_worktree( context, tmp_file) else: status, out, err = gitcmds.apply_diff(context, tmp_file) finally: core.unlink(tmp_file) Interaction.log_status(status, out, err) self.model.update_file_status(update_index=True) class ApplyPatches(ContextCommand): """Apply patches using the "git am" command""" def __init__(self, context, patches): super(ApplyPatches, self).__init__(context) self.patches = patches def do(self): status, out, err = self.git.am('-3', *self.patches) Interaction.log_status(status, out, err) # Display a diffstat self.model.update_file_status() patch_basenames = [os.path.basename(p) for p in self.patches] if len(patch_basenames) > 25: patch_basenames = patch_basenames[:25] patch_basenames.append('...') basenames = '\n'.join(patch_basenames) Interaction.information( N_('Patch(es) Applied'), (N_('%d patch(es) applied.') + '\n\n%s') % (len(self.patches), basenames)) class Archive(ContextCommand): """"Export archives using the "git archive" command""" def __init__(self, context, ref, fmt, prefix, filename): super(Archive, self).__init__(context) self.ref = ref self.fmt = fmt self.prefix = prefix self.filename = filename def do(self): fp = core.xopen(self.filename, 'wb') cmd = ['git', 'archive', '--format='+self.fmt] if self.fmt in ('tgz', 'tar.gz'): cmd.append('-9') if self.prefix: cmd.append('--prefix=' + self.prefix) cmd.append(self.ref) proc = core.start_command(cmd, stdout=fp) out, err = proc.communicate() fp.close() status = proc.returncode Interaction.log_status(status, out or '', err or '') class Checkout(EditModel): """A command object for git-checkout. 'argv' is handed off directly to git. """ def __init__(self, context, argv, checkout_branch=False): super(Checkout, self).__init__(context) self.argv = argv self.checkout_branch = checkout_branch self.new_diff_text = '' self.new_diff_type = 'text' def do(self): super(Checkout, self).do() status, out, err = self.git.checkout(*self.argv) if self.checkout_branch: self.model.update_status() else: self.model.update_file_status() Interaction.command(N_('Error'), 'git checkout', status, out, err) class BlamePaths(ContextCommand): """Blame view for paths.""" @staticmethod def name(): return N_('Blame...') def __init__(self, context, paths=None): super(BlamePaths, self).__init__(context) if not paths: paths = context.selection.union() viewer = utils.shell_split(prefs.blame_viewer(context)) self.argv = viewer + list(paths) def do(self): try: core.fork(self.argv) except OSError as e: _, details = utils.format_exception(e) title = N_('Error Launching Blame Viewer') msg = (N_('Cannot exec "%s": please configure a blame viewer') % ' '.join(self.argv)) Interaction.critical(title, message=msg, details=details) class CheckoutBranch(Checkout): """Checkout a branch.""" def __init__(self, context, branch): args = [branch] super(CheckoutBranch, self).__init__( context, args, checkout_branch=True) class CherryPick(ContextCommand): """Cherry pick commits into the current branch.""" def __init__(self, context, commits): super(CherryPick, self).__init__(context) self.commits = commits def do(self): self.model.cherry_pick_list(self.commits) self.model.update_file_status() class Revert(ContextCommand): """Cherry pick commits into the current branch.""" def __init__(self, context, oid): super(Revert, self).__init__(context) self.oid = oid def do(self): self.git.revert(self.oid) self.model.update_file_status() class ResetMode(EditModel): """Reset the mode and clear the model's diff text.""" def __init__(self, context): super(ResetMode, self).__init__(context) self.new_mode = self.model.mode_none self.new_diff_text = '' self.new_diff_type = 'text' self.new_filename = '' def do(self): super(ResetMode, self).do() self.model.update_file_status() class ResetCommand(ConfirmAction): """Reset state using the "git reset" command""" def __init__(self, context, ref): super(ResetCommand, self).__init__(context) self.ref = ref def action(self): return self.reset() def command(self): return 'git reset' def error_message(self): return N_('Error') def success(self): self.model.update_file_status() def confirm(self): raise NotImplementedError('confirm() must be overridden') def reset(self): raise NotImplementedError('reset() must be overridden') class ResetBranchHead(ResetCommand): def confirm(self): title = N_('Reset Branch') question = N_('Point the current branch head to a new commit?') info = N_('The branch will be reset using "git reset --mixed %s"') ok_text = N_('Reset Branch') info = info % self.ref return Interaction.confirm(title, question, info, ok_text) def reset(self): return self.git.reset(self.ref, '--', mixed=True) class ResetWorktree(ResetCommand): def confirm(self): title = N_('Reset Worktree') question = N_('Reset worktree?') info = N_('The worktree will be reset using "git reset --keep %s"') ok_text = N_('Reset Worktree') info = info % self.ref return Interaction.confirm(title, question, info, ok_text) def reset(self): return self.git.reset(self.ref, '--', keep=True) class ResetMerge(ResetCommand): def confirm(self): title = N_('Reset Merge') question = N_('Reset merge?') info = N_('The branch will be reset using "git reset --merge %s"') ok_text = N_('Reset Merge') info = info % self.ref return Interaction.confirm(title, question, info, ok_text) def reset(self): return self.git.reset(self.ref, '--', merge=True) class ResetSoft(ResetCommand): def confirm(self): title = N_('Reset Soft') question = N_('Reset soft?') info = N_('The branch will be reset using "git reset --soft %s"') ok_text = N_('Reset Soft') info = info % self.ref return Interaction.confirm(title, question, info, ok_text) def reset(self): return self.git.reset(self.ref, '--', soft=True) class ResetHard(ResetCommand): def confirm(self): title = N_('Reset Hard') question = N_('Reset hard?') info = N_('The branch will be reset using "git reset --hard %s"') ok_text = N_('Reset Hard') info = info % self.ref return Interaction.confirm(title, question, info, ok_text) def reset(self): return self.git.reset(self.ref, '--', hard=True) class Commit(ResetMode): """Attempt to create a new commit.""" def __init__(self, context, amend, msg, sign, no_verify=False): super(Commit, self).__init__(context) self.amend = amend self.msg = msg self.sign = sign self.no_verify = no_verify self.old_commitmsg = self.model.commitmsg self.new_commitmsg = '' def do(self): # Create the commit message file context = self.context comment_char = prefs.comment_char(context) msg = self.strip_comments(self.msg, comment_char=comment_char) tmp_file = utils.tmp_filename('commit-message') try: core.write(tmp_file, msg) # Run 'git commit' status, out, err = self.git.commit( F=tmp_file, v=True, gpg_sign=self.sign, amend=self.amend, no_verify=self.no_verify) finally: core.unlink(tmp_file) if status == 0: super(Commit, self).do() if context.cfg.get(prefs.AUTOTEMPLATE): template_loader = LoadCommitMessageFromTemplate(context) template_loader.do() else: self.model.set_commitmsg(self.new_commitmsg) title = N_('Commit failed') Interaction.command(title, 'git commit', status, out, err) return status, out, err @staticmethod def strip_comments(msg, comment_char='#'): # Strip off comments message_lines = [line for line in msg.split('\n') if not line.startswith(comment_char)] msg = '\n'.join(message_lines) if not msg.endswith('\n'): msg += '\n' return msg class CycleReferenceSort(ContextCommand): """Choose the next reference sort type""" def do(self): self.model.cycle_ref_sort() class Ignore(ContextCommand): """Add files to an exclusion file""" def __init__(self, context, filenames, local=False): super(Ignore, self).__init__(context) self.filenames = list(filenames) self.local = local def do(self): if not self.filenames: return new_additions = '\n'.join(self.filenames) + '\n' for_status = new_additions if self.local: filename = os.path.join('.git', 'info', 'exclude') else: filename = '.gitignore' if core.exists(filename): current_list = core.read(filename) new_additions = current_list.rstrip() + '\n' + new_additions core.write(filename, new_additions) Interaction.log_status(0, 'Added to %s:\n%s' % (filename, for_status), '') self.model.update_file_status() def file_summary(files): txt = core.list2cmdline(files) if len(txt) > 768: txt = txt[:768].rstrip() + '...' wrap = textwrap.TextWrapper() return '\n'.join(wrap.wrap(txt)) class RemoteCommand(ConfirmAction): def __init__(self, context, remote): super(RemoteCommand, self).__init__(context) self.remote = remote def success(self): self.cfg.reset() self.model.update_remotes() class RemoteAdd(RemoteCommand): def __init__(self, context, remote, url): super(RemoteAdd, self).__init__(context, remote) self.url = url def action(self): return self.git.remote('add', self.remote, self.url) def error_message(self): return N_('Error creating remote "%s"') % self.remote def command(self): return 'git remote add "%s" "%s"' % (self.remote, self.url) class RemoteRemove(RemoteCommand): def confirm(self): title = N_('Delete Remote') question = N_('Delete remote?') info = N_('Delete remote "%s"') % self.remote ok_text = N_('Delete') return Interaction.confirm(title, question, info, ok_text) def action(self): return self.git.remote('rm', self.remote) def error_message(self): return N_('Error deleting remote "%s"') % self.remote def command(self): return 'git remote rm "%s"' % self.remote class RemoteRename(RemoteCommand): def __init__(self, context, remote, new_name): super(RemoteRename, self).__init__(context, remote) self.new_name = new_name def confirm(self): title = N_('Rename Remote') text = (N_('Rename remote "%(current)s" to "%(new)s"?') % dict(current=self.remote, new=self.new_name)) info_text = '' ok_text = title return Interaction.confirm(title, text, info_text, ok_text) def action(self): return self.git.remote('rename', self.remote, self.new_name) def error_message(self): return (N_('Error renaming "%(name)s" to "%(new_name)s"') % dict(name=self.remote, new_name=self.new_name)) def command(self): return 'git remote rename "%s" "%s"' % (self.remote, self.new_name) class RemoteSetURL(RemoteCommand): def __init__(self, context, remote, url): super(RemoteSetURL, self).__init__(context, remote) self.url = url def action(self): return self.git.remote('set-url', self.remote, self.url) def error_message(self): return (N_('Unable to set URL for "%(name)s" to "%(url)s"') % dict(name=self.remote, url=self.url)) def command(self): return 'git remote set-url "%s" "%s"' % (self.remote, self.url) class RemoteEdit(ContextCommand): """Combine RemoteRename and RemoteSetURL""" def __init__(self, context, old_name, remote, url): super(RemoteEdit, self).__init__(context) self.rename = RemoteRename(context, old_name, remote) self.set_url = RemoteSetURL(context, remote, url) def do(self): result = self.rename.do() name_ok = result[0] url_ok = False if name_ok: result = self.set_url.do() url_ok = result[0] return name_ok, url_ok class RemoveFromSettings(ConfirmAction): def __init__(self, context, settings, repo, entry, icon=None): super(RemoveFromSettings, self).__init__(context) self.settings = settings self.repo = repo self.entry = entry self.icon = icon def success(self): self.settings.save() class RemoveBookmark(RemoveFromSettings): def confirm(self): entry = self.entry title = msg = N_('Delete Bookmark?') info = N_('%s will be removed from your bookmarks.') % entry ok_text = N_('Delete Bookmark') return Interaction.confirm(title, msg, info, ok_text, icon=self.icon) def action(self): self.settings.remove_bookmark(self.repo, self.entry) return (0, '', '') class RemoveRecent(RemoveFromSettings): def confirm(self): repo = self.repo title = msg = N_('Remove %s from the recent list?') % repo info = N_('%s will be removed from your recent repositories.') % repo ok_text = N_('Remove') return Interaction.confirm(title, msg, info, ok_text, icon=self.icon) def action(self): self.settings.remove_recent(self.repo) return (0, '', '') class RemoveFiles(ContextCommand): """Removes files""" def __init__(self, context, remover, filenames): super(RemoveFiles, self).__init__(context) if remover is None: remover = os.remove self.remover = remover self.filenames = filenames # We could git-hash-object stuff and provide undo-ability # as an option. Heh. def do(self): files = self.filenames if not files: return rescan = False bad_filenames = [] remove = self.remover for filename in files: if filename: try: remove(filename) rescan = True except OSError: bad_filenames.append(filename) if bad_filenames: Interaction.information( N_('Error'), N_('Deleting "%s" failed') % file_summary(bad_filenames)) if rescan: self.model.update_file_status() class Delete(RemoveFiles): """Delete files.""" def __init__(self, context, filenames): super(Delete, self).__init__(context, os.remove, filenames) def do(self): files = self.filenames if not files: return title = N_('Delete Files?') msg = N_('The following files will be deleted:') + '\n\n' msg += file_summary(files) info_txt = N_('Delete %d file(s)?') % len(files) ok_txt = N_('Delete Files') if Interaction.confirm(title, msg, info_txt, ok_txt, default=True, icon=icons.remove()): super(Delete, self).do() class MoveToTrash(RemoveFiles): """Move files to the trash using send2trash""" AVAILABLE = send2trash is not None def __init__(self, context, filenames): super(MoveToTrash, self).__init__(context, send2trash, filenames) class DeleteBranch(ConfirmAction): """Delete a git branch.""" def __init__(self, context, branch): super(DeleteBranch, self).__init__(context) self.branch = branch def confirm(self): title = N_('Delete Branch') question = N_('Delete branch "%s"?') % self.branch info = N_('The branch will be no longer available.') ok_txt = N_('Delete Branch') return Interaction.confirm(title, question, info, ok_txt, default=True, icon=icons.discard()) def action(self): return self.model.delete_branch(self.branch) def error_message(self): return N_('Error deleting branch "%s"' % self.branch) def command(self): command = 'git branch -D %s' return command % self.branch class Rename(ContextCommand): """Rename a set of paths.""" def __init__(self, context, paths): super(Rename, self).__init__(context) self.paths = paths def do(self): msg = N_('Untracking: %s') % (', '.join(self.paths)) Interaction.log(msg) for path in self.paths: ok = self.rename(path) if not ok: return self.model.update_status() def rename(self, path): git = self.git title = N_('Rename "%s"') % path if os.path.isdir(path): base_path = os.path.dirname(path) else: base_path = path new_path = Interaction.save_as(base_path, title) if not new_path: return False status, out, err = git.mv(path, new_path, force=True, verbose=True) Interaction.command(N_('Error'), 'git mv', status, out, err) return status == 0 class RenameBranch(ContextCommand): """Rename a git branch.""" def __init__(self, context, branch, new_branch): super(RenameBranch, self).__init__(context) self.branch = branch self.new_branch = new_branch def do(self): branch = self.branch new_branch = self.new_branch status, out, err = self.model.rename_branch(branch, new_branch) Interaction.log_status(status, out, err) class DeleteRemoteBranch(DeleteBranch): """Delete a remote git branch.""" def __init__(self, context, remote, branch): super(DeleteRemoteBranch, self).__init__(context, branch) self.remote = remote def action(self): return self.git.push(self.remote, self.branch, delete=True) def success(self): self.model.update_status() Interaction.information( N_('Remote Branch Deleted'), N_('"%(branch)s" has been deleted from "%(remote)s".') % dict(branch=self.branch, remote=self.remote)) def error_message(self): return N_('Error Deleting Remote Branch') def command(self): command = 'git push --delete %s %s' return command % (self.remote, self.branch) def get_mode(model, staged, modified, unmerged, untracked): if staged: mode = model.mode_index elif modified or unmerged: mode = model.mode_worktree elif untracked: mode = model.mode_untracked else: mode = model.mode return mode class DiffImage(EditModel): def __init__(self, context, filename, deleted, staged, modified, unmerged, untracked): super(DiffImage, self).__init__(context) self.new_filename = filename self.new_diff_text = '' self.new_diff_type = 'image' self.new_mode = get_mode( self.model, staged, modified, unmerged, untracked) self.staged = staged self.modified = modified self.unmerged = unmerged self.untracked = untracked self.deleted = deleted self.annex = self.cfg.is_annex() def do(self): filename = self.new_filename if self.staged: images = self.staged_images() elif self.modified: images = self.modified_images() elif self.unmerged: images = self.unmerged_images() elif self.untracked: images = [(filename, False)] else: images = [] self.model.set_images(images) super(DiffImage, self).do() def staged_images(self): context = self.context git = self.git head = self.model.head filename = self.new_filename annex = self.annex images = [] index = git.diff_index(head, '--', filename, cached=True)[STDOUT] if index: # Example: # :100644 100644 fabadb8... 4866510... M describe.c parts = index.split(' ') if len(parts) > 3: old_oid = parts[2] new_oid = parts[3] if old_oid != MISSING_BLOB_OID: # First, check if we can get a pre-image from git-annex annex_image = None if annex: annex_image = gitcmds.annex_path(context, head, filename) if annex_image: images.append((annex_image, False)) # git annex HEAD else: image = gitcmds.write_blob_path( context, head, old_oid, filename) if image: images.append((image, True)) if new_oid != MISSING_BLOB_OID: found_in_annex = False if annex and core.islink(filename): status, out, _ = git.annex('status', '--', filename) if status == 0: details = out.split(' ') if details and details[0] == 'A': # newly added file images.append((filename, False)) found_in_annex = True if not found_in_annex: image = gitcmds.write_blob(context, new_oid, filename) if image: images.append((image, True)) return images def unmerged_images(self): context = self.context git = self.git head = self.model.head filename = self.new_filename annex = self.annex candidate_merge_heads = ('HEAD', 'CHERRY_HEAD', 'MERGE_HEAD') merge_heads = [ merge_head for merge_head in candidate_merge_heads if core.exists(git.git_path(merge_head))] if annex: # Attempt to find files in git-annex annex_images = [] for merge_head in merge_heads: image = gitcmds.annex_path(context, merge_head, filename) if image: annex_images.append((image, False)) if annex_images: annex_images.append((filename, False)) return annex_images # DIFF FORMAT FOR MERGES # "git-diff-tree", "git-diff-files" and "git-diff --raw" # can take -c or --cc option to generate diff output also # for merge commits. The output differs from the format # described above in the following way: # # 1. there is a colon for each parent # 2. there are more "src" modes and "src" sha1 # 3. status is concatenated status characters for each parent # 4. no optional "score" number # 5. single path, only for "dst" # Example: # ::100644 100644 100644 fabadb8... cc95eb0... 4866510... \ # MM describe.c images = [] index = git.diff_index(head, '--', filename, cached=True, cc=True)[STDOUT] if index: parts = index.split(' ') if len(parts) > 3: first_mode = parts[0] num_parents = first_mode.count(':') # colon for each parent, but for the index, the "parents" # are really entries in stages 1,2,3 (head, base, remote) # remote, base, head for i in range(num_parents): offset = num_parents + i + 1 oid = parts[offset] try: merge_head = merge_heads[i] except IndexError: merge_head = 'HEAD' if oid != MISSING_BLOB_OID: image = gitcmds.write_blob_path( context, merge_head, oid, filename) if image: images.append((image, True)) images.append((filename, False)) return images def modified_images(self): context = self.context git = self.git head = self.model.head filename = self.new_filename annex = self.annex images = [] annex_image = None if annex: # Check for a pre-image from git-annex annex_image = gitcmds.annex_path(context, head, filename) if annex_image: images.append((annex_image, False)) # git annex HEAD else: worktree = git.diff_files('--', filename)[STDOUT] parts = worktree.split(' ') if len(parts) > 3: oid = parts[2] if oid != MISSING_BLOB_OID: image = gitcmds.write_blob_path( context, head, oid, filename) if image: images.append((image, True)) # HEAD images.append((filename, False)) # worktree return images class Diff(EditModel): """Perform a diff and set the model's current text.""" def __init__(self, context, filename, cached=False, deleted=False): super(Diff, self).__init__(context) opts = {} if cached: opts['ref'] = self.model.head self.new_filename = filename self.new_mode = self.model.mode_worktree self.new_diff_text = gitcmds.diff_helper( self.context, filename=filename, cached=cached, deleted=deleted, **opts) self.new_diff_type = 'text' class Diffstat(EditModel): """Perform a diffstat and set the model's diff text.""" def __init__(self, context): super(Diffstat, self).__init__(context) cfg = self.cfg diff_context = cfg.get('diff.context', 3) diff = self.git.diff( self.model.head, unified=diff_context, no_ext_diff=True, no_color=True, M=True, stat=True)[STDOUT] self.new_diff_text = diff self.new_diff_type = 'text' self.new_mode = self.model.mode_diffstat class DiffStaged(Diff): """Perform a staged diff on a file.""" def __init__(self, context, filename, deleted=None): super(DiffStaged, self).__init__( context, filename, cached=True, deleted=deleted) self.new_mode = self.model.mode_index class DiffStagedSummary(EditModel): def __init__(self, context): super(DiffStagedSummary, self).__init__(context) diff = self.git.diff( self.model.head, cached=True, no_color=True, no_ext_diff=True, patch_with_stat=True, M=True)[STDOUT] self.new_diff_text = diff self.new_diff_type = 'text' self.new_mode = self.model.mode_index class Difftool(ContextCommand): """Run git-difftool limited by path.""" def __init__(self, context, staged, filenames): super(Difftool, self).__init__(context) self.staged = staged self.filenames = filenames def do(self): difftool_launch_with_head( self.context, self.filenames, self.staged, self.model.head) class Edit(ContextCommand): """Edit a file using the configured gui.editor.""" @staticmethod def name(): return N_('Launch Editor') def __init__(self, context, filenames, line_number=None, background_editor=False): super(Edit, self).__init__(context) self.filenames = filenames self.line_number = line_number self.background_editor = background_editor def do(self): context = self.context if not self.filenames: return filename = self.filenames[0] if not core.exists(filename): return if self.background_editor: editor = prefs.background_editor(context) else: editor = prefs.editor(context) opts = [] if self.line_number is None: opts = self.filenames else: # Single-file w/ line-numbers (likely from grep) editor_opts = { '*vim*': [filename, '+%s' % self.line_number], '*emacs*': ['+%s' % self.line_number, filename], '*textpad*': ['%s(%s,0)' % (filename, self.line_number)], '*notepad++*': ['-n%s' % self.line_number, filename], '*subl*': ['%s:%s' % (filename, self.line_number)], } opts = self.filenames for pattern, opt in editor_opts.items(): if fnmatch(editor, pattern): opts = opt break try: core.fork(utils.shell_split(editor) + opts) except (OSError, ValueError) as e: message = (N_('Cannot exec "%s": please configure your editor') % editor) _, details = utils.format_exception(e) Interaction.critical(N_('Error Editing File'), message, details) class FormatPatch(ContextCommand): """Output a patch series given all revisions and a selected subset.""" def __init__(self, context, to_export, revs, output='patches'): super(FormatPatch, self).__init__(context) self.to_export = list(to_export) self.revs = list(revs) self.output = output def do(self): context = self.context status, out, err = gitcmds.format_patchsets( context, self.to_export, self.revs, self.output) Interaction.log_status(status, out, err) class LaunchDifftool(ContextCommand): @staticmethod def name(): return N_('Launch Diff Tool') def do(self): s = self.selection.selection() if s.unmerged: paths = s.unmerged if utils.is_win32(): core.fork(['git', 'mergetool', '--no-prompt', '--'] + paths) else: cfg = self.cfg cmd = cfg.terminal() argv = utils.shell_split(cmd) terminal = os.path.basename(argv[0]) shellquote_terms = set(['xfce4-terminal']) shellquote_default = terminal in shellquote_terms mergetool = ['git', 'mergetool', '--no-prompt', '--'] mergetool.extend(paths) needs_shellquote = cfg.get( 'cola.terminalshellquote', shellquote_default) if needs_shellquote: argv.append(core.list2cmdline(mergetool)) else: argv.extend(mergetool) core.fork(argv) else: difftool_run(self.context) class LaunchTerminal(ContextCommand): @staticmethod def name(): return N_('Launch Terminal') @staticmethod def is_available(context): return context.cfg.terminal() is not None def __init__(self, context, path): super(LaunchTerminal, self).__init__(context) self.path = path def do(self): cmd = self.context.cfg.terminal() if cmd is None: return if utils.is_win32(): argv = ['start', '', cmd, '--login'] shell = True else: argv = utils.shell_split(cmd) argv.append(os.getenv('SHELL', '/bin/sh')) shell = False core.fork(argv, cwd=self.path, shell=shell) class LaunchEditor(Edit): @staticmethod def name(): return N_('Launch Editor') def __init__(self, context): s = context.selection.selection() filenames = s.staged + s.unmerged + s.modified + s.untracked super(LaunchEditor, self).__init__( context, filenames, background_editor=True) class LaunchEditorAtLine(LaunchEditor): """Launch an editor at the specified line""" def __init__(self, context): super(LaunchEditorAtLine, self).__init__(context) self.line_number = context.selection.line_number class LoadCommitMessageFromFile(ContextCommand): """Loads a commit message from a path.""" UNDOABLE = True def __init__(self, context, path): super(LoadCommitMessageFromFile, self).__init__(context) self.path = path self.old_commitmsg = self.model.commitmsg self.old_directory = self.model.directory def do(self): path = os.path.expanduser(self.path) if not path or not core.isfile(path): raise UsageError(N_('Error: Cannot find commit template'), N_('%s: No such file or directory.') % path) self.model.set_directory(os.path.dirname(path)) self.model.set_commitmsg(core.read(path)) def undo(self): self.model.set_commitmsg(self.old_commitmsg) self.model.set_directory(self.old_directory) class LoadCommitMessageFromTemplate(LoadCommitMessageFromFile): """Loads the commit message template specified by commit.template.""" def __init__(self, context): cfg = context.cfg template = cfg.get('commit.template') super(LoadCommitMessageFromTemplate, self).__init__(context, template) def do(self): if self.path is None: raise UsageError( N_('Error: Unconfigured commit template'), N_('A commit template has not been configured.\n' 'Use "git config" to define "commit.template"\n' 'so that it points to a commit template.')) return LoadCommitMessageFromFile.do(self) class LoadCommitMessageFromOID(ContextCommand): """Load a previous commit message""" UNDOABLE = True def __init__(self, context, oid, prefix=''): super(LoadCommitMessageFromOID, self).__init__(context) self.oid = oid self.old_commitmsg = self.model.commitmsg self.new_commitmsg = prefix + gitcmds.prev_commitmsg(context, oid) def do(self): self.model.set_commitmsg(self.new_commitmsg) def undo(self): self.model.set_commitmsg(self.old_commitmsg) class PrepareCommitMessageHook(ContextCommand): """Use the cola-prepare-commit-msg hook to prepare the commit message """ UNDOABLE = True def __init__(self, context): super(PrepareCommitMessageHook, self).__init__(context) self.old_commitmsg = self.model.commitmsg def get_message(self): title = N_('Error running prepare-commitmsg hook') hook = gitcmds.prepare_commit_message_hook(self.context) if os.path.exists(hook): filename = self.model.save_commitmsg() status, out, err = core.run_command([hook, filename]) if status == 0: result = core.read(filename) else: result = self.old_commitmsg Interaction.command_error(title, hook, status, out, err) else: message = N_('A hook must be provided at "%s"') % hook Interaction.critical(title, message=message) result = self.old_commitmsg return result def do(self): msg = self.get_message() self.model.set_commitmsg(msg) def undo(self): self.model.set_commitmsg(self.old_commitmsg) class LoadFixupMessage(LoadCommitMessageFromOID): """Load a fixup message""" def __init__(self, context, oid): super(LoadFixupMessage, self).__init__(context, oid, prefix='fixup! ') if self.new_commitmsg: self.new_commitmsg = self.new_commitmsg.splitlines()[0] class Merge(ContextCommand): """Merge commits""" def __init__(self, context, revision, no_commit, squash, no_ff, sign): super(Merge, self).__init__(context) self.revision = revision self.no_ff = no_ff self.no_commit = no_commit self.squash = squash self.sign = sign def do(self): squash = self.squash revision = self.revision no_ff = self.no_ff no_commit = self.no_commit sign = self.sign status, out, err = self.git.merge( revision, gpg_sign=sign, no_ff=no_ff, no_commit=no_commit, squash=squash) self.model.update_status() title = N_('Merge failed. Conflict resolution is required.') Interaction.command(title, 'git merge', status, out, err) return status, out, err class OpenDefaultApp(ContextCommand): """Open a file using the OS default.""" @staticmethod def name(): return N_('Open Using Default Application') def __init__(self, context, filenames): super(OpenDefaultApp, self).__init__(context) if utils.is_darwin(): launcher = 'open' else: launcher = 'xdg-open' self.launcher = launcher self.filenames = filenames def do(self): if not self.filenames: return core.fork([self.launcher] + self.filenames) class OpenParentDir(OpenDefaultApp): """Open parent directories using the OS default.""" @staticmethod def name(): return N_('Open Parent Directory') def __init__(self, context, filenames): OpenDefaultApp.__init__(self, context, filenames) def do(self): if not self.filenames: return dirnames = list(set([os.path.dirname(x) for x in self.filenames])) # os.path.dirname() can return an empty string so we fallback to # the current directory dirs = [(dirname or core.getcwd()) for dirname in dirnames] core.fork([self.launcher] + dirs) class OpenNewRepo(ContextCommand): """Launches git-cola on a repo.""" def __init__(self, context, repo_path): super(OpenNewRepo, self).__init__(context) self.repo_path = repo_path def do(self): self.model.set_directory(self.repo_path) core.fork([sys.executable, sys.argv[0], '--repo', self.repo_path]) class OpenRepo(EditModel): def __init__(self, context, repo_path): super(OpenRepo, self).__init__(context) self.repo_path = repo_path self.new_mode = self.model.mode_none self.new_diff_text = '' self.new_diff_type = 'text' self.new_commitmsg = '' self.new_filename = '' def do(self): old_repo = self.git.getcwd() if self.model.set_worktree(self.repo_path): self.fsmonitor.stop() self.fsmonitor.start() self.model.update_status() # Check if template should be loaded if self.context.cfg.get(prefs.AUTOTEMPLATE): template_loader = LoadCommitMessageFromTemplate(self.context) template_loader.do() else: self.model.set_commitmsg(self.new_commitmsg) settings = Settings() settings.load() settings.add_recent(self.repo_path, prefs.maxrecent(self.context)) settings.save() super(OpenRepo, self).do() else: self.model.set_worktree(old_repo) class OpenParentRepo(OpenRepo): def __init__(self, context): path = '' if version.check_git(context, 'show-superproject-working-tree'): status, out, _ = context.git.rev_parse( show_superproject_working_tree=True) if status == 0: path = out if not path: path = os.path.dirname(core.getcwd()) super(OpenParentRepo, self).__init__(context, path) class Clone(ContextCommand): """Clones a repository and optionally spawns a new cola session.""" def __init__(self, context, url, new_directory, submodules=False, shallow=False, spawn=True): super(Clone, self).__init__(context) self.url = url self.new_directory = new_directory self.submodules = submodules self.shallow = shallow self.spawn = spawn self.status = -1 self.out = '' self.err = '' def do(self): kwargs = {} if self.shallow: kwargs['depth'] = 1 recurse_submodules = self.submodules shallow_submodules = self.submodules and self.shallow status, out, err = self.git.clone( self.url, self.new_directory, recurse_submodules=recurse_submodules, shallow_submodules=shallow_submodules, **kwargs) self.status = status self.out = out self.err = err if status == 0 and self.spawn: executable = sys.executable core.fork([executable, sys.argv[0], '--repo', self.new_directory]) return self class NewBareRepo(ContextCommand): """Create a new shared bare repository""" def __init__(self, context, path): super(NewBareRepo, self).__init__(context) self.path = path def do(self): path = self.path status, out, err = self.git.init(path, bare=True, shared=True) Interaction.command( N_('Error'), 'git init --bare --shared "%s"' % path, status, out, err) return status == 0 def unix_path(path, is_win32=utils.is_win32): """Git for Windows requires unix paths, so force them here """ if is_win32(): path = path.replace('\\', '/') first = path[0] second = path[1] if second == ':': # sanity check, this better be a Windows-style path path = '/' + first + path[2:] return path def sequence_editor(): """Return a GIT_SEQUENCE_EDITOR environment value that enables git-xbase""" xbase = unix_path(resources.share('bin', 'git-xbase')) editor = core.list2cmdline([unix_path(sys.executable), xbase]) return editor class GitXBaseContext(object): def __init__(self, context, **kwargs): self.env = { 'GIT_EDITOR': prefs.editor(context), 'GIT_SEQUENCE_EDITOR': sequence_editor(), 'GIT_XBASE_CANCEL_ACTION': 'save', } self.env.update(kwargs) def __enter__(self): for var, value in self.env.items(): compat.setenv(var, value) return self def __exit__(self, exc_type, exc_val, exc_tb): for var in self.env: compat.unsetenv(var) class Rebase(ContextCommand): def __init__(self, context, upstream=None, branch=None, **kwargs): """Start an interactive rebase session :param upstream: upstream branch :param branch: optional branch to checkout :param kwargs: forwarded directly to `git.rebase()` """ super(Rebase, self).__init__(context) self.upstream = upstream self.branch = branch self.kwargs = kwargs def prepare_arguments(self, upstream): args = [] kwargs = {} # Rebase actions must be the only option specified for action in ('continue', 'abort', 'skip', 'edit_todo'): if self.kwargs.get(action, False): kwargs[action] = self.kwargs[action] return args, kwargs kwargs['interactive'] = True kwargs['autosquash'] = self.kwargs.get('autosquash', True) kwargs.update(self.kwargs) if upstream: args.append(upstream) if self.branch: args.append(self.branch) return args, kwargs def do(self): (status, out, err) = (1, '', '') context = self.context cfg = self.cfg model = self.model if not cfg.get('rebase.autostash', False): if model.staged or model.unmerged or model.modified: Interaction.information( N_('Unable to rebase'), N_('You cannot rebase with uncommitted changes.')) return status, out, err upstream = self.upstream or Interaction.choose_ref( context, N_('Select New Upstream'), N_('Interactive Rebase'), default='@{upstream}') if not upstream: return status, out, err self.model.is_rebasing = True self.model.emit_updated() args, kwargs = self.prepare_arguments(upstream) upstream_title = upstream or '@{upstream}' with GitXBaseContext( self.context, GIT_XBASE_TITLE=N_('Rebase onto %s') % upstream_title, GIT_XBASE_ACTION=N_('Rebase') ): # TODO this blocks the user interface window for the duration # of git-xbase's invocation. We would need to implement # signals for QProcess and continue running the main thread. # alternatively we could hide the main window while rebasing. # that doesn't require as much effort. status, out, err = self.git.rebase( *args, _no_win32_startupinfo=True, **kwargs) self.model.update_status() if err.strip() != 'Nothing to do': title = N_('Rebase stopped') Interaction.command(title, 'git rebase', status, out, err) return status, out, err class RebaseEditTodo(ContextCommand): def do(self): (status, out, err) = (1, '', '') with GitXBaseContext( self.context, GIT_XBASE_TITLE=N_('Edit Rebase'), GIT_XBASE_ACTION=N_('Save') ): status, out, err = self.git.rebase(edit_todo=True) Interaction.log_status(status, out, err) self.model.update_status() return status, out, err class RebaseContinue(ContextCommand): def do(self): (status, out, err) = (1, '', '') with GitXBaseContext( self.context, GIT_XBASE_TITLE=N_('Rebase'), GIT_XBASE_ACTION=N_('Rebase') ): status, out, err = self.git.rebase('--continue') Interaction.log_status(status, out, err) self.model.update_status() return status, out, err class RebaseSkip(ContextCommand): def do(self): (status, out, err) = (1, '', '') with GitXBaseContext( self.context, GIT_XBASE_TITLE=N_('Rebase'), GIT_XBASE_ACTION=N_('Rebase') ): status, out, err = self.git.rebase(skip=True) Interaction.log_status(status, out, err) self.model.update_status() return status, out, err class RebaseAbort(ContextCommand): def do(self): status, out, err = self.git.rebase(abort=True) Interaction.log_status(status, out, err) self.model.update_status() class Rescan(ContextCommand): """Rescan for changes""" def do(self): self.model.update_status() class Refresh(ContextCommand): """Update refs, refresh the index, and update config""" @staticmethod def name(): return N_('Refresh') def do(self): self.model.update_status(update_index=True) self.cfg.update() self.fsmonitor.refresh() class RefreshConfig(ContextCommand): """Refresh the git config cache""" def do(self): self.cfg.update() class RevertEditsCommand(ConfirmAction): def __init__(self, context): super(RevertEditsCommand, self).__init__(context) self.icon = icons.undo() def ok_to_run(self): return self.model.undoable() # pylint: disable=no-self-use def checkout_from_head(self): return False def checkout_args(self): args = [] s = self.selection.selection() if self.checkout_from_head(): args.append(self.model.head) args.append('--') if s.staged: items = s.staged else: items = s.modified args.extend(items) return args def action(self): checkout_args = self.checkout_args() return self.git.checkout(*checkout_args) def success(self): self.model.update_file_status() class RevertUnstagedEdits(RevertEditsCommand): @staticmethod def name(): return N_('Revert Unstaged Edits...') def checkout_from_head(self): # Being in amend mode should not affect the behavior of this command. # The only sensible thing to do is to checkout from the index. return False def confirm(self): title = N_('Revert Unstaged Changes?') text = N_( 'This operation removes unstaged edits from selected files.\n' 'These changes cannot be recovered.') info = N_('Revert the unstaged changes?') ok_text = N_('Revert Unstaged Changes') return Interaction.confirm(title, text, info, ok_text, default=True, icon=self.icon) class RevertUncommittedEdits(RevertEditsCommand): @staticmethod def name(): return N_('Revert Uncommitted Edits...') def checkout_from_head(self): return True def confirm(self): """Prompt for reverting changes""" title = N_('Revert Uncommitted Changes?') text = N_( 'This operation removes uncommitted edits from selected files.\n' 'These changes cannot be recovered.') info = N_('Revert the uncommitted changes?') ok_text = N_('Revert Uncommitted Changes') return Interaction.confirm(title, text, info, ok_text, default=True, icon=self.icon) class RunConfigAction(ContextCommand): """Run a user-configured action, typically from the "Tools" menu""" def __init__(self, context, action_name): super(RunConfigAction, self).__init__(context) self.action_name = action_name def do(self): """Run the user-configured action""" for env in ('ARGS', 'DIRNAME', 'FILENAME', 'REVISION'): try: compat.unsetenv(env) except KeyError: pass rev = None args = None context = self.context cfg = self.cfg opts = cfg.get_guitool_opts(self.action_name) cmd = opts.get('cmd') if 'title' not in opts: opts['title'] = cmd if 'prompt' not in opts or opts.get('prompt') is True: prompt = N_('Run "%s"?') % cmd opts['prompt'] = prompt if opts.get('needsfile'): filename = self.selection.filename() if not filename: Interaction.information( N_('Please select a file'), N_('"%s" requires a selected file.') % cmd) return False dirname = utils.dirname(filename, current_dir='.') compat.setenv('FILENAME', filename) compat.setenv('DIRNAME', dirname) if opts.get('revprompt') or opts.get('argprompt'): while True: ok = Interaction.confirm_config_action(context, cmd, opts) if not ok: return False rev = opts.get('revision') args = opts.get('args') if opts.get('revprompt') and not rev: title = N_('Invalid Revision') msg = N_('The revision expression cannot be empty.') Interaction.critical(title, msg) continue break elif opts.get('confirm'): title = os.path.expandvars(opts.get('title')) prompt = os.path.expandvars(opts.get('prompt')) if not Interaction.question(title, prompt): return False if rev: compat.setenv('REVISION', rev) if args: compat.setenv('ARGS', args) title = os.path.expandvars(cmd) Interaction.log(N_('Running command: %s') % title) cmd = ['sh', '-c', cmd] if opts.get('background'): core.fork(cmd) status, out, err = (0, '', '') elif opts.get('noconsole'): status, out, err = core.run_command(cmd) else: status, out, err = Interaction.run_command(title, cmd) if not opts.get('background') and not opts.get('norescan'): self.model.update_status() title = N_('Error') Interaction.command(title, cmd, status, out, err) return status == 0 class SetDefaultRepo(ContextCommand): """Set the default repository""" def __init__(self, context, repo): super(SetDefaultRepo, self).__init__(context) self.repo = repo def do(self): self.cfg.set_user('cola.defaultrepo', self.repo) class SetDiffText(EditModel): """Set the diff text""" UNDOABLE = True def __init__(self, context, text): super(SetDiffText, self).__init__(context) self.new_diff_text = text self.new_diff_type = 'text' class SetUpstreamBranch(ContextCommand): """Set the upstream branch""" def __init__(self, context, branch, remote, remote_branch): super(SetUpstreamBranch, self).__init__(context) self.branch = branch self.remote = remote self.remote_branch = remote_branch def do(self): cfg = self.cfg remote = self.remote branch = self.branch remote_branch = self.remote_branch cfg.set_repo('branch.%s.remote' % branch, remote) cfg.set_repo('branch.%s.merge' % branch, 'refs/heads/' + remote_branch) class ShowUntracked(EditModel): """Show an untracked file.""" def __init__(self, context, filename): super(ShowUntracked, self).__init__(context) self.new_filename = filename self.new_mode = self.model.mode_untracked self.new_diff_text = self.read(filename) self.new_diff_type = 'text' def read(self, filename): """Read file contents""" cfg = self.cfg size = cfg.get('cola.readsize', 2048) try: result = core.read(filename, size=size, encoding=core.ENCODING, errors='ignore') except (IOError, OSError): result = '' if len(result) == size: result += '...' return result class SignOff(ContextCommand): """Append a signoff to the commit message""" UNDOABLE = True @staticmethod def name(): return N_('Sign Off') def __init__(self, context): super(SignOff, self).__init__(context) self.old_commitmsg = self.model.commitmsg def do(self): """Add a signoff to the commit message""" signoff = self.signoff() if signoff in self.model.commitmsg: return msg = self.model.commitmsg.rstrip() self.model.set_commitmsg(msg + '\n' + signoff) def undo(self): """Restore the commit message""" self.model.set_commitmsg(self.old_commitmsg) def signoff(self): """Generate the signoff string""" try: import pwd user = pwd.getpwuid(os.getuid()).pw_name except ImportError: user = os.getenv('USER', N_('unknown')) cfg = self.cfg name = cfg.get('user.name', user) email = cfg.get('user.email', '%s@%s' % (user, core.node())) return '\nSigned-off-by: %s <%s>' % (name, email) def check_conflicts(context, unmerged): """Check paths for conflicts Conflicting files can be filtered out one-by-one. """ if prefs.check_conflicts(context): unmerged = [path for path in unmerged if is_conflict_free(path)] return unmerged def is_conflict_free(path): """Return True if `path` contains no conflict markers """ rgx = re.compile(r'^(<<<<<<<|\|\|\|\|\|\|\||>>>>>>>) ') try: with core.xopen(path, 'r') as f: for line in f: line = core.decode(line, errors='ignore') if rgx.match(line): return should_stage_conflicts(path) except IOError: # We can't read this file ~ we may be staging a removal pass return True def should_stage_conflicts(path): """Inform the user that a file contains merge conflicts Return `True` if we should stage the path nonetheless. """ title = msg = N_('Stage conflicts?') info = N_('%s appears to contain merge conflicts.\n\n' 'You should probably skip this file.\n' 'Stage it anyways?') % path ok_text = N_('Stage conflicts') cancel_text = N_('Skip') return Interaction.confirm(title, msg, info, ok_text, default=False, cancel_text=cancel_text) class Stage(ContextCommand): """Stage a set of paths.""" @staticmethod def name(): return N_('Stage') def __init__(self, context, paths): super(Stage, self).__init__(context) self.paths = paths def do(self): msg = N_('Staging: %s') % (', '.join(self.paths)) Interaction.log(msg) return self.stage_paths() def stage_paths(self): """Stages add/removals to git.""" context = self.context paths = self.paths if not paths: if self.model.cfg.get('cola.safemode', False): return (0, '', '') return self.stage_all() add = [] remove = [] for path in set(paths): if core.exists(path) or core.islink(path): if path.endswith('/'): path = path.rstrip('/') add.append(path) else: remove.append(path) self.model.emit_about_to_update() # `git add -u` doesn't work on untracked files if add: status, out, err = gitcmds.add(context, add) Interaction.command(N_('Error'), 'git add', status, out, err) # If a path doesn't exist then that means it should be removed # from the index. We use `git add -u` for that. if remove: status, out, err = gitcmds.add(context, remove, u=True) Interaction.command(N_('Error'), 'git add -u', status, out, err) self.model.update_files(emit=True) return status, out, err def stage_all(self): """Stage all files""" status, out, err = self.git.add(v=True, u=True) Interaction.command(N_('Error'), 'git add -u', status, out, err) self.model.update_file_status() return (status, out, err) class StageCarefully(Stage): """Only stage when the path list is non-empty We use "git add -u -- " to stage, and it stages everything by default when no pathspec is specified, so this class ensures that paths are specified before calling git. When no paths are specified, the command does nothing. """ def __init__(self, context): super(StageCarefully, self).__init__(context, None) self.init_paths() # pylint: disable=no-self-use def init_paths(self): """Initialize path data""" return def ok_to_run(self): """Prevent catch-all "git add -u" from adding unmerged files""" return self.paths or not self.model.unmerged def do(self): """Stage files when ok_to_run() return True""" if self.ok_to_run(): return super(StageCarefully, self).do() return (0, '', '') class StageModified(StageCarefully): """Stage all modified files.""" @staticmethod def name(): return N_('Stage Modified') def init_paths(self): self.paths = self.model.modified class StageUnmerged(StageCarefully): """Stage unmerged files.""" @staticmethod def name(): return N_('Stage Unmerged') def init_paths(self): self.paths = check_conflicts(self.context, self.model.unmerged) class StageUntracked(StageCarefully): """Stage all untracked files.""" @staticmethod def name(): return N_('Stage Untracked') def init_paths(self): self.paths = self.model.untracked class StageOrUnstage(ContextCommand): """If the selection is staged, unstage it, otherwise stage""" @staticmethod def name(): return N_('Stage / Unstage') def do(self): s = self.selection.selection() if s.staged: do(Unstage, self.context, s.staged) unstaged = [] unmerged = check_conflicts(self.context, s.unmerged) if unmerged: unstaged.extend(unmerged) if s.modified: unstaged.extend(s.modified) if s.untracked: unstaged.extend(s.untracked) if unstaged: do(Stage, self.context, unstaged) class Tag(ContextCommand): """Create a tag object.""" def __init__(self, context, name, revision, sign=False, message=''): super(Tag, self).__init__(context) self._name = name self._message = message self._revision = revision self._sign = sign def do(self): result = False git = self.git revision = self._revision tag_name = self._name tag_message = self._message if not revision: Interaction.critical( N_('Missing Revision'), N_('Please specify a revision to tag.')) return result if not tag_name: Interaction.critical( N_('Missing Name'), N_('Please specify a name for the new tag.')) return result title = N_('Missing Tag Message') message = N_('Tag-signing was requested but the tag message is empty.') info = N_('An unsigned, lightweight tag will be created instead.\n' 'Create an unsigned tag?') ok_text = N_('Create Unsigned Tag') sign = self._sign if sign and not tag_message: # We require a message in order to sign the tag, so if they # choose to create an unsigned tag we have to clear the sign flag. if not Interaction.confirm(title, message, info, ok_text, default=False, icon=icons.save()): return result sign = False opts = {} tmp_file = None try: if tag_message: tmp_file = utils.tmp_filename('tag-message') opts['file'] = tmp_file core.write(tmp_file, tag_message) if sign: opts['sign'] = True if tag_message: opts['annotate'] = True status, out, err = git.tag(tag_name, revision, **opts) finally: if tmp_file: core.unlink(tmp_file) title = N_('Error: could not create tag "%s"') % tag_name Interaction.command(title, 'git tag', status, out, err) if status == 0: result = True self.model.update_status() Interaction.information( N_('Tag Created'), N_('Created a new tag named "%s"') % tag_name, details=tag_message or None) return result class Unstage(ContextCommand): """Unstage a set of paths.""" @staticmethod def name(): return N_('Unstage') def __init__(self, context, paths): super(Unstage, self).__init__(context) self.paths = paths def do(self): """Unstage paths""" context = self.context head = self.model.head paths = self.paths msg = N_('Unstaging: %s') % (', '.join(paths)) Interaction.log(msg) if not paths: return unstage_all(context) status, out, err = gitcmds.unstage_paths(context, paths, head=head) Interaction.command(N_('Error'), 'git reset', status, out, err) self.model.update_file_status() return (status, out, err) class UnstageAll(ContextCommand): """Unstage all files; resets the index.""" def do(self): return unstage_all(self.context) def unstage_all(context): """Unstage all files, even while amending""" model = context.model git = context.git head = model.head status, out, err = git.reset(head, '--', '.') Interaction.command(N_('Error'), 'git reset', status, out, err) model.update_file_status() return (status, out, err) class StageSelected(ContextCommand): """Stage selected files, or all files if no selection exists.""" def do(self): context = self.context paths = self.selection.unstaged if paths: do(Stage, context, paths) elif self.cfg.get('cola.safemode', False): do(StageModified, context) class UnstageSelected(Unstage): """Unstage selected files.""" def __init__(self, context): staged = self.selection.staged super(UnstageSelected, self).__init__(context, staged) class Untrack(ContextCommand): """Unstage a set of paths.""" def __init__(self, context, paths): super(Untrack, self).__init__(context) self.paths = paths def do(self): msg = N_('Untracking: %s') % (', '.join(self.paths)) Interaction.log(msg) status, out, err = self.model.untrack_paths(self.paths) Interaction.log_status(status, out, err) class UntrackedSummary(EditModel): """List possible .gitignore rules as the diff text.""" def __init__(self, context): super(UntrackedSummary, self).__init__(context) untracked = self.model.untracked suffix = 's' if untracked else '' io = StringIO() io.write('# %s untracked file%s\n' % (len(untracked), suffix)) if untracked: io.write('# possible .gitignore rule%s:\n' % suffix) for u in untracked: io.write('/'+u+'\n') self.new_diff_text = io.getvalue() self.new_diff_type = 'text' self.new_mode = self.model.mode_untracked class VisualizeAll(ContextCommand): """Visualize all branches.""" def do(self): context = self.context browser = utils.shell_split(prefs.history_browser(context)) launch_history_browser(browser + ['--all']) class VisualizeCurrent(ContextCommand): """Visualize all branches.""" def do(self): context = self.context browser = utils.shell_split(prefs.history_browser(context)) launch_history_browser(browser + [self.model.currentbranch] + ['--']) class VisualizePaths(ContextCommand): """Path-limited visualization.""" def __init__(self, context, paths): super(VisualizePaths, self).__init__(context) context = self.context browser = utils.shell_split(prefs.history_browser(context)) if paths: self.argv = browser + ['--'] + list(paths) else: self.argv = browser def do(self): launch_history_browser(self.argv) class VisualizeRevision(ContextCommand): """Visualize a specific revision.""" def __init__(self, context, revision, paths=None): super(VisualizeRevision, self).__init__(context) self.revision = revision self.paths = paths def do(self): context = self.context argv = utils.shell_split(prefs.history_browser(context)) if self.revision: argv.append(self.revision) if self.paths: argv.append('--') argv.extend(self.paths) launch_history_browser(argv) class SubmoduleUpdate(ConfirmAction): """Update specified submodule""" def __init__(self, context, path): super(SubmoduleUpdate, self).__init__(context) self.path = path def confirm(self): title = N_('Update Submodule...') question = N_('Update this submodule?') info = N_('The submodule will be updated using\n' '"%s"' % self.command()) ok_txt = N_('Update Submodule') return Interaction.confirm(title, question, info, ok_txt, default=False, icon=icons.pull()) def action(self): context = self.context return context.git.submodule('update', '--', self.path) def success(self): self.model.update_file_status() def error_message(self): return N_('Error updating submodule %s' % self.path) def command(self): command = 'git submodule update -- %s' return command % self.path class SubmodulesUpdate(ConfirmAction): """Update all submodules""" def confirm(self): title = N_('Update submodules...') question = N_('Update all submodules?') info = N_('All submodules will be updated using\n' '"%s"' % self.command()) ok_txt = N_('Update Submodules') return Interaction.confirm(title, question, info, ok_txt, default=False, icon=icons.pull()) def action(self): context = self.context return context.git.submodule('update') def success(self): self.model.update_file_status() def error_message(self): return N_('Error updating submodules') def command(self): return 'git submodule update' def launch_history_browser(argv): """Launch the configured history browser""" try: core.fork(argv) except OSError as e: _, details = utils.format_exception(e) title = N_('Error Launching History Browser') msg = (N_('Cannot exec "%s": please configure a history browser') % ' '.join(argv)) Interaction.critical(title, message=msg, details=details) def run(cls, *args, **opts): """ Returns a callback that runs a command If the caller of run() provides args or opts then those are used instead of the ones provided by the invoker of the callback. """ def runner(*local_args, **local_opts): """Closure return by run() which runs the command""" if args or opts: do(cls, *args, **opts) else: do(cls, *local_args, **local_opts) return runner def do(cls, *args, **opts): """Run a command in-place""" try: cmd = cls(*args, **opts) return cmd.do() except Exception as e: # pylint: disable=broad-except msg, details = utils.format_exception(e) if hasattr(cls, '__name__'): msg = ('%s exception:\n%s' % (cls.__name__, msg)) Interaction.critical(N_('Error'), message=msg, details=details) return None def difftool_run(context): """Start a default difftool session""" selection = context.selection files = selection.group() if not files: return s = selection.selection() head = context.model.head difftool_launch_with_head(context, files, bool(s.staged), head) def difftool_launch_with_head(context, filenames, staged, head): """Launch difftool against the provided head""" if head == 'HEAD': left = None else: left = head difftool_launch(context, left=left, staged=staged, paths=filenames) def difftool_launch(context, left=None, right=None, paths=None, staged=False, dir_diff=False, left_take_magic=False, left_take_parent=False): """Launches 'git difftool' with given parameters :param left: first argument to difftool :param right: second argument to difftool_args :param paths: paths to diff :param staged: activate `git difftool --staged` :param dir_diff: activate `git difftool --dir-diff` :param left_take_magic: whether to append the magic ^! diff expression :param left_take_parent: whether to append the first-parent ~ for diffing """ difftool_args = ['git', 'difftool', '--no-prompt'] if staged: difftool_args.append('--cached') if dir_diff: difftool_args.append('--dir-diff') if left: if left_take_parent or left_take_magic: suffix = '^!' if left_take_magic else '~' # Check root commit (no parents and thus cannot execute '~') git = context.git status, out, err = git.rev_list(left, parents=True, n=1) Interaction.log_status(status, out, err) if status: raise OSError('git rev-list command failed') if len(out.split()) >= 2: # Commit has a parent, so we can take its child as requested left += suffix else: # No parent, assume it's the root commit, so we have to diff # against the empty tree. left = EMPTY_TREE_OID if not right and left_take_magic: right = left difftool_args.append(left) if right: difftool_args.append(right) if paths: difftool_args.append('--') difftool_args.extend(paths) runtask = context.runtask if runtask: Interaction.async_command(N_('Difftool'), difftool_args, runtask) else: core.fork(difftool_args) git-cola-3.6/cola/compat.py000066400000000000000000000027161356743264500156610ustar00rootroot00000000000000# pylint: disable=unused-import,redefined-builtin,undefined-variable from __future__ import absolute_import, division, unicode_literals import os import sys try: import urllib2 as parse # noqa except ImportError: # Python 3 from urllib import parse # noqa PY2 = sys.version_info[0] == 2 PY3 = sys.version_info[0] >= 3 PY26_PLUS = PY2 and sys.version_info[1] >= 6 WIN32 = sys.platform == 'win32' or sys.platform == 'cygwin' ENCODING = 'utf-8' if PY3: def bstr(x, encoding=ENCODING): return bytes(x, encoding=encoding) elif PY26_PLUS: bstr = bytes else: # Python <= 2.5 bstr = str if PY3: def bchr(i): return bytes([i]) int_types = (int,) maxsize = sys.maxsize ustr = str uchr = chr else: bchr = chr maxsize = 2 ** 31 # pylint: disable=unicode-builtin ustr = unicode # noqa # pylint: disable=unichr-builtin uchr = unichr # noqa # pylint: disable=long-builtin int_types = (int, long) # noqa def setenv(key, value): """Compatibility wrapper for setting environment variables Why? win32 requires putenv(). UNIX only requires os.environ. """ if not PY3 and isinstance(value, ustr): value = value.encode(ENCODING, 'replace') os.environ[key] = value os.putenv(key, value) def unsetenv(key): """Compatibility wrapper for unsetting environment variables""" os.environ.pop(key, None) if hasattr(os, 'unsetenv'): os.unsetenv(key) git-cola-3.6/cola/core.py000066400000000000000000000332651356743264500153310ustar00rootroot00000000000000"""This module provides core functions for handling unicode and UNIX quirks The @interruptable functions retry when system calls are interrupted, e.g. when python raises an IOError or OSError with errno == EINTR. """ from __future__ import division, absolute_import, unicode_literals import functools import itertools import mimetypes import os import platform import subprocess import sys from .decorators import interruptable from .compat import ustr from .compat import PY2 from .compat import PY3 from .compat import WIN32 # /usr/include/stdlib.h # #define EXIT_SUCCESS 0 /* Successful exit status. */ # #define EXIT_FAILURE 1 /* Failing exit status. */ EXIT_SUCCESS = 0 EXIT_FAILURE = 1 # /usr/include/sysexits.h # #define EX_USAGE 64 /* command line usage error */ # #define EX_NOINPUT 66 /* cannot open input */ # #define EX_UNAVAILABLE 69 /* service unavailable */ EXIT_USAGE = 64 EXIT_NOINPUT = 66 EXIT_UNAVAILABLE = 69 # Default encoding ENCODING = 'utf-8' # Some files are not in UTF-8; some other aren't in any codification. # Remember that GIT doesn't care about encodings (saves binary data) _encoding_tests = [ ENCODING, 'iso-8859-15', 'windows1252', 'ascii', # <-- add encodings here ] class UStr(ustr): """Unicode string wrapper that remembers its encoding UStr wraps unicode strings to provide the `encoding` attribute. UStr is used when decoding strings of an unknown encoding. In order to generate patches that contain the original byte sequences, we must preserve the original encoding when calling decode() so that it can later be used when reconstructing the original byte sequences. """ def __new__(cls, string, encoding): if isinstance(string, UStr): if encoding != string.encoding: raise ValueError('Encoding conflict: %s vs. %s' % (string.encoding, encoding)) string = ustr(string) obj = ustr.__new__(cls, string) obj.encoding = encoding return obj def decode(value, encoding=None, errors='strict'): """decode(encoded_string) returns an unencoded unicode string """ if value is None: result = None elif isinstance(value, ustr): result = UStr(value, ENCODING) else: result = None if encoding is None: encoding_tests = _encoding_tests else: encoding_tests = itertools.chain([encoding], _encoding_tests) for enc in encoding_tests: try: decoded = value.decode(enc, errors) result = UStr(decoded, enc) break except ValueError: pass if result is None: decoded = value.decode(ENCODING, errors='ignore') result = UStr(decoded, ENCODING) return result def encode(string, encoding=None): """encode(unencoded_string) returns a string encoded in utf-8 """ if not isinstance(string, ustr): return string return string.encode(encoding or ENCODING, 'replace') def mkpath(path, encoding=None): # The Windows API requires unicode strings regardless of python version if WIN32: return decode(path, encoding=encoding) # UNIX prefers bytes return encode(path, encoding=encoding) def list2cmdline(cmd): return subprocess.list2cmdline([decode(c) for c in cmd]) def read(filename, size=-1, encoding=None, errors='strict'): """Read filename and return contents""" with xopen(filename, 'rb') as fh: return xread(fh, size=size, encoding=encoding, errors=errors) def write(path, contents, encoding=None): """Writes a unicode string to a file""" with xopen(path, 'wb') as fh: return xwrite(fh, contents, encoding=encoding) @interruptable def xread(fh, size=-1, encoding=None, errors='strict'): """Read from a filehandle and retry when interrupted""" return decode(fh.read(size), encoding=encoding, errors=errors) @interruptable def xwrite(fh, content, encoding=None): """Write to a filehandle and retry when interrupted""" return fh.write(encode(content, encoding=encoding)) @interruptable def wait(proc): """Wait on a subprocess and retry when interrupted""" return proc.wait() @interruptable def readline(fh, encoding=None): return decode(fh.readline(), encoding=encoding) @interruptable def start_command(cmd, cwd=None, add_env=None, universal_newlines=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, no_win32_startupinfo=False, stderr=subprocess.PIPE, **extra): """Start the given command, and return a subprocess object. This provides a simpler interface to the subprocess module. """ env = extra.pop('env', None) if add_env is not None: env = os.environ.copy() env.update(add_env) # Python3 on windows always goes through list2cmdline() internally inside # of subprocess.py so we must provide unicode strings here otherwise # Python3 breaks when bytes are provided. # # Additionally, the preferred usage on Python3 is to pass unicode # strings to subprocess. Python will automatically encode into the # default encoding (utf-8) when it gets unicode strings. shell = extra.get('shell', False) cmd = prep_for_subprocess(cmd, shell=shell) if WIN32 and cwd == getcwd(): # Windows cannot deal with passing a cwd that contains unicode # but we luckily can pass None when the supplied cwd is the same # as our current directory and get the same effect. # Not doing this causes unicode encoding errors when launching # the subprocess. cwd = None if PY2 and cwd: cwd = encode(cwd) if WIN32: # If git-cola is invoked on Windows using "start pythonw git-cola", # a console window will briefly flash on the screen each time # git-cola invokes git, which is very annoying. The code below # prevents this by ensuring that any window will be hidden. startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags = subprocess.STARTF_USESHOWWINDOW startupinfo.wShowWindow = subprocess.SW_HIDE extra['startupinfo'] = startupinfo if WIN32 and not no_win32_startupinfo: CREATE_NO_WINDOW = 0x08000000 extra['creationflags'] = CREATE_NO_WINDOW # Use line buffering when in text/universal_newlines mode, # otherwise use the system default buffer size. bufsize = 1 if universal_newlines else -1 return subprocess.Popen(cmd, bufsize=bufsize, stdin=stdin, stdout=stdout, stderr=stderr, cwd=cwd, env=env, universal_newlines=universal_newlines, **extra) def prep_for_subprocess(cmd, shell=False): """Decode on Python3, encode on Python2""" # See the comment in start_command() if shell: if PY3: cmd = decode(cmd) else: cmd = encode(cmd) else: if PY3: cmd = [decode(c) for c in cmd] else: cmd = [encode(c) for c in cmd] return cmd @interruptable def communicate(proc): return proc.communicate() def run_command(cmd, *args, **kwargs): """Run the given command to completion, and return its results. This provides a simpler interface to the subprocess module. The results are formatted as a 3-tuple: (exit_code, output, errors) The other arguments are passed on to start_command(). """ encoding = kwargs.pop('encoding', None) process = start_command(cmd, *args, **kwargs) (output, errors) = communicate(process) output = decode(output, encoding=encoding) errors = decode(errors, encoding=encoding) exit_code = process.returncode return (exit_code, output or UStr('', ENCODING), errors or UStr('', ENCODING)) @interruptable def _fork_posix(args, cwd=None, shell=False): """Launch a process in the background.""" encoded_args = [encode(arg) for arg in args] return subprocess.Popen(encoded_args, cwd=cwd, shell=shell).pid def _fork_win32(args, cwd=None, shell=False): """Launch a background process using crazy win32 voodoo.""" # This is probably wrong, but it works. Windows.. wow. if args[0] == 'git-dag': # win32 can't exec python scripts args = [sys.executable] + args if not shell: args[0] = _win32_find_exe(args[0]) if PY3: # see comment in start_command() argv = [decode(arg) for arg in args] else: argv = [encode(arg) for arg in args] DETACHED_PROCESS = 0x00000008 # Amazing! return subprocess.Popen(argv, cwd=cwd, creationflags=DETACHED_PROCESS, shell=shell).pid def _win32_find_exe(exe): """Find the actual file for a Windows executable. This function goes through the same process that the Windows shell uses to locate an executable, taking into account the PATH and PATHEXT environment variables. This allows us to avoid passing shell=True to subprocess.Popen. For reference, see: http://technet.microsoft.com/en-us/library/cc723564.aspx#XSLTsection127121120120 """ # try the argument itself candidates = [exe] # if argument does not have an extension, also try it with each of the # extensions specified in PATHEXT if '.' not in exe: extensions = getenv('PATHEXT', '').split(os.pathsep) candidates.extend([(exe + ext) for ext in extensions if ext.startswith('.')]) # search the current directory first for candidate in candidates: if exists(candidate): return candidate # if the argument does not include a path separator, search each of the # directories on the PATH if not os.path.dirname(exe): for path in getenv('PATH').split(os.pathsep): if path: for candidate in candidates: full_path = os.path.join(path, candidate) if exists(full_path): return full_path # not found, punt and return the argument unchanged return exe # Portability wrappers if sys.platform == 'win32' or sys.platform == 'cygwin': fork = _fork_win32 else: fork = _fork_posix def _decorator_noop(x): return x def wrap(action, fn, decorator=None): """Wrap arguments with `action`, optionally decorate the result""" if decorator is None: decorator = _decorator_noop @functools.wraps(fn) def wrapped(*args, **kwargs): return decorator(fn(action(*args, **kwargs))) return wrapped def decorate(decorator, fn): """Decorate the result of `fn` with `action`""" @functools.wraps(fn) def decorated(*args, **kwargs): return decorator(fn(*args, **kwargs)) return decorated def getenv(name, default=None): return decode(os.getenv(name, default)) def guess_mimetype(filename): """Robustly guess a filename's mimetype""" mimetype = None try: mimetype = mimetypes.guess_type(filename)[0] except UnicodeEncodeError: mimetype = mimetypes.guess_type(encode(filename))[0] except TypeError: mimetype = mimetypes.guess_type(decode(filename))[0] return mimetype def xopen(path, mode='r', encoding=None): return open(mkpath(path, encoding=encoding), mode) def print_stdout(msg, linesep='\n'): msg = msg + linesep if PY2: msg = encode(msg, encoding=ENCODING) sys.stdout.write(msg) def print_stderr(msg, linesep='\n'): msg = msg + linesep if PY2: msg = encode(msg, encoding=ENCODING) sys.stderr.write(msg) def error(msg, status=EXIT_FAILURE, linesep='\n'): print_stderr(msg, linesep=linesep) sys.exit(status) @interruptable def node(): return platform.node() abspath = wrap(mkpath, os.path.abspath, decorator=decode) chdir = wrap(mkpath, os.chdir) exists = wrap(mkpath, os.path.exists) expanduser = wrap(encode, os.path.expanduser, decorator=decode) if PY2: if hasattr(os, 'getcwdu'): # pylint: disable=no-member getcwd = os.getcwdu else: getcwd = decorate(decode, os.getcwd) else: getcwd = os.getcwd # NOTE: find_executable() is originally from the stdlib, but starting with # python3.7 the stdlib no longer bundles distutils. def _find_executable(executable, path=None): """Tries to find 'executable' in the directories listed in 'path'. A string listing directories separated by 'os.pathsep'; defaults to os.environ['PATH']. Returns the complete filename or None if not found. """ if path is None: path = os.environ['PATH'] paths = path.split(os.pathsep) _, ext = os.path.splitext(executable) if (sys.platform == 'win32') and (ext != '.exe'): executable = executable + '.exe' if not os.path.isfile(executable): for p in paths: f = os.path.join(p, executable) if os.path.isfile(f): # the file exists, we have a shot at spawn working return f return None return executable if PY2: find_executable = wrap(mkpath, _find_executable, decorator=decode) else: find_executable = wrap(decode, _find_executable, decorator=decode) isdir = wrap(mkpath, os.path.isdir) isfile = wrap(mkpath, os.path.isfile) islink = wrap(mkpath, os.path.islink) makedirs = wrap(mkpath, os.makedirs) try: readlink = wrap(mkpath, os.readlink, decorator=decode) except AttributeError: def _readlink_noop(p): return p readlink = _readlink_noop realpath = wrap(mkpath, os.path.realpath, decorator=decode) relpath = wrap(mkpath, os.path.relpath, decorator=decode) stat = wrap(mkpath, os.stat) unlink = wrap(mkpath, os.unlink) walk = wrap(mkpath, os.walk) git-cola-3.6/cola/dag.py000066400000000000000000000026561356743264500151340ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals import argparse import sys from cola import app from cola.widgets.dag import git_dag def main(argv=None): """Run git-dag""" app.initialize() args = parse_args(argv=argv) return args.func(args) def winmain(): """Windows git-dag entrypoint""" return app.winmain(main) def shortcut_launch(): """Run git-dag from a Windows shortcut""" return app.winmain(main, ['--prompt']) def parse_args(argv=None): """Parse command-line arguments""" if argv is None: argv = sys.argv[1:] parser = argparse.ArgumentParser() parser.set_defaults(func=cmd_dag) app.add_common_arguments(parser) parser.add_argument('-c', '--count', '--max-count', metavar='', type=int, default=1000, help='number of commits to display') parser.add_argument('args', nargs='*', metavar='', help='git log arguments') args, rest = parser.parse_known_args(args=argv) if rest: # splice unknown arguments to the beginning ~ # these are forwarded to git-log(1). args.args[:0] = rest return args def cmd_dag(args): """Run git-dag via the `git cola dag` sub-command""" context = app.application_init(args) view = git_dag(context, args=args, settings=args.settings, show=False) return app.application_start(context, view) git-cola-3.6/cola/decorators.py000066400000000000000000000041011356743264500165310ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals import errno import functools __all__ = ('decorator', 'memoize', 'interruptable') def decorator(caller, func=None): """ Create a new decorator decorator(caller) converts a caller function into a decorator; decorator(caller, func) decorates a function using a caller. """ if func is None: # return a decorator # pylint: disable=unused-argument @functools.wraps(caller) def _decorator(f, *dummy_args, **dummy_opts): @functools.wraps(f) def _caller(*args, **opts): return caller(f, *args, **opts) return _caller _decorator.func = caller return _decorator # return a decorated function @functools.wraps(func) def _decorated(*args, **opts): return caller(func, *args, **opts) _decorated.func = func return _decorated def memoize(func): """ A decorator for memoizing function calls http://en.wikipedia.org/wiki/Memoization """ func.cache = {} return decorator(_memoize, func) def _memoize(func, *args, **opts): """Implements memoized cache lookups""" if opts: # frozenset is used to ensure hashability key = (args, frozenset(list(opts.items()))) else: key = args cache = func.cache # attribute added by memoize try: result = cache[key] except KeyError: result = cache[key] = func(*args, **opts) return result @decorator def interruptable(func, *args, **opts): """Handle interruptable system calls OSX and others are known to interrupt system calls http://en.wikipedia.org/wiki/PCLSRing http://en.wikipedia.org/wiki/Unix_philosophy#Worse_is_better The @interruptable decorator handles this situation """ while True: try: result = func(*args, **opts) except (IOError, OSError) as e: if e.errno in (errno.EINTR, errno.EINVAL): continue raise e else: break return result git-cola-3.6/cola/diffparse.py000066400000000000000000000264631356743264500163460ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals import math import re from collections import defaultdict from . import compat _HUNK_HEADER_RE = re.compile(r'^@@ -([0-9,]+) \+([0-9,]+) @@(.*)') class _DiffHunk(object): def __init__(self, old_start, old_count, new_start, new_count, heading, first_line_idx, lines): self.old_start = old_start self.old_count = old_count self.new_start = new_start self.new_count = new_count self.heading = heading self.first_line_idx = first_line_idx self.lines = lines @property def last_line_idx(self): return self.first_line_idx + len(self.lines) - 1 def parse_range_str(range_str): if ',' in range_str: begin, end = range_str.split(',', 1) return int(begin), int(end) return int(range_str), 1 def _format_range(start, count): if count == 1: return str(start) return '%d,%d' % (start, count) def _format_hunk_header(old_start, old_count, new_start, new_count, heading=''): return ('@@ -%s +%s @@%s\n' % (_format_range(old_start, old_count), _format_range(new_start, new_count), heading)) def _parse_diff(diff_text): hunks = [] for line_idx, line in enumerate(diff_text.split('\n')): match = _HUNK_HEADER_RE.match(line) if match: old_start, old_count = parse_range_str(match.group(1)) new_start, new_count = parse_range_str(match.group(2)) heading = match.group(3) hunks.append(_DiffHunk(old_start, old_count, new_start, new_count, heading, line_idx, lines=[line + '\n'])) elif line and hunks: hunks[-1].lines.append(line + '\n') return hunks def digits(number): """Return the number of digits needed to display a number""" if number >= 0: result = int(math.log10(number)) + 1 else: result = 1 return result class Counter(object): """Keep track of a diff range's values""" def __init__(self, value=0, max_value=-1): self.value = value self.max_value = max_value self._initial_max_value = max_value def reset(self): """Reset the max counter and return self for convenience""" self.max_value = self._initial_max_value return self def parse(self, range_str): """Parse a diff range and setup internal state""" start, count = parse_range_str(range_str) self.value = start self.max_value = max(start + count, self.max_value) def tick(self, amount=1): """Return the current value and increment to the next""" value = self.value self.value += amount return value class DiffLines(object): """Parse diffs and gather line numbers""" EMPTY = -1 DASH = -2 def __init__(self): self.valid = True self.merge = False # diff # merge self.old = Counter() self.new = Counter() self.ours = Counter() self.theirs = Counter() def digits(self): return digits(max(self.old.max_value, self.new.max_value, self.ours.max_value, self.theirs.max_value)) def parse(self, diff_text): lines = [] DIFF_STATE = 1 state = INITIAL_STATE = 0 merge = self.merge = False NO_NEWLINE = r'\ No newline at end of file' old = self.old.reset() new = self.new.reset() ours = self.ours.reset() theirs = self.theirs.reset() for text in diff_text.split('\n'): if text.startswith('@@ -'): parts = text.split(' ', 4) if parts[0] == '@@' and parts[3] == '@@': state = DIFF_STATE old.parse(parts[1][1:]) new.parse(parts[2][1:]) lines.append((self.DASH, self.DASH)) continue if text.startswith('@@@ -'): self.merge = merge = True parts = text.split(' ', 5) if parts[0] == '@@@' and parts[4] == '@@@': state = DIFF_STATE ours.parse(parts[1][1:]) theirs.parse(parts[2][1:]) new.parse(parts[3][1:]) lines.append((self.DASH, self.DASH, self.DASH)) continue if state == INITIAL_STATE or text.rstrip() == NO_NEWLINE: if merge: lines.append((self.EMPTY, self.EMPTY, self.EMPTY)) else: lines.append((self.EMPTY, self.EMPTY)) elif not merge and text.startswith('-'): lines.append((old.tick(), self.EMPTY)) elif merge and text.startswith('- '): lines.append((self.EMPTY, theirs.tick(), self.EMPTY)) elif merge and text.startswith(' -'): lines.append((self.EMPTY, theirs.tick(), self.EMPTY)) elif merge and text.startswith('--'): lines.append((ours.tick(), theirs.tick(), self.EMPTY)) elif not merge and text.startswith('+'): lines.append((self.EMPTY, new.tick())) elif merge and text.startswith('++'): lines.append((self.EMPTY, self.EMPTY, new.tick())) elif merge and text.startswith('+ '): lines.append((self.EMPTY, theirs.tick(), new.tick())) elif merge and text.startswith(' +'): lines.append((ours.tick(), self.EMPTY, new.tick())) elif not merge and text.startswith(' '): lines.append((old.tick(), new.tick())) elif merge and text.startswith(' '): lines.append((ours.tick(), theirs.tick(), new.tick())) elif not text: new.tick() old.tick() ours.tick() theirs.tick() else: state = INITIAL_STATE if merge: lines.append((self.EMPTY, self.EMPTY, self.EMPTY)) else: lines.append((self.EMPTY, self.EMPTY)) return lines class FormatDigits(object): """Format numbers for use in diff line numbers""" DASH = DiffLines.DASH EMPTY = DiffLines.EMPTY def __init__(self, dash='', empty=''): self.fmt = '' self.empty = '' self.dash = '' self._dash = dash or compat.uchr(0xb7) self._empty = empty or ' ' def set_digits(self, value): self.fmt = ('%%0%dd' % value) self.empty = (self._empty * value) self.dash = (self._dash * value) def value(self, old, new): old_str = self._format(old) new_str = self._format(new) return '%s %s' % (old_str, new_str) def merge_value(self, old, base, new): old_str = self._format(old) base_str = self._format(base) new_str = self._format(new) return '%s %s %s' % (old_str, base_str, new_str) def number(self, value): return self.fmt % value def _format(self, value): if value == self.DASH: result = self.dash elif value == self.EMPTY: result = self.empty else: result = self.number(value) return result class DiffParser(object): """Parse and rewrite diffs to produce edited patches This parser is used for modifying the worktree and index by constructing temporary patches that are applied using "git apply". """ def __init__(self, filename, diff_text): self.filename = filename self.hunks = _parse_diff(diff_text) def generate_patch(self, first_line_idx, last_line_idx, reverse=False): """Return a patch containing a subset of the diff""" ADDITION = '+' DELETION = '-' CONTEXT = ' ' NO_NEWLINE = '\\' lines = ['--- a/%s\n' % self.filename, '+++ b/%s\n' % self.filename] start_offset = 0 for hunk in self.hunks: # skip hunks until we get to the one that contains the first # selected line if hunk.last_line_idx < first_line_idx: continue # once we have processed the hunk that contains the last selected # line, we can stop if hunk.first_line_idx > last_line_idx: break prev_skipped = False counts = defaultdict(int) filtered_lines = [] for line_idx, line in enumerate(hunk.lines[1:], start=hunk.first_line_idx + 1): line_type, line_content = line[:1], line[1:] if reverse: if line_type == ADDITION: line_type = DELETION elif line_type == DELETION: line_type = ADDITION if not first_line_idx <= line_idx <= last_line_idx: if line_type == ADDITION: # Skip additions that are not selected. prev_skipped = True continue elif line_type == DELETION: # Change deletions that are not selected to context. line_type = CONTEXT if line_type == NO_NEWLINE and prev_skipped: # If the line immediately before a "No newline" line was # skipped (because it was an unselected addition) skip # the "No newline" line as well. continue filtered_lines.append(line_type + line_content) counts[line_type] += 1 prev_skipped = False # Do not include hunks that, after filtering, have only context # lines (no additions or deletions). if not counts[ADDITION] and not counts[DELETION]: continue old_count = counts[CONTEXT] + counts[DELETION] new_count = counts[CONTEXT] + counts[ADDITION] if reverse: old_start = hunk.new_start else: old_start = hunk.old_start new_start = old_start + start_offset if old_count == 0: new_start += 1 if new_count == 0: new_start -= 1 start_offset += counts[ADDITION] - counts[DELETION] lines.append(_format_hunk_header(old_start, old_count, new_start, new_count, hunk.heading)) lines.extend(filtered_lines) # If there are only two lines, that means we did not include any hunks, # so return None. if len(lines) == 2: return None return ''.join(lines) def generate_hunk_patch(self, line_idx, reverse=False): """Return a patch containing the hunk for the specified line only""" hunk = None for hunk in self.hunks: if line_idx <= hunk.last_line_idx: break if hunk is None: return None return self.generate_patch(hunk.first_line_idx, hunk.last_line_idx, reverse=reverse) git-cola-3.6/cola/difftool.py000066400000000000000000000143541356743264500162050ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals from qtpy import QtWidgets from qtpy.QtCore import Qt from . import cmds from . import gitcmds from . import hotkeys from . import icons from . import qtutils from . import utils from .i18n import N_ from .widgets import completion from .widgets import defs from .widgets import filetree from .widgets import standard def diff_commits(context, parent, a, b): """Show a dialog for diffing two commits""" dlg = Difftool(context, parent, a=a, b=b) dlg.show() dlg.raise_() return dlg.exec_() == QtWidgets.QDialog.Accepted def diff_expression(context, parent, expr, create_widget=False, hide_expr=False, focus_tree=False): """Show a diff dialog for diff expressions""" dlg = Difftool(context, parent, expr=expr, hide_expr=hide_expr, focus_tree=focus_tree) if create_widget: return dlg dlg.show() dlg.raise_() return dlg.exec_() == QtWidgets.QDialog.Accepted class Difftool(standard.Dialog): def __init__(self, context, parent, a=None, b=None, expr=None, title=None, hide_expr=False, focus_tree=False): """Show files with differences and launch difftool""" standard.Dialog.__init__(self, parent=parent) self.context = context self.a = a self.b = b self.diff_expr = expr if title is None: title = N_('git-cola diff') self.setWindowTitle(title) self.setWindowModality(Qt.WindowModal) self.expr = completion.GitRefLineEdit(context, parent=self) if expr is not None: self.expr.setText(expr) if expr is None or hide_expr: self.expr.hide() self.tree = filetree.FileTree(parent=self) self.diff_button = qtutils.create_button(text=N_('Compare'), icon=icons.diff(), enabled=False, default=True) self.diff_button.setShortcut(hotkeys.DIFF) self.diff_all_button = qtutils.create_button(text=N_('Compare All'), icon=icons.diff()) self.edit_button = qtutils.edit_button() self.edit_button.setShortcut(hotkeys.EDIT) self.close_button = qtutils.close_button() self.button_layout = qtutils.hbox(defs.no_margin, defs.spacing, self.close_button, qtutils.STRETCH, self.edit_button, self.diff_all_button, self.diff_button) self.main_layout = qtutils.vbox(defs.margin, defs.spacing, self.expr, self.tree, self.button_layout) self.setLayout(self.main_layout) # pylint: disable=no-member self.tree.itemSelectionChanged.connect(self.tree_selection_changed) self.tree.itemDoubleClicked.connect(self.tree_double_clicked) self.tree.up.connect(self.focus_input) self.expr.textChanged.connect(self.text_changed) self.expr.activated.connect(self.focus_tree) self.expr.down.connect(self.focus_tree) self.expr.enter.connect(self.focus_tree) qtutils.connect_button(self.diff_button, self.diff) qtutils.connect_button(self.diff_all_button, lambda: self.diff(dir_diff=True)) qtutils.connect_button(self.edit_button, self.edit) qtutils.connect_button(self.close_button, self.close) qtutils.add_action(self, 'Focus Input', self.focus_input, hotkeys.FOCUS) qtutils.add_action(self, 'Diff All', lambda: self.diff(dir_diff=True), hotkeys.CTRL_ENTER, hotkeys.CTRL_RETURN) qtutils.add_close_action(self) self.init_state(None, self.resize_widget, parent) self.refresh() if focus_tree: self.focus_tree() def resize_widget(self, parent): """Set the initial size of the widget""" width, height = qtutils.default_size(parent, 720, 420) self.resize(width, height) def focus_tree(self): """Focus the files tree""" self.tree.setFocus() def focus_input(self): """Focus the expression input""" self.expr.setFocus() def text_changed(self, txt): self.diff_expr = txt self.refresh() def refresh(self): """Redo the diff when the expression changes""" if self.diff_expr is not None: self.diff_arg = utils.shell_split(self.diff_expr) elif self.b is None: self.diff_arg = [self.a] else: self.diff_arg = [self.a, self.b] self.refresh_filenames() def refresh_filenames(self): context = self.context if self.a and self.b is None: filenames = gitcmds.diff_index_filenames(context, self.a) else: filenames = gitcmds.diff(context, self.diff_arg) self.tree.set_filenames(filenames, select=True) def tree_selection_changed(self): has_selection = self.tree.has_selection() self.diff_button.setEnabled(has_selection) self.diff_all_button.setEnabled(has_selection) def tree_double_clicked(self, item, _column): path = filetree.filename_from_item(item) left, right = self._left_right_args() cmds.difftool_launch( self.context, left=left, right=right, paths=[path]) def diff(self, dir_diff=False): paths = self.tree.selected_filenames() left, right = self._left_right_args() cmds.difftool_launch(self.context, left=left, right=right, paths=paths, dir_diff=dir_diff) def _left_right_args(self): if self.diff_arg: left = self.diff_arg[0] else: left = None if len(self.diff_arg) > 1: right = self.diff_arg[1] else: right = None return (left, right) def edit(self): paths = self.tree.selected_filenames() cmds.do(cmds.Edit, self.context, paths) git-cola-3.6/cola/fsmonitor.py000066400000000000000000000464531356743264500164240ustar00rootroot00000000000000# Copyright (C) 2008-2017 David Aguilar # Copyright (C) 2015 Daniel Harding """Filesystem monitor for Linux and Windows Linux monitoring uses using inotify. Windows monitoring uses pywin32 and the ReadDirectoryChanges function. """ from __future__ import division, absolute_import, unicode_literals import errno import os import os.path import select from threading import Lock from qtpy import QtCore from qtpy.QtCore import Signal from . import utils from . import core from . import gitcmds from . import version from .compat import bchr from .i18n import N_ from .interaction import Interaction AVAILABLE = None if utils.is_win32(): try: import pywintypes import win32con import win32event import win32file except ImportError: pass else: AVAILABLE = 'pywin32' elif utils.is_linux(): try: from . import inotify except ImportError: pass else: AVAILABLE = 'inotify' class _Monitor(QtCore.QObject): files_changed = Signal() config_changed = Signal() def __init__(self, context, thread_class): QtCore.QObject.__init__(self) self.context = context self._thread_class = thread_class self._thread = None def start(self): if self._thread_class is not None: assert self._thread is None self._thread = self._thread_class(self.context, self) self._thread.start() def stop(self): if self._thread_class is not None: assert self._thread is not None self._thread.stop() self._thread.wait() self._thread = None def refresh(self): if self._thread is not None: self._thread.refresh() class _BaseThread(QtCore.QThread): #: The delay, in milliseconds, between detecting file system modification #: and triggering the 'files_changed' signal, to coalesce multiple #: modifications into a single signal. _NOTIFICATION_DELAY = 888 def __init__(self, context, monitor): QtCore.QThread.__init__(self) self.context = context self._monitor = monitor self._running = True self._use_check_ignore = version.check_git(context, 'check-ignore') self._force_notify = False self._force_config = False self._file_paths = set() @property def _pending(self): return self._force_notify or self._file_paths or self._force_config # pylint: disable=no-self-use def refresh(self): """Do any housekeeping necessary in response to repository changes.""" return def notify(self): """Notifies all observers""" do_notify = False do_config = False if self._force_config: do_config = True if self._force_notify: do_notify = True elif self._file_paths: proc = core.start_command(['git', 'check-ignore', '--verbose', '--non-matching', '-z', '--stdin']) path_list = bchr(0).join(core.encode(path) for path in self._file_paths) out, _ = proc.communicate(path_list) if proc.returncode: do_notify = True else: # Each output record is four fields separated by NULL # characters (records are also separated by NULL characters): # # For paths which are not ignored, all fields will be empty # except for . So to see if we have any non-ignored # files, we simply check every fourth field to see if any of # them are empty. source_fields = out.split(bchr(0))[0:-1:4] do_notify = not all(source_fields) self._force_notify = False self._force_config = False self._file_paths = set() # "files changed" is a bigger hammer than "config changed". # and is a superset relative to what is done in response to the # signal. Thus, the "elif" below avoids repeated work that # would be done if it were a simple "if" check instead. if do_notify: self._monitor.files_changed.emit() elif do_config: self._monitor.config_changed.emit() @staticmethod def _log_enabled_message(): msg = N_('File system change monitoring: enabled.\n') Interaction.log(msg) if AVAILABLE == 'inotify': class _InotifyThread(_BaseThread): _TRIGGER_MASK = ( inotify.IN_ATTRIB | inotify.IN_CLOSE_WRITE | inotify.IN_CREATE | inotify.IN_DELETE | inotify.IN_MODIFY | inotify.IN_MOVED_FROM | inotify.IN_MOVED_TO ) _ADD_MASK = ( _TRIGGER_MASK | inotify.IN_EXCL_UNLINK | inotify.IN_ONLYDIR ) def __init__(self, context, monitor): _BaseThread.__init__(self, context, monitor) git = context.git worktree = git.worktree() if worktree is not None: worktree = core.abspath(worktree) self._worktree = worktree self._git_dir = git.git_path() self._lock = Lock() self._inotify_fd = None self._pipe_r = None self._pipe_w = None self._worktree_wd_to_path_map = {} self._worktree_path_to_wd_map = {} self._git_dir_wd_to_path_map = {} self._git_dir_path_to_wd_map = {} self._git_dir_wd = None @staticmethod def _log_out_of_wds_message(): msg = N_('File system change monitoring: disabled because the' ' limit on the total number of inotify watches was' ' reached. You may be able to increase the limit on' ' the number of watches by running:\n' '\n' ' echo fs.inotify.max_user_watches=100000 |' ' sudo tee -a /etc/sysctl.conf &&' ' sudo sysctl -p\n') Interaction.log(msg) def run(self): try: with self._lock: self._inotify_fd = inotify.init() self._pipe_r, self._pipe_w = os.pipe() poll_obj = select.poll() poll_obj.register(self._inotify_fd, select.POLLIN) poll_obj.register(self._pipe_r, select.POLLIN) self.refresh() if self._running: self._log_enabled_message() self._process_events(poll_obj) finally: self._close_fds() def _process_events(self, poll_obj): while self._running: if self._pending: timeout = self._NOTIFICATION_DELAY else: timeout = None try: events = poll_obj.poll(timeout) # pylint: disable=duplicate-except except (OSError, select.error): continue else: if not self._running: break elif not events: self.notify() else: for (fd, _) in events: if fd == self._inotify_fd: self._handle_events() def _close_fds(self): with self._lock: if self._inotify_fd is not None: os.close(self._inotify_fd) self._inotify_fd = None if self._pipe_r is not None: os.close(self._pipe_r) self._pipe_r = None os.close(self._pipe_w) self._pipe_w = None def refresh(self): with self._lock: self._refresh() def _refresh(self): if self._inotify_fd is None: return context = self.context try: if self._worktree is not None: tracked_dirs = set([ os.path.dirname(os.path.join(self._worktree, path)) for path in gitcmds.tracked_files(context)]) self._refresh_watches(tracked_dirs, self._worktree_wd_to_path_map, self._worktree_path_to_wd_map) git_dirs = set() git_dirs.add(self._git_dir) for dirpath, _, _ in core.walk( os.path.join(self._git_dir, 'refs')): git_dirs.add(dirpath) self._refresh_watches(git_dirs, self._git_dir_wd_to_path_map, self._git_dir_path_to_wd_map) self._git_dir_wd = \ self._git_dir_path_to_wd_map.get(self._git_dir) except OSError as e: if e.errno == errno.ENOSPC: self._log_out_of_wds_message() self._running = False else: raise def _refresh_watches(self, paths_to_watch, wd_to_path_map, path_to_wd_map): watched_paths = set(path_to_wd_map) for path in watched_paths - paths_to_watch: wd = path_to_wd_map.pop(path) wd_to_path_map.pop(wd) try: inotify.rm_watch(self._inotify_fd, wd) except OSError as e: if e.errno == errno.EINVAL: # This error can occur if the target of the wd was # removed on the filesystem before we call # inotify.rm_watch() so ignore it. continue raise e for path in paths_to_watch - watched_paths: try: wd = inotify.add_watch(self._inotify_fd, core.encode(path), self._ADD_MASK) except OSError as e: if e.errno in (errno.ENOENT, errno.ENOTDIR): # These two errors should only occur as a result of # race conditions: the first if the directory # referenced by path was removed or renamed before the # call to inotify.add_watch(); the second if the # directory referenced by path was replaced with a file # before the call to inotify.add_watch(). Therefore we # simply ignore them. continue raise e else: wd_to_path_map[wd] = path path_to_wd_map[path] = wd def _check_event(self, wd, mask, name): if mask & inotify.IN_Q_OVERFLOW: self._force_notify = True elif not mask & self._TRIGGER_MASK: pass elif mask & inotify.IN_ISDIR: pass elif wd in self._worktree_wd_to_path_map: if self._use_check_ignore and name: path = os.path.join(self._worktree_wd_to_path_map[wd], core.decode(name)) self._file_paths.add(path) else: self._force_notify = True elif wd == self._git_dir_wd: name = core.decode(name) if name in ('HEAD', 'index'): self._force_notify = True elif name == 'config': self._force_config = True elif (wd in self._git_dir_wd_to_path_map and not core.decode(name).endswith('.lock')): self._force_notify = True def _handle_events(self): for wd, mask, _, name in \ inotify.read_events(self._inotify_fd): if not self._force_notify: self._check_event(wd, mask, name) def stop(self): self._running = False with self._lock: if self._pipe_w is not None: os.write(self._pipe_w, bchr(0)) self.wait() if AVAILABLE == 'pywin32': class _Win32Watch(object): def __init__(self, path, flags): self.flags = flags self.handle = None self.event = None try: self.handle = win32file.CreateFileW( path, 0x0001, # FILE_LIST_DIRECTORY win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE, None, win32con.OPEN_EXISTING, win32con.FILE_FLAG_BACKUP_SEMANTICS | win32con.FILE_FLAG_OVERLAPPED, None) self.buffer = win32file.AllocateReadBuffer(8192) self.event = win32event.CreateEvent(None, True, False, None) self.overlapped = pywintypes.OVERLAPPED() self.overlapped.hEvent = self.event self._start() except Exception: self.close() raise def _start(self): win32file.ReadDirectoryChangesW(self.handle, self.buffer, True, self.flags, self.overlapped) def read(self): if win32event.WaitForSingleObject(self.event, 0) \ == win32event.WAIT_TIMEOUT: result = [] else: nbytes = win32file.GetOverlappedResult(self.handle, self.overlapped, False) result = win32file.FILE_NOTIFY_INFORMATION(self.buffer, nbytes) self._start() return result def close(self): if self.handle is not None: win32file.CancelIo(self.handle) win32file.CloseHandle(self.handle) if self.event is not None: win32file.CloseHandle(self.event) class _Win32Thread(_BaseThread): _FLAGS = (win32con.FILE_NOTIFY_CHANGE_FILE_NAME | win32con.FILE_NOTIFY_CHANGE_DIR_NAME | win32con.FILE_NOTIFY_CHANGE_ATTRIBUTES | win32con.FILE_NOTIFY_CHANGE_SIZE | win32con.FILE_NOTIFY_CHANGE_LAST_WRITE | win32con.FILE_NOTIFY_CHANGE_SECURITY) def __init__(self, context, monitor): _BaseThread.__init__(self, context, monitor) git = context.git worktree = git.worktree() if worktree is not None: worktree = self._transform_path(core.abspath(worktree)) self._worktree = worktree self._worktree_watch = None self._git_dir = self._transform_path(core.abspath(git.git_path())) self._git_dir_watch = None self._stop_event_lock = Lock() self._stop_event = None @staticmethod def _transform_path(path): return path.replace('\\', '/').lower() def run(self): try: with self._stop_event_lock: self._stop_event = win32event.CreateEvent(None, True, False, None) events = [self._stop_event] if self._worktree is not None: self._worktree_watch = _Win32Watch(self._worktree, self._FLAGS) events.append(self._worktree_watch.event) self._git_dir_watch = _Win32Watch(self._git_dir, self._FLAGS) events.append(self._git_dir_watch.event) self._log_enabled_message() while self._running: if self._pending: timeout = self._NOTIFICATION_DELAY else: timeout = win32event.INFINITE rc = win32event.WaitForMultipleObjects(events, False, timeout) if not self._running: break elif rc == win32event.WAIT_TIMEOUT: self.notify() else: self._handle_results() finally: with self._stop_event_lock: if self._stop_event is not None: win32file.CloseHandle(self._stop_event) self._stop_event = None if self._worktree_watch is not None: self._worktree_watch.close() if self._git_dir_watch is not None: self._git_dir_watch.close() def _handle_results(self): if self._worktree_watch is not None: for _, path in self._worktree_watch.read(): if not self._running: break if self._force_notify: continue path = self._worktree + '/' + self._transform_path(path) if (path != self._git_dir and not path.startswith(self._git_dir + '/') and not os.path.isdir(path)): if self._use_check_ignore: self._file_paths.add(path) else: self._force_notify = True for _, path in self._git_dir_watch.read(): if not self._running: break if self._force_notify: continue path = self._transform_path(path) if path.endswith('.lock'): continue if path == 'config': self._force_config = True continue if (path == 'head' or path == 'index' or path.startswith('refs/')): self._force_notify = True def stop(self): self._running = False with self._stop_event_lock: if self._stop_event is not None: win32event.SetEvent(self._stop_event) self.wait() def create(context): thread_class = None cfg = context.cfg if not cfg.get('cola.inotify', default=True): msg = N_('File system change monitoring: disabled because' ' "cola.inotify" is false.\n') Interaction.log(msg) elif AVAILABLE == 'inotify': thread_class = _InotifyThread elif AVAILABLE == 'pywin32': thread_class = _Win32Thread else: if utils.is_win32(): msg = N_('File system change monitoring: disabled because pywin32' ' is not installed.\n') Interaction.log(msg) elif utils.is_linux(): msg = N_('File system change monitoring: disabled because libc' ' does not support the inotify system calls.\n') Interaction.log(msg) return _Monitor(context, thread_class) git-cola-3.6/cola/git.py000066400000000000000000000332131356743264500151550ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals from functools import partial import errno import os from os.path import join import subprocess import threading from . import core from .compat import int_types from .compat import ustr from .compat import WIN32 from .decorators import memoize from .interaction import Interaction GIT_COLA_TRACE = core.getenv('GIT_COLA_TRACE', '') GIT = core.getenv('GIT_COLA_GIT', 'git') STATUS = 0 STDOUT = 1 STDERR = 2 # Object ID / SHA1-related constants # Git's empty tree is a built-in constant object name. EMPTY_TREE_OID = '4b825dc642cb6eb9a060e54bf8d69288fbee4904' # Git's diff machinery returns zeroes for modified files whose content exists # in the worktree only. MISSING_BLOB_OID = '0000000000000000000000000000000000000000' # Git's SHA-1 object IDs are 40 characters long. # This will need to change when Git moves away from SHA-1. # When that happens we'll have to detect and update this at runtime in # order to support both old and new git. OID_LENGTH = 40 _index_lock = threading.Lock() def dashify(s): return s.replace('_', '-') def is_git_dir(git_dir): """From git's setup.c:is_git_directory().""" result = False if git_dir: headref = join(git_dir, 'HEAD') if (core.isdir(git_dir) and (core.isdir(join(git_dir, 'objects')) and core.isdir(join(git_dir, 'refs'))) or (core.isfile(join(git_dir, 'gitdir')) and core.isfile(join(git_dir, 'commondir')))): result = (core.isfile(headref) or (core.islink(headref) and core.readlink(headref).startswith('refs/'))) else: result = is_git_file(git_dir) return result def is_git_file(f): return core.isfile(f) and os.path.basename(f) == '.git' def is_git_worktree(d): return is_git_dir(join(d, '.git')) def is_git_repository(path): return is_git_worktree(path) or is_git_dir(path) def read_git_file(path): """Read the path from a .git-file `None` is returned when is not a .git-file. """ result = None if path and is_git_file(path): header = 'gitdir: ' data = core.read(path).strip() if data.startswith(header): result = data[len(header):] if result and not os.path.isabs(result): path_folder = os.path.dirname(path) repo_relative = join(path_folder, result) result = os.path.normpath(repo_relative) return result class Paths(object): """Git repository paths of interest""" def __init__(self, git_dir=None, git_file=None, worktree=None, common_dir=None): if git_dir and not is_git_dir(git_dir): git_dir = None self.git_dir = git_dir self.git_file = git_file self.worktree = worktree self.common_dir = common_dir def get(self, path): ceiling_dirs = set() ceiling = core.getenv('GIT_CEILING_DIRECTORIES') if ceiling: ceiling_dirs.update([x for x in ceiling.split(':') if x]) if path: path = core.abspath(path) if not self.git_dir or not self.worktree: # Search for a .git directory while path: if path in ceiling_dirs: break if is_git_dir(path): if not self.git_dir: self.git_dir = path basename = os.path.basename(path) if not self.worktree and basename == '.git': self.worktree = os.path.dirname(path) # We are either in a bare repository, or someone set GIT_DIR # but did not set GIT_WORK_TREE. if self.git_dir: if not self.worktree: basename = os.path.basename(self.git_dir) if basename == '.git': self.worktree = os.path.dirname(self.git_dir) elif path and not is_git_dir(path): self.worktree = path break gitpath = join(path, '.git') if is_git_dir(gitpath): if not self.git_dir: self.git_dir = gitpath if not self.worktree: self.worktree = path break path, dummy = os.path.split(path) if not dummy: break if self.git_dir: git_dir_path = read_git_file(self.git_dir) if git_dir_path: self.git_file = self.git_dir self.git_dir = git_dir_path commondir_file = join(git_dir_path, 'commondir') if core.exists(commondir_file): common_path = core.read(commondir_file).strip() if common_path: if os.path.isabs(common_path): common_dir = common_path else: common_dir = join(git_dir_path, common_path) common_dir = os.path.normpath(common_dir) self.common_dir = common_dir # usage: Paths().get() return self def find_git_directory(path): """Perform Git repository discovery """ return Paths(git_dir=core.getenv('GIT_DIR'), worktree=core.getenv('GIT_WORK_TREE')).get(path) class Git(object): """ The Git class manages communication with the Git binary """ def __init__(self): self.paths = Paths() self._valid = {} #: Store the result of is_git_dir() for performance self.set_worktree(core.getcwd()) # pylint: disable=no-self-use def is_git_repository(self, path): return is_git_repository(path) def getcwd(self): """Return the working directory used by git()""" return self.paths.worktree or self.paths.git_dir def set_worktree(self, path): path = core.decode(path) self.paths = find_git_directory(path) return self.paths.worktree def worktree(self): if not self.paths.worktree: path = core.abspath(core.getcwd()) self.paths = find_git_directory(path) return self.paths.worktree def is_valid(self): """Is this a valid git repository? Cache the result to avoid hitting the filesystem. """ git_dir = self.paths.git_dir try: valid = bool(git_dir) and self._valid[git_dir] except KeyError: valid = self._valid[git_dir] = is_git_dir(git_dir) return valid def git_path(self, *paths): result = None if self.paths.git_dir: result = join(self.paths.git_dir, *paths) if result and self.paths.common_dir and not core.exists(result): common_result = join(self.paths.common_dir, *paths) if core.exists(common_result): result = common_result return result def git_dir(self): if not self.paths.git_dir: path = core.abspath(core.getcwd()) self.paths = find_git_directory(path) return self.paths.git_dir def __getattr__(self, name): git_cmd = partial(self.git, name) setattr(self, name, git_cmd) return git_cmd @staticmethod def execute(command, _cwd=None, _decode=True, _encoding=None, _raw=False, _stdin=None, _stderr=subprocess.PIPE, _stdout=subprocess.PIPE, _readonly=False, _no_win32_startupinfo=False): """ Execute a command and returns its output :param command: argument list to execute. :param _cwd: working directory, defaults to the current directory. :param _decode: whether to decode output, defaults to True. :param _encoding: default encoding, defaults to None (utf-8). :param _raw: do not strip trailing whitespace. :param _stdin: optional stdin filehandle. :returns (status, out, err): exit status, stdout, stderr """ # Allow the user to have the command executed in their working dir. if not _cwd: _cwd = core.getcwd() extra = {} if hasattr(os, 'setsid'): # SSH uses the SSH_ASKPASS variable only if the process is really # detached from the TTY (stdin redirection and setting the # SSH_ASKPASS environment variable is not enough). To detach a # process from the console it should fork and call os.setsid(). extra['preexec_fn'] = os.setsid # Start the process # Guard against thread-unsafe .git/index.lock files if not _readonly: _index_lock.acquire() try: status, out, err = core.run_command( command, cwd=_cwd, encoding=_encoding, stdin=_stdin, stdout=_stdout, stderr=_stderr, no_win32_startupinfo=_no_win32_startupinfo, **extra) finally: # Let the next thread in if not _readonly: _index_lock.release() if not _raw and out is not None: out = core.UStr(out.rstrip('\n'), out.encoding) cola_trace = GIT_COLA_TRACE if cola_trace == 'trace': msg = 'trace: ' + core.list2cmdline(command) Interaction.log_status(status, msg, '') elif cola_trace == 'full': if out or err: core.print_stderr( "%s -> %d: '%s' '%s'" % (' '.join(command), status, out, err)) else: core.print_stderr("%s -> %d" % (' '.join(command), status)) elif cola_trace: core.print_stderr(' '.join(command)) # Allow access to the command's status code return (status, out, err) def git(self, cmd, *args, **kwargs): # Handle optional arguments prior to calling transform_kwargs # otherwise they'll end up in args, which is bad. _kwargs = dict(_cwd=self.getcwd()) execute_kwargs = ( '_cwd', '_decode', '_encoding', '_stdin', '_stdout', '_stderr', '_raw', '_readonly', '_no_win32_startupinfo', ) for kwarg in execute_kwargs: if kwarg in kwargs: _kwargs[kwarg] = kwargs.pop(kwarg) # Prepare the argument list git_args = [ GIT, '-c', 'diff.suppressBlankEmpty=false', '-c', 'log.showSignature=false', dashify(cmd), ] opt_args = transform_kwargs(**kwargs) call = git_args + opt_args call.extend(args) try: result = self.execute(call, **_kwargs) except OSError as e: if WIN32 and e.errno == errno.ENOENT: # see if git exists at all. on win32 it can fail with ENOENT in # case of argv overflow. we should be safe from that but use # defensive coding for the worst-case scenario. On UNIX # we have ENAMETOOLONG but that doesn't exist on Windows. if _git_is_installed(): raise e _print_win32_git_hint() result = (1, '', "error: unable to execute '%s'" % GIT) return result def _git_is_installed(): """Return True if git is installed""" # On win32 Git commands can fail with ENOENT in case of argv overflow. we # should be safe from that but use defensive coding for the worst-case # scenario. On UNIX we have ENAMETOOLONG but that doesn't exist on # Windows. try: status, _, _ = Git.execute([GIT, '--version']) result = status == 0 except OSError: result = False return result def transform_kwargs(**kwargs): """Transform kwargs into git command line options Callers can assume the following behavior: Passing foo=None ignores foo, so that callers can use default values of None that are ignored unless set explicitly. Passing foo=False ignore foo, for the same reason. Passing foo={string-or-number} results in ['--foo='] in the resulting arguments. """ args = [] types_to_stringify = (ustr, float, str) + int_types for k, v in kwargs.items(): if len(k) == 1: dashes = '-' eq = '' else: dashes = '--' eq = '=' # isinstance(False, int) is True, so we have to check bool first if isinstance(v, bool): if v: args.append('%s%s' % (dashes, dashify(k))) # else: pass # False is ignored; flag=False inhibits --flag elif isinstance(v, types_to_stringify): args.append('%s%s%s%s' % (dashes, dashify(k), eq, v)) return args def win32_git_error_hint(): return ( '\n' 'NOTE: If you have Git installed in a custom location, e.g.\n' 'C:\\Tools\\Git, then you can create a file at\n' '~/.config/git-cola/git-bindir with following text\n' 'and git-cola will add the specified location to your $PATH\n' 'automatically when starting cola:\n' '\n' r'C:\Tools\Git\bin') @memoize def _print_win32_git_hint(): hint = '\n' + win32_git_error_hint() + '\n' core.print_stderr("error: unable to execute 'git'" + hint) def create(): """Create Git instances >>> git = create() >>> status, out, err = git.version() >>> 'git' == out[:3].lower() True """ return Git() git-cola-3.6/cola/gitcfg.py000066400000000000000000000361041356743264500156370ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals from binascii import unhexlify import copy import fnmatch import os from os.path import join import re import struct from . import core from . import observable from . import utils from .compat import int_types from .git import STDOUT from .compat import ustr BUILTIN_READER = os.environ.get('GIT_COLA_BUILTIN_CONFIG_READER', False) _USER_CONFIG = core.expanduser(join('~', '.gitconfig')) _USER_XDG_CONFIG = core.expanduser( join(core.getenv('XDG_CONFIG_HOME', join('~', '.config')), 'git', 'config')) def create(context): """Create GitConfig instances""" return GitConfig(context) def _stat_info(git): # Try /etc/gitconfig as a fallback for the system config paths = [('system', '/etc/gitconfig'), ('user', _USER_XDG_CONFIG), ('user', _USER_CONFIG)] config = git.git_path('config') if config: paths.append(('repo', config)) statinfo = [] for category, path in paths: try: statinfo.append((category, path, core.stat(path).st_mtime)) except OSError: continue return statinfo def _cache_key(git): # Try /etc/gitconfig as a fallback for the system config paths = [ '/etc/gitconfig', _USER_XDG_CONFIG, _USER_CONFIG, ] config = git.git_path('config') if config: paths.append(config) mtimes = [] for path in paths: try: mtimes.append(core.stat(path).st_mtime) except OSError: continue return mtimes def _config_to_python(v): """Convert a Git config string into a Python value""" if v in ('true', 'yes'): v = True elif v in ('false', 'no'): v = False else: try: v = int(v) except ValueError: pass return v def unhex(value): """Convert a value (int or hex string) into bytes""" if isinstance(value, int_types): # If the value is an integer then it's a value that was converted # by the config reader. Zero-pad it into a 6-digit hex number. value = '%06d' % value return unhexlify(core.encode(value.lstrip('#'))) def _config_key_value(line, splitchar): """Split a config line into a (key, value) pair""" try: k, v = line.split(splitchar, 1) except ValueError: # the user has an empty entry in their git config, # which Git interprets as meaning "true" k = line v = 'true' return k, _config_to_python(v) class GitConfig(observable.Observable): """Encapsulate access to git-config values.""" message_user_config_changed = 'user_config_changed' message_repo_config_changed = 'repo_config_changed' message_updated = 'updated' def __init__(self, context): observable.Observable.__init__(self) self.git = context.git self._map = {} self._system = {} self._user = {} self._user_or_system = {} self._repo = {} self._all = {} self._cache_key = None self._configs = [] self._config_files = {} self._attr_cache = {} self._find_config_files() def reset(self): self._cache_key = None self._configs = [] self._config_files.clear() self._attr_cache = {} self._find_config_files() self.reset_values() def reset_values(self): self._map.clear() self._system.clear() self._user.clear() self._user_or_system.clear() self._repo.clear() self._all.clear() def user(self): return copy.deepcopy(self._user) def repo(self): return copy.deepcopy(self._repo) def all(self): return copy.deepcopy(self._all) def _find_config_files(self): """ Classify git config files into 'system', 'user', and 'repo'. Populates self._configs with a list of the files in reverse-precedence order. self._config_files is populated with {category: path} where category is one of 'system', 'user', or 'repo'. """ # Try the git config in git's installation prefix statinfo = _stat_info(self.git) self._configs = [x[1] for x in statinfo] self._config_files = {} for (cat, path, _) in statinfo: self._config_files[cat] = path def _cached(self): """ Return True when the cache matches. Updates the cache and returns False when the cache does not match. """ cache_key = _cache_key(self.git) if self._cache_key is None or cache_key != self._cache_key: self._cache_key = cache_key return False return True def update(self): """Read git config value into the system, user and repo dicts.""" if self._cached(): return self.reset_values() if 'system' in self._config_files: self._system.update( self.read_config(self._config_files['system'])) if 'user' in self._config_files: self._user.update( self.read_config(self._config_files['user'])) if 'repo' in self._config_files: self._repo.update( self.read_config(self._config_files['repo'])) for dct in (self._system, self._user): self._user_or_system.update(dct) for dct in (self._system, self._user, self._repo): self._all.update(dct) self.notify_observers(self.message_updated) def read_config(self, path): """Return git config data from a path as a dictionary.""" if BUILTIN_READER: return self._read_config_file(path) dest = {} args = ('--null', '--file', path, '--list') config_lines = self.git.config(*args)[STDOUT].split('\0') for line in config_lines: if not line: # the user has an invalid entry in their git config continue k, v = _config_key_value(line, '\n') self._map[k.lower()] = k dest[k] = v return dest def _read_config_file(self, path): """Read a .gitconfig file into a dict""" config = {} header_simple = re.compile(r'^\[(\s+)]$') header_subkey = re.compile(r'^\[(\s+) "(\s+)"\]$') with core.xopen(path, 'rt') as f: file_lines = f.readlines() stripped_lines = [line.strip() for line in file_lines] lines = [line for line in stripped_lines if bool(line)] prefix = '' for line in lines: if line.startswith('#'): continue match = header_simple.match(line) if match: prefix = match.group(1) + '.' continue match = header_subkey.match(line) if match: prefix = match.group(1) + '.' + match.group(2) + '.' continue k, v = _config_key_value(line, '=') k = prefix + k self._map[k.lower()] = k config[k] = v return config def _get(self, src, key, default, fn=None, cached=True): if not cached or not src: self.update() try: value = self._get_with_fallback(src, key) except KeyError: if fn: value = fn() else: value = default return value def _get_with_fallback(self, src, key): try: return src[key] except KeyError: pass key = self._map.get(key.lower(), key) try: return src[key] except KeyError: pass # Allow the final KeyError to bubble up return src[key.lower()] def get(self, key, default=None, fn=None, cached=True): """Return the string value for a config key.""" return self._get(self._all, key, default, fn=fn, cached=cached) def get_all(self, key): """Return all values for a key sorted in priority order The purpose of this function is to group the values returned by `git config --show-origin --get-all` so that the relative order is preserved but can still be overridden at each level. One use case is the `cola.icontheme` variable, which is an ordered list of icon themes to load. This value can be set both in ~/.gitconfig as well as .git/config, and we want to allow a relative order to be defined in either file. The problem is that git will read the system /etc/gitconfig, global ~/.gitconfig, and then the local .git/config settings and return them in that order, so we must post-process them to get them in an order which makes sense for use for our values. Otherwise, we cannot replace the order, or make a specific theme used first, in our local .git/config since the native order returned by git will always list the global config before the local one. get_all() allows for this use case by gathering all of the per-config values separately and then orders them according to the expected local > global > system order. """ result = [] status, out, _ = self.git.config( key, z=True, get_all=True, show_origin=True) if status == 0: current_source = '' current_result = [] partial_results = [] items = [x for x in out.rstrip(chr(0)).split(chr(0)) if x] for i in range(len(items) // 2): source = items[i * 2] value = items[i * 2 + 1] if source != current_source: current_source = source current_result = [] partial_results.append(current_result) current_result.append(value) # Git's results are ordered System, Global, Local. # Reverse the order here so that Local has the highest priority. for partial_result in reversed(partial_results): result.extend(partial_result) return result def get_user(self, key, default=None): return self._get(self._user, key, default) def get_repo(self, key, default=None): return self._get(self._repo, key, default) def get_user_or_system(self, key, default=None): return self._get(self._user_or_system, key, default) def set_user(self, key, value): if value in (None, ''): self.git.config('--global', key, unset=True) else: self.git.config('--global', key, python_to_git(value)) self.update() msg = self.message_user_config_changed self.notify_observers(msg, key, value) def set_repo(self, key, value): if value in (None, ''): self.git.config(key, unset=True) else: self.git.config(key, python_to_git(value)) self.update() msg = self.message_repo_config_changed self.notify_observers(msg, key, value) def find(self, pat): pat = pat.lower() match = fnmatch.fnmatch result = {} if not self._all: self.update() for key, val in self._all.items(): if match(key.lower(), pat): result[key] = val return result def is_annex(self): """Return True when git-annex is enabled""" return bool(self.get('annex.uuid', default=False)) def gui_encoding(self): return self.get('gui.encoding', default=None) def is_per_file_attrs_enabled(self): return self.get('cola.fileattributes', fn=lambda: os.path.exists('.gitattributes')) def file_encoding(self, path): if not self.is_per_file_attrs_enabled(): return self.gui_encoding() cache = self._attr_cache try: value = cache[path] except KeyError: value = cache[path] = (self._file_encoding(path) or self.gui_encoding()) return value def _file_encoding(self, path): """Return the file encoding for a path""" status, out, _ = self.git.check_attr('encoding', '--', path) if status != 0: return None header = '%s: encoding: ' % path if out.startswith(header): encoding = out[len(header):].strip() if encoding not in ('unspecified', 'unset', 'set'): return encoding return None def get_guitool_opts(self, name): """Return the guitool. namespace as a dict The dict keys are simplified so that "guitool.$name.cmd" is accessible as `opts[cmd]`. """ prefix = len('guitool.%s.' % name) guitools = self.find('guitool.%s.*' % name) return dict([(key[prefix:], value) for (key, value) in guitools.items()]) def get_guitool_names(self): guitools = self.find('guitool.*.cmd') prefix = len('guitool.') suffix = len('.cmd') return sorted([name[prefix:-suffix] for (name, _) in guitools.items()]) def get_guitool_names_and_shortcuts(self): """Return guitool names and their configured shortcut""" names = self.get_guitool_names() return [(name, self.get('guitool.%s.shortcut' % name)) for name in names] def terminal(self): term = self.get('cola.terminal', default=None) if not term: # find a suitable default terminal term = 'xterm -e' # for mac osx if utils.is_win32(): # Try to find Git's sh.exe directory in # one of the typical locations pf = os.environ.get('ProgramFiles', 'C:\\Program Files') pf32 = os.environ.get('ProgramFiles(x86)', 'C:\\Program Files (x86)') pf64 = os.environ.get('ProgramW6432', 'C:\\Program Files') for p in [pf64, pf32, pf, 'C:\\']: candidate = os.path.join(p, 'Git\\bin\\sh.exe') if os.path.isfile(candidate): return candidate return None else: candidates = ('xfce4-terminal', 'konsole', 'gnome-terminal') for basename in candidates: if core.exists('/usr/bin/%s' % basename): if basename == 'gnome-terminal': term = '%s --' % basename else: term = '%s -e' % basename break return term def color(self, key, default): value = self.get('cola.color.%s' % key, default=default) struct_layout = core.encode('BBB') try: r, g, b = struct.unpack(struct_layout, unhex(value)) except (struct.error, TypeError): r, g, b = struct.unpack(struct_layout, unhex(default)) return (r, g, b) def python_to_git(value): if isinstance(value, bool): return 'true' if value else 'false' if isinstance(value, int_types): return ustr(value) return value git-cola-3.6/cola/gitcmds.py000066400000000000000000000662341356743264500160350ustar00rootroot00000000000000"""Git commands and queries for Git""" from __future__ import division, absolute_import, unicode_literals import json import os import re from io import StringIO from . import core from . import utils from . import version from .git import STDOUT from .git import EMPTY_TREE_OID from .git import OID_LENGTH from .i18n import N_ from .interaction import Interaction class InvalidRepositoryError(Exception): pass def add(context, items, u=False): """Run "git add" while preventing argument overflow""" fn = context.git.add return utils.slice_fn( items, lambda paths: fn('--', force=True, verbose=True, u=u, *paths)) def apply_diff(context, filename): git = context.git return git.apply(filename, index=True, cached=True) def apply_diff_to_worktree(context, filename): git = context.git return git.apply(filename) def get_branch(context, branch): if branch is None: branch = current_branch(context) return branch def upstream_remote(context, branch=None): """Return the remote associated with the specified branch""" config = context.cfg branch = get_branch(context, branch) return config.get('branch.%s.remote' % branch) def remote_url(context, remote, push=False): """Return the URL for the specified remote""" config = context.cfg url = config.get('remote.%s.url' % remote, '') if push: url = config.get('remote.%s.pushurl' % remote, url) return url def diff_index_filenames(context, ref): """ Return a diff of filenames that have been modified relative to the index """ git = context.git out = git.diff_index(ref, name_only=True, z=True)[STDOUT] return _parse_diff_filenames(out) def diff_filenames(context, *args): """Return a list of filenames that have been modified""" git = context.git out = git.diff_tree(name_only=True, no_commit_id=True, r=True, z=True, _readonly=True, *args)[STDOUT] return _parse_diff_filenames(out) def listdir(context, dirname, ref='HEAD'): """Get the contents of a directory according to Git Query Git for the content of a directory, taking ignored files into account. """ dirs = [] files = [] # first, parse git ls-tree to get the tracked files # in a list of (type, path) tuples entries = ls_tree(context, dirname, ref=ref) for entry in entries: if entry[0][0] == 't': # tree dirs.append(entry[1]) else: files.append(entry[1]) # gather untracked files untracked = untracked_files(context, paths=[dirname], directory=True) for path in untracked: if path.endswith('/'): dirs.append(path[:-1]) else: files.append(path) dirs.sort() files.sort() return (dirs, files) def diff(context, args): """Return a list of filenames for the given diff arguments :param args: list of arguments to pass to "git diff --name-only" """ git = context.git out = git.diff(name_only=True, z=True, *args)[STDOUT] return _parse_diff_filenames(out) def _parse_diff_filenames(out): if out: return out[:-1].split('\0') return [] def tracked_files(context, *args): """Return the names of all files in the repository""" git = context.git out = git.ls_files('--', *args, z=True)[STDOUT] if out: return sorted(out[:-1].split('\0')) return [] def all_files(context, *args): """Returns a sorted list of all files, including untracked files.""" git = context.git ls_files = git.ls_files('--', *args, z=True, cached=True, others=True, exclude_standard=True)[STDOUT] return sorted([f for f in ls_files.split('\0') if f]) class _current_branch(object): """Cache for current_branch()""" key = None value = None def reset(): _current_branch.key = None def current_branch(context): """Return the current branch""" git = context.git head = git.git_path('HEAD') try: key = core.stat(head).st_mtime if _current_branch.key == key: return _current_branch.value except OSError: # OSError means we can't use the stat cache key = 0 status, data, _ = git.rev_parse('HEAD', symbolic_full_name=True) if status != 0: # git init -- read .git/HEAD. We could do this unconditionally... data = _read_git_head(context, head) for refs_prefix in ('refs/heads/', 'refs/remotes/', 'refs/tags/'): if data.startswith(refs_prefix): value = data[len(refs_prefix):] _current_branch.key = key _current_branch.value = value return value # Detached head return data def _read_git_head(context, head, default='master'): """Pure-python .git/HEAD reader""" # Common .git/HEAD "ref: refs/heads/master" files git = context.git islink = core.islink(head) if core.isfile(head) and not islink: data = core.read(head).rstrip() ref_prefix = 'ref: ' if data.startswith(ref_prefix): return data[len(ref_prefix):] # Detached head return data # Legacy .git/HEAD symlinks elif islink: refs_heads = core.realpath(git.git_path('refs', 'heads')) path = core.abspath(head).replace('\\', '/') if path.startswith(refs_heads + '/'): return path[len(refs_heads)+1:] return default def branch_list(context, remote=False): """ Return a list of local or remote branches This explicitly removes HEAD from the list of remote branches. """ if remote: return for_each_ref_basename(context, 'refs/remotes') return for_each_ref_basename(context, 'refs/heads') def _version_sort(context, key='version:refname'): if version.check_git(context, 'version-sort'): sort = key else: sort = False return sort def for_each_ref_basename(context, refs): """Return refs starting with 'refs'.""" git = context.git sort = _version_sort(context) _, out, _ = git.for_each_ref(refs, format='%(refname)', sort=sort, _readonly=True) output = out.splitlines() non_heads = [x for x in output if not x.endswith('/HEAD')] offset = len(refs) + 1 return [x[offset:] for x in non_heads] def _triple(x, y): return (x, len(x) + 1, y) def all_refs(context, split=False, sort_key='version:refname'): """Return a tuple of (local branches, remote branches, tags).""" git = context.git local_branches = [] remote_branches = [] tags = [] triple = _triple query = (triple('refs/tags', tags), triple('refs/heads', local_branches), triple('refs/remotes', remote_branches)) sort = _version_sort(context, key=sort_key) _, out, _ = git.for_each_ref(format='%(refname)', sort=sort, _readonly=True) for ref in out.splitlines(): for prefix, prefix_len, dst in query: if ref.startswith(prefix) and not ref.endswith('/HEAD'): dst.append(ref[prefix_len:]) continue tags.reverse() if split: return local_branches, remote_branches, tags return local_branches + remote_branches + tags def tracked_branch(context, branch=None): """Return the remote branch associated with 'branch'.""" if branch is None: branch = current_branch(context) if branch is None: return None config = context.cfg remote = config.get('branch.%s.remote' % branch) if not remote: return None merge_ref = config.get('branch.%s.merge' % branch) if not merge_ref: return None refs_heads = 'refs/heads/' if merge_ref.startswith(refs_heads): return remote + '/' + merge_ref[len(refs_heads):] return None def parse_remote_branch(branch): """Split a remote branch apart into (remote, name) components""" rgx = re.compile(r'^(?P[^/]+)/(?P.+)$') match = rgx.match(branch) remote = '' branch = '' if match: remote = match.group('remote') branch = match.group('branch') return (remote, branch) def untracked_files(context, paths=None, **kwargs): """Returns a sorted list of untracked files.""" git = context.git if paths is None: paths = [] args = ['--'] + paths out = git.ls_files(z=True, others=True, exclude_standard=True, *args, **kwargs)[STDOUT] if out: return out[:-1].split('\0') return [] def tag_list(context): """Return a list of tags.""" result = for_each_ref_basename(context, 'refs/tags') result.reverse() return result def log(git, *args, **kwargs): return git.log(no_color=True, no_abbrev_commit=True, no_ext_diff=True, _readonly=True, *args, **kwargs)[STDOUT] def commit_diff(context, oid): git = context.git return log(git, '-1', oid, '--') + '\n\n' + oid_diff(context, oid) _diff_overrides = {} def update_diff_overrides(space_at_eol, space_change, all_space, function_context): _diff_overrides['ignore_space_at_eol'] = space_at_eol _diff_overrides['ignore_space_change'] = space_change _diff_overrides['ignore_all_space'] = all_space _diff_overrides['function_context'] = function_context def common_diff_opts(context): config = context.cfg # Default to --patience when diff.algorithm is unset patience = not config.get('diff.algorithm', default='') submodule = version.check_git(context, 'diff-submodule') opts = { 'patience': patience, 'submodule': submodule, 'no_color': True, 'no_ext_diff': True, 'unified': config.get('gui.diffcontext', default=3), '_raw': True, } opts.update(_diff_overrides) return opts def _add_filename(args, filename): if filename: args.extend(['--', filename]) def oid_diff(context, oid, filename=None): """Return the diff for an oid""" # Naively "$oid^!" is what we'd like to use but that doesn't # give the correct result for merges--the diff is reversed. # Be explicit and compare oid against its first parent. git = context.git args = [oid + '~', oid] opts = common_diff_opts(context) _add_filename(args, filename) status, out, _ = git.diff(*args, **opts) if status != 0: # We probably don't have "$oid~" because this is the root commit. # "git show" is clever enough to handle the root commit. args = [oid + '^!'] _add_filename(args, filename) _, out, _ = git.show(pretty='format:', _readonly=True, *args, **opts) out = out.lstrip() return out def diff_info(context, oid, filename=None): git = context.git decoded = log(git, '-1', oid, '--', pretty='format:%b').strip() if decoded: decoded += '\n\n' return decoded + oid_diff(context, oid, filename=filename) def diff_helper(context, commit=None, ref=None, endref=None, filename=None, cached=True, deleted=False, head=None, amending=False, with_diff_header=False, suppress_header=True, reverse=False): "Invokes git diff on a filepath." git = context.git cfg = context.cfg if commit: ref, endref = commit+'^', commit argv = [] if ref and endref: argv.append('%s..%s' % (ref, endref)) elif ref: for r in utils.shell_split(ref.strip()): argv.append(r) elif head and amending and cached: argv.append(head) encoding = None if filename: argv.append('--') if isinstance(filename, (list, tuple)): argv.extend(filename) else: argv.append(filename) encoding = cfg.file_encoding(filename) status, out, _ = git.diff( R=reverse, M=True, cached=cached, _encoding=encoding, *argv, **common_diff_opts(context)) if status != 0: # git init if with_diff_header: return ('', '') return '' result = extract_diff_header(deleted, with_diff_header, suppress_header, out) return core.UStr(result, out.encoding) def extract_diff_header(deleted, with_diff_header, suppress_header, diffoutput): """Split a diff into a header section and payload section""" if diffoutput.startswith('Submodule'): if with_diff_header: return ('', diffoutput) return diffoutput start = False del_tag = 'deleted file mode ' output = StringIO() headers = StringIO() for line in diffoutput.split('\n'): if not start and line[:2] == '@@' and '@@' in line[2:]: start = True if start or (deleted and del_tag in line): output.write(line + '\n') else: if with_diff_header: headers.write(line + '\n') elif not suppress_header: output.write(line + '\n') output_text = output.getvalue() output.close() headers_text = headers.getvalue() headers.close() if with_diff_header: return (headers_text, output_text) return output_text def format_patchsets(context, to_export, revs, output='patches'): """ Group contiguous revision selection into patchsets Exists to handle multi-selection. Multiple disparate ranges in the revision selection are grouped into continuous lists. """ outs = [] errs = [] cur_rev = to_export[0] cur_master_idx = revs.index(cur_rev) patches_to_export = [[cur_rev]] patchset_idx = 0 # Group the patches into continuous sets for rev in to_export[1:]: # Limit the search to the current neighborhood for efficiency try: master_idx = revs[cur_master_idx:].index(rev) master_idx += cur_master_idx except ValueError: master_idx = revs.index(rev) if master_idx == cur_master_idx + 1: patches_to_export[patchset_idx].append(rev) cur_master_idx += 1 continue else: patches_to_export.append([rev]) cur_master_idx = master_idx patchset_idx += 1 # Export each patchsets status = 0 for patchset in patches_to_export: stat, out, err = export_patchset( context, patchset[0], patchset[-1], output=output, n=len(patchset) > 1, thread=True, patch_with_stat=True) outs.append(out) if err: errs.append(err) status = max(stat, status) return (status, '\n'.join(outs), '\n'.join(errs)) def export_patchset(context, start, end, output='patches', **kwargs): """Export patches from start^ to end.""" git = context.git return git.format_patch('-o', output, start + '^..' + end, **kwargs) # TODO Unused? def reset_paths(context, items): """Run "git reset" while preventing argument overflow""" fn = context.git.reset status, out, err = utils.slice_fn(items, lambda paths: fn('--', *paths)) return (status, out, err) def unstage_paths(context, args, head='HEAD'): git = context.git status, out, err = git.reset(head, '--', *set(args)) if status == 128: # handle git init: we have to use 'git rm --cached' # detect this condition by checking if the file is still staged return untrack_paths(context, args) return (status, out, err) def untrack_paths(context, args): if not args: return (-1, N_('Nothing to do'), '') git = context.git return git.update_index('--', force_remove=True, *set(args)) def worktree_state(context, head='HEAD', update_index=False, display_untracked=True, paths=None): """Return a dict of files in various states of being :rtype: dict, keys are staged, unstaged, untracked, unmerged, changed_upstream, and submodule. """ git = context.git if update_index: git.update_index(refresh=True) staged, unmerged, staged_deleted, staged_submods = diff_index( context, head, paths=paths) modified, unstaged_deleted, modified_submods = diff_worktree( context, paths) if display_untracked: untracked = untracked_files(context, paths=paths) else: untracked = [] # Remove unmerged paths from the modified list if unmerged: unmerged_set = set(unmerged) modified = [path for path in modified if path not in unmerged_set] # Look for upstream modified files if this is a tracking branch upstream_changed = diff_upstream(context, head) # Keep stuff sorted staged.sort() modified.sort() unmerged.sort() untracked.sort() upstream_changed.sort() return {'staged': staged, 'modified': modified, 'unmerged': unmerged, 'untracked': untracked, 'upstream_changed': upstream_changed, 'staged_deleted': staged_deleted, 'unstaged_deleted': unstaged_deleted, 'submodules': staged_submods | modified_submods} def _parse_raw_diff(out): while out: info, path, out = out.split('\0', 2) status = info[-1] is_submodule = ('160000' in info[1:14]) yield (path, status, is_submodule) def diff_index(context, head, cached=True, paths=None): git = context.git staged = [] unmerged = [] deleted = set() submodules = set() if paths is None: paths = [] args = [head, '--'] + paths status, out, _ = git.diff_index(cached=cached, z=True, *args) if status != 0: # handle git init args[0] = EMPTY_TREE_OID status, out, _ = git.diff_index(cached=cached, z=True, *args) for path, status, is_submodule in _parse_raw_diff(out): if is_submodule: submodules.add(path) if status in 'DAMT': staged.append(path) if status == 'D': deleted.add(path) elif status == 'U': unmerged.append(path) return staged, unmerged, deleted, submodules def diff_worktree(context, paths=None): git = context.git modified = [] deleted = set() submodules = set() if paths is None: paths = [] args = ['--'] + paths status, out, _ = git.diff_files(z=True, *args) for path, status, is_submodule in _parse_raw_diff(out): if is_submodule: submodules.add(path) if status in 'DAMT': modified.append(path) if status == 'D': deleted.add(path) return modified, deleted, submodules def diff_upstream(context, head): """Given `ref`, return $(git merge-base ref HEAD)..ref.""" tracked = tracked_branch(context) if not tracked: return [] base = merge_base(context, head, tracked) return diff_filenames(context, base, tracked) def list_submodule(context): """Return submodules in the format(state, sha1, path, describe)""" git = context.git status, data, _ = git.submodule('status') ret = [] if status == 0 and data: data = data.splitlines() # see git submodule status # TODO better separation for line in data: state = line[0].strip() sha1 = line[1:OID_LENGTH+1] left_bracket = line.find('(', OID_LENGTH + 3) if left_bracket == -1: left_bracket = len(line) + 1 path = line[OID_LENGTH+2:left_bracket-1] describe = line[left_bracket+1:-1] ret.append((state, sha1, path, describe)) return ret def merge_base(context, head, ref): """Return the merge-base of head and ref""" git = context.git return git.merge_base(head, ref, _readonly=True)[STDOUT] def merge_base_parent(context, branch): tracked = tracked_branch(context, branch=branch) if tracked: return tracked return 'HEAD' # TODO Unused? def parse_ls_tree(context, rev): """Return a list of (mode, type, oid, path) tuples.""" output = [] git = context.git lines = git.ls_tree(rev, r=True, _readonly=True)[STDOUT].splitlines() regex = re.compile(r'^(\d+)\W(\w+)\W(\w+)[ \t]+(.*)$') for line in lines: match = regex.match(line) if match: mode = match.group(1) objtype = match.group(2) oid = match.group(3) filename = match.group(4) output.append((mode, objtype, oid, filename,)) return output # TODO unused? def ls_tree(context, path, ref='HEAD'): """Return a parsed git ls-tree result for a single directory""" git = context.git result = [] status, out, _ = git.ls_tree(ref, '--', path, z=True, full_tree=True) if status == 0 and out: path_offset = 6 + 1 + 4 + 1 + OID_LENGTH + 1 for line in out[:-1].split('\0'): # 1 1 1 # .....6 ...4 ......................................40 # 040000 tree c127cde9a0c644a3a8fef449a244f47d5272dfa6 relative # 100644 blob 139e42bf4acaa4927ec9be1ec55a252b97d3f1e2 relative/path # 0..... 7... 12...................................... 53 # path_offset = 6 + 1 + 4 + 1 + OID_LENGTH(40) + 1 objtype = line[7:11] relpath = line[path_offset:] result.append((objtype, relpath)) return result # A regex for matching the output of git(log|rev-list) --pretty=oneline REV_LIST_REGEX = re.compile(r'^([0-9a-f]{40}) (.*)$') def parse_rev_list(raw_revs): """Parse `git log --pretty=online` output into (oid, summary) pairs.""" revs = [] for line in raw_revs.splitlines(): match = REV_LIST_REGEX.match(line) if match: rev_id = match.group(1) summary = match.group(2) revs.append((rev_id, summary,)) return revs # pylint: disable=redefined-builtin def log_helper(context, all=False, extra_args=None): """Return parallel arrays containing oids and summaries.""" revs = [] summaries = [] args = [] if extra_args: args = extra_args git = context.git output = log(git, pretty='oneline', all=all, *args) for line in output.splitlines(): match = REV_LIST_REGEX.match(line) if match: revs.append(match.group(1)) summaries.append(match.group(2)) return (revs, summaries) def rev_list_range(context, start, end): """Return (oid, summary) pairs between start and end.""" git = context.git revrange = '%s..%s' % (start, end) out = git.rev_list(revrange, pretty='oneline')[STDOUT] return parse_rev_list(out) def commit_message_path(context): """Return the path to .git/GIT_COLA_MSG""" git = context.git path = git.git_path('GIT_COLA_MSG') if core.exists(path): return path return None def merge_message_path(context): """Return the path to .git/MERGE_MSG or .git/SQUASH_MSG.""" git = context.git for basename in ('MERGE_MSG', 'SQUASH_MSG'): path = git.git_path(basename) if core.exists(path): return path return None def prepare_commit_message_hook(context): default_hook = context.git.git_path('hooks', 'cola-prepare-commit-msg') config = context.cfg return config.get('cola.preparecommitmessagehook', default=default_hook) def abort_merge(context): """Abort a merge by reading the tree at HEAD.""" # Reset the worktree git = context.git status, out, err = git.read_tree('HEAD', reset=True, u=True, v=True) # remove MERGE_HEAD merge_head = git.git_path('MERGE_HEAD') if core.exists(merge_head): core.unlink(merge_head) # remove MERGE_MESSAGE, etc. merge_msg_path = merge_message_path(context) while merge_msg_path: core.unlink(merge_msg_path) merge_msg_path = merge_message_path(context) return status, out, err def strip_remote(remotes, remote_branch): for remote in remotes: prefix = remote + '/' if remote_branch.startswith(prefix): return remote_branch[len(prefix):] return remote_branch.split('/', 1)[-1] def parse_refs(context, argv): """Parse command-line arguments into object IDs""" git = context.git status, out, _ = git.rev_parse(*argv) if status == 0: oids = [oid for oid in out.splitlines() if oid] else: oids = argv return oids def prev_commitmsg(context, *args): """Queries git for the latest commit message.""" git = context.git return git.log( '-1', no_color=True, pretty='format:%s%n%n%b', *args)[STDOUT] def rev_parse(context, name): """Call git rev-parse and return the output""" git = context.git status, out, _ = git.rev_parse(name) if status == 0: result = out.strip() else: result = name return result def write_blob(context, oid, filename): """Write a blob to a temporary file and return the path Modern versions of Git allow invoking filters. Older versions get the object content as-is. """ if version.check_git(context, 'cat-file-filters-path'): return cat_file_to_path(context, filename, oid) return cat_file_blob(context, filename, oid) def cat_file_blob(context, filename, oid): return cat_file(context, filename, 'blob', oid) def cat_file_to_path(context, filename, oid): return cat_file(context, filename, oid, path=filename, filters=True) def cat_file(context, filename, *args, **kwargs): """Redirect git cat-file output to a path""" result = None git = context.git # Use the original filename in the suffix so that the generated filename # has the correct extension, and so that it resembles the original name. basename = os.path.basename(filename) suffix = '-' + basename # ensures the correct filename extension path = utils.tmp_filename('blob', suffix=suffix) with open(path, 'wb') as fp: status, out, err = git.cat_file( _raw=True, _readonly=True, _stdout=fp, *args, **kwargs) Interaction.command( N_('Error'), 'git cat-file', status, out, err) if status == 0: result = path if not result: core.unlink(path) return result def write_blob_path(context, head, oid, filename): """Use write_blob() when modern git is available""" if version.check_git(context, 'cat-file-filters-path'): return write_blob(context, oid, filename) return cat_file_blob(context, filename, head + ':' + filename) def annex_path(context, head, filename): """Return the git-annex path for a filename at the specified commit""" git = context.git path = None annex_info = {} # unfortunately there's no way to filter this down to a single path # so we just have to scan all reported paths status, out, _ = git.annex('findref', '--json', head) if status == 0: for line in out.splitlines(): info = json.loads(line) try: annex_file = info['file'] except (ValueError, KeyError): continue # we only care about this file so we can skip the rest if annex_file == filename: annex_info = info break key = annex_info.get('key', '') if key: status, out, _ = git.annex('contentlocation', key) if status == 0 and os.path.exists(out): path = out return path git-cola-3.6/cola/gravatar.py000066400000000000000000000100341356743264500161750ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals import time import hashlib from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from qtpy import QtNetwork from . import core from . import icons from .compat import bstr from .compat import ustr from .compat import parse from .widgets import defs class Gravatar(object): @staticmethod def url_for_email(email, imgsize): email_hash = core.decode(hashlib.md5(core.encode(email)).hexdigest()) # Python2.6 requires byte strings for urllib2.quote() so we have # to force default_url = 'https://git-cola.github.io/images/git-64x64.jpg' encoded_url = parse.quote(core.encode(default_url), core.encode('')) query = '?s=%d&d=%s' % (imgsize, core.decode(encoded_url)) url = 'https://gravatar.com/avatar/' + email_hash + query return url class GravatarLabel(QtWidgets.QLabel): def __init__(self, parent=None): QtWidgets.QLabel.__init__(self, parent) self.email = None self.response = None self.timeout = 0 self.imgsize = defs.medium_icon self.pixmaps = {} self._default_pixmap_bytes = None self.network = QtNetwork.QNetworkAccessManager() # pylint: disable=no-member self.network.finished.connect(self.network_finished) def set_email(self, email): if email in self.pixmaps: self.setPixmap(self.pixmaps[email]) return if (self.timeout > 0 and (int(time.time()) - self.timeout) < (5 * 60)): self.set_pixmap_from_response() return if email == self.email and self.response is not None: self.set_pixmap_from_response() return self.email = email self.request(email) def request(self, email): url = Gravatar.url_for_email(email, self.imgsize) self.network.get(QtNetwork.QNetworkRequest(QtCore.QUrl(url))) def default_pixmap_as_bytes(self): if self._default_pixmap_bytes is None: xres = self.imgsize pixmap = icons.cola().pixmap(xres) byte_array = QtCore.QByteArray() buf = QtCore.QBuffer(byte_array) buf.open(QtCore.QIODevice.WriteOnly) pixmap.save(buf, 'PNG') buf.close() self._default_pixmap_bytes = byte_array else: byte_array = self._default_pixmap_bytes return byte_array def network_finished(self, reply): email = self.email header = QtCore.QByteArray(bstr('Location')) location = ustr(reply.rawHeader(header)).strip() if location: request_location = Gravatar.url_for_email(self.email, self.imgsize) relocated = location != request_location else: relocated = False if reply.error() == QtNetwork.QNetworkReply.NoError: if relocated: # We could do get_url(parse.unquote(location)) to # download the default image. # Save bandwidth by using a pixmap. self.response = self.default_pixmap_as_bytes() else: self.response = reply.readAll() self.timeout = 0 else: self.response = self.default_pixmap_as_bytes() self.timeout = int(time.time()) pixmap = self.set_pixmap_from_response() # If the email has not changed (e.g. no other requests) # then we know that this pixmap corresponds to this specific # email address. We can't blindly trust self.email else # we may add cache entries for thee wrong email address. url = Gravatar.url_for_email(email, self.imgsize) if url == reply.url().toString(): self.pixmaps[email] = pixmap def set_pixmap_from_response(self): if self.response is None: self.response = self._default_pixmap_bytes() pixmap = QtGui.QPixmap() pixmap.loadFromData(self.response) self.setPixmap(pixmap) return pixmap git-cola-3.6/cola/guicmds.py000066400000000000000000000203101356743264500160170ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals import os from . import cmds from . import core from . import difftool from . import gitcmds from . import icons from . import qtutils from .i18n import N_ from .interaction import Interaction from .widgets import completion from .widgets import editremotes from .widgets.browse import BrowseBranch from .widgets.selectcommits import select_commits from .widgets.selectcommits import select_commits_and_output def delete_branch(context): """Launch the 'Delete Branch' dialog.""" icon = icons.discard() branch = choose_branch( context, N_('Delete Branch'), N_('Delete'), icon=icon) if not branch: return cmds.do(cmds.DeleteBranch, context, branch) def delete_remote_branch(context): """Launch the 'Delete Remote Branch' dialog.""" remote_branch = choose_remote_branch( context, N_('Delete Remote Branch'), N_('Delete'), icon=icons.discard()) if not remote_branch: return remote, branch = gitcmds.parse_remote_branch(remote_branch) if remote and branch: cmds.do(cmds.DeleteRemoteBranch, context, remote, branch) def browse_current(context): """Launch the 'Browse Current Branch' dialog.""" branch = gitcmds.current_branch(context) BrowseBranch.browse(context, branch) def browse_other(context): """Prompt for a branch and inspect content at that point in time.""" # Prompt for a branch to browse branch = choose_ref(context, N_('Browse Commits...'), N_('Browse')) if not branch: return BrowseBranch.browse(context, branch) def checkout_branch(context): """Launch the 'Checkout Branch' dialog.""" branch = choose_potential_branch( context, N_('Checkout Branch'), N_('Checkout')) if not branch: return cmds.do(cmds.CheckoutBranch, context, branch) def cherry_pick(context): """Launch the 'Cherry-Pick' dialog.""" revs, summaries = gitcmds.log_helper(context, all=True) commits = select_commits( context, N_('Cherry-Pick Commit'), revs, summaries, multiselect=False) if not commits: return cmds.do(cmds.CherryPick, context, commits) def new_repo(context): """Prompt for a new directory and create a new Git repository :returns str: repository path or None if no repository was created. """ git = context.git path = qtutils.opendir_dialog(N_('New Repository...'), core.getcwd()) if not path: return None # Avoid needlessly calling `git init`. if git.is_git_repository(path): # We could prompt here and confirm that they really didn't # mean to open an existing repository, but I think # treating it like an "Open" is a sensible DWIM answer. return path status, out, err = git.init(path) if status == 0: return path title = N_('Error Creating Repository') Interaction.command_error(title, 'git init', status, out, err) return None def open_new_repo(context): dirname = new_repo(context) if not dirname: return cmds.do(cmds.OpenRepo, context, dirname) def new_bare_repo(context): result = None repo = prompt_for_new_bare_repo() if not repo: return result # Create bare repo ok = cmds.do(cmds.NewBareRepo, context, repo) if not ok: return result # Add a new remote pointing to the bare repo parent = qtutils.active_window() add_remote = editremotes.add_remote( context, parent, name=os.path.basename(repo), url=repo, readonly_url=True) if add_remote: result = repo return result def prompt_for_new_bare_repo(): path = qtutils.opendir_dialog(N_('Select Directory...'), core.getcwd()) if not path: return None bare_repo = None default = os.path.basename(core.getcwd()) if not default.endswith('.git'): default += '.git' while not bare_repo: name, ok = qtutils.prompt( N_('Enter a name for the new bare repo'), title=N_('New Bare Repository...'), text=default) if not name or not ok: return None if not name.endswith('.git'): name += '.git' repo = os.path.join(path, name) if core.isdir(repo): Interaction.critical( N_('Error'), N_('"%s" already exists') % repo) else: bare_repo = repo return bare_repo def export_patches(context): """Run 'git format-patch' on a list of commits.""" revs, summaries = gitcmds.log_helper(context) to_export_and_output = select_commits_and_output( context, N_('Export Patches'), revs, summaries) if not to_export_and_output['to_export']: return cmds.do( cmds.FormatPatch, context, reversed(to_export_and_output['to_export']), reversed(revs), to_export_and_output['output']) def diff_expression(context): """Diff using an arbitrary expression.""" tracked = gitcmds.tracked_branch(context) current = gitcmds.current_branch(context) if tracked and current: ref = tracked + '..' + current else: ref = 'origin/master..' difftool.diff_expression(context, qtutils.active_window(), ref) def open_repo(context): model = context.model dirname = qtutils.opendir_dialog( N_('Open Git Repository...'), model.getcwd()) if not dirname: return cmds.do(cmds.OpenRepo, context, dirname) def open_repo_in_new_window(context): """Spawn a new cola session.""" model = context.model dirname = qtutils.opendir_dialog( N_('Open Git Repository...'), model.getcwd()) if not dirname: return cmds.do(cmds.OpenNewRepo, context, dirname) def load_commitmsg(context): """Load a commit message from a file.""" model = context.model filename = qtutils.open_file( N_('Load Commit Message'), directory=model.getcwd()) if filename: cmds.do(cmds.LoadCommitMessageFromFile, context, filename) def choose_from_dialog(get, context, title, button_text, default, icon=None): parent = qtutils.active_window() return get(context, title, button_text, parent, default=default, icon=icon) def choose_ref(context, title, button_text, default=None, icon=None): return choose_from_dialog(completion.GitRefDialog.get, context, title, button_text, default, icon=icon) def choose_branch(context, title, button_text, default=None, icon=None): return choose_from_dialog(completion.GitBranchDialog.get, context, title, button_text, default, icon=icon) def choose_potential_branch(context, title, button_text, default=None, icon=None): return choose_from_dialog(completion.GitCheckoutBranchDialog.get, context, title, button_text, default, icon=icon) def choose_remote_branch(context, title, button_text, default=None, icon=None): return choose_from_dialog(completion.GitRemoteBranchDialog.get, context, title, button_text, default, icon=icon) def review_branch(context): """Diff against an arbitrary revision, branch, tag, etc.""" branch = choose_ref(context, N_('Select Branch to Review'), N_('Review')) if not branch: return merge_base = gitcmds.merge_base_parent(context, branch) difftool.diff_commits(context, qtutils.active_window(), merge_base, branch) def rename_branch(context): """Launch the 'Rename Branch' dialogs.""" branch = choose_branch(context, N_('Rename Existing Branch'), N_('Select')) if not branch: return new_branch = choose_branch( context, N_('Enter New Branch Name'), N_('Rename')) if not new_branch: return cmds.do(cmds.RenameBranch, context, branch, new_branch) def reset_branch_head(context): ref = choose_ref( context, N_('Reset Branch Head'), N_('Reset'), default='HEAD^') if ref: cmds.do(cmds.ResetBranchHead, context, ref) def reset_worktree(context): ref = choose_ref( context, N_('Reset Worktree'), N_('Reset')) if ref: cmds.do(cmds.ResetWorktree, context, ref) def install(): """Install the GUI-model interaction hooks""" Interaction.choose_ref = staticmethod(choose_ref) git-cola-3.6/cola/hidpi.py000066400000000000000000000023571356743264500154740ustar00rootroot00000000000000"""Provides High DPI support by wrapping Qt options""" from __future__ import absolute_import, division, unicode_literals from qtpy import QtCore from .i18n import N_ from . import core from . import compat from . import version class Option(object): AUTO = '0' DISABLE = 'disable' TIMES_1 = '1' TIMES_1_5 = '1.5' TIMES_2 = '2' def is_supported(): return version.check('qt-hidpi-scale', QtCore.__version__) def apply_choice(value): value = compat.ustr(value) if value == Option.AUTO: # Do not override the configuration when either of these # two environment variables are defined. if (not core.getenv('QT_AUTO_SCREEN_SCALE_FACTOR') and not core.getenv('QT_SCALE_FACTOR')): compat.setenv('QT_AUTO_SCREEN_SCALE_FACTOR', '1') compat.unsetenv('QT_SCALE_FACTOR') elif value in (Option.TIMES_1, Option.TIMES_1_5, Option.TIMES_2): compat.unsetenv('QT_AUTO_SCREEN_SCALE_FACTOR') compat.setenv('QT_SCALE_FACTOR', value) def options(): return ( (N_('Auto'), Option.AUTO), (N_('Disable'), Option.DISABLE), (N_('x 1'), Option.TIMES_1), (N_('x 1.5'), Option.TIMES_1_5), (N_('x 2'), Option.TIMES_2), ) git-cola-3.6/cola/hotkeys.py000066400000000000000000000074361356743264500160700ustar00rootroot00000000000000from __future__ import absolute_import from qtpy.QtGui import QKeySequence from qtpy.QtCore import Qt def hotkey(seq): return QKeySequence(seq) # A-G STAGE_MODIFIED = hotkey(Qt.ALT + Qt.Key_A) WORD_LEFT = hotkey(Qt.Key_B) BLAME = hotkey(Qt.CTRL + Qt.SHIFT + Qt.Key_B) BRANCH = hotkey(Qt.CTRL + Qt.Key_B) CHECKOUT = hotkey(Qt.ALT + Qt.Key_B) CHERRY_PICK = hotkey(Qt.CTRL + Qt.SHIFT + Qt.Key_C) COPY_SHA1 = hotkey(Qt.CTRL + Qt.ALT + Qt.Key_C) DIFFSTAT = hotkey(Qt.ALT + Qt.Key_D) DIFF = hotkey(Qt.CTRL + Qt.Key_D) DIFF_SECONDARY = hotkey(Qt.CTRL + Qt.SHIFT + Qt.Key_D) EDIT = hotkey(Qt.CTRL + Qt.Key_E) EDIT_SECONDARY = hotkey(Qt.CTRL + Qt.SHIFT + Qt.Key_E) EXPORT = hotkey(Qt.ALT + Qt.SHIFT + Qt.Key_E) FIT = hotkey(Qt.Key_F) FETCH = hotkey(Qt.CTRL + Qt.Key_F) FILTER = hotkey(Qt.CTRL + Qt.SHIFT + Qt.Key_F) GREP = hotkey(Qt.CTRL + Qt.Key_G) # H-P MOVE_LEFT = hotkey(Qt.Key_H) MOVE_LEFT_SHIFT = hotkey(Qt.SHIFT + Qt.Key_H) HISTORY = hotkey(Qt.CTRL + Qt.SHIFT + Qt.Key_H) SIGNOFF = hotkey(Qt.CTRL + Qt.Key_I) MOVE_DOWN = hotkey(Qt.Key_J) MOVE_DOWN_SHIFT = hotkey(Qt.SHIFT + Qt.Key_J) MOVE_DOWN_SECONDARY = hotkey(Qt.ALT + Qt.Key_J) MOVE_DOWN_TERTIARY = hotkey(Qt.SHIFT + Qt.Key_J) MOVE_UP = hotkey(Qt.Key_K) MOVE_UP_SHIFT = hotkey(Qt.SHIFT + Qt.Key_K) MOVE_UP_SECONDARY = hotkey(Qt.ALT + Qt.Key_K) MOVE_UP_TERTIARY = hotkey(Qt.SHIFT + Qt.Key_K) MOVE_RIGHT = hotkey(Qt.Key_L) MOVE_RIGHT_SHIFT = hotkey(Qt.SHIFT + Qt.Key_L) FOCUS = hotkey(Qt.CTRL + Qt.Key_L) FOCUS_DIFF = hotkey(Qt.CTRL + Qt.Key_J) FOCUS_STATUS = hotkey(Qt.CTRL + Qt.Key_K) AMEND = hotkey(Qt.CTRL + Qt.Key_M) MERGE = hotkey(Qt.CTRL + Qt.SHIFT + Qt.Key_M) PUSH = hotkey(Qt.CTRL + Qt.Key_P) PULL = hotkey(Qt.CTRL + Qt.SHIFT + Qt.Key_P) # Q-Z QUIT = hotkey(Qt.CTRL + Qt.Key_Q) REFRESH = hotkey(Qt.CTRL + Qt.Key_R) REFRESH_SECONDARY = hotkey(Qt.Key_F5) REFRESH_HOTKEYS = (REFRESH, REFRESH_SECONDARY) STAGE_DIFF = hotkey(Qt.Key_S) STAGE_SELECTION = hotkey(Qt.CTRL + Qt.Key_S) STASH = hotkey(Qt.ALT + Qt.SHIFT + Qt.Key_S) FINDER = hotkey(Qt.CTRL + Qt.Key_T) FINDER_SECONDARY = hotkey(Qt.Key_T) TERMINAL = hotkey(Qt.CTRL + Qt.SHIFT + Qt.Key_T) STAGE_UNTRACKED = hotkey(Qt.ALT + Qt.Key_U) REVERT = hotkey(Qt.CTRL + Qt.Key_U) WORD_RIGHT = hotkey(Qt.Key_W) # Numbers START_OF_LINE = hotkey(Qt.Key_0) # Special keys BACKSPACE = hotkey(Qt.Key_Backspace) TRASH = hotkey(Qt.CTRL + Qt.Key_Backspace) DELETE_FILE = hotkey(Qt.CTRL + Qt.SHIFT + Qt.Key_Backspace) DELETE_FILE_SECONDARY = hotkey(Qt.CTRL + Qt.Key_Backspace) PREFERENCES = hotkey(Qt.CTRL + Qt.Key_Comma) END_OF_LINE = hotkey(Qt.Key_Dollar) DOWN = hotkey(Qt.Key_Down) ENTER = hotkey(Qt.Key_Enter) ZOOM_OUT = hotkey(Qt.Key_Minus) REMOVE_ITEM = hotkey(Qt.Key_Minus) ADD_ITEM = hotkey(Qt.Key_Plus) ZOOM_IN = hotkey(Qt.Key_Plus) ZOOM_IN_SECONDARY = hotkey(Qt.Key_Equal) QUESTION = hotkey(Qt.Key_Question) RETURN = hotkey(Qt.Key_Return) ACCEPT = (ENTER, RETURN) COMMIT = hotkey(Qt.CTRL + Qt.Key_Return) PREPARE_COMMIT_MESSAGE = hotkey(Qt.CTRL + Qt.SHIFT + Qt.Key_Return) PRIMARY_ACTION = hotkey(hotkey(Qt.Key_Space)) SECONDARY_ACTION = hotkey(Qt.SHIFT + Qt.Key_Space) LEAVE = hotkey(Qt.SHIFT + Qt.Key_Tab) UP = hotkey(Qt.Key_Up) CTRL_RETURN = hotkey(Qt.CTRL + Qt.Key_Return) CTRL_ENTER = hotkey(Qt.CTRL + Qt.Key_Enter) # Rebase REBASE_START_AND_CONTINUE = hotkey(Qt.ALT + Qt.Key_R) REBASE_PICK = (hotkey(Qt.Key_1), hotkey(Qt.Key_P)) REBASE_REWORD = (hotkey(Qt.Key_2), hotkey(Qt.Key_R)) REBASE_EDIT = (hotkey(Qt.Key_3), hotkey(Qt.Key_E)) REBASE_FIXUP = (hotkey(Qt.Key_4), hotkey(Qt.Key_F)) REBASE_SQUASH = (hotkey(Qt.Key_5), hotkey(Qt.Key_S)) UNDO = hotkey(Qt.CTRL + Qt.Key_Z) REDO = hotkey(Qt.SHIFT + Qt.CTRL + Qt.Key_Z) # Key Sequences COPY = QKeySequence.Copy CLOSE = QKeySequence.Close CUT = QKeySequence.Cut PASTE = QKeySequence.Paste DELETE = QKeySequence.Delete NEW = QKeySequence.New OPEN = QKeySequence.Open SELECT_ALL = QKeySequence.SelectAll git-cola-3.6/cola/i18n.py000066400000000000000000000056301356743264500151530ustar00rootroot00000000000000"""i18n and l10n support for git-cola""" from __future__ import division, absolute_import, unicode_literals import gettext as _gettext import os import sys from . import compat from . import core from . import resources _null_translation = _gettext.NullTranslations() _translation = _null_translation def gettext(s): try: txt = _translation.ugettext(s) except AttributeError: # Python 3 compat _translation.ugettext = _translation.gettext txt = _translation.gettext(s) # handle @@verb / @@noun txt = txt.replace('@@verb', '').replace('@@noun', '') return txt def ngettext(s, p, n): try: txt = _translation.ungettext(s, p, n) except AttributeError: # Python 3 compat _translation.ungettext = _translation.ngettext txt = _translation.ngettext(s, p, n) return txt def N_(s): return gettext(s) def install(locale): # pylint: disable=global-statement global _translation if sys.platform == 'win32': _check_win32_locale() if locale: _set_language(locale) _install_custom_language() _gettext.textdomain('messages') _translation = _gettext.translation('git-cola', localedir=_get_locale_dir(), fallback=True) def uninstall(): # pylint: disable=global-statement global _translation _translation = _null_translation def _get_locale_dir(): return resources.prefix('share', 'locale') def _install_custom_language(): """Allow a custom language to be set in ~/.config/git-cola/language""" lang_file = resources.config_home('language') if not core.exists(lang_file): return try: locale = core.read(lang_file).strip() except (OSError, IOError): return if locale: _set_language(locale) def _set_language(locale): compat.setenv('LANGUAGE', locale) compat.setenv('LANG', locale) compat.setenv('LC_ALL', locale) compat.setenv('LC_MESSAGES', locale) def _check_win32_locale(): for i in ('LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG'): if os.environ.get(i): break else: lang = None import locale try: import ctypes except ImportError: # use only user's default locale lang = locale.getdefaultlocale()[0] else: # using ctypes to determine all locales lcid_user = ctypes.windll.kernel32.GetUserDefaultLCID() lcid_system = ctypes.windll.kernel32.GetSystemDefaultLCID() if lcid_user != lcid_system: lcid = [lcid_user, lcid_system] else: lcid = [lcid_user] lang = [locale.windows_locale.get(i) for i in lcid] lang = ':'.join([i for i in lang if i]) # set lang code for gettext if lang: compat.setenv('LANGUAGE', lang) git-cola-3.6/cola/icons.py000066400000000000000000000146661356743264500155200ustar00rootroot00000000000000"""The only file where icon filenames are mentioned""" from __future__ import absolute_import, division, unicode_literals import os from qtpy import QtGui from qtpy import QtWidgets from . import core from . import qtcompat from . import resources from .compat import ustr from .i18n import N_ KNOWN_FILE_MIME_TYPES = [ ('text', 'file-code.svg'), ('image', 'file-media.svg'), ('octet', 'file-binary.svg'), ] KNOWN_FILE_EXTENSIONS = { '.bash': 'file-code.svg', '.c': 'file-code.svg', '.cpp': 'file-code.svg', '.css': 'file-code.svg', '.cxx': 'file-code.svg', '.h': 'file-code.svg', '.hpp': 'file-code.svg', '.hs': 'file-code.svg', '.html': 'file-code.svg', '.java': 'file-code.svg', '.js': 'file-code.svg', '.ksh': 'file-code.svg', '.lisp': 'file-code.svg', '.perl': 'file-code.svg', '.pl': 'file-code.svg', '.py': 'file-code.svg', '.rb': 'file-code.svg', '.rs': 'file-code.svg', '.sh': 'file-code.svg', '.zsh': 'file-code.svg', } def install(themes): for theme in themes: icon_dir = resources.icon_dir(theme) qtcompat.add_search_path('icons', icon_dir) def icon_themes(): return ( (N_('Default'), 'default'), (N_('Dark Theme'), 'dark'), (N_('Light Theme'), 'light'), ) def name_from_basename(basename): """Prefix the basename with "icons:" so that git-cola's icons are found "icons" is registered with Qt's resource system during install(). """ return 'icons:' + basename def from_name(name): """Return a QIcon from an absolute filename or "icons:basename.svg" name""" return QtGui.QIcon(name) def icon(basename): """Given a basename returns a QIcon from the corresponding cola icon""" return from_name(name_from_basename(basename)) def from_theme(name, fallback=None): """Grab an icon from the current theme with a fallback Support older versions of Qt checking for fromTheme's availability. """ if hasattr(QtGui.QIcon, 'fromTheme'): base, _ = os.path.splitext(name) if fallback: qicon = QtGui.QIcon.fromTheme(base, icon(fallback)) else: qicon = QtGui.QIcon.fromTheme(base) if not qicon.isNull(): return qicon return icon(fallback or name) def basename_from_filename(filename): """Returns an icon name based on the filename""" mimetype = core.guess_mimetype(filename) if mimetype is not None: mimetype = mimetype.lower() for filetype, icon_name in KNOWN_FILE_MIME_TYPES: if filetype in mimetype: return icon_name extension = os.path.splitext(filename)[1] return KNOWN_FILE_EXTENSIONS.get(extension.lower(), 'file-text.svg') def from_filename(filename): basename = basename_from_filename(filename) return from_name(name_from_basename(basename)) def mkicon(value, default=None): if value is None and default is not None: value = default() elif value and isinstance(value, (str, ustr)): value = QtGui.QIcon(value) return value def from_style(key): """Maintain a cache of standard icons and return cache entries.""" style = QtWidgets.QApplication.instance().style() return style.standardIcon(key) def status(filename, deleted, is_staged, untracked): if deleted: icon_name = 'circle-slash-red.svg' elif is_staged: icon_name = 'staged.svg' elif untracked: icon_name = 'question-plain.svg' else: icon_name = basename_from_filename(filename) return icon_name # Icons creators and SVG file references def add(): return from_theme('list-add', fallback='plus.svg') def alphabetical(): return icon('a-z-order.svg') def branch(): return icon('git-branch.svg') def check_name(): return name_from_basename('check.svg') def close(): return icon('x.svg') def cola(): return icon('git-cola.svg') def commit(): return icon('document-save-symbolic.svg') def compare(): return icon('git-compare.svg') def configure(): return icon('gear.svg') def copy(): return from_theme('edit-copy.svg') def default_app(): return icon('telescope.svg') def dot_name(): return name_from_basename('primitive-dot.svg') def download(): return icon('file-download.svg') def discard(): return icon('trashcan.svg') # folder vs directory: directory is opaque, folder is just an outline # directory is used for the File Browser, where more contrast with the file # icons are needed. def folder(): return icon('folder.svg') def directory(): return icon('file-directory.svg') def diff(): return icon('diff.svg') def edit(): return icon('pencil.svg') def ellipsis(): return icon('ellipsis.svg') def external(): return icon('link-external.svg') def file_code(): return icon('file-code.svg') def file_text(): return icon('file-text.svg') def file_zip(): return icon('file-zip.svg') def fold(): return icon('fold.svg') def merge(): return icon('git-merge.svg') def modified(): return icon('modified.svg') def modified_name(): return name_from_basename('modified.svg') def new(): return icon('folder-new.svg') def ok(): return icon('check.svg') def open_directory(): return icon('folder.svg') def partial_name(): return name_from_basename('partial.svg') def pull(): return icon('repo-pull.svg') def push(): return icon('repo-push.svg') def question(): return icon('question.svg') def remove(): return from_theme('list-remove', fallback='circle-slash.svg') def repo(): return icon('repo.svg') def reverse_chronological(): return icon('last-first-order.svg') def save(): return icon('desktop-download.svg') def search(): return icon('search.svg') def select_all(): return from_theme('edit-select-all.svg') def staged(): return icon('staged.svg') def staged_name(): return name_from_basename('staged.svg') def star(): return icon('star.svg') def sync(): return icon('sync.svg') def tag(): return icon('tag.svg') def undo(): return from_theme('edit-undo', fallback='edit-undo.svg') def unfold(): return icon('unfold.svg') def visualize(): return icon('eye.svg') def upstream_name(): return name_from_basename('upstream.svg') def zoom_fit_best(): return icon('zoom-fit-best.svg') def zoom_in(): return icon('zoom-in.svg') def zoom_out(): return icon('zoom-out.svg') git-cola-3.6/cola/inotify.py000066400000000000000000000043121356743264500160510ustar00rootroot00000000000000from __future__ import absolute_import, division, unicode_literals import ctypes import ctypes.util import errno import os # constant from Linux include/uapi/linux/limits.h NAME_MAX = 255 # constants from Linux include/uapi/linux/inotify.h IN_MODIFY = 0x00000002 IN_ATTRIB = 0x00000004 IN_CLOSE_WRITE = 0x00000008 IN_MOVED_FROM = 0x00000040 IN_MOVED_TO = 0x00000080 IN_CREATE = 0x00000100 IN_DELETE = 0x00000200 IN_Q_OVERFLOW = 0x00004000 IN_ONLYDIR = 0x01000000 IN_EXCL_UNLINK = 0x04000000 IN_ISDIR = 0x80000000 class inotify_event(ctypes.Structure): _fields_ = [ ('wd', ctypes.c_int), ('mask', ctypes.c_uint32), ('cookie', ctypes.c_uint32), ('len', ctypes.c_uint32), ] MAX_EVENT_SIZE = ctypes.sizeof(inotify_event) + NAME_MAX + 1 def _errcheck(result, func, arguments): if result >= 0: return result err = ctypes.get_errno() if err == errno.EINTR: return func(*arguments) raise OSError(err, os.strerror(err)) try: _libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True) _read = _libc.read init = _libc.inotify_init add_watch = _libc.inotify_add_watch rm_watch = _libc.inotify_rm_watch except AttributeError: raise ImportError('Could not load inotify functions from libc') _read.argtypes = [ctypes.c_int, ctypes.c_void_p, ctypes.c_size_t] _read.errcheck = _errcheck init.argtypes = [] init.errcheck = _errcheck add_watch.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_uint32] add_watch.errcheck = _errcheck rm_watch.argtypes = [ctypes.c_int, ctypes.c_int] rm_watch.errcheck = _errcheck def read_events(inotify_fd, count=64): buf = ctypes.create_string_buffer(MAX_EVENT_SIZE * count) n = _read(inotify_fd, buf, ctypes.sizeof(buf)) addr = ctypes.addressof(buf) while n: assert n >= ctypes.sizeof(inotify_event) event = inotify_event.from_address(addr) addr += ctypes.sizeof(inotify_event) n -= ctypes.sizeof(inotify_event) if event.len: assert n >= event.len name = ctypes.string_at(addr) addr += event.len n -= event.len else: name = None yield event.wd, event.mask, event.cookie, name git-cola-3.6/cola/interaction.py000066400000000000000000000106621356743264500167140ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals import os import sys from . import core from .i18n import N_ # The dependency injection calls to install() in ColaApplication's constructor # triggers method-already-defined pylint warnings. Silence that warning. # # pylint: disable=function-redefined class Interaction(object): """Prompts the user and answers questions""" VERBOSE = bool(os.getenv('GIT_COLA_VERBOSE')) @classmethod def command(cls, title, cmd, status, out, err): """Log a command and display error messages on failure""" cls.log_status(status, out, err) if status != 0: cls.command_error(title, cmd, status, out, err) @classmethod def command_error(cls, title, cmd, status, out, err): """Display an error message for a failed command""" core.print_stderr(title) core.print_stderr('-' * len(title)) core.print_stderr(cls.format_command_status(cmd, status)) core.print_stdout('') if out: core.print_stdout(out) if err: core.print_stderr(err) @staticmethod def format_command_status(cmd, status): return (N_('"%(command)s" returned exit status %(status)d') % dict(command=cmd, status=status)) @staticmethod def format_out_err(out, err): """Format stdout and stderr into a single string""" details = out or '' if err: if details and not details.endswith('\n'): details += '\n' details += err return details @staticmethod def information(title, message=None, details=None, informative_text=None): if message is None: message = title scope = {} scope['title'] = title scope['title_dashes'] = '-' * len(title) scope['message'] = message scope['details'] = ('\n' + details) if details else '' scope['informative_text'] = ( ('\n' + informative_text) if informative_text else '') sys.stdout.write(""" %(title)s %(title_dashes)s %(message)s%(informative_text)s%(details)s\n""" % scope) @classmethod def critical(cls, title, message=None, details=None): """Show a warning with the provided title and message.""" cls.information(title, message=message, details=details) @classmethod def confirm(cls, title, text, informative_text, ok_text, icon=None, default=True, cancel_text=None): cancel_text = cancel_text or 'Cancel' icon = icon or '?' cls.information(title, message=text, informative_text=informative_text) if default: prompt = '%s? [Y/n] ' % ok_text else: prompt = '%s? [y/N] ' % ok_text sys.stdout.write(prompt) answer = sys.stdin.readline().strip() if answer: result = answer.lower().startswith('y') else: result = default return result @classmethod def question(cls, title, message, default=True): return cls.confirm(title, message, '', ok_text=N_('Continue'), default=default) @classmethod def run_command(cls, title, cmd): cls.log('# ' + title) cls.log('$ ' + core.list2cmdline(cmd)) status, out, err = core.run_command(cmd) cls.log_status(status, out, err) return status, out, err @classmethod def confirm_config_action(cls, _context, name, _opts): return cls.confirm( N_('Run %s?') % name, N_('Run the "%s" command?') % name, '', ok_text=N_('Run')) @classmethod def log_status(cls, status, out, err=None): msg = (((out + '\n') if out else '') + ((err + '\n') if err else '')) cls.log(msg) cls.log('exit status %s' % status) @classmethod def log(cls, message): if cls.VERBOSE: core.print_stdout(message) @classmethod def save_as(cls, filename, title): if cls.confirm(title, 'Save as %s?' % filename, '', ok_text='Save'): return filename return None @staticmethod def async_command(title, command, runtask): pass @classmethod def choose_ref(cls, _context, title, button_text, default=None, icon=None): icon = icon or '?' cls.information(title, button_text) return sys.stdin.readline().strip() or default git-cola-3.6/cola/main.py000066400000000000000000000467721356743264500153340ustar00rootroot00000000000000"""Launcher and command line interface to git-cola""" from __future__ import absolute_import, division, unicode_literals import argparse import sys from . import app from . import cmds from . import core def main(argv=None): app.initialize() if argv is None: argv = sys.argv[1:] # we're using argparse with subparser, but argparse # does not allow us to assign a default subparser # when none has been specified. We fake it by injecting # 'cola' into the command-line so that parse_args() # routes them to the 'cola' parser by default. help_commands = core.encode('--help-commands') args = [core.encode(arg) for arg in argv] if (not argv or argv[0].startswith('-') and help_commands not in args): argv.insert(0, 'cola') elif help_commands in argv: argv.append('--help') args = parse_args(argv) return args.func(args) def winmain(): return app.winmain(main) def parse_args(argv): parser = argparse.ArgumentParser() subparser = parser.add_subparsers(title='valid commands') add_cola_command(subparser) add_about_command(subparser) add_am_command(subparser) add_archive_command(subparser) add_branch_command(subparser) add_browse_command(subparser) add_clone_command(subparser) add_config_command(subparser) add_dag_command(subparser) add_diff_command(subparser) add_fetch_command(subparser) add_find_command(subparser) add_grep_command(subparser) add_merge_command(subparser) add_pull_command(subparser) add_push_command(subparser) add_rebase_command(subparser) add_recent_command(subparser) add_remote_command(subparser) add_search_command(subparser) add_stash_command(subparser) add_tag_command(subparser) add_version_command(subparser) return parser.parse_args(argv) def add_command(parent, name, description, func): parser = parent.add_parser(str(name), help=description) parser.set_defaults(func=func) app.add_common_arguments(parser) return parser def add_cola_command(subparser): parser = add_command(subparser, 'cola', 'start git-cola', cmd_cola) parser.add_argument('--amend', default=False, action='store_true', help='start in amend mode') parser.add_argument('--help-commands', default=False, action='store_true', help='show available sub-commands') parser.add_argument('--status-filter', '-s', metavar='', default='', help='status path filter') def add_about_command(parent): add_command(parent, 'about', 'about git-cola', cmd_about) def add_am_command(parent): parser = add_command(parent, 'am', 'apply patches using "git am"', cmd_am) parser.add_argument('patches', metavar='', nargs='*', help='patches to apply') def add_archive_command(parent): parser = add_command(parent, 'archive', 'save an archive', cmd_archive) parser.add_argument('ref', metavar='', nargs='?', default=None, help='commit to archive') def add_branch_command(subparser): add_command(subparser, 'branch', 'create a branch', cmd_branch) def add_browse_command(subparser): add_command(subparser, 'browse', 'browse repository', cmd_browse) def add_clone_command(subparser): add_command(subparser, 'clone', 'clone repository', cmd_clone) def add_config_command(subparser): add_command(subparser, 'config', 'edit configuration', cmd_config) def add_dag_command(subparser): parser = add_command(subparser, 'dag', 'start git-dag', cmd_dag) parser.add_argument('-c', '--count', metavar='', type=int, default=1000, help='number of commits to display') parser.add_argument('--all', action='store_true', dest='show_all', help='visualize all branches', default=False) parser.add_argument('args', nargs='*', metavar='', help='git log arguments') def add_diff_command(subparser): parser = add_command(subparser, 'diff', 'view diffs', cmd_diff) parser.add_argument('args', nargs='*', metavar='', help='git diff arguments') def add_fetch_command(subparser): add_command(subparser, 'fetch', 'fetch remotes', cmd_fetch) def add_find_command(subparser): parser = add_command(subparser, 'find', 'find files', cmd_find) parser.add_argument('paths', nargs='*', metavar='', help='filter by path') def add_grep_command(subparser): parser = add_command(subparser, 'grep', 'grep source', cmd_grep) parser.add_argument('args', nargs='*', metavar='', help='git grep arguments') def add_merge_command(subparser): parser = add_command(subparser, 'merge', 'merge branches', cmd_merge) parser.add_argument('ref', nargs='?', metavar='', help='branch, tag, or commit to merge') def add_pull_command(subparser): parser = add_command(subparser, 'pull', 'pull remote branches', cmd_pull) parser.add_argument('--rebase', default=False, action='store_true', help='rebase local branch when pulling') def add_push_command(subparser): add_command(subparser, 'push', 'push remote branches', cmd_push) def add_rebase_command(subparser): parser = add_command(subparser, 'rebase', 'interactive rebase', cmd_rebase) parser.add_argument('-v', '--verbose', default=False, action='store_true', help='display a diffstat of what changed upstream') parser.add_argument('-q', '--quiet', default=False, action='store_true', help='be quiet. implies --no-stat') parser.add_argument('-i', '--interactive', default=True, action='store_true', help=argparse.SUPPRESS) parser.add_argument('--autostash', default=False, action='store_true', help='automatically stash/stash pop before and after') parser.add_argument('--fork-point', default=False, action='store_true', help="use 'merge-base --fork-point' to refine upstream") parser.add_argument('--onto', default=None, metavar='', help='rebase onto given branch instead of upstream') parser.add_argument('-p', '--preserve-merges', default=False, action='store_true', help='try to recreate merges instead of ignoring them') parser.add_argument('-s', '--strategy', default=None, metavar='', help='use the given merge strategy') parser.add_argument('--no-ff', default=False, action='store_true', help='cherry-pick all commits, even if unchanged') parser.add_argument('-m', '--merge', default=False, action='store_true', help='use merging strategies to rebase') parser.add_argument('-x', '--exec', default=None, help='add exec lines after each commit of ' 'the editable list') parser.add_argument('-k', '--keep-empty', default=False, action='store_true', help='preserve empty commits during rebase') parser.add_argument('-f', '--force-rebase', default=False, action='store_true', help='force rebase even if branch is up to date') parser.add_argument('-X', '--strategy-option', default=None, metavar='', help='pass the argument through to the merge strategy') parser.add_argument('--stat', default=False, action='store_true', help='display a diffstat of what changed upstream') parser.add_argument('-n', '--no-stat', default=False, action='store_true', help='do not show diffstat of what changed upstream') parser.add_argument('--verify', default=False, action='store_true', help='allow pre-rebase hook to run') parser.add_argument('--rerere-autoupdate', default=False, action='store_true', help='allow rerere to update index with ' 'resolved conflicts') parser.add_argument('--root', default=False, action='store_true', help='rebase all reachable commits up to the root(s)') parser.add_argument('--autosquash', default=True, action='store_true', help='move commits that begin with ' 'squash!/fixup! under -i') parser.add_argument('--no-autosquash', default=True, action='store_false', dest='autosquash', help='do not move commits that begin with ' 'squash!/fixup! under -i') parser.add_argument('--committer-date-is-author-date', default=False, action='store_true', help="passed to 'git am' by 'git rebase'") parser.add_argument('--ignore-date', default=False, action='store_true', help="passed to 'git am' by 'git rebase'") parser.add_argument('--whitespace', default=False, action='store_true', help="passed to 'git apply' by 'git rebase'") parser.add_argument('--ignore-whitespace', default=False, action='store_true', help="passed to 'git apply' by 'git rebase'") parser.add_argument('-C', dest='context_lines', default=None, metavar='', help="passed to 'git apply' by 'git rebase'") actions = parser.add_argument_group('actions') actions.add_argument('--continue', default=False, action='store_true', help='continue') actions.add_argument('--abort', default=False, action='store_true', help='abort and check out the original branch') actions.add_argument('--skip', default=False, action='store_true', help='skip current patch and continue') actions.add_argument('--edit-todo', default=False, action='store_true', help='edit the todo list during an interactive rebase') parser.add_argument('upstream', nargs='?', default=None, metavar='', help='the upstream configured in branch..remote ' 'and branch..merge options will be used ' 'when is omitted; see git-rebase(1) ' 'for details. If you are currently not on any ' 'branch or if the current branch does not have ' 'a configured upstream, the rebase will abort') parser.add_argument('branch', nargs='?', default=None, metavar='', help='git rebase will perform an automatic ' '"git checkout " before doing anything ' 'else when is specified') def add_recent_command(subparser): add_command(subparser, 'recent', 'edit recent files', cmd_recent) def add_remote_command(subparser): add_command(subparser, 'remote', 'edit remotes', cmd_remote) def add_search_command(subparser): add_command(subparser, 'search', 'search commits', cmd_search) def add_stash_command(subparser): add_command(subparser, 'stash', 'stash and unstash changes', cmd_stash) def add_tag_command(subparser): parser = add_command(subparser, 'tag', 'create tags', cmd_tag) parser.add_argument('name', metavar='', nargs='?', default=None, help='tag name') parser.add_argument('ref', metavar='', nargs='?', default=None, help='commit to tag') parser.add_argument('-s', '--sign', default=False, action='store_true', help='annotated and GPG-signed tag') def add_version_command(subparser): parser = add_command( subparser, 'version', 'print the version', cmd_version) parser.add_argument('--brief', action='store_true', default=False, help='print the version number only') parser.add_argument('--build', action='store_true', default=False, help='print the build version') # entry points def cmd_cola(args): from .widgets.main import MainView status_filter = args.status_filter if status_filter: status_filter = core.abspath(status_filter) context = app.application_init(args) context.timer.start('view') view = MainView(context, settings=args.settings) if args.amend: cmds.do(cmds.AmendMode, context, amend=True) if status_filter: view.set_filter(core.relpath(status_filter)) context.timer.stop('view') if args.perf: context.timer.display('view') return app.application_run( context, view, start=start_cola, stop=app.default_stop) def start_cola(context, view): app.default_start(context, view) view.start(context) def cmd_about(args): from .widgets import about context = app.application_init(args) view = about.about_dialog(context) return app.application_start(context, view) def cmd_am(args): from .widgets.patch import new_apply_patches context = app.application_init(args) view = new_apply_patches(context, patches=args.patches) return app.application_start(context, view) def cmd_archive(args): from .widgets import archive context = app.application_init(args, update=True) if args.ref is None: args.ref = context.model.currentbranch view = archive.Archive(context, args.ref) return app.application_start(context, view) def cmd_branch(args): from .widgets.createbranch import create_new_branch context = app.application_init(args, update=True) view = create_new_branch(context, settings=args.settings) return app.application_start(context, view) def cmd_browse(args): from .widgets.browse import worktree_browser context = app.application_init(args) view = worktree_browser( context, show=False, update=False, settings=args.settings) return app.application_start(context, view) def cmd_clone(args): from .widgets import clone context = app.application_init(args) view = clone.clone(context, settings=args.settings) context.set_view(view) result = 0 if view.exec_() == view.Accepted else 1 app.default_stop(context, view) return result def cmd_config(args): from .widgets.prefs import preferences context = app.application_init(args) view = preferences(context) return app.application_start(context, view) def cmd_dag(args): from .widgets import dag context = app.application_init(args) # cola.main() uses parse_args(), unlike dag.main() which uses # parse_known_args(), thus we aren't able to automatically forward # all unknown arguments. Special-case support for "--all" since it's # used by the history viewer command on Windows. if args.show_all: args.args.insert(0, '--all') view = dag.git_dag(context, args=args, settings=args.settings, show=False) return app.application_start(context, view) def cmd_diff(args): from .difftool import diff_expression context = app.application_init(args) expr = core.list2cmdline(args.args) view = diff_expression(context, None, expr, create_widget=True) return app.application_start(context, view) def cmd_fetch(args): # TODO: the calls to update_status() can be done asynchronously # by hooking into the message_updated notification. from .widgets import remote context = app.application_init(args) context.model.update_status() view = remote.fetch(context) return app.application_start(context, view) def cmd_find(args): from .widgets import finder context = app.application_init(args) paths = core.list2cmdline(args.paths) view = finder.finder(context, paths=paths) return app.application_start(context, view) def cmd_grep(args): from .widgets import grep context = app.application_init(args) text = core.list2cmdline(args.args) view = grep.new_grep(context, text=text, parent=None) return app.application_start(context, view) def cmd_merge(args): from .widgets.merge import Merge context = app.application_init(args, update=True) view = Merge(context, parent=None, ref=args.ref) return app.application_start(context, view) def cmd_version(args): from . import version version.print_version(brief=args.brief, build=args.build) return 0 def cmd_pull(args): from .widgets import remote context = app.application_init(args, update=True) view = remote.pull(context) if args.rebase: view.set_rebase(True) return app.application_start(context, view) def cmd_push(args): from .widgets import remote context = app.application_init(args, update=True) view = remote.push(context) return app.application_start(context, view) def cmd_rebase(args): kwargs = { 'verbose': args.verbose, 'quiet': args.quiet, 'autostash': args.autostash, 'fork_point': args.fork_point, 'onto': args.onto, 'preserve_merges': args.preserve_merges, 'strategy': args.strategy, 'no_ff': args.no_ff, 'merge': args.merge, 'exec': getattr(args, 'exec', None), # python keyword 'keep_empty': args.keep_empty, 'force_rebase': args.force_rebase, 'strategy_option': args.strategy_option, 'stat': args.stat, 'no_stat': args.no_stat, 'verify': args.verify, 'rerere_autoupdate': args.rerere_autoupdate, 'root': args.root, 'autosquash': args.autosquash, 'committer_date_is_author_date': args.committer_date_is_author_date, 'ignore_date': args.ignore_date, 'whitespace': args.whitespace, 'ignore_whitespace': args.ignore_whitespace, 'C': args.context_lines, 'continue': getattr(args, 'continue', False), # python keyword 'abort': args.abort, 'skip': args.skip, 'edit_todo': args.edit_todo, 'upstream': args.upstream, 'branch': args.branch, } context = app.application_init(args) status, _, _ = cmds.do(cmds.Rebase, context, **kwargs) return status def cmd_recent(args): from .widgets import recent context = app.application_init(args) view = recent.browse_recent_files(context) return app.application_start(context, view) def cmd_remote(args): from .widgets import editremotes context = app.application_init(args) view = editremotes.editor(context, run=False) return app.application_start(context, view) def cmd_search(args): from .widgets.search import search context = app.application_init(args) view = search(context) return app.application_start(context, view) def cmd_stash(args): from .widgets import stash context = app.application_init(args) view = stash.view(context, show=False) return app.application_start(context, view) def cmd_tag(args): from .widgets.createtag import new_create_tag context = app.application_init(args) view = new_create_tag( context, name=args.name, ref=args.ref, sign=args.sign, settings=args.settings) return app.application_start(context, view) # Windows shortcut launch features: def shortcut_launch(): """Launch from a shortcut Prompt for the repository by default. """ argv = sys.argv[1:] if not argv: argv = ['cola', '--prompt'] return app.winmain(main, argv) git-cola-3.6/cola/models/000077500000000000000000000000001356743264500153015ustar00rootroot00000000000000git-cola-3.6/cola/models/__init__.py000066400000000000000000000000001356743264500174000ustar00rootroot00000000000000git-cola-3.6/cola/models/browse.py000066400000000000000000000310651356743264500171610ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals import time from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from qtpy.QtCore import Qt from qtpy.QtCore import Signal from .. import gitcmds from .. import core from .. import icons from .. import utils from .. import qtutils from ..git import STDOUT from ..i18n import N_ class Columns(object): """Defines columns in the worktree browser""" NAME = 0 STATUS = 1 MESSAGE = 2 AUTHOR = 3 AGE = 4 ALL = (NAME, STATUS, MESSAGE, AUTHOR, AGE) ATTRS = ('name', 'status', 'message', 'author', 'age') TEXT = [] @classmethod def init(cls): cls.TEXT.extend([ N_('Name'), N_('Status'), N_('Message'), N_('Author'), N_('Age'), ]) @classmethod def text_values(cls): if not cls.TEXT: cls.init() return cls.TEXT @classmethod def text(cls, column): try: value = cls.TEXT[column] except IndexError: # Defer translation until runtime cls.init() value = cls.TEXT[column] return value @classmethod def attr(cls, column): """Return the attribute for the column""" return cls.ATTRS[column] class GitRepoModel(QtGui.QStandardItemModel): """Provides an interface into a git repository for browsing purposes.""" model_updated = Signal() restore = Signal() def __init__(self, context, parent): QtGui.QStandardItemModel.__init__(self, parent) self.setColumnCount(len(Columns.ALL)) self.context = context self.model = model = context.model self.entries = {} cfg = context.cfg self.turbo = cfg.get('cola.turbo', False) self.default_author = cfg.get('user.name', N_('Author')) self._parent = parent self._interesting_paths = set() self._interesting_files = set() self._runtask = qtutils.RunTask(parent=parent) self.model_updated.connect(self.refresh, type=Qt.QueuedConnection) model = context.model model.add_observer(model.message_updated, self._model_updated) self.file_icon = icons.file_text() self.dir_icon = icons.directory() def mimeData(self, indexes): context = self.context paths = qtutils.paths_from_indexes(self, indexes, item_type=GitRepoNameItem.TYPE) return qtutils.mimedata_from_paths(context, paths) # pylint: disable=no-self-use def mimeTypes(self): return qtutils.path_mimetypes() def clear(self): self.entries.clear() super(GitRepoModel, self).clear() def hasChildren(self, index): if index.isValid(): item = self.itemFromIndex(index) result = item.hasChildren() else: result = True return result def get(self, path, default=None): if not path: item = self.invisibleRootItem() else: item = self.entries.get(path, default) return item def create_row(self, path, create=True, is_dir=False): try: row = self.entries[path] except KeyError: if create: column = create_column row = self.entries[path] = [ column(c, path, is_dir) for c in Columns.ALL] else: row = None return row def populate(self, item): self.populate_dir(item, item.path + '/') def add_directory(self, parent, path): """Add a directory entry to the model.""" # First, try returning an existing item current_item = self.get(path) if current_item is not None: return current_item[0] # Create model items row_items = self.create_row(path, is_dir=True) # Use a standard directory icon name_item = row_items[0] name_item.setIcon(self.dir_icon) parent.appendRow(row_items) return name_item def add_file(self, parent, path): """Add a file entry to the model.""" file_entry = self.get(path) if file_entry is not None: return file_entry # Create model items row_items = self.create_row(path) name_item = row_items[0] # Use a standard file icon for the name field name_item.setIcon(self.file_icon) # Add file paths at the end of the list parent.appendRow(row_items) return name_item def populate_dir(self, parent, path): """Populate a subtree""" context = self.context dirs, paths = gitcmds.listdir(context, path) # Insert directories before file paths for dirname in dirs: dir_parent = parent if '/' in dirname: dir_parent = self.add_parent_directories(parent, dirname) self.add_directory(dir_parent, dirname) self.update_entry(dirname) for filename in paths: file_parent = parent if '/' in filename: file_parent = self.add_parent_directories(parent, filename) self.add_file(file_parent, filename) self.update_entry(filename) def add_parent_directories(self, parent, dirname): """Ensure that all parent directory entries exist""" sub_parent = parent parent_dir = utils.dirname(dirname) for path in utils.pathset(parent_dir): sub_parent = self.add_directory(sub_parent, path) return sub_parent def path_is_interesting(self, path): """Return True if path has a status.""" return path in self._interesting_paths def get_paths(self, files=None): """Return paths of interest; e.g. paths with a status.""" if files is None: files = self.get_files() return utils.add_parents(files) def get_files(self): model = self.model return set(model.staged + model.unstaged) def _model_updated(self): """Observes model changes and updates paths accordingly.""" self.model_updated.emit() def refresh(self): old_files = self._interesting_files old_paths = self._interesting_paths new_files = self.get_files() new_paths = self.get_paths(files=new_files) if new_files != old_files or not old_paths: self.clear() self._initialize() self.restore.emit() # Existing items for path in sorted(new_paths.union(old_paths)): self.update_entry(path) self._interesting_files = new_files self._interesting_paths = new_paths def _initialize(self): self.setHorizontalHeaderLabels(Columns.text_values()) self.entries = {} self._interesting_files = files = self.get_files() self._interesting_paths = self.get_paths(files=files) root = self.invisibleRootItem() self.populate_dir(root, './') def update_entry(self, path): if self.turbo or path not in self.entries: return # entry doesn't currently exist context = self.context task = GitRepoInfoTask( context, self._parent, path, self.default_author) self._runtask.start(task) def create_column(col, path, is_dir): """Creates a StandardItem for use in a treeview cell.""" # GitRepoNameItem is the only one that returns a custom type() # and is used to infer selections. if col == Columns.NAME: item = GitRepoNameItem(path, is_dir) else: item = GitRepoItem(path) return item class GitRepoInfoTask(qtutils.Task): """Handles expensive git lookups for a path.""" def __init__(self, context, parent, path, default_author): qtutils.Task.__init__(self, parent) self.context = context self.path = path self._parent = parent self._default_author = default_author self._data = {} def data(self, key): """Return git data for a path Supported keys are 'date', 'message', and 'author' """ git = self.context.git if not self._data: log_line = git.log( '-1', '--', self.path, no_color=True, pretty=r'format:%ar%x01%s%x01%an', _readonly=True)[STDOUT] if log_line: log_line = log_line date, message, author = log_line.split(chr(0x01), 2) self._data['date'] = date self._data['message'] = message self._data['author'] = author else: self._data['date'] = self.date() self._data['message'] = '-' self._data['author'] = self._default_author return self._data[key] def date(self): """Returns a relative date for a file path This is typically used for new entries that do not have 'git log' information. """ try: st = core.stat(self.path) except OSError: return N_('%d minutes ago') % 0 elapsed = time.time() - st.st_mtime minutes = int(elapsed / 60) if minutes < 60: return N_('%d minutes ago') % minutes hours = int(elapsed / 60 / 60) if hours < 24: return N_('%d hours ago') % hours return N_('%d days ago') % int(elapsed / 60 / 60 / 24) def status(self): """Return the status for the entry's path.""" model = self.context.model unmerged = utils.add_parents(model.unmerged) modified = utils.add_parents(model.modified) staged = utils.add_parents(model.staged) untracked = utils.add_parents(model.untracked) upstream_changed = utils.add_parents(model.upstream_changed) path = self.path if path in unmerged: status = (icons.modified_name(), N_('Unmerged')) elif path in modified and self.path in staged: status = (icons.partial_name(), N_('Partially Staged')) elif path in modified: status = (icons.modified_name(), N_('Modified')) elif path in staged: status = (icons.staged_name(), N_('Staged')) elif path in upstream_changed: status = (icons.upstream_name(), N_('Changed Upstream')) elif path in untracked: status = (None, '?') else: status = (None, '') return status def task(self): """Perform expensive lookups and post corresponding events.""" data = ( self.path, self.status(), self.data('message'), self.data('author'), self.data('date'), ) app = QtWidgets.QApplication.instance() try: app.postEvent(self._parent, GitRepoInfoEvent(data)) except RuntimeError: pass # The app exited before this task finished class GitRepoInfoEvent(QtCore.QEvent): """Transport mechanism for communicating from a GitRepoInfoTask.""" # Custom event type TYPE = QtCore.QEvent.Type(QtCore.QEvent.registerEventType()) def __init__(self, data): QtCore.QEvent.__init__(self, self.TYPE) self.data = data def type(self): return self.TYPE class GitRepoItem(QtGui.QStandardItem): """Represents a cell in a treeview. Many GitRepoItems map to a single repository path. Each GitRepoItem manages a different cell in the tree view. One is created for each column -- Name, Status, Age, etc. """ def __init__(self, path): QtGui.QStandardItem.__init__(self) self.path = path self.cached = False self.setDragEnabled(False) self.setEditable(False) def set_status(self, data): icon, txt = data if icon: self.setIcon(QtGui.QIcon(icon)) else: self.setIcon(QtGui.QIcon()) self.setText(txt) class GitRepoNameItem(GitRepoItem): """Subclass GitRepoItem to provide a custom type().""" TYPE = QtGui.QStandardItem.ItemType(QtGui.QStandardItem.UserType + 1) def __init__(self, path, is_dir): GitRepoItem.__init__(self, path) self.is_dir = is_dir self.setDragEnabled(True) self.setText(utils.basename(path)) def type(self): """ Indicate that this item is of a special user-defined type. 'name' is the only column that registers a user-defined type. This is done to allow filtering out other columns when determining which paths are selected. """ return self.TYPE def hasChildren(self): return self.is_dir git-cola-3.6/cola/models/dag.py000066400000000000000000000220221356743264500164040ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals import json from .. import core from .. import utils from ..observable import Observable # put summary at the end b/c it can contain # any number of funky characters, including the separator logfmt = r'format:%H%x01%P%x01%d%x01%an%x01%ad%x01%ae%x01%s' logsep = chr(0x01) class CommitFactory(object): root_generation = 0 commits = {} @classmethod def reset(cls): cls.commits.clear() cls.root_generation = 0 @classmethod def new(cls, oid=None, log_entry=None): if not oid and log_entry: oid = log_entry[:40] try: commit = cls.commits[oid] if log_entry and not commit.parsed: commit.parse(log_entry) cls.root_generation = max(commit.generation, cls.root_generation) except KeyError: commit = Commit(oid=oid, log_entry=log_entry) if not log_entry: cls.root_generation += 1 commit.generation = max(commit.generation, cls.root_generation) cls.commits[oid] = commit return commit class DAG(Observable): ref_updated = 'ref_updated' count_updated = 'count_updated' def __init__(self, ref, count): Observable.__init__(self) self.ref = ref self.count = count self.overrides = {} def set_ref(self, ref): changed = ref != self.ref if changed: self.ref = ref self.notify_observers(self.ref_updated) return changed def set_count(self, count): changed = count != self.count if changed: self.count = count self.notify_observers(self.count_updated) return changed def set_arguments(self, args): if args is None: return if self.set_count(args.count): self.overrides['count'] = args.count if hasattr(args, 'args') and args.args: ref = core.list2cmdline(args.args) if self.set_ref(ref): self.overrides['ref'] = ref def overridden(self, opt): return opt in self.overrides def paths(self): all_refs = utils.shell_split(self.ref) if '--' in all_refs: all_refs = all_refs[all_refs.index('--'):] return [p for p in all_refs if p and core.exists(p)] class Commit(object): root_generation = 0 __slots__ = ('oid', 'summary', 'parents', 'children', 'tags', 'author', 'authdate', 'email', 'generation', 'column', 'row', 'parsed') def __init__(self, oid=None, log_entry=None): self.oid = oid self.summary = None self.parents = [] self.children = [] self.tags = set() self.email = None self.author = None self.authdate = None self.parsed = False self.generation = CommitFactory.root_generation self.column = None self.row = None if log_entry: self.parse(log_entry) def parse(self, log_entry, sep=logsep): self.oid = log_entry[:40] after_oid = log_entry[41:] details = after_oid.split(sep, 5) (parents, tags, author, authdate, email, summary) = details self.summary = summary if summary else '' self.author = author if author else '' self.authdate = authdate if authdate else '' self.email = email if email else '' if parents: generation = None for parent_oid in parents.split(' '): parent = CommitFactory.new(oid=parent_oid) parent.children.append(self) if generation is None: generation = parent.generation+1 self.parents.append(parent) generation = max(parent.generation+1, generation) self.generation = generation if tags: for tag in tags[2:-1].split(', '): self.add_label(tag) self.parsed = True return self def add_label(self, tag): """Add tag/branch labels from `git log --decorate ....`""" if tag.startswith('tag: '): tag = tag[5:] # strip off "tag: " leaving refs/tags/ if tag.startswith('refs/'): # strip off refs/ leaving just tags/XXX remotes/XXX heads/XXX tag = tag[5:] if tag.endswith('/HEAD'): return # Git 2.4 Release Notes (draft) # ============================= # # Backward compatibility warning(s) # --------------------------------- # # This release has a few changes in the user-visible output from # Porcelain commands. These are not meant to be parsed by scripts, but # the users still may want to be aware of the changes: # # * Output from "git log --decorate" (and "%d" format specifier used in # the userformat "--format=" parameter "git log" family of # command takes) used to list "HEAD" just like other tips of branch # names, separated with a comma in between. E.g. # # $ git log --decorate -1 master # commit bdb0f6788fa5e3cacc4315e9ff318a27b2676ff4 (HEAD, master) # ... # # This release updates the output slightly when HEAD refers to the tip # of a branch whose name is also shown in the output. The above is # shown as: # # $ git log --decorate -1 master # commit bdb0f6788fa5e3cacc4315e9ff318a27b2676ff4 (HEAD -> master) # ... # # C.f. http://thread.gmane.org/gmane.linux.kernel/1931234 head_arrow = 'HEAD -> ' if tag.startswith(head_arrow): self.tags.add('HEAD') self.add_label(tag[len(head_arrow):]) else: self.tags.add(tag) def __str__(self): return self.oid def data(self): return { 'oid': self.oid, 'summary': self.summary, 'author': self.author, 'authdate': self.authdate, 'parents': [p.oid for p in self.parents], 'tags': self.tags, } def __repr__(self): return json.dumps(self.data(), sort_keys=True, indent=4, default=list) def is_fork(self): ''' Returns True if the node is a fork''' return len(self.children) > 1 def is_merge(self): ''' Returns True if the node is a fork''' return len(self.parents) > 1 class RepoReader(object): def __init__(self, context, params): self.context = context self.params = params self.git = context.git self.returncode = 0 self._proc = None self._objects = {} self._cmd = ['git', '-c', 'log.abbrevCommit=false', '-c', 'log.showSignature=false', 'log', '--topo-order', '--reverse', '--decorate=full', '--pretty='+logfmt] self._cached = False """Indicates that all data has been read""" self._topo_list = [] """List of commits objects in topological order""" cached = property(lambda self: self._cached) """Return True when no commits remain to be read""" def __len__(self): return len(self._topo_list) def reset(self): CommitFactory.reset() if self._proc: self._proc.kill() self._proc = None self._cached = False self._topo_list = [] def get(self): """Generator function returns Commit objects found by the params""" if self._cached: idx = 0 while True: try: yield self._topo_list[idx] except IndexError: break idx += 1 return self.reset() ref_args = utils.shell_split(self.params.ref) cmd = self._cmd + ['-%d' % self.params.count] + ref_args self._proc = core.start_command(cmd) while True: log_entry = core.readline(self._proc.stdout).rstrip() if not log_entry: self._cached = True self._proc.wait() self.returncode = self._proc.returncode self._proc = None break oid = log_entry[:40] try: yield self._objects[oid] except KeyError: commit = CommitFactory.new(log_entry=log_entry) self._objects[commit.oid] = commit self._topo_list.append(commit) yield commit return def __getitem__(self, oid): return self._objects[oid] def items(self): return list(self._objects.items()) git-cola-3.6/cola/models/main.py000066400000000000000000000410601356743264500166000ustar00rootroot00000000000000# Copyright (C) 2007-2018 David Aguilar """This module provides the central cola model. """ from __future__ import division, absolute_import, unicode_literals import os from .. import core from .. import gitcmds from .. import version from ..git import STDOUT from ..observable import Observable from . import prefs def create(context): """Create the repository status model""" return MainModel(context) class MainModel(Observable): """Repository status model""" # TODO this class can probably be split apart into a DiffModel, # CommitMessageModel, StatusModel, and an AppStatusStateMachine. # Observable messages message_about_to_update = 'about_to_update' message_commit_message_changed = 'commit_message_changed' message_diff_text_changed = 'diff_text_changed' message_diff_text_updated = 'diff_text_updated' message_diff_type_changed = 'diff_type_changed' message_filename_changed = 'filename_changed' message_images_changed = 'images_changed' message_mode_about_to_change = 'mode_about_to_change' message_mode_changed = 'mode_changed' message_submodules_changed = 'message_submodules_changed' message_refs_updated = 'message_refs_updated' message_updated = 'updated' message_worktree_changed = 'message_worktree_changed' # States mode_none = 'none' # Default: nothing's happened, do nothing mode_worktree = 'worktree' # Comparing index to worktree mode_diffstat = 'diffstat' # Showing a diffstat mode_untracked = 'untracked' # Dealing with an untracked file mode_index = 'index' # Comparing index to last commit mode_amend = 'amend' # Amending a commit # Modes where we can checkout files from the $head modes_undoable = set((mode_amend, mode_index, mode_worktree)) # Modes where we can partially stage files modes_stageable = set((mode_amend, mode_worktree, mode_untracked)) # Modes where we can partially unstage files modes_unstageable = set((mode_amend, mode_index)) unstaged = property( lambda self: self.modified + self.unmerged + self.untracked) """An aggregate of the modified, unmerged, and untracked file lists.""" def __init__(self, context, cwd=None): """Interface to the main repository status""" Observable.__init__(self) self.context = context self.git = context.git self.cfg = context.cfg self.selection = context.selection self.initialized = False self.annex = False self.lfs = False self.head = 'HEAD' self.diff_text = '' self.diff_type = 'text' # text, image self.mode = self.mode_none self.filename = None self.is_merging = False self.is_rebasing = False self.currentbranch = '' self.directory = '' self.project = '' self.remotes = [] self.filter_paths = None self.images = [] self.commitmsg = '' # current commit message self._auto_commitmsg = '' # e.g. .git/MERGE_MSG self._prev_commitmsg = '' # saved here when clobbered by .git/MERGE_MSG self.modified = [] # modified, staged, untracked, unmerged paths self.staged = [] self.untracked = [] self.unmerged = [] self.upstream_changed = [] # paths that've changed upstream self.staged_deleted = set() self.unstaged_deleted = set() self.submodules = set() self.submodules_list = [] self.ref_sort = 0 # (0: version, 1:reverse-chrono) self.local_branches = [] self.remote_branches = [] self.tags = [] if cwd: self.set_worktree(cwd) def unstageable(self): return self.mode in self.modes_unstageable def amending(self): return self.mode == self.mode_amend def undoable(self): """Whether we can checkout files from the $head.""" return self.mode in self.modes_undoable def stageable(self): """Whether staging should be allowed.""" return self.mode in self.modes_stageable def all_branches(self): return self.local_branches + self.remote_branches def set_worktree(self, worktree): self.git.set_worktree(worktree) is_valid = self.git.is_valid() if is_valid: cwd = self.git.getcwd() self.project = os.path.basename(cwd) self.set_directory(cwd) core.chdir(cwd) self.update_config(reset=True) self.notify_observers(self.message_worktree_changed) return is_valid def is_git_lfs_enabled(self): """Return True if `git lfs install` has been run We check for the existence of the "lfs" object-storea, and one of the "git lfs install"-provided hooks. This allows us to detect when "git lfs uninstall" has been run. """ lfs_filter = self.cfg.get('filter.lfs.clean', default=False) lfs_dir = lfs_filter and self.git.git_path('lfs') lfs_hook = lfs_filter and self.git.git_path('hooks', 'post-merge') return (lfs_filter and lfs_dir and core.exists(lfs_dir) and lfs_hook and core.exists(lfs_hook)) def set_commitmsg(self, msg, notify=True): self.commitmsg = msg if notify: self.notify_observers(self.message_commit_message_changed, msg) def save_commitmsg(self, msg=None): if msg is None: msg = self.commitmsg path = self.git.git_path('GIT_COLA_MSG') try: if not msg.endswith('\n'): msg += '\n' core.write(path, msg) except (OSError, IOError): pass return path def set_diff_text(self, txt): """Update the text displayed in the diff editor""" changed = txt != self.diff_text self.diff_text = txt self.notify_observers(self.message_diff_text_updated, txt) if changed: self.notify_observers(self.message_diff_text_changed) def set_diff_type(self, diff_type): # text, image """Set the diff type to either text or image""" self.diff_type = diff_type self.notify_observers(self.message_diff_type_changed, diff_type) def set_images(self, images): """Update the images shown in the preview pane""" self.images = images self.notify_observers(self.message_images_changed, images) def set_directory(self, path): self.directory = path def set_filename(self, filename): self.filename = filename self.notify_observers(self.message_filename_changed, filename) def set_mode(self, mode): if self.amending(): if mode != self.mode_none: return if self.is_merging and mode == self.mode_amend: mode = self.mode if mode == self.mode_amend: head = 'HEAD^' else: head = 'HEAD' self.notify_observers(self.message_mode_about_to_change, mode) self.head = head self.mode = mode self.notify_observers(self.message_mode_changed, mode) def update_path_filter(self, filter_paths): self.filter_paths = filter_paths self.update_file_status() def emit_about_to_update(self): self.notify_observers(self.message_about_to_update) def emit_updated(self): self.notify_observers(self.message_updated) def update_file_status(self, update_index=False): self.emit_about_to_update() self.update_files(update_index=update_index, emit=True) def update_status(self, update_index=False): # Give observers a chance to respond self.emit_about_to_update() self.initialized = True self._update_merge_rebase_status() self._update_files(update_index=update_index) self._update_remotes() self._update_branches_and_tags() self._update_commitmsg() self.update_config() self.update_submodules_list() self.emit_updated() def update_config(self, emit=False, reset=False): if reset: self.cfg.reset() self.annex = self.cfg.is_annex() self.lfs = self.is_git_lfs_enabled() if emit: self.emit_updated() def update_files(self, update_index=False, emit=False): self._update_files(update_index=update_index) if emit: self.emit_updated() def _update_files(self, update_index=False): context = self.context display_untracked = prefs.display_untracked(context) state = gitcmds.worktree_state( context, head=self.head, update_index=update_index, display_untracked=display_untracked, paths=self.filter_paths) self.staged = state.get('staged', []) self.modified = state.get('modified', []) self.unmerged = state.get('unmerged', []) self.untracked = state.get('untracked', []) self.upstream_changed = state.get('upstream_changed', []) self.staged_deleted = state.get('staged_deleted', set()) self.unstaged_deleted = state.get('unstaged_deleted', set()) self.submodules = state.get('submodules', set()) selection = self.selection if self.is_empty(): selection.reset() else: selection.update(self) if selection.is_empty(): self.set_diff_text('') def is_empty(self): return not(bool(self.staged or self.modified or self.unmerged or self.untracked)) def is_empty_repository(self): return not self.local_branches def _update_remotes(self): self.remotes = self.git.remote()[STDOUT].splitlines() def _update_branches_and_tags(self): context = self.context sort_types = ( 'version:refname', '-committerdate', ) sort_key = sort_types[self.ref_sort] local_branches, remote_branches, tags = gitcmds.all_refs( context, split=True, sort_key=sort_key) self.local_branches = local_branches self.remote_branches = remote_branches self.tags = tags # Set these early since they are used to calculate 'upstream_changed'. self.currentbranch = gitcmds.current_branch(self.context) self.notify_observers(self.message_refs_updated) def _update_merge_rebase_status(self): merge_head = self.git.git_path('MERGE_HEAD') rebase_merge = self.git.git_path('rebase-merge') self.is_merging = merge_head and core.exists(merge_head) self.is_rebasing = rebase_merge and core.exists(rebase_merge) if self.is_merging and self.mode == self.mode_amend: self.set_mode(self.mode_none) def _update_commitmsg(self): """Check for merge message files and update the commit message The message is cleared when the merge completes """ if self.amending(): return # Check if there's a message file in .git/ context = self.context merge_msg_path = gitcmds.merge_message_path(context) if merge_msg_path: msg = core.read(merge_msg_path) if msg != self._auto_commitmsg: self._auto_commitmsg = msg self._prev_commitmsg = self.commitmsg self.set_commitmsg(msg) elif self._auto_commitmsg and self._auto_commitmsg == self.commitmsg: self._auto_commitmsg = '' self.set_commitmsg(self._prev_commitmsg) def update_submodules_list(self): self.submodules_list = gitcmds.list_submodule(self.context) self.notify_observers(self.message_submodules_changed) def update_remotes(self): self._update_remotes() self.update_refs() def update_refs(self): """Update tag and branch names""" self.emit_about_to_update() self._update_branches_and_tags() self.emit_updated() def delete_branch(self, branch): status, out, err = self.git.branch(branch, D=True) self.update_refs() return status, out, err def rename_branch(self, branch, new_branch): status, out, err = self.git.branch(branch, new_branch, M=True) self.update_refs() return status, out, err def remote_url(self, name, action): push = action == 'PUSH' return gitcmds.remote_url(self.context, name, push=push) def fetch(self, remote, **opts): result = run_remote_action(self.context, self.git.fetch, remote, **opts) self.update_refs() return result def push(self, remote, remote_branch='', local_branch='', **opts): # Swap the branches in push mode (reverse of fetch) opts.update(dict(local_branch=remote_branch, remote_branch=local_branch)) result = run_remote_action( self.context, self.git.push, remote, push=True, **opts) self.update_refs() return result def pull(self, remote, **opts): result = run_remote_action( self.context, self.git.pull, remote, pull=True, **opts) # Pull can result in merge conflicts self.update_refs() self.update_files(update_index=False, emit=True) return result def create_branch(self, name, base, track=False, force=False): """Create a branch named 'name' from revision 'base' Pass track=True to create a local tracking branch. """ return self.git.branch(name, base, track=track, force=force) def cherry_pick_list(self, revs): """Cherry-picks each revision into the current branch. Returns a list of command output strings (1 per cherry pick)""" if not revs: return [] outs = [] errs = [] status = 0 for rev in revs: stat, out, err = self.git.cherry_pick(rev) status = max(stat, status) outs.append(out) errs.append(err) return (status, '\n'.join(outs), '\n'.join(errs)) def is_commit_published(self): """Return True if the latest commit exists in any remote branch""" return bool(self.git.branch(r=True, contains='HEAD')[STDOUT]) def untrack_paths(self, paths): context = self.context status, out, err = gitcmds.untrack_paths(context, paths) self.update_file_status() return status, out, err def getcwd(self): """If we've chosen a directory then use it, otherwise use current""" if self.directory: return self.directory return core.getcwd() def cycle_ref_sort(self): """Choose the next ref sort type (version, reverse-chronological)""" self.set_ref_sort(self.ref_sort + 1) def set_ref_sort(self, raw_value): value = raw_value % 2 # Currently two sort types if value == self.ref_sort: return self.ref_sort = value self.update_refs() # Helpers # pylint: disable=too-many-arguments def remote_args(context, remote, local_branch='', remote_branch='', ff_only=False, force=False, no_ff=False, tags=False, rebase=False, pull=False, push=False, set_upstream=False, prune=False): """Return arguments for git fetch/push/pull""" args = [remote] what = refspec_arg(local_branch, remote_branch, pull, push) if what: args.append(what) kwargs = { 'verbose': True, } if pull: if rebase: kwargs['rebase'] = True elif ff_only: kwargs['ff_only'] = True elif no_ff: kwargs['no_ff'] = True elif force: # pylint: disable=simplifiable-if-statement if push and version.check_git(context, 'force-with-lease'): kwargs['force_with_lease'] = True else: kwargs['force'] = True if push and set_upstream: kwargs['set_upstream'] = True if tags: kwargs['tags'] = True if prune: kwargs['prune'] = True return (args, kwargs) def refspec(src, dst, push=False): if push and src == dst: spec = src else: spec = '%s:%s' % (src, dst) return spec def refspec_arg(local_branch, remote_branch, pull, push): """Return the refspec for a fetch or pull command""" if not pull and local_branch and remote_branch: what = refspec(remote_branch, local_branch, push=push) else: what = local_branch or remote_branch or None return what def run_remote_action(context, action, remote, **kwargs): args, kwargs = remote_args(context, remote, **kwargs) return action(*args, **kwargs) git-cola-3.6/cola/models/prefs.py000066400000000000000000000141461356743264500170000ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals import sys from .. import core from .. import hidpi from .. import observable from .. import utils from ..cmd import Command AUTOTEMPLATE = 'cola.autoloadcommittemplate' BACKGROUND_EDITOR = 'cola.backgroundeditor' BLAME_VIEWER = 'cola.blameviewer' BOLD_HEADERS = 'cola.boldheaders' CHECKCONFLICTS = 'cola.checkconflicts' COMMENT_CHAR = 'core.commentchar' DIFFCONTEXT = 'gui.diffcontext' DIFFTOOL = 'diff.tool' DISPLAY_UNTRACKED = 'gui.displayuntracked' EDITOR = 'gui.editor' FONTDIFF = 'cola.fontdiff' HISTORY_BROWSER = 'gui.historybrowser' ICON_THEME = 'cola.icontheme' LINEBREAK = 'cola.linebreak' MAXRECENT = 'cola.maxrecent' MERGE_DIFFSTAT = 'merge.diffstat' MERGE_KEEPBACKUP = 'merge.keepbackup' MERGE_SUMMARY = 'merge.summary' MERGE_VERBOSITY = 'merge.verbosity' MERGETOOL = 'merge.tool' EXPANDTAB = 'cola.expandtab' SAVEWINDOWSETTINGS = 'cola.savewindowsettings' SORT_BOOKMARKS = 'cola.sortbookmarks' STATUS_INDENT = 'cola.statusindent' STATUS_SHOW_TOTALS = 'cola.statusshowtotals' TABWIDTH = 'cola.tabwidth' TEXTWIDTH = 'cola.textwidth' USER_EMAIL = 'user.email' USER_NAME = 'user.name' SAFE_MODE = 'cola.safemode' AUTOCOMPLETE_PATHS = 'cola.autocompletepaths' SHOW_PATH = 'cola.showpath' SPELL_CHECK = 'cola.spellcheck' THEME = 'cola.theme' HIDPI = 'cola.hidpi' class Defaults(object): """Read-only class for holding defaults that get overridden""" # These should match Git's defaults for git-defined values. autotemplate = False blame_viewer = 'git gui blame' bold_headers = False check_conflicts = True comment_char = '#' display_untracked = True diff_context = 5 difftool = 'xxdiff' editor = 'gvim' expandtab = False history_browser = 'gitk' icon_theme = 'default' linebreak = True maxrecent = 8 mergetool = difftool merge_diffstat = True merge_keep_backup = True merge_summary = True merge_verbosity = 2 save_window_settings = True safe_mode = False autocomplete_paths = True show_path = True sort_bookmarks = True spellcheck = False tabwidth = 8 textwidth = 72 theme = 'default' hidpi = hidpi.Option.AUTO status_indent = False status_show_totals = False def blame_viewer(context): default = Defaults.blame_viewer return context.cfg.get(BLAME_VIEWER, default=default) def bold_headers(context): return context.cfg.get(BOLD_HEADERS, default=Defaults.bold_headers) def check_conflicts(context): return context.cfg.get(CHECKCONFLICTS, default=Defaults.check_conflicts) def display_untracked(context): return context.cfg.get(DISPLAY_UNTRACKED, default=Defaults.display_untracked) def editor(context): app = context.cfg.get(EDITOR, default=Defaults.editor) return _remap_editor(app) def background_editor(context): app = context.cfg.get(BACKGROUND_EDITOR, default=editor(context)) return _remap_editor(app) def _remap_editor(app): return {'vim': 'gvim -f'}.get(app, app) def comment_char(context): return context.cfg.get(COMMENT_CHAR, default=Defaults.comment_char) def default_history_browser(): if utils.is_win32(): # On Windows, a sensible default is "python git-cola dag" # which is different than `gitk` below, but is preferred # because we don't have to guess paths. git_cola = sys.argv[0].replace('\\', '/') python = sys.executable.replace('\\', '/') cwd = core.getcwd().replace('\\', '/') argv = [python, git_cola, 'dag', '--repo', cwd] argv = core.prep_for_subprocess(argv) default = core.list2cmdline(argv) else: # The `gitk` script can be launched as-is on unix default = Defaults.history_browser return default def history_browser(context): default = default_history_browser() return context.cfg.get(HISTORY_BROWSER, default=default) def linebreak(context): return context.cfg.get(LINEBREAK, default=Defaults.linebreak) def maxrecent(context): value = Defaults.maxrecent if context: value = context.cfg.get(MAXRECENT, default=value) return value def spellcheck(context): return context.cfg.get(SPELL_CHECK, default=Defaults.spellcheck) def expandtab(context): return context.cfg.get(EXPANDTAB, default=Defaults.expandtab) def sort_bookmarks(context): return context.cfg.get(SORT_BOOKMARKS, default=Defaults.sort_bookmarks) def tabwidth(context): return context.cfg.get(TABWIDTH, default=Defaults.tabwidth) def textwidth(context): return context.cfg.get(TEXTWIDTH, default=Defaults.textwidth) def status_indent(context): return context.cfg.get(STATUS_INDENT, default=Defaults.status_indent) def status_show_totals(context): return context.cfg.get(STATUS_SHOW_TOTALS, default=Defaults.status_show_totals) class PreferencesModel(observable.Observable): message_config_updated = 'config_updated' def __init__(self, context): observable.Observable.__init__(self) self.context = context self.config = context.cfg def set_config(self, source, config, value): if source == 'repo': self.config.set_repo(config, value) else: self.config.set_user(config, value) message = self.message_config_updated self.notify_observers(message, source, config, value) def get_config(self, source, config): if source == 'repo': value = self.config.get_repo(config) else: value = self.config.get(config) return value class SetConfig(Command): """Store a gitconfig value""" UNDOABLE = True def __init__(self, model, source, config, value): self.source = source self.config = config self.value = value self.old_value = None self.model = model def do(self): self.old_value = self.model.get_config(self.source, self.config) self.model.set_config(self.source, self.config, self.value) def undo(self): if self.old_value is None: return self.model.set_config(self.source, self.config, self.old_value) git-cola-3.6/cola/models/selection.py000066400000000000000000000066741356743264500176550ustar00rootroot00000000000000"""Provides a selection model to handle selection.""" from __future__ import division, absolute_import, unicode_literals import collections from ..observable import Observable State = collections.namedtuple('State', 'staged unmerged modified untracked') def create(): """Create a SelectionModel""" return SelectionModel() def pick(s): """Choose the first list from stage, unmerged, modified, untracked""" if s.staged: files = s.staged elif s.unmerged: files = s.unmerged elif s.modified: files = s.modified elif s.untracked: files = s.untracked else: files = [] return files def union(s): """Return the union of all selected items in a sorted list""" return list(sorted(set(s.staged + s.unmerged + s.modified + s.untracked))) def _filter(a, b): b_set = set(b) a_copy = list(a) last = len(a_copy) - 1 for idx, i in enumerate(reversed(a)): if i not in b_set: a.pop(last - idx) class SelectionModel(Observable): """Provides information about selected file paths.""" # Notification message sent out when selection changes message_selection_changed = 'selection_changed' # These properties wrap the individual selection items # to provide higher-level pseudo-selections. unstaged = property(lambda self: self.unmerged + self.modified + self.untracked) def __init__(self): Observable.__init__(self) self.staged = [] self.unmerged = [] self.modified = [] self.untracked = [] self.line_number = None def reset(self): self.staged = [] self.unmerged = [] self.modified = [] self.untracked = [] self.line_number = None def is_empty(self): return not(bool(self.staged or self.unmerged or self.modified or self.untracked)) def set_selection(self, s): """Set the new selection.""" self.staged = s.staged self.unmerged = s.unmerged self.modified = s.modified self.untracked = s.untracked self.notify_observers(self.message_selection_changed) def update(self, other): _filter(self.staged, other.staged) _filter(self.unmerged, other.unmerged) _filter(self.modified, other.modified) _filter(self.untracked, other.untracked) self.notify_observers(self.message_selection_changed) def selection(self): return State(self.staged, self.unmerged, self.modified, self.untracked) def single_selection(self): """Scan across staged, modified, etc. and return a single item.""" st = None m = None um = None ut = None if self.staged: st = self.staged[0] elif self.modified: m = self.modified[0] elif self.unmerged: um = self.unmerged[0] elif self.untracked: ut = self.untracked[0] return State(st, um, m, ut) def filename(self): paths = [p for p in self.single_selection() if p is not None] if paths: filename = paths[0] else: filename = None return filename def group(self): """A list of selected files in various states of being""" return pick(self.selection()) def union(self): """Return the union of all selected items in a sorted list""" return union(self) git-cola-3.6/cola/models/stash.py000066400000000000000000000150111356743264500167730ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals from .. import cmds from .. import core from .. import observable from .. import gitcmds from .. import utils from ..i18n import N_ from ..git import STDOUT from ..interaction import Interaction class StashModel(observable.Observable): def __init__(self, context): observable.Observable.__init__(self) self.context = context self.git = context.git self.model = model = context.model if not model.initialized: model.update_status() def stash_list(self, *args): return self.git.stash('list', *args)[STDOUT].splitlines() def is_staged(self): return bool(self.model.staged) def is_changed(self): model = self.model return bool(model.modified or model.staged) def stash_info(self, revids=False, names=False): """Parses "git stash list" and returns a list of stashes.""" stashes = self.stash_list(r'--format=%gd/%aD/%s') split_stashes = [s.split('/', 3) for s in stashes if s] stashes = ['{0}: {1}'.format(s[0], s[2]) for s in split_stashes] revids = [s[0] for s in split_stashes] author_dates = [s[1] for s in split_stashes] names = [s[2] for s in split_stashes] return stashes, revids, author_dates, names def stash_diff(self, rev): git = self.git diffstat = git.stash('show', rev)[STDOUT] diff = git.stash('show', '-p', '--no-ext-diff', rev)[STDOUT] return diffstat + '\n\n' + diff class ApplyStash(cmds.ContextCommand): def __init__(self, context, stash_index, index, pop): super(ApplyStash, self).__init__(context) self.stash_ref = 'refs/' + stash_index self.index = index self.pop = pop def do(self): ref = self.stash_ref pop = self.pop if pop: action = 'pop' else: action = 'apply' if self.index: args = [action, '--index', ref] else: args = [action, ref] status, out, err = self.git.stash(*args) if status == 0: Interaction.log_status(status, out, err) else: title = N_('Error') cmdargs = core.list2cmdline(args) Interaction.command_error( title, 'git stash ' + cmdargs, status, out, err) self.model.update_status() class DropStash(cmds.ContextCommand): def __init__(self, context, stash_index): super(DropStash, self).__init__(context) self.stash_ref = 'refs/' + stash_index def do(self): git = self.git status, out, err = git.stash('drop', self.stash_ref) if status == 0: Interaction.log_status(status, out, err) else: title = N_('Error') Interaction.command_error( title, 'git stash drop ' + self.stash_ref, status, out, err) class SaveStash(cmds.ContextCommand): def __init__(self, context, stash_name, keep_index): super(SaveStash, self).__init__(context) self.stash_name = stash_name self.keep_index = keep_index def do(self): if self.keep_index: args = ['save', '--keep-index', self.stash_name] else: args = ['save', self.stash_name] status, out, err = self.git.stash(*args) if status == 0: Interaction.log_status(status, out, err) else: title = N_('Error') cmdargs = core.list2cmdline(args) Interaction.command_error( title, 'git stash ' + cmdargs, status, out, err) self.model.update_status() class StashIndex(cmds.ContextCommand): """Stash the index away""" def __init__(self, context, stash_name): super(StashIndex, self).__init__(context) self.stash_name = stash_name def do(self): # Manually create a stash representing the index state context = self.context git = self.git name = self.stash_name branch = gitcmds.current_branch(context) head = gitcmds.rev_parse(context, 'HEAD') message = 'On %s: %s' % (branch, name) # Get the message used for the "index" commit status, out, err = git.rev_list('HEAD', '--', oneline=True, n=1) if status != 0: stash_error('rev-list', status, out, err) return head_msg = out.strip() # Create a commit representing the index status, out, err = git.write_tree() if status != 0: stash_error('write-tree', status, out, err) return index_tree = out.strip() status, out, err = git.commit_tree( '-m', 'index on %s: %s' % (branch, head_msg), '-p', head, index_tree) if status != 0: stash_error('commit-tree', status, out, err) return index_commit = out.strip() # Create a commit representing the worktree status, out, err = git.commit_tree( '-p', head, '-p', index_commit, '-m', message, index_tree) if status != 0: stash_error('commit-tree', status, out, err) return worktree_commit = out.strip() # Record the stash entry status, out, err = git.update_ref( '-m', message, 'refs/stash', worktree_commit, create_reflog=True) if status != 0: stash_error('update-ref', status, out, err) return # Sync the worktree with the post-stash state. We've created the # stash ref, so now we have to remove the staged changes from the # worktree. We do this by applying a reverse diff of the staged # changes. The diff from stash->HEAD is a reverse diff of the stash. patch = utils.tmp_filename('stash') with core.xopen(patch, mode='wb') as patch_fd: status, out, err = git.diff_tree( 'refs/stash', 'HEAD', '--', binary=True, _stdout=patch_fd) if status != 0: stash_error('diff-tree', status, out, err) return # Apply the patch status, out, err = git.apply(patch) core.unlink(patch) ok = status == 0 if ok: # Finally, clear the index we just stashed git.reset() else: stash_error('apply', status, out, err) self.model.update_status() def stash_error(cmd, status, out, err): title = N_('Error creating stash') Interaction.command_error(title, cmd, status, out, err) git-cola-3.6/cola/observable.py000066400000000000000000000021321356743264500165120ustar00rootroot00000000000000# Copyright (C) 2007-2018 David Aguilar and contributors """This module provides the Observable class""" from __future__ import division, absolute_import, unicode_literals class Observable(object): """Handles subject/observer notifications.""" def __init__(self): self.notification_enabled = True self.observers = {} def add_observer(self, message, observer): """Add an observer for a specific message.""" observers = self.observers.setdefault(message, set()) observers.add(observer) def remove_observer(self, observer): """Remove an observer.""" for _, observers in self.observers.items(): if observer in observers: observers.remove(observer) def notify_observers(self, message, *args, **opts): """Pythonic signals and slots.""" if not self.notification_enabled: return # observers can remove themselves during their callback so grab a copy observers = set(self.observers.get(message, set())) for method in observers: method(*args, **opts) git-cola-3.6/cola/qtcompat.py000066400000000000000000000032141356743264500162200ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals from qtpy import PYQT4 from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from qtpy.QtCore import Qt from . import hotkeys def patch(obj, attr, value): if not hasattr(obj, attr): setattr(obj, attr, value) def install(): patch(QtWidgets.QGraphicsItem, 'mapRectToScene', _map_rect_to_scene) patch(QtGui.QKeySequence, 'Preferences', hotkeys.PREFERENCES) def add_search_path(prefix, path): if hasattr(QtCore.QDir, 'addSearchPath'): QtCore.QDir.addSearchPath(prefix, path) def set_common_dock_options(window): if not hasattr(window, 'setDockOptions'): return nested = QtWidgets.QMainWindow.AllowNestedDocks tabbed = QtWidgets.QMainWindow.AllowTabbedDocks animated = QtWidgets.QMainWindow.AnimatedDocks window.setDockOptions(nested | tabbed | animated) def _map_rect_to_scene(self, rect): """Only available in newer PyQt4 versions""" return self.sceneTransform().mapRect(rect) def wheel_translation(event): """Return the Tx Ty translation delta for a pan""" if PYQT4: tx = event.delta() ty = 0.0 if event.orientation() == Qt.Vertical: (tx, ty) = (ty, tx) else: angle = event.angleDelta() tx = angle.x() ty = angle.y() return (tx, ty) def wheel_delta(event): """Return a single wheel delta""" if PYQT4: delta = event.delta() else: angle = event.angleDelta() x = angle.x() y = angle.y() if abs(x) > abs(y): delta = x else: delta = y return delta git-cola-3.6/cola/qtutils.py000066400000000000000000000746171356743264500161140ustar00rootroot00000000000000# Copyright (C) 2007-2018 David Aguilar and contributors """Miscellaneous Qt utility functions.""" from __future__ import division, absolute_import, unicode_literals import os from qtpy import compat from qtpy import QtGui from qtpy import QtCore from qtpy import QtWidgets from qtpy.QtCore import Qt from qtpy.QtCore import Signal from . import core from . import hotkeys from . import icons from . import utils from .i18n import N_ from .compat import int_types from .compat import ustr from .models import prefs from .widgets import defs STRETCH = object() SKIPPED = object() def active_window(): """Return the active window for the current application""" return QtWidgets.QApplication.activeWindow() def connect_action(action, fn): """Connect an action to a function""" action.triggered[bool].connect(lambda x: fn()) def connect_action_bool(action, fn): """Connect a triggered(bool) action to a function""" action.triggered[bool].connect(fn) def connect_button(button, fn): """Connect a button to a function""" # Some versions of Qt send the `bool` argument to the clicked callback, # and some do not. The lambda consumes all callback-provided arguments. button.clicked.connect(lambda *args, **kwargs: fn()) def connect_checkbox(widget, fn): """Connect a checkbox to a function taking bool""" widget.clicked.connect(lambda *args, **kwargs: fn(get(checkbox))) def connect_released(button, fn): """Connect a button to a function""" button.released.connect(fn) def button_action(button, action): """Make a button trigger an action""" connect_button(button, action.trigger) def connect_toggle(toggle, fn): """Connect a toggle button to a function""" toggle.toggled.connect(fn) def disconnect(signal): """Disconnect signal from all slots""" try: signal.disconnect() except TypeError: # allow unconnected slots pass def get(widget): """Query a widget for its python value""" if hasattr(widget, 'isChecked'): value = widget.isChecked() elif hasattr(widget, 'value'): value = widget.value() elif hasattr(widget, 'text'): value = widget.text() elif hasattr(widget, 'toPlainText'): value = widget.toPlainText() elif hasattr(widget, 'sizes'): value = widget.sizes() elif hasattr(widget, 'date'): value = widget.date().toString(Qt.ISODate) else: value = None return value def hbox(margin, spacing, *items): """Create an HBoxLayout with the specified sizes and items""" return box(QtWidgets.QHBoxLayout, margin, spacing, *items) def vbox(margin, spacing, *items): """Create a VBoxLayout with the specified sizes and items""" return box(QtWidgets.QVBoxLayout, margin, spacing, *items) def buttongroup(*items): """Create a QButtonGroup for the specified items""" group = QtWidgets.QButtonGroup() for i in items: group.addButton(i) return group def set_margin(layout, margin): """Set the content margins for a layout""" layout.setContentsMargins(margin, margin, margin, margin) def box(cls, margin, spacing, *items): """Create a QBoxLayout with the specified sizes and items""" stretch = STRETCH skipped = SKIPPED layout = cls() layout.setSpacing(spacing) set_margin(layout, margin) for i in items: if isinstance(i, QtWidgets.QWidget): layout.addWidget(i) elif isinstance(i, (QtWidgets.QHBoxLayout, QtWidgets.QVBoxLayout, QtWidgets.QFormLayout, QtWidgets.QLayout)): layout.addLayout(i) elif i is stretch: layout.addStretch() elif i is skipped: continue elif isinstance(i, int_types): layout.addSpacing(i) return layout def form(margin, spacing, *widgets): """Create a QFormLayout with the specified sizes and items""" layout = QtWidgets.QFormLayout() layout.setSpacing(spacing) layout.setFieldGrowthPolicy(QtWidgets.QFormLayout.ExpandingFieldsGrow) set_margin(layout, margin) for idx, (name, widget) in enumerate(widgets): if isinstance(name, (str, ustr)): layout.addRow(name, widget) else: layout.setWidget(idx, QtWidgets.QFormLayout.LabelRole, name) layout.setWidget(idx, QtWidgets.QFormLayout.FieldRole, widget) return layout def grid(margin, spacing, *widgets): """Create a QGridLayout with the specified sizes and items""" layout = QtWidgets.QGridLayout() layout.setSpacing(spacing) set_margin(layout, margin) for row in widgets: item = row[0] if isinstance(item, QtWidgets.QWidget): layout.addWidget(*row) elif isinstance(item, QtWidgets.QLayoutItem): layout.addItem(*row) return layout def splitter(orientation, *widgets): """Create a spliter over the specified widgets :param orientation: Qt.Horizontal or Qt.Vertical """ layout = QtWidgets.QSplitter() layout.setOrientation(orientation) layout.setHandleWidth(defs.handle_width) layout.setChildrenCollapsible(True) for idx, widget in enumerate(widgets): layout.addWidget(widget) layout.setStretchFactor(idx, 1) # Workaround for Qt not setting the WA_Hover property for QSplitter # Cf. https://bugreports.qt.io/browse/QTBUG-13768 layout.handle(1).setAttribute(Qt.WA_Hover) return layout def label(text=None, align=None, fmt=None, selectable=True): """Create a QLabel with the specified properties""" widget = QtWidgets.QLabel() if align is not None: widget.setAlignment(align) if fmt is not None: widget.setTextFormat(fmt) if selectable: widget.setTextInteractionFlags(Qt.TextBrowserInteraction) widget.setOpenExternalLinks(True) if text: widget.setText(text) return widget class ComboBox(QtWidgets.QComboBox): """Custom read-only combobox with a convenient API""" def __init__(self, items=None, editable=False, parent=None, transform=None): super(ComboBox, self).__init__(parent) self.setEditable(editable) self.transform = transform self.item_data = [] if items: self.addItems(items) self.item_data.extend(items) def set_index(self, idx): idx = utils.clamp(idx, 0, self.count()-1) self.setCurrentIndex(idx) def add_item(self, text, data): self.addItem(text) self.item_data.append(data) def current_data(self): return self.item_data[self.currentIndex()] def set_value(self, value): if self.transform: value = self.transform(value) try: index = self.item_data.index(value) except ValueError: index = 0 self.setCurrentIndex(index) def combo(items, editable=False, parent=None): """Create a readonly (by default) combobox from a list of items""" return ComboBox(editable=editable, items=items, parent=parent) def combo_mapped(data, editable=False, transform=None, parent=None): """Create a readonly (by default) combobox from a list of items""" widget = ComboBox(editable=editable, transform=transform, parent=parent) for (k, v) in data: widget.add_item(k, v) return widget def textbrowser(text=None): """Create a QTextBrowser for the specified text""" widget = QtWidgets.QTextBrowser() widget.setOpenExternalLinks(True) if text: widget.setText(text) return widget def add_completer(widget, items): """Add simple completion to a widget""" completer = QtWidgets.QCompleter(items, widget) completer.setCaseSensitivity(Qt.CaseInsensitive) completer.setCompletionMode(QtWidgets.QCompleter.InlineCompletion) widget.setCompleter(completer) def prompt(msg, title=None, text='', parent=None): """Presents the user with an input widget and returns the input.""" if title is None: title = msg if parent is None: parent = active_window() result = QtWidgets.QInputDialog.getText( parent, title, msg, QtWidgets.QLineEdit.Normal, text) return (result[0], result[1]) def prompt_n(msg, inputs): """Presents the user with N input widgets and returns the results""" dialog = QtWidgets.QDialog(active_window()) dialog.setWindowModality(Qt.WindowModal) dialog.setWindowTitle(msg) long_value = msg for k, v in inputs: if len(k + v) > len(long_value): long_value = k + v metrics = QtGui.QFontMetrics(dialog.font()) min_width = metrics.width(long_value) + 100 if min_width > 720: min_width = 720 dialog.setMinimumWidth(min_width) ok_b = ok_button(msg, enabled=False) close_b = close_button() form_widgets = [] def get_values(): return [pair[1].text().strip() for pair in form_widgets] for name, value in inputs: lineedit = QtWidgets.QLineEdit() # Enable the OK button only when all fields have been populated # pylint: disable=no-member lineedit.textChanged.connect( lambda x: ok_b.setEnabled(all(get_values()))) if value: lineedit.setText(value) form_widgets.append((name, lineedit)) # layouts form_layout = form(defs.no_margin, defs.button_spacing, *form_widgets) button_layout = hbox(defs.no_margin, defs.button_spacing, STRETCH, close_b, ok_b) main_layout = vbox(defs.margin, defs.button_spacing, form_layout, button_layout) dialog.setLayout(main_layout) # connections connect_button(ok_b, dialog.accept) connect_button(close_b, dialog.reject) accepted = dialog.exec_() == QtWidgets.QDialog.Accepted text = get_values() ok = accepted and all(text) return (ok, text) class TreeWidgetItem(QtWidgets.QTreeWidgetItem): TYPE = QtGui.QStandardItem.UserType + 101 def __init__(self, path, icon, deleted): QtWidgets.QTreeWidgetItem.__init__(self) self.path = path self.deleted = deleted self.setIcon(0, icons.from_name(icon)) self.setText(0, path) def type(self): return self.TYPE def paths_from_indexes(model, indexes, item_type=TreeWidgetItem.TYPE, item_filter=None): """Return paths from a list of QStandardItemModel indexes""" items = [model.itemFromIndex(i) for i in indexes] return paths_from_items(items, item_type=item_type, item_filter=item_filter) def _true_filter(_x): return True def paths_from_items(items, item_type=TreeWidgetItem.TYPE, item_filter=None): """Return a list of paths from a list of items""" if item_filter is None: item_filter = _true_filter return [i.path for i in items if i.type() == item_type and item_filter(i)] def tree_selection(tree_item, items): """Returns an array of model items that correspond to the selected QTreeWidgetItem children""" selected = [] count = min(tree_item.childCount(), len(items)) for idx in range(count): if tree_item.child(idx).isSelected(): selected.append(items[idx]) return selected def tree_selection_items(tree_item): """Returns selected widget items""" selected = [] for idx in range(tree_item.childCount()): child = tree_item.child(idx) if child.isSelected(): selected.append(child) return selected def selected_item(list_widget, items): """Returns the model item that corresponds to the selected QListWidget row.""" widget_items = list_widget.selectedItems() if not widget_items: return None widget_item = widget_items[0] row = list_widget.row(widget_item) if row < len(items): item = items[row] else: item = None return item def selected_items(list_widget, items): """Returns an array of model items that correspond to the selected QListWidget rows.""" item_count = len(items) selected = [] for widget_item in list_widget.selectedItems(): row = list_widget.row(widget_item) if row < item_count: selected.append(items[row]) return selected def open_file(title, directory=None): """Creates an Open File dialog and returns a filename.""" result = compat.getopenfilename(parent=active_window(), caption=title, basedir=directory) return result[0] def open_files(title, directory=None, filters=''): """Creates an Open File dialog and returns a list of filenames.""" result = compat.getopenfilenames(parent=active_window(), caption=title, basedir=directory, filters=filters) return result[0] def opendir_dialog(caption, path): """Prompts for a directory path""" options = (QtWidgets.QFileDialog.ShowDirsOnly | QtWidgets.QFileDialog.DontResolveSymlinks) return compat.getexistingdirectory(parent=active_window(), caption=caption, basedir=path, options=options) def save_as(filename, title='Save As...'): """Creates a Save File dialog and returns a filename.""" result = compat.getsavefilename(parent=active_window(), caption=title, basedir=filename) return result[0] def copy_path(filename, absolute=True): """Copy a filename to the clipboard""" if filename is None: return if absolute: filename = core.abspath(filename) set_clipboard(filename) def set_clipboard(text): """Sets the copy/paste buffer to text.""" if not text: return clipboard = QtWidgets.QApplication.clipboard() clipboard.setText(text, QtGui.QClipboard.Clipboard) clipboard.setText(text, QtGui.QClipboard.Selection) persist_clipboard() # pylint: disable=line-too-long def persist_clipboard(): """Persist the clipboard X11 stores only a reference to the clipboard data. Send a clipboard event to force a copy of the clipboard to occur. This ensures that the clipboard is present after git-cola exits. Otherwise, the reference is destroyed on exit. C.f. https://stackoverflow.com/questions/2007103/how-can-i-disable-clear-of-clipboard-on-exit-of-pyqt4-application """ # noqa clipboard = QtWidgets.QApplication.clipboard() event = QtCore.QEvent(QtCore.QEvent.Clipboard) QtWidgets.QApplication.sendEvent(clipboard, event) def add_action_bool(widget, text, fn, checked, *shortcuts): tip = text action = _add_action(widget, text, tip, fn, connect_action_bool, *shortcuts) action.setCheckable(True) action.setChecked(checked) return action def add_action(widget, text, fn, *shortcuts): tip = text return _add_action(widget, text, tip, fn, connect_action, *shortcuts) def add_action_with_status_tip(widget, text, tip, fn, *shortcuts): return _add_action(widget, text, tip, fn, connect_action, *shortcuts) def _add_action(widget, text, tip, fn, connect, *shortcuts): action = QtWidgets.QAction(text, widget) if hasattr(action, 'setIconVisibleInMenu'): action.setIconVisibleInMenu(True) if tip: action.setStatusTip(tip) connect(action, fn) if shortcuts: action.setShortcuts(shortcuts) if hasattr(Qt, 'WidgetWithChildrenShortcut'): action.setShortcutContext(Qt.WidgetWithChildrenShortcut) widget.addAction(action) return action def set_selected_item(widget, idx): """Sets a the currently selected item to the item at index idx.""" if isinstance(widget, QtWidgets.QTreeWidget): item = widget.topLevelItem(idx) if item: item.setSelected(True) widget.setCurrentItem(item) def add_items(widget, items): """Adds items to a widget.""" for item in items: if item is None: continue widget.addItem(item) def set_items(widget, items): """Clear the existing widget contents and set the new items.""" widget.clear() add_items(widget, items) def create_treeitem(filename, staged=False, deleted=False, untracked=False): """Given a filename, return a TreeWidgetItem for a status widget "staged", "deleted, and "untracked" control which icon is used. """ icon_name = icons.status(filename, deleted, staged, untracked) return TreeWidgetItem(filename, icons.name_from_basename(icon_name), deleted=deleted) def add_close_action(widget): """Adds close action and shortcuts to a widget.""" return add_action(widget, N_('Close...'), widget.close, hotkeys.CLOSE, hotkeys.QUIT) def app(): """Return the current application""" return QtWidgets.QApplication.instance() def desktop(): """Return the desktop""" return app().desktop() def desktop_size(): desk = desktop() rect = desk.screenGeometry(QtGui.QCursor().pos()) return (rect.width(), rect.height()) def center_on_screen(widget): """Move widget to the center of the default screen""" width, height = desktop_size() cx = width // 2 cy = height // 2 widget.move(cx - widget.width()//2, cy - widget.height()//2) def default_size(parent, width, height, use_parent_height=True): """Return the parent's size, or the provided defaults""" if parent is not None: width = parent.width() if use_parent_height: height = parent.height() return (width, height) def default_monospace_font(): if utils.is_darwin(): family = 'Monaco' else: family = 'Monospace' mfont = QtGui.QFont() mfont.setFamily(family) return mfont def diff_font_str(context): cfg = context.cfg font_str = cfg.get(prefs.FONTDIFF) if not font_str: font_str = default_monospace_font().toString() return font_str def diff_font(context): return font(diff_font_str(context)) def font(string): qfont = QtGui.QFont() qfont.fromString(string) return qfont def create_button(text='', layout=None, tooltip=None, icon=None, enabled=True, default=False): """Create a button, set its title, and add it to the parent.""" button = QtWidgets.QPushButton() button.setCursor(Qt.PointingHandCursor) button.setFocusPolicy(Qt.NoFocus) if text: button.setText(' ' + text) if icon is not None: button.setIcon(icon) button.setIconSize(QtCore.QSize(defs.small_icon, defs.small_icon)) if tooltip is not None: button.setToolTip(tooltip) if layout is not None: layout.addWidget(button) if not enabled: button.setEnabled(False) if default: button.setDefault(True) return button def tool_button(): """Create a flat border-less button""" button = QtWidgets.QToolButton() button.setPopupMode(QtWidgets.QToolButton.InstantPopup) button.setCursor(Qt.PointingHandCursor) button.setFocusPolicy(Qt.NoFocus) # Highlight colors palette = QtGui.QPalette() highlight = palette.color(QtGui.QPalette.Highlight) highlight_rgb = rgb_css(highlight) button.setStyleSheet(""" /* No borders */ QToolButton { border: none; background-color: none; } /* Hide the menu indicator */ QToolButton::menu-indicator { image: none; } QToolButton:hover { border: %(border)spx solid %(highlight_rgb)s; } """ % dict(border=defs.border, highlight_rgb=highlight_rgb)) return button def create_action_button(tooltip=None, icon=None): """Create a small toolbutton for use in dock title widgets""" button = tool_button() if tooltip is not None: button.setToolTip(tooltip) if icon is not None: button.setIcon(icon) button.setIconSize(QtCore.QSize(defs.small_icon, defs.small_icon)) return button def ok_button(text, default=True, enabled=True, icon=None): if icon is None: icon = icons.ok() return create_button(text=text, icon=icon, default=default, enabled=enabled) def close_button(text=None, icon=None): text = text or N_('Close') icon = icons.mkicon(icon, icons.close) return create_button(text=text, icon=icon) def edit_button(enabled=True, default=False): return create_button(text=N_('Edit'), icon=icons.edit(), enabled=enabled, default=default) def refresh_button(enabled=True, default=False): return create_button(text=N_('Refresh'), icon=icons.sync(), enabled=enabled, default=default) def checkbox(text='', tooltip='', checked=None): """Create a checkbox""" return _checkbox(QtWidgets.QCheckBox, text, tooltip, checked) def radio(text='', tooltip='', checked=None): """Create a radio button""" return _checkbox(QtWidgets.QRadioButton, text, tooltip, checked) def _checkbox(cls, text, tooltip, checked): """Create a widget and apply properties""" widget = cls() if text: widget.setText(text) if tooltip: widget.setToolTip(tooltip) if checked is not None: widget.setChecked(checked) return widget class DockTitleBarWidget(QtWidgets.QFrame): def __init__(self, parent, title, stretch=True): QtWidgets.QFrame.__init__(self, parent) self.setAutoFillBackground(True) self.label = qlabel = QtWidgets.QLabel(title, self) qfont = qlabel.font() qfont.setBold(True) qlabel.setFont(qfont) qlabel.setCursor(Qt.OpenHandCursor) self.close_button = create_action_button( tooltip=N_('Close'), icon=icons.close()) self.toggle_button = create_action_button( tooltip=N_('Detach'), icon=icons.external()) self.corner_layout = hbox(defs.no_margin, defs.spacing) if stretch: separator = STRETCH else: separator = SKIPPED self.main_layout = hbox(defs.small_margin, defs.titlebar_spacing, qlabel, separator, self.corner_layout, self.toggle_button, self.close_button) self.setLayout(self.main_layout) connect_button(self.toggle_button, self.toggle_floating) connect_button(self.close_button, self.toggle_visibility) def toggle_floating(self): self.parent().setFloating(not self.parent().isFloating()) self.update_tooltips() def toggle_visibility(self): self.parent().toggleViewAction().trigger() def set_title(self, title): self.label.setText(title) def add_corner_widget(self, widget): self.corner_layout.addWidget(widget) def update_tooltips(self): if self.parent().isFloating(): tooltip = N_('Attach') else: tooltip = N_('Detach') self.toggle_button.setToolTip(tooltip) def create_dock(title, parent, stretch=True, widget=None, fn=None): """Create a dock widget and set it up accordingly.""" dock = QtWidgets.QDockWidget(parent) dock.setWindowTitle(title) dock.setObjectName(title) titlebar = DockTitleBarWidget(dock, title, stretch=stretch) dock.setTitleBarWidget(titlebar) dock.setAutoFillBackground(True) if hasattr(parent, 'dockwidgets'): parent.dockwidgets.append(dock) if fn: widget = fn(dock) assert isinstance(widget, QtWidgets.QFrame),\ "Docked widget has to be a QFrame" if widget: dock.setWidget(widget) return dock def hide_dock(widget): widget.toggleViewAction().setChecked(False) widget.hide() def create_menu(title, parent): """Create a menu and set its title.""" qmenu = DebouncingMenu(title, parent) return qmenu class DebouncingMenu(QtWidgets.QMenu): """Menu that debounces mouse release action ie. stops it if occurred right after menu creation. Disables annoying behaviour when RMB is pressed to show menu, cursor is moved accidentally 1px onto newly created menu and released causing to execute menu action """ threshold_ms = 400 def __init__(self, title, parent): QtWidgets.QMenu.__init__(self, title, parent) self.created_at = utils.epoch_millis() def mouseReleaseEvent(self, event): threshold = DebouncingMenu.threshold_ms if (utils.epoch_millis() - self.created_at) > threshold: QtWidgets.QMenu.mouseReleaseEvent(self, event) def add_menu(title, parent): """Create a menu and set its title.""" menu = create_menu(title, parent) parent.addAction(menu.menuAction()) return menu def create_toolbutton(text=None, layout=None, tooltip=None, icon=None): button = tool_button() if icon is not None: button.setIcon(icon) button.setIconSize(QtCore.QSize(defs.small_icon, defs.small_icon)) if text is not None: button.setText(' ' + text) button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) if tooltip is not None: button.setToolTip(tooltip) if layout is not None: layout.addWidget(button) return button # pylint: disable=line-too-long def mimedata_from_paths(context, paths): """Return mimedata with a list of absolute path URLs The text/x-moz-list format is always included by Qt, and doing mimedata.removeFormat('text/x-moz-url') has no effect. C.f. http://www.qtcentre.org/threads/44643-Dragging-text-uri-list-Qt-inserts-garbage gnome-terminal expects utf-16 encoded text, but other terminals, e.g. terminator, prefer utf-8, so allow cola.dragencoding to override the default. """ # noqa cfg = context.cfg abspaths = [core.abspath(path) for path in paths] urls = [QtCore.QUrl.fromLocalFile(path) for path in abspaths] mimedata = QtCore.QMimeData() mimedata.setUrls(urls) paths_text = core.list2cmdline(abspaths) encoding = cfg.get('cola.dragencoding', 'utf-16') moz_text = core.encode(paths_text, encoding=encoding) mimedata.setData('text/x-moz-url', moz_text) return mimedata def path_mimetypes(): return ['text/uri-list', 'text/x-moz-url'] class BlockSignals(object): """Context manager for blocking a signals on a widget""" def __init__(self, *widgets): self.widgets = widgets self.values = {} def __enter__(self): for w in self.widgets: self.values[w] = w.blockSignals(True) return self def __exit__(self, exc_type, exc_val, exc_tb): for w in self.widgets: w.blockSignals(self.values[w]) class Channel(QtCore.QObject): finished = Signal(object) result = Signal(object) class Task(QtCore.QRunnable): """Disable auto-deletion to avoid gc issues Python's garbage collector will try to double-free the task once it's finished, so disable Qt's auto-deletion as a workaround. """ def __init__(self, parent): QtCore.QRunnable.__init__(self) self.channel = Channel(parent) self.result = None self.setAutoDelete(False) def run(self): self.result = self.task() self.channel.result.emit(self.result) self.channel.finished.emit(self) # pylint: disable=no-self-use def task(self): return None def connect(self, handler): self.channel.result.connect(handler, type=Qt.QueuedConnection) class SimpleTask(Task): """Run a simple callable as a task""" def __init__(self, parent, fn, *args, **kwargs): Task.__init__(self, parent) self.fn = fn self.args = args self.kwargs = kwargs def task(self): return self.fn(*self.args, **self.kwargs) class RunTask(QtCore.QObject): """Runs QRunnable instances and transfers control when they finish""" def __init__(self, parent=None): QtCore.QObject.__init__(self, parent) self.tasks = [] self.task_details = {} self.threadpool = QtCore.QThreadPool.globalInstance() self.result_fn = None def start(self, task, progress=None, finish=None, result=None): """Start the task and register a callback""" self.result_fn = result if progress is not None: progress.show() # prevents garbage collection bugs in certain PyQt4 versions self.tasks.append(task) task_id = id(task) self.task_details[task_id] = (progress, finish, result) task.channel.finished.connect(self.finish, type=Qt.QueuedConnection) self.threadpool.start(task) def finish(self, task): task_id = id(task) try: self.tasks.remove(task) except ValueError: pass try: progress, finish, result = self.task_details[task_id] del self.task_details[task_id] except KeyError: finish = progress = result = None if progress is not None: progress.hide() if result is not None: result(task.result) if finish is not None: finish(task) # Syntax highlighting def rgb(r, g, b): color = QtGui.QColor() color.setRgb(r, g, b) return color def rgba(r, g, b, a=255): color = rgb(r, g, b) color.setAlpha(a) return color def RGB(args): return rgb(*args) def rgb_css(color): """Convert a QColor into an rgb(int, int, int) CSS string""" return 'rgb(%d, %d, %d)' % (color.red(), color.green(), color.blue()) def rgb_hex(color): """Convert a QColor into a hex aabbcc string""" return '%02x%02x%02x' % (color.red(), color.green(), color.blue()) def hsl(h, s, l): return QtGui.QColor.fromHslF( utils.clamp(h, 0.0, 1.0), utils.clamp(s, 0.0, 1.0), utils.clamp(l, 0.0, 1.0) ) def hsl_css(h, s, l): return rgb_css(hsl(h, s, l)) def make_format(fg=None, bg=None, bold=False): fmt = QtGui.QTextCharFormat() if fg: fmt.setForeground(fg) if bg: fmt.setBackground(bg) if bold: fmt.setFontWeight(QtGui.QFont.Bold) return fmt class ImageFormats(object): def __init__(self): # returns a list of QByteArray objects formats_qba = QtGui.QImageReader.supportedImageFormats() # portability: python3 data() returns bytes, python2 returns str decode = core.decode formats = [decode(x.data()) for x in formats_qba] self.extensions = set(['.' + fmt for fmt in formats]) def ok(self, filename): _, ext = os.path.splitext(filename) return ext.lower() in self.extensions git-cola-3.6/cola/resources.py000066400000000000000000000053441356743264500164100ustar00rootroot00000000000000"""Provides the prefix() function for finding cola resources""" from __future__ import division, absolute_import, unicode_literals import os from os.path import dirname import webbrowser from . import core # Default git-cola icon theme _default_icon_theme = 'light' _modpath = core.abspath(__file__) if os.path.join('share', 'git-cola', 'lib') in _modpath: # this is the release tree # __file__ = '$prefix/share/git-cola/lib/cola/__file__.py' _lib_dir = dirname(dirname(_modpath)) _prefix = dirname(dirname(dirname(_lib_dir))) elif os.path.join('pkgs', 'cola') in _modpath: # Windows release tree # __file__ = $installdir/pkgs/cola/resources.py _prefix = dirname(dirname(dirname(_modpath))) else: # this is the source tree # __file__ = '$prefix/cola/__file__.py' _prefix = dirname(dirname(_modpath)) def prefix(*args): """Return a path relative to cola's installation prefix""" return os.path.join(_prefix, *args) def doc(*args): """Return a path relative to cola's /usr/share/doc/ directory""" return os.path.join(_prefix, 'share', 'doc', 'git-cola', *args) def html_docs(): """Return the path to the cola html documentation.""" # html/index.html only exists after the install-docs target is run. # Fallback to the source tree and lastly git-cola.rst. paths_to_try = (('html', 'index.html'), ('_build', 'html', 'index.html')) for paths in paths_to_try: docdir = doc(*paths) if core.exists(docdir): return docdir return doc('git-cola.rst') def show_html_docs(): url = html_docs() webbrowser.open_new_tab('file://' + url) def share(*args): """Return a path relative to cola's /usr/share/ directory""" return prefix('share', 'git-cola', *args) def icon_dir(theme): """Return the path to the icons directory This typically returns share/git-cola/icons within the git-cola installation prefix. When theme is defined then it will return a subdirectory of the icons/ directory, e.g. "dark" for the dark icon theme. When theme is set to an absolute directory path, that directory will be returned, which effectively makes git-cola use those icons. """ if not theme or theme == _default_icon_theme: icons = share('icons') else: theme_dir = share('icons', theme) if os.path.isabs(theme) and os.path.isdir(theme): icons = theme elif os.path.isdir(theme_dir): icons = theme_dir else: icons = share('icons') return icons def config_home(*args): config = core.getenv('XDG_CONFIG_HOME', os.path.join(core.expanduser('~'), '.config')) return os.path.join(config, 'git-cola', *args) git-cola-3.6/cola/settings.py000066400000000000000000000154641356743264500162420ustar00rootroot00000000000000"""Save settings, bookmarks, etc. """ from __future__ import division, absolute_import, unicode_literals import json import os import sys from . import core from . import git from . import resources def mkdict(obj): """Transform None and non-dicts into dicts""" if isinstance(obj, dict): value = obj else: value = {} return value def mklist(obj): """Transform None and non-lists into lists""" if isinstance(obj, list): value = obj elif isinstance(obj, tuple): value = list(obj) else: value = [] return value def read_json(path): try: with core.xopen(path, 'rt') as fp: return mkdict(json.load(fp)) except (ValueError, TypeError, OSError, IOError): # bad path or json return {} def write_json(values, path): try: parent = os.path.dirname(path) if not core.isdir(parent): core.makedirs(parent) with core.xopen(path, 'wt') as fp: json.dump(values, fp, indent=4) except (ValueError, TypeError, OSError, IOError): sys.stderr.write('git-cola: error writing "%s"\n' % path) class Settings(object): config_path = resources.config_home('settings') bookmarks = property(lambda self: mklist(self.values['bookmarks'])) gui_state = property(lambda self: mkdict(self.values['gui_state'])) recent = property(lambda self: mklist(self.values['recent'])) copy_formats = property(lambda self: mklist(self.values['copy_formats'])) def __init__(self, verify=git.is_git_worktree): """Load existing settings if they exist""" self.values = { 'bookmarks': [], 'gui_state': {}, 'recent': [], 'copy_formats': [], } self.verify = verify def remove_missing(self): missing_bookmarks = [] missing_recent = [] for bookmark in self.bookmarks: if not self.verify(bookmark['path']): missing_bookmarks.append(bookmark) for bookmark in missing_bookmarks: try: self.bookmarks.remove(bookmark) except ValueError: pass for recent in self.recent: if not self.verify(recent['path']): missing_recent.append(recent) for recent in missing_recent: try: self.recent.remove(recent) except ValueError: pass def add_bookmark(self, path, name): """Adds a bookmark to the saved settings""" bookmark = {'path': path, 'name': name} if bookmark not in self.bookmarks: self.bookmarks.append(bookmark) def remove_bookmark(self, path, name): """Remove a bookmark""" bookmark = {'path': path, 'name': name} try: self.bookmarks.remove(bookmark) except ValueError: pass def rename_bookmark(self, path, name, new_name): return rename_entry(self.bookmarks, path, name, new_name) def add_recent(self, path, max_recent): try: index = [recent['path'] for recent in self.recent].index(path) entry = self.recent.pop(index) except (IndexError, ValueError): entry = { 'name': os.path.basename(path), 'path': path, } self.recent.insert(0, entry) if len(self.recent) >= max_recent: self.recent.pop() def remove_recent(self, path): """Removes an item from the recent items list""" try: index = [ recent.get('path', '') for recent in self.recent ].index(path) except ValueError: return try: self.recent.pop(index) except IndexError: return def rename_recent(self, path, name, new_name): return rename_entry(self.recent, path, name, new_name) def path(self): return self.config_path def save(self): write_json(self.values, self.path()) def load(self): self.values.update(self.asdict()) self.upgrade_settings() self.remove_missing() def upgrade_settings(self): """Upgrade git-cola settings""" # Upgrade bookmarks to the new dict-based bookmarks format. if self.bookmarks and not isinstance(self.bookmarks[0], dict): bookmarks = [dict(name=os.path.basename(path), path=path) for path in self.bookmarks] self.values['bookmarks'] = bookmarks if self.recent and not isinstance(self.recent[0], dict): recent = [dict(name=os.path.basename(path), path=path) for path in self.recent] self.values['recent'] = recent def asdict(self): path = self.path() if core.exists(path): return read_json(path) # We couldn't find ~/.config/git-cola, try ~/.cola values = {} path = os.path.join(core.expanduser('~'), '.cola') if core.exists(path): json_values = read_json(path) # Keep only the entries we care about for key in self.values: try: values[key] = json_values[key] except KeyError: pass return values def reload_recent(self): values = self.asdict() self.values['recent'] = mklist(values.get('recent', [])) def save_gui_state(self, gui): """Saves settings for a cola view""" name = gui.name() self.gui_state[name] = mkdict(gui.export_state()) self.save() def get_gui_state(self, gui): """Returns the saved state for a gui""" try: state = mkdict(self.gui_state[gui.name()]) except KeyError: state = self.gui_state[gui.name()] = {} return state def rename_entry(entries, path, name, new_name): entry = {'name': name, 'path': path} try: index = entries.index(entry) except ValueError: return False if all([item['name'] != new_name for item in entries]): entries[index]['name'] = new_name return True return False class Session(Settings): """Store per-session settings""" _sessions_dir = resources.config_home('sessions') repo = property(lambda self: self.values['repo']) def __init__(self, session_id, repo=None): Settings.__init__(self) self.session_id = session_id self.values.update({'repo': repo}) def path(self): return os.path.join(self._sessions_dir, self.session_id) def load(self): path = self.path() if core.exists(path): self.values.update(read_json(path)) try: os.unlink(path) except (OSError, ValueError): pass return True return False git-cola-3.6/cola/spellcheck.py000066400000000000000000000062531356743264500165130ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals import collections import os from cola import core __copyright__ = """ 2012 Peter Norvig (http://norvig.com/spell-correct.html) 2013-2018 David Aguilar """ alphabet = 'abcdefghijklmnopqrstuvwxyz' def train(features, model): for f in features: model[f] += 1 return model def edits1(word): splits = [(word[:i], word[i:]) for i in range(len(word) + 1)] deletes = [a + b[1:] for a, b in splits if b] transposes = [a + b[1] + b[0] + b[2:] for a, b in splits if len(b) > 1] replaces = [a + c + b[1:] for a, b in splits for c in alphabet if b] inserts = [a + c + b for a, b in splits for c in alphabet] return set(deletes + transposes + replaces + inserts) def known_edits2(word, words): return set(e2 for e1 in edits1(word) for e2 in edits1(e1) if e2 in words) def known(word, words): return set(w for w in word if w in words) def suggest(word, words): candidates = (known([word], words) or known(edits1(word), words) or known_edits2(word, words) or [word]) return candidates def correct(word, words): candidates = suggest(word, words) return max(candidates, key=words.get) class NorvigSpellCheck(object): def __init__(self, words='/usr/share/dict/words', cracklib='/usr/share/dict/cracklib-small', propernames='/usr/share/dict/propernames'): self.dictwords = words self.cracklib = cracklib self.propernames = propernames self.words = collections.defaultdict(lambda: 1) self.extra_words = set() self.dictionary = None self.initialized = False def set_dictionary(self, dictionary): self.dictionary = dictionary def init(self): if self.initialized: return self.initialized = True train(self.read(), self.words) train(self.extra_words, self.words) def add_word(self, word): self.extra_words.add(word) def suggest(self, word): self.init() return suggest(word, self.words) def check(self, word): self.init() return word.replace('.', '') in self.words def read(self): """Read dictionary words""" paths = [] words = self.dictwords cracklib = self.cracklib propernames = self.propernames cfg_dictionary = self.dictionary if cracklib and os.path.exists(cracklib): paths.append((cracklib, True)) elif words and os.path.exists(words): paths.append((words, True)) if propernames and os.path.exists(propernames): paths.append((propernames, False)) if cfg_dictionary and os.path.exists(cfg_dictionary): paths.append((cfg_dictionary, False)) for (path, title) in paths: try: with open(path, 'r') as f: for word in f: word = core.decode(word.rstrip()) yield word if title: yield word.title() except IOError: pass git-cola-3.6/cola/textwrap.py000066400000000000000000000221511356743264500162470ustar00rootroot00000000000000"""Text wrapping and filling. """ from __future__ import division, absolute_import, unicode_literals import re from .compat import ustr # Copyright (C) 1999-2001 Gregory P. Ward. # Copyright (C) 2002, 2003 Python Software Foundation. # Copyright (C) 2013, David Aguilar # Written by Greg Ward # Simplified for git-cola by David Aguilar class TextWrapper(object): """ Object for wrapping/filling text. The public interface consists of the wrap() and fill() methods; the other methods are just there for subclasses to override in order to tweak the default behaviour. If you want to completely replace the main wrapping algorithm, you'll probably have to override _wrap_chunks(). Several instance attributes control various aspects of wrapping: width (default: 70) The preferred width of wrapped lines. tabwidth (default: 8) The width of a tab used when calculating line length. break_on_hyphens (default: false) Allow breaking hyphenated words. If true, wrapping will occur preferably on whitespaces and right after hyphens part of compound words. drop_whitespace (default: true) Drop leading and trailing whitespace from lines. """ # This funky little regex is just the trick for splitting # text up into word-wrappable chunks. E.g. # "Hello there -- you goof-ball, use the -b option!" # splits into # Hello/ /there/ /--/ /you/ /goof-/ball,/ /use/ /the/ /-b/ /option! # (after stripping out empty strings). wordsep_re = re.compile( r'(\s+|' # any whitespace r'[^\s\w]*\w+[^0-9\W]-(?=\w+[^0-9\W])|' # hyphenated words r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))') # em-dash # This less funky little regex just split on recognized spaces. E.g. # "Hello there -- you goof-ball, use the -b option!" # splits into # Hello/ /there/ /--/ /you/ /goof-ball,/ /use/ /the/ /-b/ /option!/ wordsep_simple_re = re.compile(r'(\s+)') def __init__(self, width=70, tabwidth=8, break_on_hyphens=False, drop_whitespace=True): self.width = width self.tabwidth = tabwidth self.break_on_hyphens = break_on_hyphens self.drop_whitespace = drop_whitespace # recompile the regexes for Unicode mode -- done in this clumsy way for # backwards compatibility because it's rather common to monkey-patch # the TextWrapper class' wordsep_re attribute. self.wordsep_re_uni = re.compile(self.wordsep_re.pattern, re.U) self.wordsep_simple_re_uni = re.compile( self.wordsep_simple_re.pattern, re.U) def _split(self, text): """_split(text : string) -> [string] Split the text to wrap into indivisible chunks. Chunks are not quite the same as words; see _wrap_chunks() for full details. As an example, the text Look, goof-ball -- use the -b option! breaks into the following chunks: 'Look,', ' ', 'goof-', 'ball', ' ', '--', ' ', 'use', ' ', 'the', ' ', '-b', ' ', 'option!' if break_on_hyphens is True, or in: 'Look,', ' ', 'goof-ball', ' ', '--', ' ', 'use', ' ', 'the', ' ', '-b', ' ', option!' otherwise. """ if isinstance(text, ustr): if self.break_on_hyphens: pat = self.wordsep_re_uni else: pat = self.wordsep_simple_re_uni else: if self.break_on_hyphens: pat = self.wordsep_re else: pat = self.wordsep_simple_re chunks = pat.split(text) chunks = list(filter(None, chunks)) # remove empty chunks return chunks def _wrap_chunks(self, chunks): """_wrap_chunks(chunks : [string]) -> [string] Wrap a sequence of text chunks and return a list of lines of length 'self.width' or less. Some lines may be longer than this. Chunks correspond roughly to words and the whitespace between them: each chunk is indivisible, but a line break can come between any two chunks. Chunks should not have internal whitespace; ie. a chunk is either all whitespace or a "word". Whitespace chunks will be removed from the beginning and end of lines, but apart from that whitespace is preserved. """ lines = [] # Arrange in reverse order so items can be efficiently popped # from a stack of chucks. chunks = list(reversed(chunks)) while chunks: # Start the list of chunks that will make up the current line. # cur_len is just the length of all the chunks in cur_line. cur_line = [] cur_len = 0 # Maximum width for this line. width = self.width # First chunk on line is a space -- drop it, unless this # is the very beginning of the text (ie. no lines started yet). if self.drop_whitespace and is_blank(chunks[-1]) and lines: chunks.pop() linebreak = False while chunks: length = self.chunklen(chunks[-1]) # Can at least squeeze this chunk onto the current line. if cur_len + length <= width: cur_line.append(chunks.pop()) cur_len += length # Nope, this line is full. else: linebreak = True break # The current line is full, and the next chunk is too big to # fit on *any* line (not just this one). if chunks and self.chunklen(chunks[-1]) > width: if not cur_line: cur_line.append(chunks.pop()) # Avoid whitespace at the beginining of split lines if (linebreak and self.drop_whitespace and cur_line and is_blank(cur_line[0])): cur_line.pop(0) # If the last chunk on this line is all a space, drop it. if self.drop_whitespace and cur_line and is_blank(cur_line[-1]): cur_line.pop() # Convert current line back to a string and store it in list # of all lines (return value). if cur_line: lines.append(''.join(cur_line)) return lines def chunklen(self, word): """Return length of a word taking tabs into account >>> w = TextWrapper(tabwidth=8) >>> w.chunklen("\\t\\t\\t\\tX") 33 """ return len(word.replace('\t', '')) + word.count('\t') * self.tabwidth # -- Public interface ---------------------------------------------- def wrap(self, text): """wrap(text : string) -> [string] Reformat the single paragraph in 'text' so it fits in lines of no more than 'self.width' columns, and return a list of wrapped lines. Tabs in 'text' are expanded with string.expandtabs(), and all other whitespace characters (including newline) are converted to space. """ chunks = self._split(text) return self._wrap_chunks(chunks) def fill(self, text): """fill(text : string) -> string Reformat the single paragraph in 'text' to fit in lines of no more than 'self.width' columns, and return a new string containing the entire wrapped paragraph. """ return "\n".join(self.wrap(text)) def word_wrap(text, tabwidth, limit, break_on_hyphens=False): """Wrap long lines to the specified limit""" lines = [] # Acked-by:, Signed-off-by:, Helped-by:, etc. special_tag_rgx = re.compile( r'^(' r'((' r'Acked-by|' r"Ack'd-by|" r'Based-on-patch-by|' r'Cheered-on-by|' r'Co-authored-by|' r'Comments-by|' r'Confirmed-by|' r'Contributions-by|' r'Debugged-by|' r'Discovered-by|' r'Explained-by|' r'Backtraced-by|' r'Helped-by|' r'Liked-by|' r'Link|' r'Improved-by|' r'Inspired-by|' r'Initial-patch-by|' r'Noticed-by|' r'Original-patch-by|' r'Originally-by|' r'Mentored-by|' r'Patch-by|' r'Proposed-by|' r'References|' r'Related-to|' r'Reported-by|' r'Requested-by|' r'Reviewed-by|' r'See-also|' r'Signed-off-by|' r'Signed-Off-by|' r'Spotted-by|' r'Suggested-by|' r'Tested-by|' r'Tested-on-([a-zA-Z-_]+)-by|' r'With-suggestions-by' r'):)' r'|([Cc]\.\s*[Ff]\.\s+)' r')') w = TextWrapper(width=limit, tabwidth=tabwidth, break_on_hyphens=break_on_hyphens, drop_whitespace=True) for line in text.split('\n'): if special_tag_rgx.match(line): lines.append(line) else: lines.append(w.fill(line)) return '\n'.join(lines) def is_blank(string): return string and not string.strip(' ') git-cola-3.6/cola/themes.py000066400000000000000000000453531356743264500156670ustar00rootroot00000000000000"""Provides themes generator""" from __future__ import absolute_import, division, unicode_literals from qtpy import QtGui from .i18n import N_ from .widgets import defs from . import icons from . import qtutils class EStylesheet(object): DEFAULT = 1 FLAT = 2 class Theme(object): def __init__(self, name, hr_name, is_dark, style_sheet=EStylesheet.DEFAULT, main_color=None): self.name = name self.hr_name = hr_name self.is_dark = is_dark self.style_sheet = style_sheet self.main_color = main_color def build_style_sheet(self, app_palette): if self.style_sheet == EStylesheet.FLAT: return self.style_sheet_flat() else: return self.style_sheet_default(app_palette) def build_palette(self, app_palette): QPalette = QtGui.QPalette palette_dark = app_palette.color(QPalette.Base).lightnessF() < 0.5 if palette_dark and self.is_dark: return app_palette if not palette_dark and not self.is_dark: return app_palette if self.is_dark: bg_color = QtGui.QColor('#202025') else: bg_color = QtGui.QColor('#edeef3') txt_color = QtGui.QColor('#777') palette = QPalette(bg_color) palette.setColor(QPalette.Base, bg_color) palette.setColor(QPalette.Disabled, QPalette.Text, txt_color) return palette @staticmethod def style_sheet_default(palette): window = palette.color(QtGui.QPalette.Window) highlight = palette.color(QtGui.QPalette.Highlight) shadow = palette.color(QtGui.QPalette.Shadow) base = palette.color(QtGui.QPalette.Base) window_rgb = qtutils.rgb_css(window) highlight_rgb = qtutils.rgb_css(highlight) shadow_rgb = qtutils.rgb_css(shadow) base_rgb = qtutils.rgb_css(base) return """ QCheckBox::indicator { width: %(checkbox_size)spx; height: %(checkbox_size)spx; } QCheckBox::indicator::unchecked { border: %(checkbox_border)spx solid %(shadow_rgb)s; background: %(base_rgb)s; } QCheckBox::indicator::checked { image: url(%(checkbox_icon)s); border: %(checkbox_border)spx solid %(shadow_rgb)s; background: %(base_rgb)s; } QRadioButton::indicator { width: %(radio_size)spx; height: %(radio_size)spx; } QRadioButton::indicator::unchecked { border: %(radio_border)spx solid %(shadow_rgb)s; border-radius: %(radio_radius)spx; background: %(base_rgb)s; } QRadioButton::indicator::checked { image: url(%(radio_icon)s); border: %(radio_border)spx solid %(shadow_rgb)s; border-radius: %(radio_radius)spx; background: %(base_rgb)s; } QSplitter::handle:hover { background: %(highlight_rgb)s; } QMainWindow::separator { background: %(window_rgb)s; width: %(separator)spx; height: %(separator)spx; } QMainWindow::separator:hover { background: %(highlight_rgb)s; } """ % dict(separator=defs.separator, window_rgb=window_rgb, highlight_rgb=highlight_rgb, shadow_rgb=shadow_rgb, base_rgb=base_rgb, checkbox_border=defs.border, checkbox_icon=icons.check_name(), checkbox_size=defs.checkbox, radio_border=defs.radio_border, radio_icon=icons.dot_name(), radio_radius=defs.radio//2, radio_size=defs.radio) def style_sheet_flat(self): main_color = self.main_color color = QtGui.QColor(main_color) color_rgb = qtutils.rgb_css(color) if self.is_dark: background = '#2e2f30' field = '#383a3c' grayed = '#06080a' button_text = '#000000' field_text = '#d0d0d0' darker = qtutils.hsl_css( color.hslHueF(), color.hslSaturationF()*0.3, color.lightnessF()*1.3 ) lighter = qtutils.hsl_css( color.hslHueF(), color.hslSaturationF()*0.7, color.lightnessF()*0.6 ) focus = qtutils.hsl_css( color.hslHueF(), color.hslSaturationF()*0.7, color.lightnessF()*0.7 ) else: background = '#edeef3' field = '#ffffff' grayed = '#a2a2b0' button_text = '#ffffff' field_text = '#000000' darker = qtutils.hsl_css( color.hslHueF(), color.hslSaturationF(), color.lightnessF()*0.4 ) lighter = qtutils.hsl_css( color.hslHueF(), color.hslSaturationF()*2, 0.92 ) focus = color_rgb return """ /* regular widgets */ * { background-color: %(background)s; color: %(field_text)s; selection-background-color: %(lighter)s; alternate-background-color: %(field)s; selection-color: %(field_text)s; show-decoration-selected: 1; spacing: 2px; } /* Focused widths get a thin border */ QTreeView:focus, QListView:focus, QLineEdit:focus, QTextEdit:focus, QPlainTextEdit:focus { border-width: 1px; border-style: solid; border-color: %(focus)s; } QWidget:disabled { border-color: %(grayed)s; color: %(grayed)s; } QDockWidget > QFrame { margin: 0 2px 2px 2px; min-height: 40px; } QPlainTextEdit, QLineEdit, QTextEdit, QAbstractItemView, QAbstractSpinBox { background-color: %(field)s; border-color: %(grayed)s; border-style: solid; border-width: 1px; } QAbstractItemView::item:selected { background-color: %(lighter)s; } QAbstractItemView::item:hover { background-color: %(lighter)s; } QLabel { color: %(darker)s; background-color: transparent; } DockTitleBarWidget { padding-bottom: 4px; } /* buttons */ QPushButton[flat="false"] { background-color: %(button)s; color: %(button_text)s; border-radius: 2px; border-width: 0; margin-bottom: 1px; min-width: 55px; padding: 4px 5px; } QPushButton[flat="true"], QToolButton { background-color: transparent; border-radius: 0px; } QPushButton[flat="true"] { margin-bottom: 10px; } QPushButton:hover, QToolButton:hover { background-color: %(darker)s; } QPushButton[flat="false"]:pressed, QToolButton:pressed { background-color: %(darker)s; margin: 1px 1px 2px 1px; } QPushButton:disabled { background-color: %(grayed)s; color: %(field)s; padding-left: 5px; padding-top: 5px; } QPushButton[flat="true"]:disabled { background-color: transparent; } /*menus*/ QMenuBar { background-color: %(background)s; color: %(field_text)s; border-width: 0; padding: 1px; } QMenuBar::item { background: transparent; } QMenuBar::item:selected { background: %(button)s; } QMenuBar::item:pressed { background: %(button)s; } QMenu { background-color: %(field)s; } QMenu::separator { background: %(background)s; height: 1px; } /* combo box */ QComboBox { background-color: %(field)s; border-color: %(grayed)s; border-style: solid; color: %(field_text)s; border-radius: 0px; border-width: 1px; margin-bottom: 1px; padding: 0 5px; } QComboBox::drop-down { border-color: %(field_text)s %(field)s %(field)s %(field)s; border-style: solid; subcontrol-position: right; border-width: 4px 3px 0 3px; height: 0; margin-right: 5px; width: 0; } QComboBox::drop-down:hover { border-color: %(button)s %(field)s %(field)s %(field)s; } QComboBox:item { background-color: %(button)s; color: %(button_text)s; border-width: 0; height: 22px; } QComboBox:item:selected { background-color: %(darker)s; color: %(button_text)s; } QComboBox:item:checked { background-color: %(darker)s; color: %(button_text)s; } /* MainWindow separator */ QMainWindow::separator { width: %(separator)spx; height: %(separator)spx; } QMainWindow::separator:hover { background: %(focus)s; } /* scroll bar */ QScrollBar { background-color: %(field)s; border: 0; } QScrollBar::handle { background: %(background)s } QScrollBar::handle:hover { background: %(button)s } QScrollBar:horizontal { margin: 0 11px 0 11px; height: 10px; } QScrollBar:vertical { margin: 11px 0 11px 0; width: 10px; } QScrollBar::add-line, QScrollBar::sub-line { background: %(background)s; subcontrol-origin: margin; } QScrollBar::sub-line:horizontal { /*required by a buggy Qt version*/ subcontrol-position: left; } QScrollBar::add-line:hover, QScrollBar::sub-line:hover { background: %(button)s; } QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { width: 10px; } QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { height: 10px; } QScrollBar:left-arrow, QScrollBar::right-arrow, QScrollBar::up-arrow, QScrollBar::down-arrow { border-style: solid; height: 0; width: 0; } QScrollBar:right-arrow { border-color: %(background)s %(background)s %(background)s %(darker)s; border-width: 3px 0 3px 4px; } QScrollBar:left-arrow { border-color: %(background)s %(darker)s %(background)s %(background)s; border-width: 3px 4px 3px 0; } QScrollBar:up-arrow { border-color: %(background)s %(background)s %(darker)s %(background)s; border-width: 0 3px 4px 3px; } QScrollBar:down-arrow { border-color: %(darker)s %(background)s %(background)s %(background)s; border-width: 4px 3px 0 3px; } QScrollBar:right-arrow:hover { border-color: %(button)s %(button)s %(button)s %(darker)s; } QScrollBar:left-arrow:hover { border-color: %(button)s %(darker)s %(button)s %(button)s; } QScrollBar:up-arrow:hover { border-color: %(button)s %(button)s %(darker)s %(button)s; } QScrollBar:down-arrow:hover { border-color: %(darker)s %(button)s %(button)s %(button)s; } /* tab bar (stacked & docked widgets) */ QTabBar::tab { background: transparent; border-color: %(darker)s; border-width: 1px; margin: 1px; padding: 3px 5px; } QTabBar::tab:selected { background: %(grayed)s; } /* check box */ QCheckBox { spacing: 8px; margin: 4px; background-color: transparent; } QCheckBox::indicator { background-color: %(field)s; border-color: %(darker)s; border-style: solid; subcontrol-position: left; border-width: 1px; height: 13px; width: 13px; } QCheckBox::indicator:unchecked:hover { background-color: %(button)s; } QCheckBox::indicator:unchecked:pressed { background-color: %(darker)s; } QCheckBox::indicator:checked { background-color: %(darker)s; } QCheckBox::indicator:checked:hover { background-color: %(button)s; } QCheckBox::indicator:checked:pressed { background-color: %(field)s; } /* radio checkbox */ QRadioButton { spacing: 8px; margin: 4px; } QRadioButton::indicator { height: 0.75em; width: 0.75em; } /* progress bar */ QProgressBar { background-color: %(field)s; border: 1px solid %(darker)s; } QProgressBar::chunk { background-color: %(button)s; width: 1px; } /* spin box */ QAbstractSpinBox::up-button, QAbstractSpinBox::down-button { background-color: transparent; } QAbstractSpinBox::up-arrow, QAbstractSpinBox::down-arrow { border-style: solid; height: 0; width: 0; } QAbstractSpinBox::up-arrow { border-color: %(field)s %(field)s %(darker)s %(field)s; border-width: 0 3px 4px 3px; } QAbstractSpinBox::up-arrow:hover { border-color: %(field)s %(field)s %(button)s %(field)s; border-width: 0 3px 4px 3px; } QAbstractSpinBox::down-arrow { border-color: %(darker)s %(field)s %(field)s %(field)s; border-width: 4px 3px 0 3px; } QAbstractSpinBox::down-arrow:hover { border-color: %(button)s %(field)s %(field)s %(field)s; border-width: 4px 3px 0 3px; } /* dialogs */ QDialog > QFrame { margin: 2px 2px 2px 2px; } /* headers */ QHeaderView { color: %(field_text)s; border-style: solid; border-width: 0 0 1px 0; border-color: %(grayed)s; } QHeaderView::section { border-style: solid; border-right: 1px solid %(grayed)s; background-color: %(background)s; color: %(field_text)s; padding-left: 4px; } /* headers */ QHeaderView { color: %(field_text)s; border-style: solid; border-width: 0 0 1px 0; border-color: %(grayed)s; } QHeaderView::section { border-style: solid; border-right: 1px solid %(grayed)s; background-color: %(background)s; color: %(field_text)s; padding-left: 4px; } """ % dict(background=background, field=field, button=color_rgb, darker=darker, lighter=lighter, grayed=grayed, button_text=button_text, field_text=field_text, separator=defs.separator, focus=focus) def get_all_themes(): return [ Theme('default', N_('Default'), False, EStylesheet.DEFAULT, None), Theme('flat-light-blue', N_('Flat light blue'), False, EStylesheet.FLAT, '#5271cc'), Theme('flat-light-red', N_('Flat light red'), False, EStylesheet.FLAT, '#cc5452'), Theme('flat-light-grey', N_('Flat light grey'), False, EStylesheet.FLAT, '#707478'), Theme('flat-light-green', N_('Flat light green'), False, EStylesheet.FLAT, '#42a65c'), Theme('flat-dark-blue', N_('Flat dark blue'), True, EStylesheet.FLAT, '#5271cc'), Theme('flat-dark-red', N_('Flat dark red'), True, EStylesheet.FLAT, '#cc5452'), Theme('flat-dark-grey', N_('Flat dark grey'), True, EStylesheet.FLAT, '#aaaaaa'), Theme('flat-dark-green', N_('Flat dark green'), True, EStylesheet.FLAT, '#42a65c') ] def options(): """Return a dictionary mapping display names to theme names""" items = get_all_themes() return [(item.hr_name, item.name) for item in items] def find_theme(name): themes = get_all_themes() for item in themes: if item.name == name: return item return themes[0] git-cola-3.6/cola/utils.py000066400000000000000000000220141356743264500155270ustar00rootroot00000000000000# Copyright (C) 2007-2018 David Aguilar and contributors """This module provides miscellaneous utility functions.""" from __future__ import division, absolute_import, unicode_literals import copy import os import random import re import shlex import sys import tempfile import time import traceback from . import core from . import compat random.seed(hash(time.time())) def asint(obj, default=0): """Make any value into an int, even if the cast fails""" try: value = int(obj) except (TypeError, ValueError): value = default return value def clamp(value, lo, hi): """Clamp a value to the specified range""" return min(hi, max(lo, value)) def epoch_millis(): return int(time.time() * 1000) def add_parents(paths): """Iterate over each item in the set and add its parent directories.""" all_paths = set() for path in paths: while '//' in path: path = path.replace('//', '/') all_paths.add(path) if '/' in path: parent_dir = dirname(path) while parent_dir: all_paths.add(parent_dir) parent_dir = dirname(parent_dir) return all_paths def format_exception(e): exc_type, exc_value, exc_tb = sys.exc_info() details = traceback.format_exception(exc_type, exc_value, exc_tb) details = '\n'.join(map(core.decode, details)) if hasattr(e, 'msg'): msg = e.msg else: msg = core.decode(repr(e)) return (msg, details) def sublist(a, b): """Subtracts list b from list a and returns the resulting list.""" # conceptually, c = a - b c = [] for item in a: if item not in b: c.append(item) return c __grep_cache = {} def grep(pattern, items, squash=True): """Greps a list for items that match a pattern :param squash: If only one item matches, return just that item :returns: List of matching items """ isdict = isinstance(items, dict) if pattern in __grep_cache: regex = __grep_cache[pattern] else: regex = __grep_cache[pattern] = re.compile(pattern) matched = [] matchdict = {} for item in items: match = regex.match(item) if not match: continue groups = match.groups() if not groups: subitems = match.group(0) else: if len(groups) == 1: subitems = groups[0] else: subitems = list(groups) if isdict: matchdict[item] = items[item] else: matched.append(subitems) if isdict: result = matchdict elif squash and len(matched) == 1: result = matched[0] else: result = matched return result def basename(path): """ An os.path.basename() implementation that always uses '/' Avoid os.path.basename because git's output always uses '/' regardless of platform. """ return path.rsplit('/', 1)[-1] def strip_one(path): """Strip one level of directory""" return path.strip('/').split('/', 1)[-1] def dirname(path, current_dir=''): """ An os.path.dirname() implementation that always uses '/' Avoid os.path.dirname because git's output always uses '/' regardless of platform. """ while '//' in path: path = path.replace('//', '/') path_dirname = path.rsplit('/', 1)[0] if path_dirname == path: return current_dir return path.rsplit('/', 1)[0] def splitpath(path): """Split paths using '/' regardless of platform """ return path.split('/') def join(*paths): """Join paths using '/' regardless of platform """ return '/'.join(paths) def pathset(path): """Return all of the path components for the specified path >>> pathset('foo/bar/baz') == ['foo', 'foo/bar', 'foo/bar/baz'] True """ result = [] parts = splitpath(path) prefix = '' for part in parts: result.append(prefix + part) prefix += part + '/' return result def select_directory(paths): """Return the first directory in a list of paths""" if not paths: return core.getcwd() for path in paths: if core.isdir(path): return path return os.path.dirname(paths[0]) def strip_prefix(prefix, string): """Return string, without the prefix. Blow up if string doesn't start with prefix.""" assert string.startswith(prefix) return string[len(prefix):] def sanitize(s): """Removes shell metacharacters from a string.""" for c in """ \t!@#$%^&*()\\;,<>"'[]{}~|""": s = s.replace(c, '_') return s def tablength(word, tabwidth): """Return length of a word taking tabs into account >>> tablength("\\t\\t\\t\\tX", 8) 33 """ return len(word.replace('\t', '')) + word.count('\t') * tabwidth def _shell_split_py2(s): """Python2 requires bytes inputs to shlex.split(). Returns [unicode]""" try: result = shlex.split(core.encode(s)) except ValueError: result = core.encode(s).strip().split() # Decode to unicode strings return [core.decode(arg) for arg in result] def _shell_split_py3(s): """Python3 requires unicode inputs to shlex.split(). Converts to unicode""" try: result = shlex.split(s) except ValueError: result = core.decode(s).strip().split() # Already unicode return result def shell_split(s): if compat.PY2: # Encode before calling split() values = _shell_split_py2(s) else: # Python3 does not need the encode/decode dance values = _shell_split_py3(s) return values def tmp_filename(label, suffix=''): label = 'git-cola-' + label.replace('/', '-').replace('\\', '-') fd = tempfile.NamedTemporaryFile(prefix=label+'-', suffix=suffix) fd.close() return fd.name def is_linux(): """Is this a linux machine?""" return sys.platform.startswith('linux') def is_debian(): """Is it debian?""" return os.path.exists('/usr/bin/apt-get') def is_darwin(): """Return True on OSX.""" return sys.platform == 'darwin' def is_win32(): """Return True on win32""" return sys.platform == 'win32' or sys.platform == 'cygwin' def expandpath(path): """Expand ~user/ and environment $variables""" path = os.path.expandvars(path) if path.startswith('~'): path = os.path.expanduser(path) return path class Group(object): """Operate on a collection of objects as a single unit""" def __init__(self, *members): self._members = members def __getattr__(self, name): """Return a function that relays calls to the group""" def relay(*args, **kwargs): for member in self._members: method = getattr(member, name) method(*args, **kwargs) setattr(self, name, relay) return relay class Proxy(object): """Wrap an object and override attributes""" def __init__(self, obj, **overrides): self._obj = obj for k, v in overrides.items(): setattr(self, k, v) def __getattr__(self, name): return getattr(self._obj, name) def slice_fn(input_items, map_fn): """Slice input_items and call map_fn over every slice This exists because of "errno: Argument list too long" """ # This comment appeared near the top of include/linux/binfmts.h # in the Linux source tree: # # /* # * MAX_ARG_PAGES defines the number of pages allocated for arguments # * and envelope for the new program. 32 should suffice, this gives # * a maximum env+arg of 128kB w/4KB pages! # */ # #define MAX_ARG_PAGES 32 # # 'size' is a heuristic to keep things highly performant by minimizing # the number of slices. If we wanted it to run as few commands as # possible we could call "getconf ARG_MAX" and make a better guess, # but it's probably not worth the complexity (and the extra call to # getconf that we can't do on Windows anyways). # # In my testing, getconf ARG_MAX on Mac OS X Mountain Lion reported # 262144 and Debian/Linux-x86_64 reported 2097152. # # The hard-coded max_arg_len value is safely below both of these # real-world values. # 4K pages x 32 MAX_ARG_PAGES max_arg_len = (32 * 4096) // 4 # allow plenty of space for the environment max_filename_len = 256 size = max_arg_len // max_filename_len status = 0 outs = [] errs = [] items = copy.copy(input_items) while items: stat, out, err = map_fn(items[:size]) if stat < 0: status = min(stat, status) else: status = max(stat, status) outs.append(out) errs.append(err) items = items[size:] return (status, '\n'.join(outs), '\n'.join(errs)) class seq(object): def __init__(self, sequence): self.seq = sequence def index(self, item, default=-1): try: idx = self.seq.index(item) except ValueError: idx = default return idx def __getitem__(self, idx): return self.seq[idx] git-cola-3.6/cola/version.py000066400000000000000000000064501356743264500160620ustar00rootroot00000000000000# Copyright (C) 2007-2018 David Aguilar and contributors """Provide git-cola's version number""" from __future__ import division, absolute_import, unicode_literals import os import sys if __name__ == '__main__': srcdir = os.path.dirname(os.path.dirname(__file__)) sys.path.insert(1, srcdir) from .git import STDOUT # noqa from .decorators import memoize # noqa from ._version import VERSION # noqa try: from ._build_version import BUILD_VERSION except ImportError: BUILD_VERSION = '' # minimum version requirements _versions = { # git diff learned --patience in 1.6.2 # git mergetool learned --no-prompt in 1.6.2 # git difftool moved out of contrib in git 1.6.3 'git': '1.6.3', 'python': '2.6', # new: git cat-file --filters --path= SHA1 # old: git cat-file --filters blob SHA1: 'cat-file-filters-path': '2.11.0', # git diff --submodule was introduced in 1.6.6 'diff-submodule': '1.6.6', # git check-ignore was introduced in 1.8.2, but did not follow the same # rules as git add and git status until 1.8.5 'check-ignore': '1.8.5', # git push --force-with-lease 'force-with-lease': '1.8.5', # git for-each-ref --sort=version:refname 'version-sort': '2.7.0', # Qt support for QT_AUTO_SCREEN_SCALE_FACTOR and QT_SCALE_FACTOR 'qt-hidpi-scale': '5.6.0', # git rev-parse --show-superproject-working-tree was added in 2.13.0 'show-superproject-working-tree': '2.13.0', } def get(key): """Returns an entry from the known versions table""" return _versions.get(key) def version(): """Returns the current version""" return VERSION def build_version(): """Return the build version, which includes the Git ID""" return BUILD_VERSION @memoize def check_version(min_ver, ver): """Check whether ver is greater or equal to min_ver """ min_ver_list = version_to_list(min_ver) ver_list = version_to_list(ver) return min_ver_list <= ver_list @memoize def check(key, ver): """Checks if a version is greater than the known version for """ return check_version(get(key), ver) def check_git(context, key): """Checks if Git has a specific feature""" return check(key, git_version(context)) def version_to_list(value): """Convert a version string to a list of numbers or strings """ ver_list = [] for p in value.split('.'): try: n = int(p) except ValueError: n = p ver_list.append(n) return ver_list @memoize def git_version_str(context): """Returns the current GIT version""" git = context.git return git.version()[STDOUT].strip() @memoize def git_version(context): """Returns the current GIT version""" parts = git_version_str(context).split() if parts and len(parts) >= 3: result = parts[2] else: # minimum supported version result = '1.6.3' return result def cola_version(build=False): if build: suffix = build_version() or version() else: suffix = version() return 'cola version %s' % suffix def print_version(brief=False, build=False): if brief: if build: msg = build_version() else: msg = version() else: msg = cola_version(build=build) sys.stdout.write('%s\n' % msg) git-cola-3.6/cola/widgets/000077500000000000000000000000001356743264500154645ustar00rootroot00000000000000git-cola-3.6/cola/widgets/__init__.py000066400000000000000000000000001356743264500175630ustar00rootroot00000000000000git-cola-3.6/cola/widgets/about.py000066400000000000000000000445071356743264500171620ustar00rootroot00000000000000# encoding: utf-8 from __future__ import division, absolute_import, unicode_literals import platform import webbrowser import sys import qtpy from qtpy.QtCore import Qt from qtpy import QtGui from qtpy import QtWidgets from ..i18n import N_ from .. import core from .. import resources from .. import hotkeys from .. import icons from .. import qtutils from .. import version from . import defs def about_dialog(context): """Launches the Help -> About dialog""" view = AboutView(context, qtutils.active_window()) view.show() return view class ExpandingTabBar(QtWidgets.QTabBar): """A TabBar with tabs that expand to fill the empty space The setExpanding(True) method does not work in practice because it respects the OS style. We override the style by implementing tabSizeHint() so that we can specify the size explicitly. """ def tabSizeHint(self, tab_index): width = self.parent().width() / max(1, self.count()) - 1 size = super(ExpandingTabBar, self).tabSizeHint(tab_index) size.setWidth(width) return size class ExpandingTabWidget(QtWidgets.QTabWidget): def __init__(self, parent=None): super(ExpandingTabWidget, self).__init__(parent) self.setTabBar(ExpandingTabBar(self)) def resizeEvent(self, event): """Forward resize events to the ExpandingTabBar""" # Qt does not resize the tab bar when the dialog is resized # so manually forward resize events to the tab bar. width = event.size().width() height = self.tabBar().height() self.tabBar().resize(width, height) return super(ExpandingTabWidget, self).resizeEvent(event) class AboutView(QtWidgets.QDialog): """Provides the git-cola 'About' dialog""" def __init__(self, context, parent=None): QtWidgets.QDialog.__init__(self, parent) self.context = context self.setWindowTitle(N_('About git-cola')) self.setWindowModality(Qt.WindowModal) # Top-most large icon logo_pixmap = icons.cola().pixmap(defs.huge_icon, defs.large_icon) self.logo_label = QtWidgets.QLabel() self.logo_label.setPixmap(logo_pixmap) self.logo_label.setAlignment(Qt.AlignCenter) self.logo_text_label = QtWidgets.QLabel() self.logo_text_label.setText('Git Cola') self.logo_text_label.setAlignment(Qt.AlignLeft | Qt.AlignCenter) font = self.logo_text_label.font() font.setPointSize(defs.logo_text) self.logo_text_label.setFont(font) self.text = qtutils.textbrowser(text=copyright_text()) self.version = qtutils.textbrowser(text=version_text(context)) self.authors = qtutils.textbrowser(text=authors_text()) self.translators = qtutils.textbrowser(text=translators_text()) self.tabs = ExpandingTabWidget() self.tabs.addTab(self.text, N_('About')) self.tabs.addTab(self.version, N_('Version')) self.tabs.addTab(self.authors, N_('Authors')) self.tabs.addTab(self.translators, N_('Translators')) self.close_button = qtutils.close_button() self.close_button.setDefault(True) self.logo_layout = qtutils.hbox(defs.no_margin, defs.button_spacing, self.logo_label, self.logo_text_label, qtutils.STRETCH) self.button_layout = qtutils.hbox(defs.spacing, defs.margin, qtutils.STRETCH, self.close_button) self.main_layout = qtutils.vbox(defs.no_margin, defs.spacing, self.logo_layout, self.tabs, self.button_layout) self.setLayout(self.main_layout) qtutils.connect_button(self.close_button, self.accept) self.resize(defs.scale(600), defs.scale(720)) def copyright_text(): return """ Git Cola: The highly caffeinated Git GUI Copyright (C) 2007-2018 David Aguilar and contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. """ def version_text(context): git_version = version.git_version(context) cola_version = version.version() build_version = version.build_version() python_path = sys.executable python_version = sys.version qt_version = qtpy.QT_VERSION qtpy_version = qtpy.__version__ pyqt_api_name = qtpy.API_NAME if qtpy.PYQT5 or qtpy.PYQT4: pyqt_api_version = qtpy.PYQT_VERSION elif qtpy.PYSIDE: pyqt_api_version = qtpy.PYSIDE_VERSION else: pyqt_api_version = 'unknown' platform_version = platform.platform() # Only show the build version if _build_version.py exists if build_version: build_version = '(%s)' % build_version else: build_version = '' scope = dict( cola_version=cola_version, build_version=build_version, git_version=git_version, platform_version=platform_version, pyqt_api_name=pyqt_api_name, pyqt_api_version=pyqt_api_version, python_path=python_path, python_version=python_version, qt_version=qt_version, qtpy_version=qtpy_version) return N_("""
Git Cola version %(cola_version)s %(build_version)s
  • %(platform_version)s
  • Python (%(python_path)s) %(python_version)s
  • Git %(git_version)s
  • Qt %(qt_version)s
  • QtPy %(qtpy_version)s
  • %(pyqt_api_name)s %(pyqt_api_version)s
""") % scope def link(url, text, palette=None): if palette is None: palette = QtGui.QPalette() color = palette.color(QtGui.QPalette.Foreground) rgb = 'rgb(%s, %s, %s)' % (color.red(), color.green(), color.blue()) scope = dict(rgb=rgb, text=text, url=url) return """ %(text)s """ % scope def mailto(email, text, palette): return link('mailto:%s' % email, text, palette) + '
' def render_authors(authors): """Render a list of author details into richtext html""" for x in authors: x.setdefault('email', '') entries = [("""

%(name)s
%(title)s
%(email)s

""" % author) for author in authors] return ''.join(entries) def contributors_text(authors, prelude='', epilogue=''): author_text = render_authors(authors) scope = dict(author_text=author_text, epilogue=epilogue, prelude=prelude) return """ %(prelude)s %(author_text)s %(epilogue)s """ % scope def authors_text(): palette = QtGui.QPalette() contact = N_('Email contributor') authors = ( # The names listed here are listed in the same order as # `git shortlog --summary --numbered --no-merges` # Please submit a pull request if you would like to include your # email address in the about screen. # See the `generate-about` script in the "todo" branch. # vim :read! ./Meta/generate-about dict(name='David Aguilar', title=N_('Maintainer (since 2007) and developer'), email=mailto('davvid@gmail.com', contact, palette)), dict(name='Daniel Harding', title=N_('Developer')), dict(name='V字龍(Vdragon)', title=N_('Developer'), email=mailto('Vdragon.Taiwan@gmail.com', contact, palette)), dict(name='Efimov Vasily', title=N_('Developer')), dict(name='Guillaume de Bure', title=N_('Developer')), dict(name='Javier Rodriguez Cuevas', title=N_('Developer')), dict(name='Uri Okrent', title=N_('Developer')), dict(name='Alex Chernetz', title=N_('Developer')), dict(name='xhl', title=N_('Developer')), dict(name='Andreas Sommer', title=N_('Developer')), dict(name='Thomas Kluyver', title=N_('Developer')), dict(name='Minarto Margoliono', title=N_('Developer')), dict(name='Szymon Judasz', title=N_('Developer')), dict(name='Ville Skyttä', title=N_('Developer')), dict(name='jm4R', title=N_('Developer')), dict(name='Igor Galarraga', title=N_('Developer')), dict(name='Stanislaw Halik', title=N_('Developer')), dict(name='Virgil Dupras', title=N_('Developer')), dict(name='Barry Roberts', title=N_('Developer')), dict(name='wsdfhjxc', title=N_('Developer')), dict(name='林博仁(Buo-ren Lin)', title=N_('Developer')), dict(name='Guo Yunhe', title=N_('Developer')), dict(name='cclauss', title=N_('Developer')), dict(name='Stefan Naewe', title=N_('Developer')), dict(name='Victor Nepveu', title=N_('Developer')), dict(name='Benedict Lee', title=N_('Developer')), dict(name='Filip Danilović', title=N_('Developer')), dict(name='NotSqrt', title=N_('Developer')), dict(name='Pavel Rehak', title=N_('Developer')), dict(name='Steffen Prohaska', title=N_('Developer')), dict(name='Tim Brown', title=N_('Developer')), dict(name='Michael Geddes', title=N_('Developer')), dict(name='Rustam Safin', title=N_('Developer')), dict(name='Alex Gulyás', title=N_('Developer')), dict(name='David Martínez Martí', title=N_('Developer')), dict(name='Hualiang Xie', title=N_('Developer')), dict(name='Justin Lecher', title=N_('Developer')), dict(name='Kai Krakow', title=N_('Developer')), dict(name='Karl Bielefeldt', title=N_('Developer')), dict(name='Marco Costalba', title=N_('Developer')), dict(name='Michael Homer', title=N_('Developer')), dict(name='Sebastian Schuberth', title=N_('Developer')), dict(name='Sven Claussner', title=N_('Developer')), dict(name='bsomers', title=N_('Developer')), dict(name='real', title=N_('Developer')), dict(name='v.paritskiy', title=N_('Developer')), dict(name='0xflotus', title=N_('Developer')), dict(name='AJ Bagwell', title=N_('Developer')), dict(name='Adrien be', title=N_('Developer')), dict(name='Andrej', title=N_('Developer')), dict(name='Arthur Coelho', title=N_('Developer')), dict(name='Audrius Karabanovas', title=N_('Developer')), dict(name='Barrett Lowe', title=N_('Developer')), dict(name='Ben Boeckel', title=N_('Developer')), dict(name='Boris W', title=N_('Developer')), dict(name='Charles', title=N_('Developer')), dict(name='Clément Pit--Claudel', title=N_('Developer')), dict(name='Daniel Haskin', title=N_('Developer')), dict(name='Daniel King', title=N_('Developer')), dict(name='Daniel Pavel', title=N_('Developer')), dict(name='David Zumbrunnen', title=N_('Developer')), dict(name='Felipe Morales', title=N_('Developer')), dict(name='George Vasilakos', title=N_('Developer')), dict(name='Ilya Tumaykin', title=N_('Developer')), dict(name='Iulian Udrea', title=N_('Developer')), dict(name='Jake Biesinger', title=N_('Developer')), dict(name='Jakub Szymański', title=N_('Developer')), dict(name='Jamie Pate', title=N_('Developer')), dict(name='Jean-Francois Dagenais', title=N_('Developer')), dict(name='Joachim Lusiardi', title=N_('Developer')), dict(name='Karthik Manamcheri', title=N_('Developer')), dict(name='Kelvie Wong', title=N_('Developer')), dict(name='Kyle', title=N_('Developer')), dict(name='Maciej Filipiak', title=N_('Developer')), dict(name='Maicon D. Filippsen', title=N_('Developer')), dict(name='Markus Heidelberg', title=N_('Developer')), dict(name='Matthew E. Levine', title=N_('Developer')), dict(name='Matthias Mailänder', title=N_('Developer')), dict(name='Md. Mahbub Alam', title=N_('Developer')), dict(name='Mikhail Terekhov', title=N_('Developer')), dict(name='Paul Hildebrandt', title=N_('Developer')), dict(name='Paul Weingardt', title=N_('Developer')), dict(name='Paulo Fidalgo', title=N_('Developer')), dict(name='Petr Gladkikh', title=N_('Developer')), dict(name='Philip Stark', title=N_('Developer')), dict(name='Radek Postołowicz', title=N_('Developer')), dict(name='Rainer Müller', title=N_('Developer')), dict(name='Ricardo J. Barberis', title=N_('Developer')), dict(name='Rolando Espinoza', title=N_('Developer')), dict(name="Samsul Ma'arif", title=N_('Developer')), dict(name='Sebastian Brass', title=N_('Developer')), dict(name='Simon Peeters', title=N_('Developer')), dict(name='Stephen', title=N_('Developer')), dict(name='Vaibhav Sagar', title=N_('Developer')), dict(name='Ved Vyas', title=N_('Developer')), dict(name='Voicu Hodrea', title=N_('Developer')), dict(name='Wesley Wong', title=N_('Developer')), dict(name='Wolfgang Ocker', title=N_('Developer')), dict(name='Zhang Han', title=N_('Developer')), dict(name='beauxq', title=N_('Developer')), dict(name='ochristi', title=N_('Developer')), ) bug_url = 'https://github.com/git-cola/git-cola/issues' bug_link = link(bug_url, bug_url) scope = dict(bug_link=bug_link) prelude = N_("""
Please use %(bug_link)s to report issues.
""") % scope return contributors_text(authors, prelude=prelude) def translators_text(): palette = QtGui.QPalette() contact = N_('Email contributor') translators = ( # See the `generate-about` script in the "todo" branch. # vim :read! ./Meta/generate-about --translators dict(name='V字龍(Vdragon)', title=N_('Traditional Chinese (Taiwan) translation'), email=mailto('Vdragon.Taiwan@gmail.com', contact, palette)), dict(name='Pavel Rehak', title=N_('Czech translation')), dict(name='Victorhck', title=N_('Spanish translation')), dict(name='Vitor Lobo', title=N_('Brazilian translation')), dict(name='Zhang Han', title=N_('Simplified Chinese translation')), dict(name='Igor Kopach', title=N_('Ukranian translation')), dict(name='Barış ÇELİK', title=N_('Turkish translation')), dict(name='Guo Yunhe', title=N_('Simplified Chinese translation')), dict(name='Minarto Margoliono', title=N_('Indonesian translation')), dict(name='Rafael Nascimento', title=N_('Brazilian translation')), dict(name='Shun Sakai', title=N_('Japanese translation')), dict(name='Sven Claussner', title=N_('German translation')), dict(name='Vaiz', title=N_('Russian translation')), dict(name='adlgrbz', title=N_('Turkish translation')), dict(name='fu7mu4', title=N_('Japanese translation')), dict(name='Gyuris Gellért', title=N_('Hungarian translation')), dict(name='Joachim Lusiardi', title=N_('German translation')), dict(name='Kai Krakow', title=N_('German translation')), dict(name='Louis Rousseau', title=N_('French translation')), dict(name='Mickael Albertus', title=N_('French translation')), dict(name='Peter Dave Hello', title=N_('Traditional Chinese (Taiwan) translation')), dict(name='Pilar Molina Lopez', title=N_('Spanish translation')), dict(name='Rafael Reuber', title=N_('Brazilian translation')), dict(name='Sabri Ünal', title=N_('Turkish translation')), dict(name="Samsul Ma'arif", title=N_('Indonesian translation')), dict(name='Zeioth', title=N_('Spanish translation')), dict(name='balping', title=N_('Hungarian translation')), dict(name='p-bo', title=N_('Czech translation')), dict(name='Łukasz Wojniłowicz', title=N_('Polish translation')), dict(name='林博仁(Buo-ren Lin)', title=N_('Traditional Chinese (Taiwan) translation')), ) bug_url = 'https://github.com/git-cola/git-cola/issues' bug_link = link(bug_url, bug_url) scope = dict(bug_link=bug_link) prelude = N_("""
Git Cola has been translated into different languages thanks to the help of the individuals listed below.

Translation is approximate. If you find a mistake, please let us know by opening an issue on Github:

%(bug_link)s


We invite you to participate in translation by adding or updating a translation and opening a pull request.


""") % scope return contributors_text(translators, prelude=prelude) def show_shortcuts(): hotkeys_html = resources.doc(N_('hotkeys.html')) try: from qtpy import QtWebEngineWidgets except (ImportError, qtpy.PythonQtError): # redhat disabled QtWebKit in their qt build but don't punish the users webbrowser.open_new_tab('file://' + hotkeys_html) return html = core.read(hotkeys_html) parent = qtutils.active_window() widget = QtWidgets.QDialog(parent) widget.setWindowModality(Qt.WindowModal) widget.setWindowTitle(N_('Shortcuts')) web = QtWebEngineWidgets.QWebEngineView() web.setHtml(html) layout = qtutils.hbox(defs.no_margin, defs.spacing, web) widget.setLayout(layout) widget.resize(800, min(parent.height(), 600)) qtutils.add_action(widget, N_('Close'), widget.accept, hotkeys.QUESTION, *hotkeys.ACCEPT) widget.show() widget.exec_() git-cola-3.6/cola/widgets/action.py000066400000000000000000000061601356743264500173160ustar00rootroot00000000000000"""The "Actions" widget""" from __future__ import division, absolute_import, unicode_literals from functools import partial from qtpy import QtCore from qtpy import QtWidgets from .. import cmds from .. import qtutils from ..i18n import N_ from ..widgets import defs from ..widgets import remote from ..widgets import stash from ..qtutils import create_button from ..qtutils import connect_button class QFlowLayoutWidget(QtWidgets.QFrame): _horizontal = QtWidgets.QBoxLayout.LeftToRight _vertical = QtWidgets.QBoxLayout.TopToBottom def __init__(self, parent): QtWidgets.QFrame.__init__(self, parent) self._direction = self._vertical self._layout = layout = QtWidgets.QBoxLayout(self._direction) layout.setSpacing(defs.spacing) qtutils.set_margin(layout, defs.margin) self.setLayout(layout) policy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) self.setSizePolicy(policy) self.setMinimumSize(QtCore.QSize(1, 1)) self.aspect_ratio = 0.8 def resizeEvent(self, event): size = event.size() if size.width() * self.aspect_ratio < size.height(): dxn = self._vertical else: dxn = self._horizontal if dxn != self._direction: self._direction = dxn self.layout().setDirection(dxn) def tooltip_button(text, layout): button = create_button(text, layout=layout) button.setToolTip(text) return button class ActionButtons(QFlowLayoutWidget): def __init__(self, context, parent=None): QFlowLayoutWidget.__init__(self, parent) layout = self.layout() self.context = context self.stage_button = tooltip_button(N_('Stage'), layout) self.unstage_button = tooltip_button(N_('Unstage'), layout) self.refresh_button = tooltip_button(N_('Refresh'), layout) self.fetch_button = tooltip_button(N_('Fetch...'), layout) self.push_button = tooltip_button(N_('Push...'), layout) self.pull_button = tooltip_button(N_('Pull...'), layout) self.stash_button = tooltip_button(N_('Stash...'), layout) self.aspect_ratio = 0.4 layout.addStretch() self.setMinimumHeight(30) # Add callbacks connect_button(self.refresh_button, cmds.run(cmds.Refresh, context)) connect_button(self.fetch_button, partial(remote.fetch, context)) connect_button(self.push_button, partial(remote.push, context)) connect_button(self.pull_button, partial(remote.pull, context)) connect_button(self.stash_button, partial(stash.view, context)) connect_button(self.stage_button, cmds.run(cmds.StageSelected, context)) connect_button(self.unstage_button, self.unstage) def unstage(self): """Unstage selected files, or all files if no selection exists.""" context = self.context paths = context.selection.staged context = self.context if not paths: cmds.do(cmds.UnstageAll, context) else: cmds.do(cmds.Unstage, context, paths) git-cola-3.6/cola/widgets/archive.py000066400000000000000000000206531356743264500174650ustar00rootroot00000000000000"""Git Archive dialog""" from __future__ import division, absolute_import, unicode_literals import os from qtpy import QtCore from qtpy import QtWidgets from qtpy.QtCore import Qt from qtpy.QtCore import Signal from ..git import STDOUT from ..i18n import N_ from ..interaction import Interaction from .. import cmds from .. import core from .. import icons from .. import qtutils from .text import LineEdit from .standard import Dialog from . import defs class ExpandableGroupBox(QtWidgets.QGroupBox): expanded = Signal(bool) def __init__(self, parent=None): QtWidgets.QGroupBox.__init__(self, parent) self.setFlat(True) self.is_expanded = True self.click_pos = None self.arrow_icon_size = defs.small_icon def set_expanded(self, expanded): if expanded == self.is_expanded: self.expanded.emit(expanded) return self.is_expanded = expanded for widget in self.findChildren(QtWidgets.QWidget): widget.setHidden(not expanded) self.expanded.emit(expanded) def mousePressEvent(self, event): if event.button() == Qt.LeftButton: option = QtWidgets.QStyleOptionGroupBox() self.initStyleOption(option) icon_size = defs.small_icon button_area = QtCore.QRect(0, 0, icon_size, icon_size) offset = icon_size + defs.spacing adjusted = option.rect.adjusted(0, 0, -offset, 0) top_left = adjusted.topLeft() button_area.moveTopLeft(QtCore.QPoint(top_left)) self.click_pos = event.pos() QtWidgets.QGroupBox.mousePressEvent(self, event) def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton and self.click_pos == event.pos(): self.set_expanded(not self.is_expanded) QtWidgets.QGroupBox.mouseReleaseEvent(self, event) def paintEvent(self, _event): painter = QtWidgets.QStylePainter(self) option = QtWidgets.QStyleOptionGroupBox() self.initStyleOption(option) painter.save() painter.translate(self.arrow_icon_size + defs.spacing, 0) painter.drawText(option.rect, Qt.AlignLeft, self.title()) painter.restore() style = QtWidgets.QStyle point = option.rect.adjusted(0, -4, 0, 0).topLeft() icon_size = self.arrow_icon_size option.rect = QtCore.QRect(point.x(), point.y(), icon_size, icon_size) if self.is_expanded: painter.drawPrimitive(style.PE_IndicatorArrowDown, option) else: painter.drawPrimitive(style.PE_IndicatorArrowRight, option) def save_archive(context): oid = context.git.rev_parse('HEAD')[STDOUT] show_save_dialog(context, oid, parent=qtutils.active_window()) def show_save_dialog(context, oid, parent=None): shortoid = oid[:7] dlg = Archive(context, oid, shortoid, parent=parent) dlg.show() if dlg.exec_() != dlg.Accepted: return None return dlg class Archive(Dialog): def __init__(self, context, ref, shortref=None, parent=None): Dialog.__init__(self, parent=parent) self.context = context if parent is not None: self.setWindowModality(Qt.WindowModal) # input self.ref = ref if shortref is None: shortref = ref # outputs self.fmt = None filename = '%s-%s' % (os.path.basename(core.getcwd()), shortref) self.prefix = filename + '/' self.filename = filename # widgets self.setWindowTitle(N_('Save Archive')) self.filetext = LineEdit() self.filetext.set_value(self.filename) self.browse = qtutils.create_toolbutton(icon=icons.file_zip()) stdout = context.git.archive('--list')[STDOUT] self.format_strings = stdout.rstrip().splitlines() self.format_combo = qtutils.combo(self.format_strings) self.close_button = qtutils.close_button() self.save_button = qtutils.create_button(text=N_('Save'), icon=icons.save(), default=True) self.prefix_label = QtWidgets.QLabel() self.prefix_label.setText(N_('Prefix')) self.prefix_text = LineEdit() self.prefix_text.set_value(self.prefix) self.prefix_group = ExpandableGroupBox() self.prefix_group.setTitle(N_('Advanced')) # layouts self.filelayt = qtutils.hbox(defs.no_margin, defs.spacing, self.browse, self.filetext, self.format_combo) self.prefixlayt = qtutils.hbox(defs.margin, defs.spacing, self.prefix_label, self.prefix_text) self.prefix_group.setLayout(self.prefixlayt) self.prefix_group.set_expanded(False) self.btnlayt = qtutils.hbox(defs.no_margin, defs.spacing, self.close_button, qtutils.STRETCH, self.save_button) self.mainlayt = qtutils.vbox(defs.margin, defs.no_spacing, self.filelayt, self.prefix_group, qtutils.STRETCH, self.btnlayt) self.setLayout(self.mainlayt) # initial setup; done before connecting to avoid # signal/slot side-effects if 'tar.gz' in self.format_strings: idx = self.format_strings.index('tar.gz') elif 'zip' in self.format_strings: idx = self.format_strings.index('zip') else: idx = 0 self.format_combo.setCurrentIndex(idx) self.update_format(idx) # connections # pylint: disable=no-member self.filetext.textChanged.connect(self.filetext_changed) self.prefix_text.textChanged.connect(self.prefix_text_changed) self.format_combo.currentIndexChanged.connect(self.update_format) self.prefix_group.expanded.connect(self.prefix_group_expanded) self.accepted.connect(self.archive_saved) qtutils.connect_button(self.browse, self.choose_filename) qtutils.connect_button(self.close_button, self.reject) qtutils.connect_button(self.save_button, self.save_archive) self.init_size(parent=parent) def archive_saved(self): context = self.context ref = self.ref fmt = self.fmt prefix = self.prefix filename = self.filename cmds.do(cmds.Archive, context, ref, fmt, prefix, filename) Interaction.information( N_('File Saved'), N_('File saved to "%s"') % self.filename) def save_archive(self): filename = self.filename if not filename: return if core.exists(filename): title = N_('Overwrite File?') msg = N_('The file "%s" exists and will be overwritten.') % filename info_txt = N_('Overwrite "%s"?') % filename ok_txt = N_('Overwrite') if not Interaction.confirm( title, msg, info_txt, ok_txt, default=False, icon=icons.save()): return self.accept() def choose_filename(self): filename = qtutils.save_as(self.filename) if not filename: return self.filetext.setText(filename) self.update_format(self.format_combo.currentIndex()) def filetext_changed(self, filename): self.filename = filename self.save_button.setEnabled(bool(self.filename)) prefix = self.strip_exts(os.path.basename(self.filename)) + '/' self.prefix_text.setText(prefix) def prefix_text_changed(self, prefix): self.prefix = prefix def strip_exts(self, text): for format_string in self.format_strings: ext = '.'+format_string if text.endswith(ext): return text[:-len(ext)] return text def update_format(self, idx): self.fmt = self.format_strings[idx] text = self.strip_exts(self.filetext.text()) self.filename = '%s.%s' % (text, self.fmt) self.filetext.setText(self.filename) self.filetext.setFocus() if '/' in text: start = text.rindex('/') + 1 else: start = 0 self.filetext.setSelection(start, len(text) - start) def prefix_group_expanded(self, expanded): if expanded: self.prefix_text.setFocus() else: self.filetext.setFocus() git-cola-3.6/cola/widgets/bookmarks.py000066400000000000000000000314251356743264500200330ustar00rootroot00000000000000"""Provides widgets related to bookmarks""" from __future__ import division, absolute_import, unicode_literals import os from qtpy import QtCore from qtpy import QtWidgets from qtpy.QtCore import Qt from qtpy.QtCore import Signal from .. import cmds from .. import core from .. import git from .. import hotkeys from .. import icons from .. import qtutils from .. import utils from ..i18n import N_ from ..interaction import Interaction from ..models import prefs from ..settings import Settings from ..widgets import defs from ..widgets import standard BOOKMARKS = 0 RECENT_REPOS = 1 def bookmark(context, parent): return BookmarksWidget(context, BOOKMARKS, parent=parent) def recent(context, parent): return BookmarksWidget(context, RECENT_REPOS, parent=parent) class BookmarksWidget(QtWidgets.QFrame): def __init__(self, context, style=BOOKMARKS, parent=None): QtWidgets.QFrame.__init__(self, parent) self.style = style self.settings = Settings() self.tree = BookmarksTreeWidget( context, style, self.settings, parent=self) self.add_button = qtutils.create_action_button( tooltip=N_('Add'), icon=icons.add()) self.delete_button = qtutils.create_action_button( tooltip=N_('Delete'), icon=icons.remove()) self.open_button = qtutils.create_action_button( tooltip=N_('Open'), icon=icons.repo()) self.button_group = utils.Group(self.delete_button, self.open_button) self.button_group.setEnabled(False) self.setFocusProxy(self.tree) if style == BOOKMARKS: self.setToolTip(N_('Favorite repositories')) elif style == RECENT_REPOS: self.setToolTip(N_('Recent repositories')) self.add_button.hide() self.button_layout = qtutils.hbox(defs.no_margin, defs.spacing, self.open_button, self.add_button, self.delete_button) self.main_layout = qtutils.vbox(defs.no_margin, defs.spacing, self.tree) self.setLayout(self.main_layout) self.corner_widget = QtWidgets.QWidget(self) self.corner_widget.setLayout(self.button_layout) titlebar = parent.titleBarWidget() titlebar.add_corner_widget(self.corner_widget) qtutils.connect_button(self.add_button, self.tree.add_bookmark) qtutils.connect_button(self.delete_button, self.tree.delete_bookmark) qtutils.connect_button(self.open_button, self.tree.open_repo) item_selection_changed = self.tree_item_selection_changed # pylint: disable=no-member self.tree.itemSelectionChanged.connect(item_selection_changed) QtCore.QTimer.singleShot(0, self.reload_bookmarks) def reload_bookmarks(self): # Called once after the GUI is initialized self.settings.load() self.tree.refresh() def tree_item_selection_changed(self): enabled = bool(self.tree.selected_item()) self.button_group.setEnabled(enabled) def connect_to(self, other): self.tree.default_changed.connect(other.tree.refresh) other.tree.default_changed.connect(self.tree.refresh) def disable_rename(_path, _name, _new_name): return False # pylint: disable=too-many-ancestors class BookmarksTreeWidget(standard.TreeWidget): default_changed = Signal() worktree_changed = Signal() def __init__(self, context, style, settings, parent=None): standard.TreeWidget.__init__(self, parent=parent) self.context = context self.style = style self.settings = settings self.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) self.setHeaderHidden(True) # We make the items editable, but we don't want the double-click # behavior to trigger editing. Make it behave like Mac OS X's Finder. self.setEditTriggers(self.SelectedClicked) self.open_action = qtutils.add_action( self, N_('Open'), self.open_repo, hotkeys.OPEN) self.accept_action = qtutils.add_action( self, N_('Accept'), self.accept_repo, *hotkeys.ACCEPT) self.open_new_action = qtutils.add_action( self, N_('Open in New Window'), self.open_new_repo, hotkeys.NEW) self.set_default_repo_action = qtutils.add_action( self, N_('Set Default Repository'), self.set_default_repo) self.clear_default_repo_action = qtutils.add_action( self, N_('Clear Default Repository'), self.clear_default_repo) self.rename_repo_action = qtutils.add_action( self, N_('Rename Repository'), self.rename_repo) self.open_default_action = qtutils.add_action( self, cmds.OpenDefaultApp.name(), self.open_default, hotkeys.PRIMARY_ACTION) self.launch_editor_action = qtutils.add_action( self, cmds.Edit.name(), self.launch_editor, hotkeys.EDIT) self.launch_terminal_action = qtutils.add_action( self, cmds.LaunchTerminal.name(), self.launch_terminal, hotkeys.TERMINAL) self.copy_action = qtutils.add_action( self, N_('Copy'), self.copy, hotkeys.COPY) self.delete_action = qtutils.add_action( self, N_('Delete'), self.delete_bookmark) # pylint: disable=no-member self.itemChanged.connect(self.item_changed) self.itemSelectionChanged.connect(self.item_selection_changed) self.itemDoubleClicked.connect(self.tree_double_clicked) self.action_group = utils.Group(self.open_action, self.open_new_action, self.copy_action, self.launch_editor_action, self.launch_terminal_action, self.open_default_action, self.rename_repo_action, self.delete_action) self.action_group.setEnabled(False) self.set_default_repo_action.setEnabled(False) self.clear_default_repo_action.setEnabled(False) # Connections if style == RECENT_REPOS: self.worktree_changed.connect(self.refresh, type=Qt.QueuedConnection) context.model.add_observer(context.model.message_worktree_changed, self.worktree_changed.emit) def refresh(self): context = self.context settings = self.settings builder = BuildItem(context) # bookmarks if self.style == BOOKMARKS: entries = settings.bookmarks # recent items elif self.style == RECENT_REPOS: settings.reload_recent() entries = settings.recent items = [builder.get(entry['path'], entry['name']) for entry in entries] if self.style == BOOKMARKS and prefs.sort_bookmarks(context): items.sort(key=lambda x: x.name) self.clear() self.addTopLevelItems(items) def contextMenuEvent(self, event): menu = qtutils.create_menu(N_('Actions'), self) menu.addAction(self.open_action) menu.addAction(self.open_new_action) menu.addAction(self.open_default_action) menu.addSeparator() menu.addAction(self.copy_action) menu.addAction(self.launch_editor_action) menu.addAction(self.launch_terminal_action) menu.addSeparator() item = self.selected_item() is_default = bool(item and item.is_default) if is_default: menu.addAction(self.clear_default_repo_action) else: menu.addAction(self.set_default_repo_action) menu.addAction(self.rename_repo_action) menu.addSeparator() menu.addAction(self.delete_action) menu.exec_(self.mapToGlobal(event.pos())) def item_changed(self, item, _index): self.rename_entry(item, item.text(0)) def rename_entry(self, item, new_name): if self.style == BOOKMARKS: rename = self.settings.rename_bookmark elif self.style == RECENT_REPOS: rename = self.settings.rename_recent else: rename = disable_rename if rename(item.path, item.name, new_name): self.settings.save() item.name = new_name else: item.setText(0, item.name) def apply_fn(self, fn, *args, **kwargs): item = self.selected_item() if item: fn(item, *args, **kwargs) def copy(self): self.apply_fn(lambda item: qtutils.set_clipboard(item.path)) def open_default(self): context = self.context self.apply_fn( lambda item: cmds.do(cmds.OpenDefaultApp, context, [item.path])) def set_default_repo(self): self.apply_fn(self.set_default_item) def set_default_item(self, item): context = self.context cmds.do(cmds.SetDefaultRepo, context, item.path) self.refresh() self.default_changed.emit() def clear_default_repo(self): self.apply_fn(self.clear_default_item) self.default_changed.emit() def clear_default_item(self, _item): context = self.context cmds.do(cmds.SetDefaultRepo, context, None) self.refresh() def rename_repo(self): self.apply_fn(lambda item: self.editItem(item, 0)) def accept_repo(self): self.apply_fn(self.accept_item) def accept_item(self, item): if self.state() & self.EditingState: widget = self.itemWidget(item, 0) if widget: self.commitData(widget) self.closePersistentEditor(item, 0) else: self.open_repo() def open_repo(self): context = self.context self.apply_fn(lambda item: cmds.do(cmds.OpenRepo, context, item.path)) def open_new_repo(self): context = self.context self.apply_fn( lambda item: cmds.do(cmds.OpenNewRepo, context, item.path)) def launch_editor(self): context = self.context self.apply_fn(lambda item: cmds.do(cmds.Edit, context, [item.path])) def launch_terminal(self): context = self.context self.apply_fn( lambda item: cmds.do(cmds.LaunchTerminal, context, item.path)) def item_selection_changed(self): item = self.selected_item() enabled = bool(item) self.action_group.setEnabled(enabled) is_default = bool(item and item.is_default) self.set_default_repo_action.setEnabled(not is_default) self.clear_default_repo_action.setEnabled(is_default) def tree_double_clicked(self, item, _column): context = self.context cmds.do(cmds.OpenRepo, context, item.path) def add_bookmark(self): normpath = utils.expandpath(core.getcwd()) name = os.path.basename(normpath) prompt = ( (N_('Name'), name), (N_('Path'), core.getcwd()), ) ok, values = qtutils.prompt_n(N_('Add Favorite'), prompt) if not ok: return name, path = values normpath = utils.expandpath(path) if git.is_git_worktree(normpath): self.settings.add_bookmark(normpath, name) self.settings.save() self.refresh() else: Interaction.critical( N_('Error'), N_('%s is not a Git repository.') % path) def delete_bookmark(self): """Removes a bookmark from the bookmarks list""" item = self.selected_item() context = self.context if not item: return if self.style == BOOKMARKS: cmd = cmds.RemoveBookmark elif self.style == RECENT_REPOS: cmd = cmds.RemoveRecent else: return ok, _, _, _ = cmds.do( cmd, context, self.settings, item.path, item.name, icon=icons.discard()) if ok: self.refresh() class BuildItem(object): def __init__(self, context): self.star_icon = icons.star() self.folder_icon = icons.folder() cfg = context.cfg self.default_repo = cfg.get('cola.defaultrepo') def get(self, path, name): is_default = self.default_repo == path if is_default: icon = self.star_icon else: icon = self.folder_icon return BookmarksTreeWidgetItem(path, name, icon, is_default) class BookmarksTreeWidgetItem(QtWidgets.QTreeWidgetItem): def __init__(self, path, name, icon, is_default): QtWidgets.QTreeWidgetItem.__init__(self) self.path = path self.name = name self.is_default = is_default self.setIcon(0, icon) self.setText(0, name) self.setToolTip(0, path) self.setFlags(self.flags() | Qt.ItemIsEditable) git-cola-3.6/cola/widgets/branch.py000066400000000000000000000603661356743264500173060ustar00rootroot00000000000000"""Provides widgets related to branches""" from __future__ import division, absolute_import, unicode_literals from functools import partial from qtpy import QtWidgets from qtpy.QtCore import Qt from qtpy.QtCore import Signal from ..compat import uchr from ..i18n import N_ from ..interaction import Interaction from ..widgets import defs from ..widgets import standard from ..qtutils import get from .. import cmds from .. import gitcmds from .. import hotkeys from .. import icons from .. import qtutils from .text import LineEdit def defer_fn(parent, title, fn, *args, **kwargs): return qtutils.add_action(parent, title, partial(fn, *args, **kwargs)) def add_branch_to_menu(menu, branch, remote_branch, remote, upstream, fn): """Add a remote branch to the context menu""" branch_remote, _ = gitcmds.parse_remote_branch(remote_branch) if branch_remote != remote: menu.addSeparator() action = defer_fn(menu, remote_branch, fn, branch, remote_branch) if remote_branch == upstream: action.setIcon(icons.star()) menu.addAction(action) return branch_remote class AsyncGitActionTask(qtutils.Task): """Run git action asynchronously""" def __init__(self, parent, git_helper, action, args, kwarg): qtutils.Task.__init__(self, parent) self.git_helper = git_helper self.action = action self.args = args self.kwarg = kwarg def task(self): """Runs action and captures the result""" git_action = getattr(self.git_helper, self.action) return git_action(*self.args, **self.kwarg) class BranchesWidget(QtWidgets.QFrame): updated = Signal() def __init__(self, context, parent): QtWidgets.QFrame.__init__(self, parent) self.model = model = context.model tooltip = N_('Toggle the branches filter') icon = icons.ellipsis() self.filter_button = qtutils.create_action_button( tooltip=tooltip, icon=icon) self.order_icons = ( icons.alphabetical(), icons.reverse_chronological(), ) tooltip_order = N_( 'Set the sort order for branches and tags.\n' 'Toggle between date-based and version-name-based sorting.' ) icon = self.order_icon(model.ref_sort) self.sort_order_button = qtutils.create_action_button( tooltip=tooltip_order, icon=icon) self.tree = BranchesTreeWidget(context, parent=self) self.filter_widget = BranchesFilterWidget(self.tree) self.filter_widget.hide() self.setFocusProxy(self.tree) self.setToolTip(N_('Branches')) self.main_layout = qtutils.vbox(defs.no_margin, defs.spacing, self.filter_widget, self.tree) self.setLayout(self.main_layout) self.toggle_action = qtutils.add_action(self, tooltip, self.toggle_filter, hotkeys.FILTER) qtutils.connect_button(self.filter_button, self.toggle_filter) qtutils.connect_button( self.sort_order_button, cmds.run(cmds.CycleReferenceSort, context)) self.updated.connect(self.refresh, Qt.QueuedConnection) model.add_observer(model.message_refs_updated, self.updated.emit) def toggle_filter(self): shown = not self.filter_widget.isVisible() self.filter_widget.setVisible(shown) if shown: self.filter_widget.setFocus() else: self.tree.setFocus() def order_icon(self, idx): return self.order_icons[idx % len(self.order_icons)] def refresh(self): icon = self.order_icon(self.model.ref_sort) self.sort_order_button.setIcon(icon) self.tree.refresh() # pylint: disable=too-many-ancestors class BranchesTreeWidget(standard.TreeWidget): updated = Signal() def __init__(self, context, parent=None): standard.TreeWidget.__init__(self, parent) model = context.model self.context = context self.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) self.setHeaderHidden(True) self.setAlternatingRowColors(False) self.setColumnCount(1) self.setExpandsOnDoubleClick(False) self.tree_helper = BranchesTreeHelper() self.git_helper = GitHelper(context) self.current_branch = None self.runtask = qtutils.RunTask(parent=self) self._active = False self.updated.connect(self.refresh, type=Qt.QueuedConnection) model.add_observer(model.message_updated, self.updated.emit) # Expand items when they are clicked # pylint: disable=no-member self.clicked.connect(self._toggle_expanded) # Checkout branch when double clicked self.doubleClicked.connect(self.checkout_action) def refresh(self): if not self._active: return model = self.context.model self.current_branch = model.currentbranch states = self.save_tree_state() ellipsis = icons.ellipsis() local_tree = create_tree_entries(model.local_branches) local_tree.basename = N_('Local') local = create_toplevel_item( local_tree, icon=icons.branch(), ellipsis=ellipsis) remote_tree = create_tree_entries(model.remote_branches) remote_tree.basename = N_('Remote') remote = create_toplevel_item( remote_tree, icon=icons.branch(), ellipsis=ellipsis) tags_tree = create_tree_entries(model.tags) tags_tree.basename = N_('Tags') tags = create_toplevel_item( tags_tree, icon=icons.tag(), ellipsis=ellipsis) self.clear() self.addTopLevelItems([local, remote, tags]) self.update_select_branch() self.load_tree_state(states) def showEvent(self, event): """Defer updating widgets until the widget is visible""" if not self._active: self._active = True self.refresh() return super(BranchesTreeWidget, self).showEvent(event) def _toggle_expanded(self, index): """Toggle expanded/collapsed state when items are clicked""" self.setExpanded(index, not self.isExpanded(index)) def contextMenuEvent(self, event): """Build and execute the context menu""" context = self.context selected = self.selected_item() if not selected: return # Only allow actions on leaf nodes that have a valid refname. if not selected.refname: return root = get_toplevel_item(selected) full_name = selected.refname menu = qtutils.create_menu(N_('Actions'), self) # all branches except current the current branch if full_name != self.current_branch: menu.addAction(qtutils.add_action( menu, N_('Checkout'), self.checkout_action)) # remote branch if root.name == N_('Remote'): label = N_('Checkout as new branch') action = self.checkout_new_branch_action menu.addAction(qtutils.add_action(menu, label, action)) merge_menu_action = qtutils.add_action( menu, N_('Merge into current branch'), self.merge_action) merge_menu_action.setIcon(icons.merge()) menu.addAction(merge_menu_action) # local and remote branch if root.name != N_('Tags'): # local branch if root.name == N_('Local'): remote = gitcmds.tracked_branch(context, full_name) if remote is not None: menu.addSeparator() pull_menu_action = qtutils.add_action( menu, N_('Pull'), self.pull_action) pull_menu_action.setIcon(icons.pull()) menu.addAction(pull_menu_action) push_menu_action = qtutils.add_action( menu, N_('Push'), self.push_action) push_menu_action.setIcon(icons.push()) menu.addAction(push_menu_action) rename_menu_action = qtutils.add_action( menu, N_('Rename Branch'), self.rename_action) rename_menu_action.setIcon(icons.edit()) menu.addSeparator() menu.addAction(rename_menu_action) # not current branch if full_name != self.current_branch: delete_label = N_('Delete Branch') if root.name == N_('Remote'): delete_label = N_('Delete Remote Branch') delete_menu_action = qtutils.add_action( menu, delete_label, self.delete_action) delete_menu_action.setIcon(icons.discard()) menu.addSeparator() menu.addAction(delete_menu_action) # manage upstreams for local branches if root.name == N_('Local'): upstream_menu = menu.addMenu(N_('Set Upstream Branch')) upstream_menu.setIcon(icons.branch()) self.build_upstream_menu(upstream_menu) menu.exec_(self.mapToGlobal(event.pos())) def build_upstream_menu(self, menu): """Build the "Set Upstream Branch" sub-menu""" context = self.context model = context.model selected_branch = self.selected_refname() remote = None upstream = None branches = [] other_branches = [] if selected_branch: remote = gitcmds.upstream_remote(context, selected_branch) upstream = gitcmds.tracked_branch(context, branch=selected_branch) if not remote and 'origin' in model.remotes: remote = 'origin' if remote: prefix = remote + '/' for branch in model.remote_branches: if branch.startswith(prefix): branches.append(branch) else: other_branches.append(branch) else: # This can be a pretty big list, let's try to split it apart branch_remote = '' target = branches for branch in model.remote_branches: new_branch_remote, _ = gitcmds.parse_remote_branch(branch) if branch_remote and branch_remote != new_branch_remote: target = other_branches branch_remote = new_branch_remote target.append(branch) limit = 16 if not other_branches and len(branches) > limit: branches, other_branches = (branches[:limit], branches[limit:]) # Add an action for each remote branch current_remote = remote for branch in branches: current_remote = add_branch_to_menu( menu, selected_branch, branch, current_remote, upstream, self.set_upstream) # This list could be longer so we tuck it away in a sub-menu. # Selecting a branch from the non-default remote is less common. if other_branches: menu.addSeparator() sub_menu = menu.addMenu(N_('Other branches')) for branch in other_branches: current_remote = add_branch_to_menu( sub_menu, selected_branch, branch, current_remote, upstream, self.set_upstream) def set_upstream(self, branch, remote_branch): """Configure the upstream for a branch""" context = self.context remote, r_branch = gitcmds.parse_remote_branch(remote_branch) if remote and r_branch: cmds.do(cmds.SetUpstreamBranch, context, branch, remote, r_branch) def save_tree_state(self): states = {} for item in self.items(): states.update(self.tree_helper.save_state(item)) return states def load_tree_state(self, states): for item in self.items(): if item.name in states: self.tree_helper.load_state(item, states[item.name]) def update_select_branch(self): context = self.context current_branch = self.current_branch top_item = self.topLevelItem(0) item = find_by_refname(top_item, current_branch) if item is not None: expand_item_parents(item) item.setIcon(0, icons.star()) tracked_branch = gitcmds.tracked_branch(context, current_branch) if current_branch and tracked_branch: status = {'ahead': 0, 'behind': 0} status_str = '' origin = tracked_branch + '..' + self.current_branch log = self.git_helper.log(origin) status['ahead'] = len(log[1].splitlines()) origin = self.current_branch + '..' + tracked_branch log = self.git_helper.log(origin) status['behind'] = len(log[1].splitlines()) if status['ahead'] > 0: status_str += '%s%s' % (uchr(0x2191), status['ahead']) if status['behind'] > 0: status_str += ' %s%s' % (uchr(0x2193), status['behind']) if status_str: item.setText(0, '%s\t%s' % (item.text(0), status_str)) def git_action_async(self, action, args, kwarg=None): if kwarg is None: kwarg = {} task = AsyncGitActionTask(self, self.git_helper, action, args, kwarg) progress = standard.progress( N_('Executing action %s') % action, N_('Updating'), self) self.runtask.start(task, progress=progress, finish=self.git_action_completed) def git_action_completed(self, task): status, out, err = task.result self.git_helper.show_result(task.action, status, out, err) self.context.model.update_refs() def push_action(self): context = self.context branch = self.selected_refname() remote_branch = gitcmds.tracked_branch(context, branch) if remote_branch: remote, branch_name = gitcmds.parse_remote_branch(remote_branch) if remote and branch_name: # we assume that user wants to "Push" the selected local # branch to a remote with same name self.git_action_async('push', [remote, branch_name]) def rename_action(self): branch = self.selected_refname() new_branch, ok = qtutils.prompt( N_('Enter New Branch Name'), title=N_('Rename branch'), text=branch) if ok and new_branch: self.git_action_async('rename', [branch, new_branch]) def pull_action(self): context = self.context branch = self.selected_refname() if not branch: return remote_branch = gitcmds.tracked_branch(context, branch) if remote_branch: remote, branch_name = gitcmds.parse_remote_branch(remote_branch) if remote and branch_name: self.git_action_async('pull', [remote, branch_name]) def delete_action(self): branch = self.selected_refname() if not branch or branch == self.current_branch: return remote = False root = get_toplevel_item(self.selected_item()) if root.name == N_('Remote'): remote = True if remote: remote, branch = gitcmds.parse_remote_branch(branch) if remote and branch: cmds.do(cmds.DeleteRemoteBranch, self.context, remote, branch) else: cmds.do(cmds.DeleteBranch, self.context, branch) def merge_action(self): branch = self.selected_refname() if branch and branch != self.current_branch: self.git_action_async('merge', [branch]) def checkout_action(self): branch = self.selected_refname() if branch and branch != self.current_branch: self.git_action_async('checkout', [branch]) def checkout_new_branch_action(self): branch = self.selected_refname() if branch and branch != self.current_branch: _, new_branch = gitcmds.parse_remote_branch(branch) self.git_action_async('checkout', ['-b', new_branch, branch]) def selected_refname(self): return getattr(self.selected_item(), 'refname', None) class BranchTreeWidgetItem(QtWidgets.QTreeWidgetItem): def __init__(self, name, refname=None, icon=None): QtWidgets.QTreeWidgetItem.__init__(self) self.name = name self.refname = refname self.setText(0, name) self.setToolTip(0, name) if icon is not None: self.setIcon(0, icon) self.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) # TODO: review standard.py 317. # original function returns 'QTreeWidgetItem' object which has no # attribute 'rowCount'. This workaround fix error throw when # navigating with keyboard and press left key @staticmethod def rowCount(): return 1 class TreeEntry(object): """Tree representation for the branches widget The branch widget UI displays the basename. For intermediate names, e.g. "xxx" in the "xxx/abc" and "xxx/def" branches, the 'refname' will be None. 'children' contains a list of TreeEntry, and is empty when refname is defined. """ def __init__(self, basename, refname, children): self.basename = basename self.refname = refname self.children = children def create_tree_entries(names): """Create a nested tree structure with a single root TreeEntry. When names == ['xxx/abc', 'xxx/def'] the result will be:: TreeEntry( basename=None, refname=None, children=[ TreeEntry( basename='xxx', refname=None, children=[ TreeEntry( basename='abc', refname='xxx/abc', children=[] ), TreeEntry( basename='def', refname='xxx/def', children=[] ) ] ) ] ) """ # Phase 1: build a nested dictionary representing the intermediate # names in the branches. e.g. {'xxx': {'abc': {}, 'def': {}}} tree_names = create_name_dict(names) # Loop over the names again, this time we'll create tree entries entries = {} root = TreeEntry(None, None, []) for item in names: cur_names = tree_names cur_entries = entries tree = root children = root.children for part in item.split('/'): if cur_names[part]: # This has children try: tree, _ = cur_entries[part] except KeyError: # New entry tree = TreeEntry(part, None, []) cur_entries[part] = (tree, {}) # Append onto the parent children list only once children.append(tree) else: # This is the actual branch tree = TreeEntry(part, item, []) children.append(tree) cur_entries[part] = (tree, {}) # Advance into the nested child list children = tree.children # Advance into the inner dict cur_names = cur_names[part] _, cur_entries = cur_entries[part] return root def create_name_dict(names): # Phase 1: build a nested dictionary representing the intermediate # names in the branches. e.g. {'xxx': {'abc': {}, 'def': {}}} tree_names = {} for item in names: part_names = tree_names for part in item.split('/'): # Descend into the inner names dict. part_names = part_names.setdefault(part, {}) return tree_names def create_toplevel_item(tree, icon=None, ellipsis=None): """Create a top-level BranchTreeWidgetItem and its children""" item = BranchTreeWidgetItem(tree.basename, icon=ellipsis) children = create_tree_items(tree.children, icon=icon, ellipsis=ellipsis) if children: item.addChildren(children) return item def create_tree_items(entries, icon=None, ellipsis=None): """Create children items for a tree item""" result = [] for tree in entries: item = BranchTreeWidgetItem( tree.basename, refname=tree.refname, icon=icon) children = create_tree_items( tree.children, icon=icon, ellipsis=ellipsis) if children: item.addChildren(children) if ellipsis is not None: item.setIcon(0, ellipsis) result.append(item) return result def expand_item_parents(item): """Expand tree parents from item""" parent = item.parent() while parent is not None: parent.setExpanded(True) parent = parent.parent() def find_by_refname(item, refname): """Find child by full name recursive""" result = None for i in range(item.childCount()): child = item.child(i) if child.refname and child.refname == refname: return child result = find_by_refname(child, refname) if result is not None: return result return result def get_toplevel_item(item): """Returns top-most item found by traversing up the specified item""" parents = [item] parent = item.parent() while parent is not None: parents.append(parent) parent = parent.parent() return parents[-1] class BranchesTreeHelper(object): def load_state(self, item, state): """Load expanded items from a dict""" if state.keys(): item.setExpanded(True) for i in range(item.childCount()): child = item.child(i) if child.name in state: self.load_state(child, state[child.name]) def save_state(self, item): """Save expanded items in a dict""" result = {item.name: {}} if item.isExpanded(): for i in range(item.childCount()): child = item.child(i) result[item.name].update(self.save_state(child)) return result class GitHelper(object): def __init__(self, context): self.context = context self.git = context.git def log(self, origin): return self.git.log(origin, oneline=True) def push(self, remote, branch): return self.git.push(remote, branch, verbose=True) def pull(self, remote, branch): return self.git.pull(remote, branch, no_ff=True, verbose=True) def merge(self, branch): return self.git.merge(branch, no_commit=True) def rename(self, branch, new_branch): return self.git.branch(branch, new_branch, m=True) def checkout(self, *args, **options): return self.git.checkout(*args, **options) @staticmethod def show_result(command, status, out, err): Interaction.log_status(status, out, err) if status != 0: Interaction.command_error(N_('Error'), command, status, out, err) class BranchesFilterWidget(QtWidgets.QWidget): def __init__(self, tree, parent=None): QtWidgets.QWidget.__init__(self, parent) self.tree = tree hint = N_('Filter branches...') self.text = LineEdit(parent=self, clear_button=True) self.text.setToolTip(hint) self.setFocusProxy(self.text) self._filter = None self.main_layout = qtutils.hbox(defs.no_margin, defs.spacing, self.text) self.setLayout(self.main_layout) text = self.text # pylint: disable=no-member text.textChanged.connect(self.apply_filter) self.tree.updated.connect(self.apply_filter, type=Qt.QueuedConnection) def apply_filter(self): text = get(self.text) if text == self._filter: return self._apply_bold(self._filter, False) self._filter = text if text: self._apply_bold(text, True) def _apply_bold(self, text, value): match = Qt.MatchContains | Qt.MatchRecursive children = self.tree.findItems(text, match) for child in children: if child.childCount() == 0: font = child.font(0) font.setBold(value) child.setFont(0, font) git-cola-3.6/cola/widgets/browse.py000066400000000000000000000671331356743264500173510ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals from qtpy.QtCore import Qt from qtpy.QtCore import Signal from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from ..models.browse import GitRepoModel from ..models.browse import GitRepoNameItem from ..models.selection import State from ..i18n import N_ from ..interaction import Interaction from ..models import browse from .. import cmds from .. import core from .. import gitcmds from .. import hotkeys from .. import icons from .. import utils from .. import qtutils from .selectcommits import select_commits from . import common from . import defs from . import standard def worktree_browser(context, parent=None, update=True, settings=None, show=True): """Create a new worktree browser""" view = Browser(context, parent, update=update, settings=settings) model = GitRepoModel(context, view.tree) view.set_model(model) if update: view.refresh() if show: view.show() return view def save_path(context, path, model): """Choose an output filename based on the selected path""" filename = qtutils.save_as(path) if filename: model.filename = filename cmds.do(SaveBlob, context, model) result = True else: result = False return result class Browser(standard.Widget): updated = Signal() # Read-only mode property mode = property(lambda self: self.model.mode) def __init__(self, context, parent, update=True, settings=None): standard.Widget.__init__(self, parent) self.settings = settings self.tree = RepoTreeView(context, self) self.mainlayout = qtutils.hbox(defs.no_margin, defs.spacing, self.tree) self.setLayout(self.mainlayout) self.updated.connect(self._updated_callback, type=Qt.QueuedConnection) self.model = context.model self.model.add_observer(self.model.message_updated, self.model_updated) if parent is None: qtutils.add_close_action(self) if update: self.model_updated() self.init_state(settings, self.resize, 720, 420) def set_model(self, model): """Set the model""" self.tree.set_model(model) def refresh(self): """Refresh the model triggering view updates""" self.tree.refresh() def model_updated(self): """Update the title with the current branch and directory name.""" self.updated.emit() def _updated_callback(self): branch = self.model.currentbranch curdir = core.getcwd() msg = N_('Repository: %s') % curdir msg += '\n' msg += N_('Branch: %s') % branch self.setToolTip(msg) scope = dict(project=self.model.project, branch=branch) title = N_('%(project)s: %(branch)s - Browse') % scope if self.mode == self.model.mode_amend: title += ' %s' % N_('(Amending)') self.setWindowTitle(title) # pylint: disable=too-many-ancestors class RepoTreeView(standard.TreeView): """Provides a filesystem-like view of a git repository.""" about_to_update = Signal() updated = Signal() def __init__(self, context, parent): standard.TreeView.__init__(self, parent) self.context = context self.selection = context.selection self.saved_selection = [] self.saved_current_path = None self.saved_open_folders = set() self.restoring_selection = False self.info_event_type = browse.GitRepoInfoEvent.TYPE self.setDragEnabled(True) self.setRootIsDecorated(False) self.setSortingEnabled(False) self.setSelectionMode(self.ExtendedSelection) # Observe model updates model = context.model model.add_observer(model.message_about_to_update, self.emit_about_to_update) model.add_observer(model.message_updated, self.emit_update) # pylint: disable=no-member self.about_to_update.connect(self.save_selection, type=Qt.QueuedConnection) self.updated.connect(self.update_actions, type=Qt.QueuedConnection) self.expanded.connect(self.index_expanded) self.collapsed.connect(lambda idx: self.size_columns()) self.collapsed.connect(self.index_collapsed) # Sync selection before the key press event changes the model index queued = Qt.QueuedConnection self.index_about_to_change.connect(self.sync_selection, type=queued) self.action_history = qtutils.add_action_with_status_tip( self, N_('View History...'), N_('View history for selected paths'), self.view_history, hotkeys.HISTORY) self.action_stage = qtutils.add_action_with_status_tip( self, cmds.StageOrUnstage.name(), N_('Stage/unstage selected paths for commit'), cmds.run(cmds.StageOrUnstage, context), hotkeys.STAGE_SELECTION) self.action_untrack = qtutils.add_action_with_status_tip( self, N_('Untrack Selected'), N_('Stop tracking paths'), self.untrack_selected) self.action_rename = qtutils.add_action_with_status_tip( self, N_('Rename'), N_('Rename selected paths'), self.rename_selected) self.action_difftool = qtutils.add_action_with_status_tip( self, cmds.LaunchDifftool.name(), N_('Launch git-difftool on the current path'), cmds.run(cmds.LaunchDifftool, context), hotkeys.DIFF) self.action_difftool_predecessor = qtutils.add_action_with_status_tip( self, N_('Diff Against Predecessor...'), N_('Launch git-difftool against previous versions'), self.diff_predecessor, hotkeys.DIFF_SECONDARY) self.action_revert_unstaged = qtutils.add_action_with_status_tip( self, cmds.RevertUnstagedEdits.name(), N_('Revert unstaged changes to selected paths'), cmds.run(cmds.RevertUnstagedEdits, context), hotkeys.REVERT) self.action_revert_uncommitted = qtutils.add_action_with_status_tip( self, cmds.RevertUncommittedEdits.name(), N_('Revert uncommitted changes to selected paths'), cmds.run(cmds.RevertUncommittedEdits, context), hotkeys.UNDO) self.action_editor = qtutils.add_action_with_status_tip( self, cmds.LaunchEditor.name(), N_('Edit selected paths'), cmds.run(cmds.LaunchEditor, context), hotkeys.EDIT) self.action_blame = qtutils.add_action_with_status_tip( self, cmds.BlamePaths.name(), N_('Blame selected paths'), cmds.run(cmds.BlamePaths, context)) self.action_refresh = common.refresh_action(context, self) if not utils.is_win32(): self.action_default_app = common.default_app_action( context, self, self.selected_paths) self.action_parent_dir = common.parent_dir_action( context, self, self.selected_paths) self.action_terminal = common.terminal_action( context, self, self.selected_paths) self.x_width = QtGui.QFontMetrics(self.font()).width('x') self.size_columns() def index_expanded(self, index): """Update information about a directory as it is expanded.""" # Remember open folders so that we can restore them when refreshing item = self.name_item_from_index(index) self.saved_open_folders.add(item.path) self.size_columns() # update information about a directory as it is expanded if item.cached: return path = item.path model = self.model() model.populate(item) model.update_entry(path) for row in range(item.rowCount()): path = item.child(row, 0).path model.update_entry(path) item.cached = True def index_collapsed(self, index): item = self.name_item_from_index(index) self.saved_open_folders.remove(item.path) def refresh(self): self.model().refresh() def size_columns(self): """Set the column widths.""" self.resizeColumnToContents(0) self.resizeColumnToContents(1) self.resizeColumnToContents(2) self.resizeColumnToContents(3) self.resizeColumnToContents(4) def sizeHintForColumn(self, column): x_width = self.x_width if column == 1: # Status size = x_width * 11 elif column == 2: # Summary size = x_width * 64 elif column == 3: # Author size = x_width * 18 elif column == 4: # Age size = x_width * 16 else: # Filename and others use the actual content size = super(RepoTreeView, self).sizeHintForColumn(column) return size def emit_update(self): self.updated.emit() def emit_about_to_update(self): self.about_to_update.emit() def save_selection(self): selection = self.selected_paths() if selection: self.saved_selection = selection current = self.current_item() if current: self.saved_current_path = current.path def restore(self): selection = self.selectionModel() flags = selection.Select | selection.Rows self.restoring_selection = True # Restore opened folders model = self.model() for path in sorted(self.saved_open_folders): row = model.get(path) if not row: continue index = row[0].index() if index.isValid(): self.setExpanded(index, True) # Restore the current item. We do this first, otherwise # setCurrentIndex() can mess with the selection we set below current_index = None current_path = self.saved_current_path if current_path: row = model.get(current_path) if row: current_index = row[0].index() if current_index and current_index.isValid(): self.setCurrentIndex(current_index) # Restore selected items for path in self.saved_selection: row = model.get(path) if not row: continue index = row[0].index() if index.isValid(): self.scrollTo(index) selection.select(index, flags) self.restoring_selection = False self.size_columns() self.update_diff() def event(self, ev): """Respond to GitRepoInfoEvents""" if ev.type() == self.info_event_type: ev.accept() self.apply_data(ev.data) return super(RepoTreeView, self).event(ev) def apply_data(self, data): entry = self.model().get(data[0]) if entry: entry[1].set_status(data[1]) entry[2].setText(data[2]) entry[3].setText(data[3]) entry[4].setText(data[4]) def update_actions(self): """Enable/disable actions.""" selection = self.selected_paths() selected = bool(selection) staged = bool(self.selected_staged_paths(selection=selection)) modified = bool(self.selected_modified_paths(selection=selection)) unstaged = bool(self.selected_unstaged_paths(selection=selection)) tracked = bool(self.selected_tracked_paths(selection=selection)) revertable = staged or modified self.action_editor.setEnabled(selected) self.action_history.setEnabled(selected) if not utils.is_win32(): self.action_default_app.setEnabled(selected) self.action_parent_dir.setEnabled(selected) if self.action_terminal is not None: self.action_terminal.setEnabled(selected) self.action_stage.setEnabled(staged or unstaged) self.action_untrack.setEnabled(tracked) self.action_rename.setEnabled(tracked) self.action_difftool.setEnabled(staged or modified) self.action_difftool_predecessor.setEnabled(tracked) self.action_revert_unstaged.setEnabled(revertable) self.action_revert_uncommitted.setEnabled(revertable) def contextMenuEvent(self, event): """Create a context menu.""" self.update_actions() menu = qtutils.create_menu(N_('Actions'), self) menu.addAction(self.action_editor) menu.addAction(self.action_stage) menu.addSeparator() menu.addAction(self.action_history) menu.addAction(self.action_difftool) menu.addAction(self.action_difftool_predecessor) menu.addAction(self.action_blame) menu.addSeparator() menu.addAction(self.action_revert_unstaged) menu.addAction(self.action_revert_uncommitted) menu.addAction(self.action_untrack) menu.addAction(self.action_rename) if not utils.is_win32(): menu.addSeparator() menu.addAction(self.action_default_app) menu.addAction(self.action_parent_dir) if self.action_terminal is not None: menu.addAction(self.action_terminal) menu.exec_(self.mapToGlobal(event.pos())) def mousePressEvent(self, event): """Synchronize the selection on mouse-press.""" result = QtWidgets.QTreeView.mousePressEvent(self, event) self.sync_selection() return result def sync_selection(self): """Push selection into the selection model.""" staged = [] unmerged = [] modified = [] untracked = [] state = State(staged, unmerged, modified, untracked) paths = self.selected_paths() model = self.context.model model_staged = utils.add_parents(model.staged) model_modified = utils.add_parents(model.modified) model_unmerged = utils.add_parents(model.unmerged) model_untracked = utils.add_parents(model.untracked) for path in paths: if path in model_unmerged: unmerged.append(path) elif path in model_untracked: untracked.append(path) elif path in model_staged: staged.append(path) elif path in model_modified: modified.append(path) else: staged.append(path) # Push the new selection into the model. self.selection.set_selection(state) return paths def selectionChanged(self, old, new): """Override selectionChanged to update available actions.""" result = QtWidgets.QTreeView.selectionChanged(self, old, new) if not self.restoring_selection: self.update_actions() self.update_diff() return result def update_diff(self): context = self.context model = context.model paths = self.sync_selection() if paths and self.model().path_is_interesting(paths[0]): cached = paths[0] in model.staged cmds.do(cmds.Diff, context, paths[0], cached) def set_model(self, model): """Set the concrete QAbstractItemModel instance.""" self.setModel(model) model.restore.connect(self.restore, type=Qt.QueuedConnection) def name_item_from_index(self, model_index): """Return the name item corresponding to the model index.""" index = model_index.sibling(model_index.row(), 0) return self.model().itemFromIndex(index) def paths_from_indexes(self, indexes): return qtutils.paths_from_indexes(self.model(), indexes, item_type=GitRepoNameItem.TYPE) def selected_paths(self): """Return the selected paths.""" return self.paths_from_indexes(self.selectedIndexes()) def selected_staged_paths(self, selection=None): """Return selected staged paths.""" if selection is None: selection = self.selected_paths() model = self.context.model staged = utils.add_parents(model.staged) return [p for p in selection if p in staged] def selected_modified_paths(self, selection=None): """Return selected modified paths.""" if selection is None: selection = self.selected_paths() model = self.context.model modified = utils.add_parents(model.modified) return [p for p in selection if p in modified] def selected_unstaged_paths(self, selection=None): """Return selected unstaged paths.""" if selection is None: selection = self.selected_paths() model = self.context.model modified = utils.add_parents(model.modified) untracked = utils.add_parents(model.untracked) unstaged = modified.union(untracked) return [p for p in selection if p in unstaged] def selected_tracked_paths(self, selection=None): """Return selected tracked paths.""" if selection is None: selection = self.selected_paths() model = self.context.model staged = set(self.selected_staged_paths(selection=selection)) modified = set(self.selected_modified_paths(selection=selection)) untracked = utils.add_parents(model.untracked) tracked = staged.union(modified) return [p for p in selection if p not in untracked or p in tracked] def view_history(self): """Launch the configured history browser path-limited to entries.""" paths = self.selected_paths() cmds.do(cmds.VisualizePaths, self.context, paths) def untrack_selected(self): """untrack selected paths.""" context = self.context cmds.do(cmds.Untrack, context, self.selected_tracked_paths()) def rename_selected(self): """untrack selected paths.""" context = self.context cmds.do(cmds.Rename, context, self.selected_tracked_paths()) def diff_predecessor(self): """Diff paths against previous versions.""" context = self.context paths = self.selected_tracked_paths() args = ['--'] + paths revs, summaries = gitcmds.log_helper( context, all=False, extra_args=args) commits = select_commits( context, N_('Select Previous Version'), revs, summaries, multiselect=False) if not commits: return commit = commits[0] cmds.difftool_launch(context, left=commit, paths=paths) def current_path(self): """Return the path for the current item.""" index = self.currentIndex() if not index.isValid(): return None return self.name_item_from_index(index).path class BrowseModel(object): """Context data used for browsing branches via git-ls-tree""" def __init__(self, ref, filename=None): self.ref = ref self.relpath = filename self.filename = filename class SaveBlob(cmds.ContextCommand): def __init__(self, context, model): super(SaveBlob, self).__init__(context) self.browse_model = model def do(self): git = self.context.git model = self.browse_model ref = '%s:%s' % (model.ref, model.relpath) with core.xopen(model.filename, 'wb') as fp: status, _, _ = git.show(ref, _stdout=fp) msg = (N_('Saved "%(filename)s" from "%(ref)s" to "%(destination)s"') % dict(filename=model.relpath, ref=model.ref, destination=model.filename)) Interaction.log_status(status, msg, '') Interaction.information( N_('File Saved'), N_('File saved to "%s"') % model.filename) class BrowseBranch(standard.Dialog): @classmethod def browse(cls, context, ref): model = BrowseModel(ref) dlg = cls(context, model, parent=qtutils.active_window()) dlg_model = GitTreeModel(context, ref, dlg) dlg.setModel(dlg_model) dlg.setWindowTitle(N_('Browsing %s') % model.ref) dlg.show() dlg.raise_() if dlg.exec_() != dlg.Accepted: return None return dlg def __init__(self, context, model, parent=None): standard.Dialog.__init__(self, parent=parent) if parent is not None: self.setWindowModality(Qt.WindowModal) # updated for use by commands self.context = context self.model = model # widgets self.tree = GitTreeWidget(parent=self) self.close_button = qtutils.close_button() text = N_('Save') self.save = qtutils.create_button(text=text, enabled=False, default=True) # layouts self.btnlayt = qtutils.hbox(defs.margin, defs.spacing, self.close_button, qtutils.STRETCH, self.save) self.layt = qtutils.vbox(defs.margin, defs.spacing, self.tree, self.btnlayt) self.setLayout(self.layt) # connections self.tree.path_chosen.connect(self.save_path) self.tree.selection_changed.connect(self.selection_changed, type=Qt.QueuedConnection) qtutils.connect_button(self.close_button, self.close) qtutils.connect_button(self.save, self.save_blob) self.init_size(parent=parent) def expandAll(self): self.tree.expandAll() def setModel(self, model): self.tree.setModel(model) def path_chosen(self, path, close=True): """Update the model from the view""" model = self.model model.relpath = path model.filename = path if close: self.accept() def save_path(self, path): """Choose an output filename based on the selected path""" self.path_chosen(path, close=False) if save_path(self.context, path, self.model): self.accept() def save_blob(self): """Save the currently selected file""" filenames = self.tree.selected_files() if not filenames: return self.save_path(filenames[0]) def selection_changed(self): """Update actions based on the current selection""" filenames = self.tree.selected_files() self.save.setEnabled(bool(filenames)) # pylint: disable=too-many-ancestors class GitTreeWidget(standard.TreeView): selection_changed = Signal() path_chosen = Signal(object) def __init__(self, parent=None): standard.TreeView.__init__(self, parent) self.setHeaderHidden(True) # pylint: disable=no-member self.doubleClicked.connect(self.double_clicked) def double_clicked(self, index): item = self.model().itemFromIndex(index) if item is None: return if item.is_dir: return self.path_chosen.emit(item.path) def selected_files(self): items = self.selected_items() return [i.path for i in items if not i.is_dir] def selectionChanged(self, old_selection, new_selection): QtWidgets.QTreeView.selectionChanged(self, old_selection, new_selection) self.selection_changed.emit() def select_first_file(self): """Select the first filename in the tree""" model = self.model() idx = self.indexAt(QtCore.QPoint(0, 0)) item = model.itemFromIndex(idx) while idx and idx.isValid() and item and item.is_dir: idx = self.indexBelow(idx) item = model.itemFromIndex(idx) if idx and idx.isValid() and item: self.setCurrentIndex(idx) class GitFileTreeModel(QtGui.QStandardItemModel): """Presents a list of file paths as a hierarchical tree.""" def __init__(self, parent): QtGui.QStandardItemModel.__init__(self, parent) self.dir_entries = {'': self.invisibleRootItem()} self.dir_rows = {} def clear(self): QtGui.QStandardItemModel.clear(self) self.dir_rows = {} self.dir_entries = {'': self.invisibleRootItem()} def add_files(self, files): """Add a list of files""" add_file = self.add_file for f in files: add_file(f) def add_file(self, path): """Add a file to the model.""" dirname = utils.dirname(path) dir_entries = self.dir_entries try: parent = dir_entries[dirname] except KeyError: parent = dir_entries[dirname] = self.create_dir_entry(dirname) row_items = create_row(path, False) parent.appendRow(row_items) def add_directory(self, parent, path): """Add a directory entry to the model.""" # Create model items row_items = create_row(path, True) try: parent_path = parent.path except AttributeError: # root QStandardItem parent_path = '' # Insert directories before file paths try: row = self.dir_rows[parent_path] except KeyError: row = self.dir_rows[parent_path] = 0 parent.insertRow(row, row_items) self.dir_rows[parent_path] += 1 self.dir_entries[path] = row_items[0] return row_items[0] def create_dir_entry(self, dirname): """ Create a directory entry for the model. This ensures that directories are always listed before files. """ entries = dirname.split('/') curdir = [] parent = self.invisibleRootItem() curdir_append = curdir.append self_add_directory = self.add_directory dir_entries = self.dir_entries for entry in entries: curdir_append(entry) path = '/'.join(curdir) try: parent = dir_entries[path] except KeyError: grandparent = parent parent = self_add_directory(grandparent, path) dir_entries[path] = parent return parent def create_row(path, is_dir): """Return a list of items representing a row.""" return [GitTreeItem(path, is_dir)] class GitTreeModel(GitFileTreeModel): def __init__(self, context, ref, parent): GitFileTreeModel.__init__(self, parent) self.context = context self.ref = ref self._initialize() def _initialize(self): """Iterate over git-ls-tree and create GitTreeItems.""" git = self.context.git status, out, err = git.ls_tree( '--full-tree', '-r', '-t', '-z', self.ref) if status != 0: Interaction.log_status(status, out, err) return if not out: return for line in out[:-1].split('\0'): # .....6 ...4 ......................................40 # 040000 tree c127cde9a0c644a3a8fef449a244f47d5272dfa6 relative # 100644 blob 139e42bf4acaa4927ec9be1ec55a252b97d3f1e2 relative/path objtype = line[7] relpath = line[6 + 1 + 4 + 1 + 40 + 1:] if objtype == 't': parent = self.dir_entries[utils.dirname(relpath)] self.add_directory(parent, relpath) elif objtype == 'b': self.add_file(relpath) class GitTreeItem(QtGui.QStandardItem): """ Represents a cell in a treeview. Many GitRepoItems could map to a single repository path, but this tree only has a single column. Each GitRepoItem manages a different cell in the tree view. """ def __init__(self, path, is_dir): QtGui.QStandardItem.__init__(self) self.is_dir = is_dir self.path = path self.setEditable(False) self.setDragEnabled(False) self.setText(utils.basename(path)) if is_dir: icon = icons.directory() else: icon = icons.file_text() self.setIcon(icon) git-cola-3.6/cola/widgets/cfgactions.py000066400000000000000000000253631356743264500201670ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals import os from qtpy import QtCore from qtpy import QtWidgets from qtpy.QtCore import Qt from .. import core from .. import gitcmds from .. import icons from .. import qtutils from ..i18n import N_ from ..interaction import Interaction from . import defs from . import completion from . import standard from .text import LineEdit def install(): Interaction.run_command = staticmethod(run_command) Interaction.confirm_config_action = staticmethod(confirm_config_action) def get_config_actions(context): cfg = context.cfg return cfg.get_guitool_names_and_shortcuts() def confirm_config_action(context, name, opts): dlg = ActionDialog(context, qtutils.active_window(), name, opts) dlg.show() if dlg.exec_() != QtWidgets.QDialog.Accepted: return False rev = dlg.revision() if rev: opts['revision'] = rev args = dlg.args() if args: opts['args'] = args return True def run_command(title, command): """Show a command widget""" view = GitCommandWidget(title, qtutils.active_window()) view.set_command(command) view.show() view.raise_() view.run() view.exec_() return (view.exitstatus, view.out, view.err) class GitCommandWidget(standard.Dialog): """Text viewer that reads the output of a command synchronously""" # Keep us in scope otherwise PyQt kills the widget def __init__(self, title, parent=None): standard.Dialog.__init__(self, parent) self.setWindowTitle(title) if parent is not None: self.setWindowModality(Qt.ApplicationModal) # Construct the process self.proc = QtCore.QProcess(self) self.exitstatus = 0 self.out = '' self.err = '' self.command = [] # Create the text browser self.output_text = QtWidgets.QTextBrowser(self) self.output_text.setAcceptDrops(False) self.output_text.setTabChangesFocus(True) self.output_text.setUndoRedoEnabled(False) self.output_text.setReadOnly(True) self.output_text.setAcceptRichText(False) # Create abort / close buttons # Start with abort disabled - will be enabled when the process is run. self.button_abort = qtutils.create_button(text=N_('Abort'), enabled=False) self.button_close = qtutils.close_button() # Put them in a horizontal layout at the bottom. self.button_box = QtWidgets.QDialogButtonBox(self) self.button_box.addButton(self.button_abort, QtWidgets.QDialogButtonBox.RejectRole) self.button_box.addButton(self.button_close, QtWidgets.QDialogButtonBox.AcceptRole) # Connect the signals to the process # pylint: disable=no-member self.proc.readyReadStandardOutput.connect(self.read_stdout) self.proc.readyReadStandardError.connect(self.read_stderr) self.proc.finished.connect(self.proc_finished) self.proc.stateChanged.connect(self.proc_state_changed) qtutils.connect_button(self.button_abort, self.abort) qtutils.connect_button(self.button_close, self.close) self._layout = qtutils.vbox(defs.margin, defs.spacing, self.output_text, self.button_box) self.setLayout(self._layout) self.resize(720, 420) def set_command(self, command): self.command = command def run(self): """Runs the process""" self.proc.start(self.command[0], self.command[1:]) def read_stdout(self): text = self.read_stream(self.proc.readAllStandardOutput) self.out += text def read_stderr(self): text = self.read_stream(self.proc.readAllStandardError) self.err += text def read_stream(self, fn): data = fn().data() text = core.decode(data) self.append_text(text) return text def append_text(self, text): cursor = self.output_text.textCursor() cursor.movePosition(cursor.End) cursor.insertText(text) cursor.movePosition(cursor.End) self.output_text.setTextCursor(cursor) def abort(self): if self.proc.state() != QtCore.QProcess.NotRunning: # Terminate seems to do nothing in windows self.proc.terminate() # Kill the process. QtCore.QTimer.singleShot(1000, self.proc.kill) def closeEvent(self, event): if self.proc.state() != QtCore.QProcess.NotRunning: # The process is still running, make sure we really want to abort. title = N_('Abort Action') msg = N_('An action is still running.\n' 'Terminating it could result in data loss.') info_text = N_('Abort the action?') ok_text = N_('Abort Action') if Interaction.confirm(title, msg, info_text, ok_text, default=False, icon=icons.close()): self.abort() event.accept() else: event.ignore() else: event.accept() return standard.Dialog.closeEvent(self, event) def proc_state_changed(self, newstate): # State of process has changed - change the abort button state. if newstate == QtCore.QProcess.NotRunning: self.button_abort.setEnabled(False) else: self.button_abort.setEnabled(True) def proc_finished(self, status): self.exitstatus = status class ActionDialog(standard.Dialog): VALUES = {} def __init__(self, context, parent, name, opts): standard.Dialog.__init__(self, parent) self.context = context self.action_name = name self.opts = opts try: values = self.VALUES[name] except KeyError: values = self.VALUES[name] = {} self.setWindowModality(Qt.ApplicationModal) title = opts.get('title') if title: self.setWindowTitle(os.path.expandvars(title)) self.prompt = QtWidgets.QLabel() prompt = opts.get('prompt') if prompt: self.prompt.setText(os.path.expandvars(prompt)) self.argslabel = QtWidgets.QLabel() if 'argprompt' not in opts or opts.get('argprompt') is True: argprompt = N_('Arguments') else: argprompt = opts.get('argprompt') self.argslabel.setText(argprompt) self.argstxt = LineEdit() if self.opts.get('argprompt'): try: # Remember the previous value saved_value = values['argstxt'] self.argstxt.setText(saved_value) except KeyError: pass else: self.argslabel.setMinimumSize(1, 1) self.argstxt.setMinimumSize(1, 1) self.argstxt.hide() self.argslabel.hide() revs = ( (N_('Local Branch'), gitcmds.branch_list(context, remote=False)), (N_('Tracking Branch'), gitcmds.branch_list(context, remote=True)), (N_('Tag'), gitcmds.tag_list(context)), ) if 'revprompt' not in opts or opts.get('revprompt') is True: revprompt = N_('Revision') else: revprompt = opts.get('revprompt') self.revselect = RevisionSelector(context, self, revs) self.revselect.set_revision_label(revprompt) if not opts.get('revprompt'): self.revselect.hide() # Close/Run buttons self.closebtn = qtutils.close_button() self.runbtn = qtutils.create_button(text=N_('Run'), default=True, icon=icons.ok()) self.argslayt = qtutils.hbox(defs.margin, defs.spacing, self.argslabel, self.argstxt) self.btnlayt = qtutils.hbox(defs.margin, defs.spacing, qtutils.STRETCH, self.closebtn, self.runbtn) self.layt = qtutils.vbox(defs.margin, defs.spacing, self.prompt, self.argslayt, self.revselect, self.btnlayt) self.setLayout(self.layt) # pylint: disable=no-member self.argstxt.textChanged.connect(self._argstxt_changed) qtutils.connect_button(self.closebtn, self.reject) qtutils.connect_button(self.runbtn, self.accept) # Widen the dialog by default self.resize(666, self.height()) def revision(self): return self.revselect.revision() def args(self): return self.argstxt.text() def _argstxt_changed(self, value): """Store the argstxt value so that we can remember it between calls""" self.VALUES[self.action_name]['argstxt'] = value class RevisionSelector(QtWidgets.QWidget): def __init__(self, context, parent, revs): QtWidgets.QWidget.__init__(self, parent) self.context = context self._revs = revs self._revdict = dict(revs) self._rev_label = QtWidgets.QLabel(self) self._revision = completion.GitRefLineEdit(context, parent=self) # Create the radio buttons radio_btns = [] self._radio_btns = {} for label, rev_list in self._revs: radio = qtutils.radio(text=label) radio.setObjectName(label) qtutils.connect_button(radio, self._set_revision_list) radio_btns.append(radio) self._radio_btns[label] = radio radio_btns.append(qtutils.STRETCH) self._rev_list = QtWidgets.QListWidget() label, rev_list = self._revs[0] self._radio_btns[label].setChecked(True) qtutils.set_items(self._rev_list, rev_list) self._rev_layt = qtutils.hbox(defs.no_margin, defs.spacing, self._rev_label, self._revision) self._radio_layt = qtutils.hbox(defs.margin, defs.spacing, *radio_btns) self._layt = qtutils.vbox(defs.no_margin, defs.spacing, self._rev_layt, self._radio_layt, self._rev_list) self.setLayout(self._layt) # pylint: disable=no-member self._rev_list.itemSelectionChanged.connect(self.selection_changed) def revision(self): return self._revision.text() def set_revision_label(self, txt): self._rev_label.setText(txt) def _set_revision_list(self): sender = self.sender().objectName() revs = self._revdict[sender] qtutils.set_items(self._rev_list, revs) def selection_changed(self): items = self._rev_list.selectedItems() if not items: return self._revision.setText(items[0].text()) git-cola-3.6/cola/widgets/clone.py000066400000000000000000000156101356743264500171410ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals import os from functools import partial from qtpy import QtCore from qtpy import QtWidgets from qtpy.QtCore import Qt from .. import cmds from .. import core from .. import icons from .. import utils from .. import qtutils from ..i18n import N_ from ..interaction import Interaction from ..qtutils import get from . import defs from . import standard from . import text def clone(context, spawn=True, show=True, settings=None, parent=None): """Clone a repository and spawn a new git-cola instance""" parent = qtutils.active_window() progress = standard.progress('', '', parent) return clone_repo(context, parent, show, settings, progress, task_finished, spawn) def clone_repo(context, parent, show, settings, progress, finish, spawn): """Clone a repository asynchronously with progress animation""" fn = partial(start_clone_task, context, parent, progress, finish, spawn) prompt = prompt_for_clone(context, show=show, settings=settings) prompt.result.connect(fn) return prompt def prompt_for_clone(context, show=True, settings=None): """Presents a GUI for cloning a repository""" view = Clone(context, settings=settings, parent=qtutils.active_window()) if show: view.show() return view def task_finished(task): """Report errors from the clone task if they exist""" cmd = task.cmd if cmd is None: return status = cmd.status out = cmd.out err = cmd.err title = N_('Error: could not clone "%s"') % cmd.url Interaction.command(title, 'git clone', status, out, err) def start_clone_task(context, parent, progress, finish, spawn, url, destdir, submodules, shallow): # Use a thread to update in the background runtask = context.runtask progress.set_details(N_('Clone Repository'), N_('Cloning repository at %s') % url) task = CloneTask(context, url, destdir, submodules, shallow, spawn, parent) runtask.start(task, finish=finish, progress=progress) class CloneTask(qtutils.Task): """Clones a Git repository""" def __init__(self, context, url, destdir, submodules, shallow, spawn, parent): qtutils.Task.__init__(self, parent) self.context = context self.url = url self.destdir = destdir self.submodules = submodules self.shallow = shallow self.spawn = spawn self.cmd = None def task(self): """Runs the model action and captures the result""" self.cmd = cmds.do( cmds.Clone, self.context, self.url, self.destdir, self.submodules, self.shallow, spawn=self.spawn) return self.cmd class Clone(standard.Dialog): # Signal binding for returning the input data result = QtCore.Signal(object, object, bool, bool) def __init__(self, context, settings=None, parent=None): standard.Dialog.__init__(self, parent=parent) self.context = context self.model = context.model self.setWindowTitle(N_('Clone Repository')) if parent is not None: self.setWindowModality(Qt.WindowModal) # Repository location self.url_label = QtWidgets.QLabel(N_('URL')) hint = 'git://git.example.com/repo.git' self.url = text.HintedLineEdit(context, hint, parent=self) self.url.setToolTip(N_('Path or URL to clone (Env. $VARS okay)')) # Initialize submodules self.submodules = qtutils.checkbox( text=N_('Inititalize submodules'), checked=False) # Reduce commit history self.shallow = qtutils.checkbox( text=N_('Reduce commit history to minimum'), checked=False) # Buttons self.ok_button = qtutils.create_button( text=N_('Clone'), icon=icons.ok(), default=True) self.close_button = qtutils.close_button() # Form layout for inputs self.input_layout = qtutils.form( defs.no_margin, defs.button_spacing, (self.url_label, self.url)) self.button_layout = qtutils.hbox( defs.margin, defs.spacing, self.submodules, defs.button_spacing, self.shallow, qtutils.STRETCH, self.ok_button, self.close_button) self.main_layout = qtutils.vbox(defs.margin, defs.spacing, self.input_layout, self.button_layout) self.setLayout(self.main_layout) qtutils.connect_button(self.close_button, self.close) qtutils.connect_button(self.ok_button, self.prepare_to_clone) # pylint: disable=no-member self.url.textChanged.connect(lambda x: self.update_actions()) self.init_state(settings, self.resize, 720, 200) self.update_actions() def update_actions(self): url = get(self.url).strip() enabled = bool(url) self.ok_button.setEnabled(enabled) def prepare_to_clone(self): """Grabs and validates the input data""" submodules = get(self.submodules) shallow = get(self.shallow) url = get(self.url) url = utils.expandpath(url) if not url: return # Pick a suitable basename by parsing the URL newurl = url.replace('\\', '/').rstrip('/') try: default = newurl.rsplit('/', 1)[-1] except IndexError: default = '' if default == '.git': # The end of the URL is /.git, so assume it's a file path default = os.path.basename(os.path.dirname(newurl)) if default.endswith('.git'): # The URL points to a bare repo default = default[:-4] if url == '.': # The URL is the current repo default = os.path.basename(core.getcwd()) if not default: Interaction.information( N_('Error Cloning'), N_('Could not parse Git URL: "%s"') % url) Interaction.log(N_('Could not parse Git URL: "%s"') % url) return # Prompt the user for a directory to use as the parent directory msg = N_('Select a parent directory for the new clone') dirname = qtutils.opendir_dialog(msg, self.model.getcwd()) if not dirname: return count = 1 destdir = os.path.join(dirname, default) olddestdir = destdir if core.exists(destdir): # An existing path can be specified msg = ( N_('"%s" already exists, cola will create a new directory') % destdir) Interaction.information(N_('Directory Exists'), msg) # Make sure the new destdir doesn't exist while core.exists(destdir): destdir = olddestdir + str(count) count += 1 # Return the input data and close the dialog self.result.emit(url, destdir, submodules, shallow) self.close() git-cola-3.6/cola/widgets/commitmsg.py000066400000000000000000000611661356743264500200470ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals from functools import partial from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from qtpy.QtCore import Qt from qtpy.QtCore import Signal from .. import actions from .. import cmds from .. import core from .. import gitcmds from .. import hotkeys from .. import icons from .. import textwrap from .. import qtutils from ..interaction import Interaction from ..gitcmds import commit_message_path from ..i18n import N_ from ..models import dag from ..models import prefs from ..qtutils import get from ..utils import Group from . import defs from .selectcommits import select_commits from .spellcheck import SpellCheckTextEdit from .text import HintedLineEdit class CommitMessageEditor(QtWidgets.QFrame): commit_message_changed = Signal(object) cursor_changed = Signal(int, int) down = Signal() up = Signal() updated = Signal() def __init__(self, context, parent): QtWidgets.QFrame.__init__(self, parent) self.context = context self.model = model = context.model self.spellcheck_initialized = False self._linebreak = None self._textwidth = None self._tabwidth = None # Actions self.signoff_action = qtutils.add_action( self, cmds.SignOff.name(), cmds.run(cmds.SignOff, context), hotkeys.SIGNOFF) self.signoff_action.setToolTip(N_('Sign off on this commit')) self.commit_action = qtutils.add_action( self, N_('Commit@@verb'), self.commit, hotkeys.COMMIT) self.commit_action.setIcon(icons.commit()) self.commit_action.setToolTip(N_('Commit staged changes')) self.clear_action = qtutils.add_action( self, N_('Clear...'), self.clear) self.launch_editor = actions.launch_editor(context, self) self.launch_difftool = actions.launch_difftool(context, self) self.stage_or_unstage = actions.stage_or_unstage(context, self) self.move_up = actions.move_up(self) self.move_down = actions.move_down(self) # Menu acctions self.menu_actions = menu_actions = [ None, self.signoff_action, self.commit_action, None, self.launch_editor, self.launch_difftool, self.stage_or_unstage, None, self.move_up, self.move_down, ] # Widgets self.summary = CommitSummaryLineEdit(context) self.summary.setMinimumHeight(defs.tool_button_height) self.summary.menu_actions.extend(menu_actions) cfg = context.cfg self.summary_validator = MessageValidator(context, parent=self.summary) self.summary.setValidator(self.summary_validator) self.description = CommitMessageTextEdit(context, parent=self) self.description.set_dictionary(cfg.get('cola.dictionary', None)) self.description.menu_actions.extend(menu_actions) commit_button_tooltip = N_('Commit staged changes\n' 'Shortcut: Ctrl+Enter') self.commit_button = qtutils.create_button( text=N_('Commit@@verb'), tooltip=commit_button_tooltip, icon=icons.commit()) self.commit_group = Group(self.commit_action, self.commit_button) self.actions_menu = qtutils.create_menu(N_('Actions'), self) self.actions_button = qtutils.create_toolbutton( icon=icons.configure(), tooltip=N_('Actions...')) self.actions_button.setMenu(self.actions_menu) self.actions_menu.addAction(self.signoff_action) self.actions_menu.addAction(self.commit_action) self.actions_menu.addSeparator() # Amend checkbox self.amend_action = self.actions_menu.addAction( N_('Amend Last Commit')) self.amend_action.setCheckable(True) self.amend_action.setShortcut(hotkeys.AMEND) self.amend_action.setShortcutContext(Qt.ApplicationShortcut) # Bypass hooks self.bypass_commit_hooks_action = self.actions_menu.addAction( N_('Bypass Commit Hooks')) self.bypass_commit_hooks_action.setCheckable(True) self.bypass_commit_hooks_action.setChecked(False) # Sign commits self.sign_action = self.actions_menu.addAction( N_('Create Signed Commit')) self.sign_action.setCheckable(True) signcommits = cfg.get('cola.signcommits', default=False) self.sign_action.setChecked(signcommits) # Spell checker self.check_spelling_action = self.actions_menu.addAction( N_('Check Spelling')) self.check_spelling_action.setCheckable(True) spellcheck = prefs.spellcheck(context) self.check_spelling_action.setChecked(spellcheck) self.toggle_check_spelling(spellcheck) # Line wrapping self.autowrap_action = self.actions_menu.addAction( N_('Auto-Wrap Lines')) self.autowrap_action.setCheckable(True) self.autowrap_action.setChecked(prefs.linebreak(context)) # Commit message self.actions_menu.addSeparator() self.load_commitmsg_menu = self.actions_menu.addMenu( N_('Load Previous Commit Message')) self.load_commitmsg_menu.aboutToShow.connect(self.build_commitmsg_menu) self.fixup_commit_menu = self.actions_menu.addMenu( N_('Fixup Previous Commit')) self.fixup_commit_menu.aboutToShow.connect(self.build_fixup_menu) self.toplayout = qtutils.hbox(defs.no_margin, defs.spacing, self.actions_button, self.summary, self.commit_button) self.toplayout.setContentsMargins(defs.margin, defs.no_margin, defs.no_margin, defs.no_margin) self.mainlayout = qtutils.vbox(defs.no_margin, defs.spacing, self.toplayout, self.description) self.setLayout(self.mainlayout) qtutils.connect_button(self.commit_button, self.commit) # Broadcast the amend mode qtutils.connect_action_bool( self.amend_action, partial(cmds.run(cmds.AmendMode), context)) qtutils.connect_action_bool(self.check_spelling_action, self.toggle_check_spelling) # Handle the one-off autowrapping qtutils.connect_action_bool(self.autowrap_action, self.set_linebreak) qtutils.add_action(self.summary, N_('Move Down'), self.focus_description, *hotkeys.ACCEPT) qtutils.add_action(self.summary, N_('Move Down'), self.summary_cursor_down, hotkeys.DOWN) self.selection = selection = context.selection selection.add_observer( selection.message_selection_changed, self.updated.emit) self.model.add_observer(self.model.message_commit_message_changed, self.commit_message_changed.emit) self.commit_message_changed.connect(self.set_commit_message, type=Qt.QueuedConnection) self.summary.cursor_changed.connect(self.cursor_changed.emit) self.description.cursor_changed.connect( # description starts at line 2 lambda row, col: self.cursor_changed.emit(row + 2, col)) # pylint: disable=no-member self.summary.textChanged.connect(self.commit_summary_changed) self.description.textChanged.connect(self._commit_message_changed) self.description.leave.connect(self.focus_summary) self.updated.connect(self.refresh) self.commit_group.setEnabled(False) self.set_expandtab(prefs.expandtab(context)) self.set_tabwidth(prefs.tabwidth(context)) self.set_textwidth(prefs.textwidth(context)) self.set_linebreak(prefs.linebreak(context)) # Loading message commit_msg = '' commit_msg_path = commit_message_path(context) if commit_msg_path: commit_msg = core.read(commit_msg_path) model.set_commitmsg(commit_msg) # Allow tab to jump from the summary to the description self.setTabOrder(self.summary, self.description) self.setFont(qtutils.diff_font(context)) self.setFocusProxy(self.summary) cfg.add_observer(cfg.message_user_config_changed, self.config_changed) def config_changed(self, key, value): if key != prefs.SPELL_CHECK: return if get(self.check_spelling_action) == value: return self.check_spelling_action.setChecked(value) self.toggle_check_spelling(value) def refresh(self): enabled = self.model.stageable() or self.model.unstageable() if self.model.stageable(): text = N_('Stage') else: text = N_('Unstage') self.stage_or_unstage.setEnabled(enabled) self.stage_or_unstage.setText(text) def set_initial_size(self): self.setMaximumHeight(133) QtCore.QTimer.singleShot(1, self.restore_size) def restore_size(self): self.setMaximumHeight(2 ** 13) def focus_summary(self): self.summary.setFocus() def focus_description(self): self.description.setFocus() def summary_cursor_down(self): """Handle the down key in the summary field If the cursor is at the end of the line then focus the description. Otherwise, move the cursor to the end of the line so that a subsequence "down" press moves to the end of the line. """ cur_position = self.summary.cursorPosition() end_position = len(get(self.summary)) if cur_position == end_position: self.focus_description() else: self.summary.setCursorPosition(end_position) def commit_message(self, raw=True): """Return the commit message as a unicode string""" summary = get(self.summary) if raw: description = get(self.description) else: description = self.formatted_description() if summary and description: return summary + '\n\n' + description if summary: return summary if description: return '\n\n' + description return '' def formatted_description(self): text = get(self.description) if not self._linebreak: return text return textwrap.word_wrap(text, self._tabwidth, self._textwidth) def commit_summary_changed(self, value): """Respond to changes to the `summary` field Newlines can enter the `summary` field when pasting, which is undesirable. Break the pasted value apart into the separate (summary, description) values and move the description over to the "extended description" field. """ if '\n' in value: summary, description = value.split('\n', 1) description = description.lstrip('\n') cur_description = get(self.description) if cur_description: description = description + '\n' + cur_description # this callback is triggered by changing `summary` # so disable signals for `summary` only. self.summary.set_value(summary, block=True) self.description.set_value(description) self._commit_message_changed() def _commit_message_changed(self, _value=None): """Update the model when values change""" message = self.commit_message() self.model.set_commitmsg(message, notify=False) self.refresh_palettes() self.update_actions() def clear(self): if not Interaction.confirm( N_('Clear commit message?'), N_('The commit message will be cleared.'), N_('This cannot be undone. Clear commit message?'), N_('Clear commit message'), default=True, icon=icons.discard()): return self.model.set_commitmsg('') def update_actions(self): commit_enabled = bool(get(self.summary)) self.commit_group.setEnabled(commit_enabled) def refresh_palettes(self): """Update the color palette for the hint text""" self.summary.hint.refresh() self.description.hint.refresh() def set_commit_message(self, message): """Set the commit message to match the observed model""" # Parse the "summary" and "description" fields lines = message.splitlines() num_lines = len(lines) if num_lines == 0: # Message is empty summary = '' description = '' elif num_lines == 1: # Message has a summary only summary = lines[0] description = '' elif num_lines == 2: # Message has two lines; this is not a common case summary = lines[0] description = lines[1] else: # Summary and several description lines summary = lines[0] if lines[1]: # We usually skip this line but check just in case description_lines = lines[1:] else: description_lines = lines[2:] description = '\n'.join(description_lines) focus_summary = not summary focus_description = not description # Update summary self.summary.set_value(summary, block=True) # Update description self.description.set_value(description, block=True) # Update text color self.refresh_palettes() # Focus the empty summary or description if focus_summary: self.summary.setFocus() elif focus_description: self.description.setFocus() else: self.summary.cursor_position.emit() self.update_actions() def set_expandtab(self, value): self.description.set_expandtab(value) def set_tabwidth(self, width): self._tabwidth = width self.description.set_tabwidth(width) def set_textwidth(self, width): self._textwidth = width self.description.set_textwidth(width) def set_linebreak(self, brk): self._linebreak = brk self.description.set_linebreak(brk) blocksignals = self.autowrap_action.blockSignals(True) self.autowrap_action.setChecked(brk) self.autowrap_action.blockSignals(blocksignals) def setFont(self, font): """Pass the setFont() calls down to the text widgets""" self.summary.setFont(font) self.description.setFont(font) def set_mode(self, mode): can_amend = not self.model.is_merging checked = (mode == self.model.mode_amend) blocksignals = self.amend_action.blockSignals(True) self.amend_action.setEnabled(can_amend) self.amend_action.setChecked(checked) self.amend_action.blockSignals(blocksignals) def commit(self): """Attempt to create a commit from the index and commit message.""" context = self.context if not bool(get(self.summary)): # Describe a good commit message error_msg = N_( 'Please supply a commit message.\n\n' 'A good commit message has the following format:\n\n' '- First line: Describe in one sentence what you did.\n' '- Second line: Blank\n' '- Remaining lines: Describe why this change is good.\n') Interaction.log(error_msg) Interaction.information(N_('Missing Commit Message'), error_msg) return msg = self.commit_message(raw=False) # We either need to have something staged, or be merging. # If there was a merge conflict resolved, there may not be anything # to stage, but we still need to commit to complete the merge. if not (self.model.staged or self.model.is_merging): error_msg = N_( 'No changes to commit.\n\n' 'You must stage at least 1 file before you can commit.') if self.model.modified: informative_text = N_('Would you like to stage and ' 'commit all modified files?') if not Interaction.confirm( N_('Stage and commit?'), error_msg, informative_text, N_('Stage and Commit'), default=True, icon=icons.save()): return else: Interaction.information(N_('Nothing to commit'), error_msg) return cmds.do(cmds.StageModified, context) # Warn that amending published commits is generally bad amend = get(self.amend_action) if (amend and self.model.is_commit_published() and not Interaction.confirm( N_('Rewrite Published Commit?'), N_('This commit has already been published.\n' 'This operation will rewrite published history.\n' 'You probably don\'t want to do this.'), N_('Amend the published commit?'), N_('Amend Commit'), default=False, icon=icons.save())): return no_verify = get(self.bypass_commit_hooks_action) sign = get(self.sign_action) cmds.do(cmds.Commit, context, amend, msg, sign, no_verify=no_verify) self.bypass_commit_hooks_action.setChecked(False) def build_fixup_menu(self): self.build_commits_menu(cmds.LoadFixupMessage, self.fixup_commit_menu, self.choose_fixup_commit, prefix='fixup! ') def build_commitmsg_menu(self): self.build_commits_menu(cmds.LoadCommitMessageFromOID, self.load_commitmsg_menu, self.choose_commit_message) def build_commits_menu(self, cmd, menu, chooser, prefix=''): context = self.context params = dag.DAG('HEAD', 6) commits = dag.RepoReader(context, params) menu_commits = [] for idx, c in enumerate(commits.get()): menu_commits.insert(0, c) if idx > 5: continue menu.clear() for c in menu_commits: menu.addAction(prefix + c.summary, cmds.run(cmd, context, c.oid)) if len(commits) == 6: menu.addSeparator() menu.addAction(N_('More...'), chooser) def choose_commit(self, cmd): context = self.context revs, summaries = gitcmds.log_helper(context) oids = select_commits( context, N_('Select Commit'), revs, summaries, multiselect=False) if not oids: return oid = oids[0] cmds.do(cmd, context, oid) def choose_commit_message(self): self.choose_commit(cmds.LoadCommitMessageFromOID) def choose_fixup_commit(self): self.choose_commit(cmds.LoadFixupMessage) def toggle_check_spelling(self, enabled): spellcheck = self.description.spellcheck cfg = self.context.cfg if cfg.get_user(prefs.SPELL_CHECK) != enabled: cfg.set_user(prefs.SPELL_CHECK, enabled) if enabled and not self.spellcheck_initialized: # Add our name to the dictionary self.spellcheck_initialized = True user_name = cfg.get('user.name') if user_name: for part in user_name.split(): spellcheck.add_word(part) # Add our email address to the dictionary user_email = cfg.get('user.email') if user_email: for part in user_email.split('@'): for elt in part.split('.'): spellcheck.add_word(elt) # git jargon spellcheck.add_word('Acked') spellcheck.add_word('Signed') spellcheck.add_word('Closes') spellcheck.add_word('Fixes') self.description.highlighter.enable(enabled) class MessageValidator(QtGui.QValidator): """Prevent invalid branch names""" config_updated = Signal() def __init__(self, context, parent=None): super(MessageValidator, self).__init__(parent) self.context = context self._comment_char = None self._cfg = cfg = context.cfg self.refresh() # pylint: disable=no-member self.config_updated.connect(self.refresh, type=Qt.QueuedConnection) cfg.add_observer(cfg.message_updated, self.emit_config_updated) self.destroyed.connect(self.teardown) def teardown(self): self._cfg.remove_observer(self.emit_config_updated) def emit_config_updated(self): self.config_updated.emit() def refresh(self): """Update comment char in response to config changes""" self._comment_char = prefs.comment_char(self.context) def validate(self, string, idx): """Scrub whitespace and validate the commit message""" string = string.lstrip() if string.startswith(self._comment_char): state = self.Invalid else: state = self.Acceptable return (state, string, idx) class CommitSummaryLineEdit(HintedLineEdit): cursor = Signal(int, int) def __init__(self, context, parent=None): hint = N_('Commit summary') HintedLineEdit.__init__(self, context, hint, parent=parent) self.menu_actions = [] def build_menu(self): menu = self.createStandardContextMenu() add_menu_actions(menu, self.menu_actions) return menu def contextMenuEvent(self, event): menu = self.build_menu() menu.exec_(self.mapToGlobal(event.pos())) # pylint: disable=too-many-ancestors class CommitMessageTextEdit(SpellCheckTextEdit): leave = Signal() def __init__(self, context, parent=None): hint = N_('Extended description...') SpellCheckTextEdit.__init__(self, context, hint, parent) self.menu_actions = [] self.action_emit_leave = qtutils.add_action( self, 'Shift Tab', self.leave.emit, hotkeys.LEAVE) def build_menu(self): menu, _ = self.context_menu() add_menu_actions(menu, self.menu_actions) return menu def contextMenuEvent(self, event): menu = self.build_menu() menu.exec_(self.mapToGlobal(event.pos())) def keyPressEvent(self, event): if event.key() == Qt.Key_Up: cursor = self.textCursor() position = cursor.position() if position == 0: # The cursor is at the beginning of the line. # If we have selection then simply reset the cursor. # Otherwise, emit a signal so that the parent can # change focus. if cursor.hasSelection(): cursor.setPosition(0) self.setTextCursor(cursor) else: self.leave.emit() event.accept() return text_before = self.toPlainText()[:position] lines_before = text_before.count('\n') if lines_before == 0: # If we're on the first line, but not at the # beginning, then move the cursor to the beginning # of the line. if event.modifiers() & Qt.ShiftModifier: mode = QtGui.QTextCursor.KeepAnchor else: mode = QtGui.QTextCursor.MoveAnchor cursor.setPosition(0, mode) self.setTextCursor(cursor) event.accept() return elif event.key() == Qt.Key_Down: cursor = self.textCursor() position = cursor.position() all_text = self.toPlainText() text_after = all_text[position:] lines_after = text_after.count('\n') if lines_after == 0: if event.modifiers() & Qt.ShiftModifier: mode = QtGui.QTextCursor.KeepAnchor else: mode = QtGui.QTextCursor.MoveAnchor cursor.setPosition(len(all_text), mode) self.setTextCursor(cursor) event.accept() return SpellCheckTextEdit.keyPressEvent(self, event) def setFont(self, font): SpellCheckTextEdit.setFont(self, font) fm = self.fontMetrics() self.setMinimumSize(QtCore.QSize(1, fm.height() * 2)) def add_menu_actions(menu, menu_actions): """Add actions to a menu, treating None as a separator""" for action in menu_actions: if action is None: menu.addSeparator() else: menu.addAction(action) git-cola-3.6/cola/widgets/common.py000066400000000000000000000040311356743264500173240ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals from ..i18n import N_ from .. import cmds from .. import hotkeys from .. import icons from .. import qtutils from .. import utils def cmd_action(parent, cmd, context, fn, *keys): """Wrap a standard Command object in a QAction This function assumes that :func:`fn()` takes no arguments, that `cmd` has a :func:`name()` method, and that the `cmd` constructor takes a single argument, as returned by `fn`. """ return qtutils.add_action( parent, cmd.name(), lambda: cmds.do(cmd, context, fn()), *keys) def default_app_action(context, parent, fn): """Open paths with the OS-default app -> QAction""" action = cmd_action(parent, cmds.OpenDefaultApp, context, fn, hotkeys.PRIMARY_ACTION) action.setIcon(icons.default_app()) return action def edit_action(context, parent, *keys): """Launch an editor -> QAction""" action = qtutils.add_action_with_status_tip( parent, cmds.LaunchEditor.name(), N_('Edit selected paths'), cmds.run(cmds.LaunchEditor, context), hotkeys.EDIT, *keys) action.setIcon(icons.edit()) return action def parent_dir_action(context, parent, fn): """Open the parent directory of paths -> QAction""" hotkey = hotkeys.SECONDARY_ACTION action = cmd_action(parent, cmds.OpenParentDir, context, fn, hotkey) action.setIcon(icons.folder()) return action def refresh_action(context, parent): """Refresh the repository state -> QAction""" return qtutils.add_action(parent, cmds.Refresh.name(), cmds.run(cmds.Refresh, context), hotkeys.REFRESH) def terminal_action(context, parent, fn): """Launch a terminal -> QAction""" action = None if cmds.LaunchTerminal.is_available(context): action = cmd_action(parent, cmds.LaunchTerminal, context, lambda: utils.select_directory(fn()), hotkeys.TERMINAL) return action git-cola-3.6/cola/widgets/compare.py000066400000000000000000000216521356743264500174720ustar00rootroot00000000000000"""Provides dialogs for comparing branches and commits.""" from __future__ import division, absolute_import, unicode_literals from qtpy import QtWidgets from qtpy.QtCore import Qt from .. import cmds from .. import gitcmds from .. import icons from .. import qtutils from ..i18n import N_ from ..qtutils import connect_button from . import defs from . import standard class FileItem(QtWidgets.QTreeWidgetItem): def __init__(self, path, icon): QtWidgets.QTreeWidgetItem.__init__(self, [path]) self.path = path self.setIcon(0, icon) def compare_branches(context): """Launches a dialog for comparing a pair of branches""" view = CompareBranchesDialog(context, qtutils.active_window()) view.show() return view class CompareBranchesDialog(standard.Dialog): def __init__(self, context, parent): standard.Dialog.__init__(self, parent=parent) self.context = context self.BRANCH_POINT = N_('*** Branch Point ***') self.SANDBOX = N_('*** Sandbox ***') self.LOCAL = N_('Local') self.diff_arg = () self.use_sandbox = False self.start = None self.end = None self.setWindowTitle(N_('Branch Diff Viewer')) self.remote_branches = gitcmds.branch_list(context, remote=True) self.local_branches = gitcmds.branch_list(context, remote=False) self.top_widget = QtWidgets.QWidget() self.bottom_widget = QtWidgets.QWidget() self.left_combo = QtWidgets.QComboBox() self.left_combo.addItem(N_('Local')) self.left_combo.addItem(N_('Remote')) self.left_combo.setCurrentIndex(0) self.right_combo = QtWidgets.QComboBox() self.right_combo.addItem(N_('Local')) self.right_combo.addItem(N_('Remote')) self.right_combo.setCurrentIndex(1) self.left_list = QtWidgets.QListWidget() self.right_list = QtWidgets.QListWidget() Expanding = QtWidgets.QSizePolicy.Expanding Minimum = QtWidgets.QSizePolicy.Minimum self.button_spacer = QtWidgets.QSpacerItem(1, 1, Expanding, Minimum) self.button_compare = qtutils.create_button(text=N_('Compare'), icon=icons.diff()) self.button_close = qtutils.close_button() self.diff_files = standard.TreeWidget() self.diff_files.headerItem().setText(0, N_('File Differences')) self.top_grid_layout = qtutils.grid( defs.no_margin, defs.spacing, (self.left_combo, 0, 0, 1, 1), (self.left_list, 1, 0, 1, 1), (self.right_combo, 0, 1, 1, 1), (self.right_list, 1, 1, 1, 1)) self.top_widget.setLayout(self.top_grid_layout) self.bottom_grid_layout = qtutils.grid( defs.no_margin, defs.button_spacing, (self.diff_files, 0, 0, 1, 4), (self.button_spacer, 1, 1, 1, 1), (self.button_close, 1, 0, 1, 1), (self.button_compare, 1, 3, 1, 1)) self.bottom_widget.setLayout(self.bottom_grid_layout) self.splitter = qtutils.splitter(Qt.Vertical, self.top_widget, self.bottom_widget) self.main_layout = qtutils.vbox(defs.margin, defs.spacing, self.splitter) self.setLayout(self.main_layout) connect_button(self.button_close, self.accept) connect_button(self.button_compare, self.compare) # pylint: disable=no-member self.diff_files.itemDoubleClicked.connect(lambda _: self.compare()) self.left_combo.currentIndexChanged.connect( lambda x: self.update_combo_boxes(left=True)) self.right_combo.currentIndexChanged.connect( lambda x: self.update_combo_boxes(left=False)) self.left_list.itemSelectionChanged.connect(self.update_diff_files) self.right_list.itemSelectionChanged.connect(self.update_diff_files) self.update_combo_boxes(left=True) self.update_combo_boxes(left=False) # Pre-select the 0th elements item = self.left_list.item(0) if item: self.left_list.setCurrentItem(item) item.setSelected(True) item = self.right_list.item(0) if item: self.right_list.setCurrentItem(item) item.setSelected(True) self.init_size(parent=parent) def selection(self): left_item = self.left_list.currentItem() if left_item and left_item.isSelected(): left_item = left_item.text() else: left_item = None right_item = self.right_list.currentItem() if right_item and right_item.isSelected(): right_item = right_item.text() else: right_item = None return (left_item, right_item) def update_diff_files(self): """Updates the list of files whenever the selection changes""" # Left and Right refer to the comparison pair (l,r) left_item, right_item = self.selection() if (not left_item or not right_item or left_item == right_item): self.set_diff_files([]) return left_item = self.remote_ref(left_item) right_item = self.remote_ref(right_item) # If any of the selection includes sandbox then we # generate the same diff, regardless. This means we don't # support reverse diffs against sandbox aka worktree. if self.SANDBOX in (left_item, right_item): self.use_sandbox = True if left_item == self.SANDBOX: self.diff_arg = (right_item,) else: self.diff_arg = (left_item,) else: self.diff_arg = (left_item, right_item) self.use_sandbox = False # start and end as in 'git diff start end' self.start = left_item self.end = right_item context = self.context if len(self.diff_arg) == 1: files = gitcmds.diff_index_filenames(context, self.diff_arg[0]) else: files = gitcmds.diff_filenames(context, *self.diff_arg) self.set_diff_files(files) def set_diff_files(self, files): mk = FileItem icon = icons.file_code() self.diff_files.clear() self.diff_files.addTopLevelItems([mk(f, icon) for f in files]) def remote_ref(self, branch): """Returns the remote ref for 'git diff [local] [remote]' """ context = self.context if branch == self.BRANCH_POINT: # Compare against the branch point so find the merge-base branch = gitcmds.current_branch(context) tracked_branch = gitcmds.tracked_branch(context) if tracked_branch: return gitcmds.merge_base(context, branch, tracked_branch) else: remote_branches = gitcmds.branch_list(context, remote=True) remote_branch = 'origin/%s' % branch if remote_branch in remote_branches: return gitcmds.merge_base(context, branch, remote_branch) if 'origin/master' in remote_branches: return gitcmds.merge_base(context, branch, 'origin/master') return 'HEAD' else: # Compare against the remote branch return branch def update_combo_boxes(self, left=False): """Update listwidgets from the combobox selection Update either the left or right listwidgets to reflect the available items. """ if left: which = self.left_combo.currentText() widget = self.left_list else: which = self.right_combo.currentText() widget = self.right_list if not which: return # If we're looking at "local" stuff then provide the # sandbox as a valid choice. If we're looking at # "remote" stuff then also include the branch point. if which == self.LOCAL: new_list = ([self.SANDBOX] + self.local_branches) else: new_list = ([self.BRANCH_POINT] + self.remote_branches) widget.clear() widget.addItems(new_list) if new_list: item = widget.item(0) widget.setCurrentItem(item) item.setSelected(True) def compare(self): """Shows the diff for a specific file """ tree_widget = self.diff_files item = tree_widget.currentItem() if item and item.isSelected(): self.compare_file(item.path) def compare_file(self, filename): """Initiates the difftool session""" if self.use_sandbox: left = self.diff_arg[0] if len(self.diff_arg) > 1: right = self.diff_arg[1] else: right = None else: left, right = self.start, self.end context = self.context cmds.difftool_launch(context, left=left, right=right, paths=[filename]) git-cola-3.6/cola/widgets/completion.py000066400000000000000000000655711356743264500202250ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals import re from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from qtpy.QtCore import Qt from qtpy.QtCore import Signal from ..models import prefs from .. import core from .. import gitcmds from .. import icons from .. import qtutils from .. import utils from . import defs from .text import HintedLineEdit class ValidateRegex(object): def __init__(self, regex): self.regex = re.compile(regex) # regex to scrub def validate(self, string, idx): """Scrub and validate the user-supplied input""" state = QtGui.QValidator.Acceptable if self.regex.search(string): string = self.regex.sub('', string) # scrub matching bits idx = min(idx-1, len(string)) return (state, string, idx) class RemoteValidator(QtGui.QValidator): """Prevent invalid remote names""" def __init__(self, parent=None): super(RemoteValidator, self).__init__(parent) self._validate = ValidateRegex(r'[ \t\\/]') def validate(self, string, idx): return self._validate.validate(string, idx) class BranchValidator(QtGui.QValidator): """Prevent invalid branch names""" def __init__(self, git, parent=None): super(BranchValidator, self).__init__(parent) self._git = git self._validate = ValidateRegex(r'[ \t\\]') # forward-slash is okay def validate(self, string, idx): """Scrub and validate the user-supplied input""" state, string, idx = self._validate.validate(string, idx) if string: # Allow empty strings status, _, _ = self._git.check_ref_format(string, branch=True) if status != 0: # The intermediate string, when deleting characters, might # end in a name that is invalid to Git, but we must allow it # otherwise we won't be able to delete it using backspace. if string.endswith('/') or string.endswith('.'): state = self.Intermediate else: state = self.Invalid return (state, string, idx) def _is_case_sensitive(text): return bool([char for char in text if char.isupper()]) class CompletionLineEdit(HintedLineEdit): """A lineedit with advanced completion abilities""" activated = Signal() changed = Signal() cleared = Signal() enter = Signal() up = Signal() down = Signal() # Activation keys will cause a selected completion item to be chosen ACTIVATION_KEYS = (Qt.Key_Return, Qt.Key_Enter) # Navigation keys trigger signals that widgets can use for customization NAVIGATION_KEYS = { Qt.Key_Return: 'enter', Qt.Key_Enter: 'enter', Qt.Key_Up: 'up', Qt.Key_Down: 'down', } def __init__(self, context, model_factory, hint='', parent=None): HintedLineEdit.__init__(self, context, hint, parent=parent) # Tracks when the completion popup was active during key events self.context = context # The most recently selected completion item self._selection = None # Create a completion model completion_model = model_factory(context, self) completer = Completer(completion_model, self) completer.setWidget(self) self._completer = completer self._completion_model = completion_model # The delegate highlights matching completion text in the popup widget self._delegate = HighlightDelegate(self) completer.popup().setItemDelegate(self._delegate) # pylint: disable=no-member self.textChanged.connect(self._text_changed) self._completer.activated.connect(self.choose_completion) self._completion_model.updated.connect(self._completions_updated, type=Qt.QueuedConnection) self.destroyed.connect(self.dispose) def __del__(self): self.dispose() # pylint: disable=unused-argument def dispose(self, *args): self._completer.dispose() def completion_selection(self): """Return the last completion's selection""" return self._selection def complete(self): """Trigger the completion popup to appear and offer completions""" self._completer.complete() def refresh(self): """Refresh the completion model""" return self._completer.model().update() def popup(self): """Return the completer's popup""" return self._completer.popup() def _text_changed(self, full_text): match_text = self._last_word() self._do_text_changed(full_text, match_text) self.complete_last_word() def _do_text_changed(self, full_text, match_text): case_sensitive = _is_case_sensitive(match_text) if case_sensitive: self._completer.setCaseSensitivity(Qt.CaseSensitive) else: self._completer.setCaseSensitivity(Qt.CaseInsensitive) self._delegate.set_highlight_text(match_text, case_sensitive) self._completer.set_match_text(full_text, match_text, case_sensitive) def update_matches(self): text = self._last_word() case_sensitive = _is_case_sensitive(text) self._completer.setCompletionPrefix(text) self._completer.model().update_matches(case_sensitive) def choose_completion(self, completion): """ This is the event handler for the QCompleter.activated(QString) signal, it is called when the user selects an item in the completer popup. """ if not completion: self._do_text_changed('', '') return words = self._words() if words and not self._ends_with_whitespace(): words.pop() words.append(completion) text = core.list2cmdline(words) self.setText(text) self.changed.emit() self._do_text_changed(text, '') self.popup().hide() def _words(self): return utils.shell_split(self.value()) def _ends_with_whitespace(self): value = self.value() return value != value.rstrip() def _last_word(self): if self._ends_with_whitespace(): return '' words = self._words() if not words: return self.value() if not words[-1]: return '' return words[-1] def complete_last_word(self): self.update_matches() self.complete() def close_popup(self): if self.popup().isVisible(): self.popup().close() def _completions_updated(self): popup = self.popup() if not popup.isVisible(): return # Select the first item idx = self._completion_model.index(0, 0) selection = QtCore.QItemSelection(idx, idx) mode = QtCore.QItemSelectionModel.Select popup.selectionModel().select(selection, mode) def selected_completion(self): """Return the selected completion item""" popup = self.popup() if not popup.isVisible(): return None model = popup.selectionModel() indexes = model.selectedIndexes() if not indexes: return None idx = indexes[0] item = self._completion_model.itemFromIndex(idx) if not item: return None return item.text() def select_completion(self): """Choose the selected completion option from the completion popup""" result = False visible = self.popup().isVisible() if visible: selection = self.selected_completion() if selection: self.choose_completion(selection) result = True return result # Qt overrides def event(self, event): """Override QWidget::event() for tab completion""" event_type = event.type() if (event_type == QtCore.QEvent.KeyPress and event.key() == Qt.Key_Tab and self.select_completion()): return True # Make sure the popup goes away during teardown if event_type == QtCore.QEvent.Hide: self.close_popup() return super(CompletionLineEdit, self).event(event) def keyPressEvent(self, event): """Process completion and navigation events""" super(CompletionLineEdit, self).keyPressEvent(event) visible = self.popup().isVisible() # Hide the popup when the field is empty is_empty = not self.value() if is_empty: self.cleared.emit() if visible: self.popup().hide() # Activation keys select the completion when pressed and emit the # activated signal. Navigation keys have lower priority, and only # emit when it wasn't already handled as an activation event. key = event.key() if key in self.ACTIVATION_KEYS and visible: if self.select_completion(): self.activated.emit() return navigation = self.NAVIGATION_KEYS.get(key, None) if navigation: signal = getattr(self, navigation) signal.emit() class GatherCompletionsThread(QtCore.QThread): items_gathered = Signal(object) def __init__(self, model): QtCore.QThread.__init__(self) self.model = model self.case_sensitive = False self.running = False def dispose(self): self.running = False self.wait() def run(self): text = None self.running = True # Loop when the matched text changes between the start and end time. # This happens when gather_matches() takes too long and the # model's match_text changes in-between. while self.running and text != self.model.match_text: text = self.model.match_text items = self.model.gather_matches(self.case_sensitive) if self.running and text is not None: self.items_gathered.emit(items) class HighlightDelegate(QtWidgets.QStyledItemDelegate): """A delegate used for auto-completion to give formatted completion""" def __init__(self, parent): QtWidgets.QStyledItemDelegate.__init__(self, parent) self.widget = parent self.highlight_text = '' self.case_sensitive = False self.doc = QtGui.QTextDocument() # older PyQt4 does not have setDocumentMargin if hasattr(self.doc, 'setDocumentMargin'): self.doc.setDocumentMargin(0) def set_highlight_text(self, text, case_sensitive): """Sets the text that will be made bold when displayed""" self.highlight_text = text self.case_sensitive = case_sensitive def paint(self, painter, option, index): """Overloaded Qt method for custom painting of a model index""" if not self.highlight_text: QtWidgets.QStyledItemDelegate.paint(self, painter, option, index) return text = index.data() if self.case_sensitive: html = text.replace(self.highlight_text, '%s' % self.highlight_text) else: match = re.match(r'(.*)(%s)(.*)' % re.escape(self.highlight_text), text, re.IGNORECASE) if match: start = match.group(1) or '' middle = match.group(2) or '' end = match.group(3) or '' html = (start + ('%s' % middle) + end) else: html = text self.doc.setHtml(html) # Painting item without text, Text Document will paint the text params = QtWidgets.QStyleOptionViewItem(option) self.initStyleOption(params, index) params.text = '' style = QtWidgets.QApplication.style() style.drawControl(QtWidgets.QStyle.CE_ItemViewItem, params, painter) ctx = QtGui.QAbstractTextDocumentLayout.PaintContext() # Highlighting text if item is selected if params.state & QtWidgets.QStyle.State_Selected: color = params.palette.color(QtGui.QPalette.Active, QtGui.QPalette.HighlightedText) ctx.palette.setColor(QtGui.QPalette.Text, color) # translate the painter to where the text is drawn item_text = QtWidgets.QStyle.SE_ItemViewItemText rect = style.subElementRect(item_text, params, self.widget) painter.save() start = rect.topLeft() + QtCore.QPoint(defs.margin, 0) painter.translate(start) # tell the text document to draw the html for us self.doc.documentLayout().draw(painter, ctx) painter.restore() def ref_sort_key(ref): """Sort key function that causes shorter refs to sort first, but alphabetizes refs of equal length (in order to make local branches sort before remote ones).""" return len(ref), ref class CompletionModel(QtGui.QStandardItemModel): updated = Signal() items_gathered = Signal(object) model_updated = Signal() def __init__(self, context, parent): QtGui.QStandardItemModel.__init__(self, parent) self.context = context self.match_text = '' self.full_text = '' self.case_sensitive = False self.update_thread = GatherCompletionsThread(self) self.update_thread.items_gathered.connect(self.apply_matches, type=Qt.QueuedConnection) def update(self): case_sensitive = self.update_thread.case_sensitive self.update_matches(case_sensitive) def set_match_text(self, full_text, match_text, case_sensitive): self.full_text = full_text self.match_text = match_text self.update_matches(case_sensitive) def update_matches(self, case_sensitive): self.case_sensitive = case_sensitive self.update_thread.case_sensitive = case_sensitive if not self.update_thread.isRunning(): self.update_thread.start() # pylint: disable=unused-argument,no-self-use def gather_matches(self, case_sensitive): return ((), (), set()) def apply_matches(self, match_tuple): matched_refs, matched_paths, dirs = match_tuple QStandardItem = QtGui.QStandardItem dir_icon = icons.directory() git_icon = icons.cola() items = [] for ref in matched_refs: item = QStandardItem() item.setText(ref) item.setIcon(git_icon) items.append(item) from_filename = icons.from_filename for match in matched_paths: item = QStandardItem() item.setText(match) if match in dirs: item.setIcon(dir_icon) else: item.setIcon(from_filename(match)) items.append(item) try: self.clear() self.invisibleRootItem().appendRows(items) self.updated.emit() except RuntimeError: # C++ object has been deleted pass def dispose(self): self.update_thread.dispose() def _identity(x): return x def _lower(x): return x.lower() def filter_matches(match_text, candidates, case_sensitive, sort_key=lambda x: x): """Filter candidates and return the matches""" if case_sensitive: case_transform = _identity else: case_transform = _lower if match_text: match_text = case_transform(match_text) matches = [r for r in candidates if match_text in case_transform(r)] else: matches = list(candidates) matches.sort(key=lambda x: sort_key(case_transform(x))) return matches def filter_path_matches(match_text, file_list, case_sensitive): """Return matching completions from a list of candidate files""" files = set(file_list) files_and_dirs = utils.add_parents(files) dirs = files_and_dirs.difference(files) paths = filter_matches(match_text, files_and_dirs, case_sensitive) return (paths, dirs) class Completer(QtWidgets.QCompleter): def __init__(self, model, parent): QtWidgets.QCompleter.__init__(self, parent) self._model = model self.setCompletionMode(QtWidgets.QCompleter.UnfilteredPopupCompletion) self.setCaseSensitivity(Qt.CaseInsensitive) model.model_updated.connect(self.update, type=Qt.QueuedConnection) self.setModel(model) def update(self): self._model.update() def dispose(self): self._model.dispose() def set_match_text(self, full_text, match_text, case_sensitive): self._model.set_match_text(full_text, match_text, case_sensitive) class GitCompletionModel(CompletionModel): def __init__(self, context, parent): CompletionModel.__init__(self, context, parent) self.context = context model = context.model model.add_observer(model.message_updated, self.emit_model_updated) # pylint: disable=no-member self.destroyed.connect(self.dispose) def gather_matches(self, case_sensitive): refs = filter_matches(self.match_text, self.matches(), case_sensitive, sort_key=ref_sort_key) return (refs, (), set()) def emit_model_updated(self): try: self.model_updated.emit() except RuntimeError: # C++ object has been deleted self.dispose() # pylint: disable=no-self-use def matches(self): return [] def dispose(self): super(GitCompletionModel, self).dispose() self.context.model.remove_observer(self.emit_model_updated) class GitRefCompletionModel(GitCompletionModel): """Completer for branches and tags""" def __init__(self, context, parent): GitCompletionModel.__init__(self, context, parent) model = context.model model.add_observer(model.message_refs_updated, self.emit_model_updated) def matches(self): model = self.context.model return model.local_branches + model.remote_branches + model.tags def find_potential_branches(model): remotes = model.remotes remote_branches = model.remote_branches ambiguous = set() allnames = set(model.local_branches) potential = [] for remote_branch in remote_branches: branch = gitcmds.strip_remote(remotes, remote_branch) if branch in allnames or branch == remote_branch: ambiguous.add(branch) continue potential.append(branch) allnames.add(branch) potential_branches = [p for p in potential if p not in ambiguous] return potential_branches class GitCreateBranchCompletionModel(GitCompletionModel): """Completer for naming new branches""" def matches(self): model = self.context.model potential_branches = find_potential_branches(model) return (model.local_branches + potential_branches + model.tags) class GitCheckoutBranchCompletionModel(GitCompletionModel): """Completer for git checkout """ def matches(self): model = self.context.model potential_branches = find_potential_branches(model) return (model.local_branches + potential_branches + model.remote_branches + model.tags) class GitBranchCompletionModel(GitCompletionModel): """Completer for local branches""" def __init__(self, context, parent): GitCompletionModel.__init__(self, context, parent) def matches(self): model = self.context.model return model.local_branches class GitRemoteBranchCompletionModel(GitCompletionModel): """Completer for remote branches""" def __init__(self, context, parent): GitCompletionModel.__init__(self, context, parent) def matches(self): model = self.context.model return model.remote_branches class GitPathCompletionModel(GitCompletionModel): """Base class for path completion""" def __init__(self, context, parent): GitCompletionModel.__init__(self, context, parent) # pylint: disable=no-self-use def candidate_paths(self): return [] def gather_matches(self, case_sensitive): paths, dirs = filter_path_matches(self.match_text, self.candidate_paths(), case_sensitive) return ((), paths, dirs) class GitStatusFilterCompletionModel(GitPathCompletionModel): """Completer for modified files and folders for status filtering""" def __init__(self, context, parent): GitPathCompletionModel.__init__(self, context, parent) def candidate_paths(self): model = self.context.model return (model.staged + model.unmerged + model.modified + model.untracked) class GitTrackedCompletionModel(GitPathCompletionModel): """Completer for tracked files and folders""" def __init__(self, context, parent): GitPathCompletionModel.__init__(self, context, parent) self.model_updated.connect(self.gather_paths, type=Qt.QueuedConnection) self._paths = [] def gather_paths(self): context = self.context self._paths = gitcmds.tracked_files(context) def gather_matches(self, case_sensitive): if not self._paths: self.gather_paths() refs = [] paths, dirs = filter_path_matches(self.match_text, self._paths, case_sensitive) return (refs, paths, dirs) class GitLogCompletionModel(GitRefCompletionModel): """Completer for arguments suitable for git-log like commands""" def __init__(self, context, parent): GitRefCompletionModel.__init__(self, context, parent) self.model_updated.connect(self.gather_paths, type=Qt.QueuedConnection) self._paths = [] self._model = context.model def gather_paths(self): if not self._model.cfg.get(prefs.AUTOCOMPLETE_PATHS, True): self._paths = [] return context = self.context self._paths = gitcmds.tracked_files(context) def gather_matches(self, case_sensitive): if not self._paths: self.gather_paths() refs = filter_matches(self.match_text, self.matches(), case_sensitive, sort_key=ref_sort_key) paths, dirs = filter_path_matches(self.match_text, self._paths, case_sensitive) has_doubledash = (self.match_text == '--' or self.full_text.startswith('-- ') or ' -- ' in self.full_text) if has_doubledash: refs = [] elif refs and paths: paths.insert(0, '--') return (refs, paths, dirs) def bind_lineedit(model, hint=''): """Create a line edit bound against a specific model""" class BoundLineEdit(CompletionLineEdit): def __init__(self, context, hint=hint, parent=None): CompletionLineEdit.__init__(self, context, model, hint=hint, parent=parent) self.context = context return BoundLineEdit # Concrete classes GitLogLineEdit = bind_lineedit(GitLogCompletionModel, hint='') GitRefLineEdit = bind_lineedit(GitRefCompletionModel, hint='') GitCheckoutBranchLineEdit = bind_lineedit(GitCheckoutBranchCompletionModel, hint='') GitCreateBranchLineEdit = bind_lineedit(GitCreateBranchCompletionModel, hint='') GitBranchLineEdit = bind_lineedit(GitBranchCompletionModel, hint='') GitRemoteBranchLineEdit = bind_lineedit(GitRemoteBranchCompletionModel, hint='') GitStatusFilterLineEdit = bind_lineedit(GitStatusFilterCompletionModel, hint='') GitTrackedLineEdit = bind_lineedit(GitTrackedCompletionModel, hint='') class GitDialog(QtWidgets.QDialog): def __init__(self, lineedit, context, title, text, parent, icon=None): QtWidgets.QDialog.__init__(self, parent) self.context = context self.setWindowTitle(title) self.setWindowModality(Qt.WindowModal) self.setMinimumWidth(333) self.label = QtWidgets.QLabel() self.label.setText(title) self.lineedit = lineedit(context) self.ok_button = qtutils.ok_button(text, icon=icon, enabled=False) self.close_button = qtutils.close_button() self.button_layout = qtutils.hbox(defs.no_margin, defs.button_spacing, qtutils.STRETCH, self.ok_button, self.close_button) self.main_layout = qtutils.vbox(defs.margin, defs.spacing, self.label, self.lineedit, self.button_layout) self.setLayout(self.main_layout) self.lineedit.textChanged.connect(self.text_changed) self.lineedit.enter.connect(self.accept) qtutils.connect_button(self.ok_button, self.accept) qtutils.connect_button(self.close_button, self.reject) self.setFocusProxy(self.lineedit) self.lineedit.setFocus() def text(self): return self.lineedit.text() def text_changed(self, _txt): self.ok_button.setEnabled(bool(self.text())) def set_text(self, ref): self.lineedit.setText(ref) @classmethod def get(cls, context, title, text, parent, default=None, icon=None): dlg = cls(context, title, text, parent, icon=icon) if default: dlg.set_text(default) dlg.show() def show_popup(): x = dlg.lineedit.x() y = dlg.lineedit.y() + dlg.lineedit.height() point = QtCore.QPoint(x, y) mapped = dlg.mapToGlobal(point) dlg.lineedit.popup().move(mapped.x(), mapped.y()) dlg.lineedit.popup().show() dlg.lineedit.refresh() dlg.lineedit.setFocus() QtCore.QTimer().singleShot(100, show_popup) if dlg.exec_() == cls.Accepted: return dlg.text() return None class GitRefDialog(GitDialog): def __init__(self, context, title, text, parent, icon=None): GitDialog.__init__( self, GitRefLineEdit, context, title, text, parent, icon=icon) class GitCheckoutBranchDialog(GitDialog): def __init__(self, context, title, text, parent, icon=None): GitDialog.__init__(self, GitCheckoutBranchLineEdit, context, title, text, parent, icon=icon) class GitBranchDialog(GitDialog): def __init__(self, context, title, text, parent, icon=None): GitDialog.__init__( self, GitBranchLineEdit, context, title, text, parent, icon=icon) class GitRemoteBranchDialog(GitDialog): def __init__(self, context, title, text, parent, icon=None): GitDialog.__init__(self, GitRemoteBranchLineEdit, context, title, text, parent, icon=icon) git-cola-3.6/cola/widgets/createbranch.py000066400000000000000000000317421356743264500204660ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals from qtpy import QtWidgets from qtpy import QtCore from qtpy.QtCore import Qt from qtpy.QtCore import Signal from ..i18n import N_ from ..interaction import Interaction from ..qtutils import get from .. import gitcmds from .. import icons from .. import qtutils from . import defs from . import completion from . import standard def create_new_branch(context, revision='', settings=None): """Launches a dialog for creating a new branch""" view = CreateBranchDialog(context, settings=settings, parent=qtutils.active_window()) if revision: view.set_revision(revision) view.show() return view class CreateOpts(object): def __init__(self, context): self.context = context self.reset = False self.track = False self.fetch = True self.checkout = True self.revision = 'HEAD' self.branch = '' class CreateThread(QtCore.QThread): command = Signal(object, object, object) result = Signal(object) def __init__(self, opts, parent): QtCore.QThread.__init__(self, parent) self.opts = opts def run(self): branch = self.opts.branch revision = self.opts.revision reset = self.opts.reset checkout = self.opts.checkout track = self.opts.track context = self.opts.context git = context.git model = context.model results = [] status = 0 if track and '/' in revision: remote = revision.split('/', 1)[0] status, out, err = git.fetch(remote) self.command.emit(status, out, err) results.append(('fetch', status, out, err)) if status == 0: status, out, err = model.create_branch( branch, revision, force=reset, track=track) self.command.emit(status, out, err) results.append(('branch', status, out, err)) if status == 0 and checkout: status, out, err = git.checkout(branch) self.command.emit(status, out, err) results.append(('checkout', status, out, err)) model.update_status() self.result.emit(results) class CreateBranchDialog(standard.Dialog): """A dialog for creating branches.""" def __init__(self, context, settings=None, parent=None): standard.Dialog.__init__(self, parent=parent) self.setWindowTitle(N_('Create Branch')) if parent is not None: self.setWindowModality(Qt.WindowModal) self.context = context self.model = context.model self.opts = CreateOpts(context) self.thread = CreateThread(self.opts, self) self.progress = None self.branch_name_label = QtWidgets.QLabel() self.branch_name_label.setText(N_('Branch Name')) self.branch_name = completion.GitCreateBranchLineEdit(context) self.branch_validator = completion.BranchValidator( context.git, parent=self.branch_name) self.branch_name.setValidator(self.branch_validator) self.rev_label = QtWidgets.QLabel() self.rev_label.setText(N_('Starting Revision')) self.revision = completion.GitRefLineEdit(context) current = gitcmds.current_branch(context) if current: self.revision.setText(current) self.local_radio = qtutils.radio(text=N_('Local branch'), checked=True) self.remote_radio = qtutils.radio(text=N_('Tracking branch')) self.tag_radio = qtutils.radio(text=N_('Tag')) self.branch_list = QtWidgets.QListWidget() self.update_existing_label = QtWidgets.QLabel() self.update_existing_label.setText(N_('Update Existing Branch:')) self.no_update_radio = qtutils.radio(text=N_('No')) self.ffwd_only_radio = qtutils.radio(text=N_('Fast Forward Only'), checked=True) self.reset_radio = qtutils.radio(text=N_('Reset')) text = N_('Fetch Tracking Branch') self.fetch_checkbox = qtutils.checkbox(text=text, checked=True) text = N_('Checkout After Creation') self.checkout_checkbox = qtutils.checkbox(text=text, checked=True) icon = icons.branch() self.create_button = qtutils.create_button(text=N_('Create Branch'), icon=icon, default=True) self.close_button = qtutils.close_button() self.options_checkbox_layout = qtutils.hbox(defs.margin, defs.spacing, self.fetch_checkbox, self.checkout_checkbox, qtutils.STRETCH) self.branch_name_layout = qtutils.hbox(defs.margin, defs.spacing, self.branch_name_label, self.branch_name) self.rev_radio_group = qtutils.buttongroup(self.local_radio, self.remote_radio, self.tag_radio) self.rev_radio_layout = qtutils.hbox(defs.margin, defs.spacing, self.local_radio, self.remote_radio, self.tag_radio, qtutils.STRETCH) self.rev_start_textinput_layout = qtutils.hbox(defs.no_margin, defs.spacing, self.rev_label, defs.spacing, self.revision) self.rev_start_layout = qtutils.vbox(defs.no_margin, defs.spacing, self.rev_radio_layout, self.branch_list, self.rev_start_textinput_layout) self.options_radio_group = qtutils.buttongroup(self.no_update_radio, self.ffwd_only_radio, self.reset_radio) self.options_radio_layout = qtutils.hbox(defs.no_margin, defs.spacing, self.update_existing_label, self.no_update_radio, self.ffwd_only_radio, self.reset_radio, qtutils.STRETCH) self.buttons_layout = qtutils.hbox(defs.margin, defs.spacing, self.close_button, qtutils.STRETCH, self.create_button) self.main_layout = qtutils.vbox(defs.margin, defs.spacing, self.branch_name_layout, self.rev_start_layout, defs.button_spacing, self.options_radio_layout, self.options_checkbox_layout, self.buttons_layout) self.setLayout(self.main_layout) qtutils.add_close_action(self) qtutils.connect_button(self.close_button, self.close) qtutils.connect_button(self.create_button, self.create_branch) qtutils.connect_toggle(self.local_radio, self.display_model) qtutils.connect_toggle(self.remote_radio, self.display_model) qtutils.connect_toggle(self.tag_radio, self.display_model) branches = self.branch_list # pylint: disable=no-member branches.itemSelectionChanged.connect(self.branch_item_changed) thread = self.thread thread.command.connect(Interaction.log_status, type=Qt.QueuedConnection) thread.result.connect(self.thread_result, type=Qt.QueuedConnection) self.init_size(settings=settings, parent=parent) self.display_model() def set_revision(self, revision): self.revision.setText(revision) def getopts(self): self.opts.revision = get(self.revision) self.opts.branch = get(self.branch_name) self.opts.checkout = get(self.checkout_checkbox) self.opts.reset = get(self.reset_radio) self.opts.fetch = get(self.fetch_checkbox) self.opts.track = get(self.remote_radio) def create_branch(self): """Creates a branch; called by the "Create Branch" button""" context = self.context self.getopts() revision = self.opts.revision branch = self.opts.branch no_update = get(self.no_update_radio) ffwd_only = get(self.ffwd_only_radio) existing_branches = gitcmds.branch_list(context) check_branch = False if not branch or not revision: Interaction.critical( N_('Missing Data'), N_('Please provide both a branch ' 'name and revision expression.')) return if branch in existing_branches: if no_update: msg = N_('Branch "%s" already exists.') % branch Interaction.critical(N_('Branch Exists'), msg) return # Whether we should prompt the user for lost commits commits = gitcmds.rev_list_range(context, revision, branch) check_branch = bool(commits) if check_branch: msg = (N_('Resetting "%(branch)s" to "%(revision)s" ' 'will lose commits.') % dict(branch=branch, revision=revision)) if ffwd_only: Interaction.critical(N_('Branch Exists'), msg) return lines = [msg] for idx, commit in enumerate(commits): subject = commit[1][0:min(len(commit[1]), 16)] if len(subject) < len(commit[1]): subject += '...' lines.append('\t' + commit[0][:8] + '\t' + subject) if idx >= 5: skip = len(commits) - 5 lines.append('\t(%s)' % (N_('%d skipped') % skip)) break line = N_('Recovering lost commits may not be easy.') lines.append(line) info_text = (N_('Reset "%(branch)s" to "%(revision)s"?') % dict(branch=branch, revision=revision)) if not Interaction.confirm( N_('Reset Branch?'), '\n'.join(lines), info_text, N_('Reset Branch'), default=False, icon=icons.undo()): return title = N_('Create Branch') label = N_('Updating') self.progress = standard.progress(title, label, self) self.progress.show() self.thread.start() def thread_result(self, results): self.progress.hide() del self.progress for (cmd, status, _, _) in results: if status != 0: Interaction.critical( N_('Error Creating Branch'), (N_('"%(command)s" returned exit status "%(status)d"') % dict(command='git '+cmd, status=status))) return self.accept() # pylint: disable=unused-argument def branch_item_changed(self, *rest): """This callback is called when the branch selection changes""" # When the branch selection changes then we should update # the "Revision Expression" accordingly. qlist = self.branch_list remote_branch = qtutils.selected_item(qlist, self.branch_sources()) if not remote_branch: return # Update the model with the selection self.revision.setText(remote_branch) # Set the branch field if we're branching from a remote branch. if not get(self.remote_radio): return branch = gitcmds.strip_remote(self.model.remotes, remote_branch) if branch == 'HEAD': return # Signal that we've clicked on a remote branch self.branch_name.set_value(branch) def display_model(self): """Sets the branch list to the available branches """ branches = self.branch_sources() qtutils.set_items(self.branch_list, branches) def branch_sources(self): """Get the list of items for populating the branch root list. """ if get(self.local_radio): value = self.model.local_branches elif get(self.remote_radio): value = self.model.remote_branches elif get(self.tag_radio): value = self.model.tags else: value = [] return value def dispose(self): self.branch_name.dispose() self.revision.dispose() git-cola-3.6/cola/widgets/createtag.py000066400000000000000000000106161356743264500200010ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals from qtpy import QtWidgets from qtpy.QtCore import Qt from .. import cmds from .. import icons from .. import qtutils from ..i18n import N_ from ..qtutils import get from . import defs from . import completion from . import standard from . import text def new_create_tag(context, name='', ref='', sign=False, settings=None, parent=None): """Entry point for external callers.""" opts = TagOptions(name, ref, sign) view = CreateTag(context, opts, settings=settings, parent=parent) return view def create_tag(context, name='', ref='', sign=False, settings=None): """Entry point for external callers.""" view = new_create_tag(context, name=name, ref=ref, sign=sign, settings=settings, parent=qtutils.active_window()) view.show() view.raise_() return view class TagOptions(object): """Simple data container for the CreateTag dialog.""" def __init__(self, name, ref, sign): self.name = name or '' self.ref = ref or 'HEAD' self.sign = sign class CreateTag(standard.Dialog): def __init__(self, context, opts, settings=None, parent=None): standard.Dialog.__init__(self, parent=parent) self.context = context self.model = model = context.model self.opts = opts self.setWindowTitle(N_('Create Tag')) if parent is not None: self.setWindowModality(Qt.WindowModal) # Tag label self.tag_name_label = QtWidgets.QLabel(self) self.tag_name_label.setText(N_('Name')) self.tag_name = text.HintedLineEdit(context, N_('vX.Y.Z'), parent=self) self.tag_name.set_value(opts.name) self.tag_name.setToolTip(N_('Specifies the tag name')) qtutils.add_completer(self.tag_name, model.tags) # Sign Tag self.sign_label = QtWidgets.QLabel(self) self.sign_label.setText(N_('Sign Tag')) tooltip = N_('Whether to sign the tag (git tag -s)') self.sign_tag = qtutils.checkbox(checked=True, tooltip=tooltip) # Tag message self.tag_msg_label = QtWidgets.QLabel(self) self.tag_msg_label.setText(N_('Message')) self.tag_msg = text.HintedPlainTextEdit( context, N_('Tag message...'), self) self.tag_msg.setToolTip(N_('Specifies the tag message')) # Revision self.rev_label = QtWidgets.QLabel(self) self.rev_label.setText(N_('Revision')) self.revision = completion.GitRefLineEdit(context) self.revision.setText(self.opts.ref) self.revision.setToolTip(N_('Specifies the SHA-1 to tag')) # Buttons self.create_button = qtutils.create_button(text=N_('Create Tag'), icon=icons.tag(), default=True) self.close_button = qtutils.close_button() # Form layout for inputs self.input_layout = qtutils.form(defs.margin, defs.spacing, (self.tag_name_label, self.tag_name), (self.tag_msg_label, self.tag_msg), (self.rev_label, self.revision), (self.sign_label, self.sign_tag)) self.button_layout = qtutils.hbox(defs.no_margin, defs.button_spacing, self.close_button, qtutils.STRETCH, self.create_button) self.main_layt = qtutils.vbox(defs.margin, defs.spacing, self.input_layout, self.button_layout) self.setLayout(self.main_layt) qtutils.connect_button(self.close_button, self.close) qtutils.connect_button(self.create_button, self.create_tag) self.init_state(settings, self.resize, defs.scale(720), defs.scale(210)) def create_tag(self): """Verifies inputs and emits a notifier tag message.""" context = self.context revision = get(self.revision) tag_name = get(self.tag_name) tag_msg = get(self.tag_msg) sign_tag = get(self.sign_tag) ok = cmds.do(cmds.Tag, context, tag_name, revision, sign=sign_tag, message=tag_msg) if ok: self.close() git-cola-3.6/cola/widgets/dag.py000066400000000000000000002175211356743264500166010ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals import collections import itertools import math from functools import partial from qtpy.QtCore import Qt from qtpy.QtCore import Signal from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from ..compat import maxsize from ..i18n import N_ from ..models import dag from ..qtutils import get from .. import core from .. import cmds from .. import difftool from .. import gitcmds from .. import hotkeys from .. import icons from .. import observable from .. import qtcompat from .. import qtutils from .. import utils from . import archive from . import browse from . import completion from . import createbranch from . import createtag from . import defs from . import diff from . import filelist from . import standard def git_dag(context, args=None, settings=None, existing_view=None, show=True): """Return a pre-populated git DAG widget.""" model = context.model branch = model.currentbranch # disambiguate between branch names and filenames by using '--' branch_doubledash = (branch + ' --') if branch else '' params = dag.DAG(branch_doubledash, 1000) params.set_arguments(args) if existing_view is None: view = GitDAG(context, params, settings=settings) else: view = existing_view view.set_params(params) if params.ref: view.display() if show: view.show() return view class FocusRedirectProxy(object): """Redirect actions from the main widget to child widgets""" def __init__(self, *widgets): """Provide proxied widgets; the default widget must be first""" self.widgets = widgets self.default = widgets[0] def __getattr__(self, name): return (lambda *args, **kwargs: self._forward_action(name, *args, **kwargs)) def _forward_action(self, name, *args, **kwargs): """Forward the captured action to the focused or default widget""" widget = QtWidgets.QApplication.focusWidget() if widget in self.widgets and hasattr(widget, name): fn = getattr(widget, name) else: fn = getattr(self.default, name) return fn(*args, **kwargs) class ViewerMixin(object): """Implementations must provide selected_items()""" def __init__(self): self.context = None # provided by implementation self.selected = None self.clicked = None self.menu_actions = None # provided by implementation def selected_item(self): """Return the currently selected item""" selected_items = self.selected_items() if not selected_items: return None return selected_items[0] def selected_oid(self): item = self.selected_item() if item is None: result = None else: result = item.commit.oid return result def selected_oids(self): return [i.commit for i in self.selected_items()] def with_oid(self, fn): oid = self.selected_oid() if oid: result = fn(oid) else: result = None return result def diff_selected_this(self): clicked_oid = self.clicked.oid selected_oid = self.selected.oid self.diff_commits.emit(selected_oid, clicked_oid) def diff_this_selected(self): clicked_oid = self.clicked.oid selected_oid = self.selected.oid self.diff_commits.emit(clicked_oid, selected_oid) def cherry_pick(self): context = self.context self.with_oid(lambda oid: cmds.do(cmds.CherryPick, context, [oid])) def revert(self): context = self.context self.with_oid(lambda oid: cmds.do(cmds.Revert, context, oid)) def copy_to_clipboard(self): self.with_oid(qtutils.set_clipboard) def create_branch(self): context = self.context create_new_branch = partial(createbranch.create_new_branch, context) self.with_oid(lambda oid: create_new_branch(revision=oid)) def create_tag(self): context = self.context self.with_oid(lambda oid: createtag.create_tag(context, ref=oid)) def create_tarball(self): context = self.context self.with_oid( lambda oid: archive.show_save_dialog(context, oid, parent=self)) def show_diff(self): context = self.context self.with_oid(lambda oid: difftool.diff_expression(context, self, oid + '^!', hide_expr=False, focus_tree=True)) def show_dir_diff(self): context = self.context self.with_oid(lambda oid: cmds.difftool_launch(context, left=oid, left_take_magic=True, dir_diff=True)) def reset_branch_head(self): context = self.context self.with_oid(lambda oid: cmds.do(cmds.ResetBranchHead, context, ref=oid)) def reset_worktree(self): context = self.context self.with_oid(lambda oid: cmds.do(cmds.ResetWorktree, context, ref=oid)) def reset_merge(self): context = self.context self.with_oid(lambda oid: cmds.do(cmds.ResetMerge, context, ref=oid)) def reset_soft(self): context = self.context self.with_oid(lambda oid: cmds.do(cmds.ResetSoft, context, ref=oid)) def reset_hard(self): context = self.context self.with_oid(lambda oid: cmds.do(cmds.ResetHard, context, ref=oid)) def checkout_detached(self): context = self.context self.with_oid(lambda oid: cmds.do(cmds.Checkout, context, [oid])) def save_blob_dialog(self): context = self.context self.with_oid(lambda oid: browse.BrowseBranch.browse(context, oid)) def update_menu_actions(self, event): selected_items = self.selected_items() item = self.itemAt(event.pos()) if item is None: self.clicked = commit = None else: self.clicked = commit = item.commit has_single_selection = len(selected_items) == 1 has_selection = bool(selected_items) can_diff = bool(commit and has_single_selection and commit is not selected_items[0].commit) if can_diff: self.selected = selected_items[0].commit else: self.selected = None self.menu_actions['diff_this_selected'].setEnabled(can_diff) self.menu_actions['diff_selected_this'].setEnabled(can_diff) self.menu_actions['diff_commit'].setEnabled(has_single_selection) self.menu_actions['diff_commit_all'].setEnabled(has_single_selection) self.menu_actions['checkout_detached'].setEnabled(has_single_selection) self.menu_actions['cherry_pick'].setEnabled(has_single_selection) self.menu_actions['copy'].setEnabled(has_single_selection) self.menu_actions['create_branch'].setEnabled(has_single_selection) self.menu_actions['create_patch'].setEnabled(has_selection) self.menu_actions['create_tag'].setEnabled(has_single_selection) self.menu_actions['create_tarball'].setEnabled(has_single_selection) self.menu_actions['reset_branch_head'].setEnabled(has_single_selection) self.menu_actions['reset_worktree'].setEnabled(has_single_selection) self.menu_actions['reset_merge'].setEnabled(has_single_selection) self.menu_actions['reset_soft'].setEnabled(has_single_selection) self.menu_actions['reset_hard'].setEnabled(has_single_selection) self.menu_actions['revert'].setEnabled(has_single_selection) self.menu_actions['save_blob'].setEnabled(has_single_selection) def context_menu_event(self, event): self.update_menu_actions(event) menu = qtutils.create_menu(N_('Actions'), self) menu.addAction(self.menu_actions['diff_this_selected']) menu.addAction(self.menu_actions['diff_selected_this']) menu.addAction(self.menu_actions['diff_commit']) menu.addAction(self.menu_actions['diff_commit_all']) menu.addSeparator() menu.addAction(self.menu_actions['create_branch']) menu.addAction(self.menu_actions['create_tag']) menu.addSeparator() menu.addAction(self.menu_actions['cherry_pick']) menu.addAction(self.menu_actions['revert']) menu.addAction(self.menu_actions['create_patch']) menu.addAction(self.menu_actions['create_tarball']) menu.addSeparator() reset_menu = menu.addMenu(N_('Reset')) reset_menu.addAction(self.menu_actions['reset_branch_head']) reset_menu.addAction(self.menu_actions['reset_worktree']) reset_menu.addSeparator() reset_menu.addAction(self.menu_actions['reset_merge']) reset_menu.addAction(self.menu_actions['reset_soft']) reset_menu.addAction(self.menu_actions['reset_hard']) menu.addAction(self.menu_actions['checkout_detached']) menu.addSeparator() menu.addAction(self.menu_actions['save_blob']) menu.addAction(self.menu_actions['copy']) menu.exec_(self.mapToGlobal(event.pos())) def viewer_actions(widget): return { 'diff_this_selected': qtutils.add_action(widget, N_('Diff this -> selected'), widget.proxy.diff_this_selected), 'diff_selected_this': qtutils.add_action(widget, N_('Diff selected -> this'), widget.proxy.diff_selected_this), 'create_branch': qtutils.add_action(widget, N_('Create Branch'), widget.proxy.create_branch), 'create_patch': qtutils.add_action(widget, N_('Create Patch'), widget.proxy.create_patch), 'create_tag': qtutils.add_action(widget, N_('Create Tag'), widget.proxy.create_tag), 'create_tarball': qtutils.add_action(widget, N_('Save As Tarball/Zip...'), widget.proxy.create_tarball), 'cherry_pick': qtutils.add_action(widget, N_('Cherry Pick'), widget.proxy.cherry_pick), 'revert': qtutils.add_action(widget, N_('Revert'), widget.proxy.revert), 'diff_commit': qtutils.add_action(widget, N_('Launch Diff Tool'), widget.proxy.show_diff, hotkeys.DIFF), 'diff_commit_all': qtutils.add_action(widget, N_('Launch Directory Diff Tool'), widget.proxy.show_dir_diff, hotkeys.DIFF_SECONDARY), 'checkout_detached': qtutils.add_action(widget, N_('Checkout Detached HEAD'), widget.proxy.checkout_detached), 'reset_branch_head': qtutils.add_action(widget, N_('Reset Branch Head'), widget.proxy.reset_branch_head), 'reset_worktree': qtutils.add_action(widget, N_('Reset Worktree'), widget.proxy.reset_worktree), 'reset_merge': qtutils.add_action(widget, N_('Reset Merge'), widget.proxy.reset_merge), 'reset_soft': qtutils.add_action(widget, N_('Reset Soft'), widget.proxy.reset_soft), 'reset_hard': qtutils.add_action(widget, N_('Reset Hard'), widget.proxy.reset_hard), 'save_blob': qtutils.add_action(widget, N_('Grab File...'), widget.proxy.save_blob_dialog), 'copy': qtutils.add_action(widget, N_('Copy SHA-1'), widget.proxy.copy_to_clipboard, hotkeys.COPY_SHA1), } class CommitTreeWidgetItem(QtWidgets.QTreeWidgetItem): def __init__(self, commit, parent=None): QtWidgets.QTreeWidgetItem.__init__(self, parent) self.commit = commit self.setText(0, commit.summary) self.setText(1, commit.author) self.setText(2, commit.authdate) # pylint: disable=too-many-ancestors class CommitTreeWidget(standard.TreeWidget, ViewerMixin): diff_commits = Signal(object, object) zoom_to_fit = Signal() def __init__(self, context, notifier, parent): standard.TreeWidget.__init__(self, parent) ViewerMixin.__init__(self) self.setSelectionMode(self.ExtendedSelection) self.setHeaderLabels([N_('Summary'), N_('Author'), N_('Date, Time')]) self.context = context self.oidmap = {} self.menu_actions = None self.notifier = notifier self.selecting = False self.commits = [] self._adjust_columns = False self.action_up = qtutils.add_action( self, N_('Go Up'), self.go_up, hotkeys.MOVE_UP) self.action_down = qtutils.add_action( self, N_('Go Down'), self.go_down, hotkeys.MOVE_DOWN) self.zoom_to_fit_action = qtutils.add_action( self, N_('Zoom to Fit'), self.zoom_to_fit.emit, hotkeys.FIT) notifier.add_observer(diff.COMMITS_SELECTED, self.commits_selected) # pylint: disable=no-member self.itemSelectionChanged.connect(self.selection_changed) def export_state(self): """Export the widget's state""" # The base class method is intentionally overridden because we only # care about the details below for this subwidget. state = {} state['column_widths'] = self.column_widths() return state def apply_state(self, state): """Apply the exported widget state""" try: column_widths = state['column_widths'] except (KeyError, ValueError): column_widths = None if column_widths: self.set_column_widths(column_widths) else: # Defer showing the columns until we are shown, and our true width # is known. Calling adjust_columns() here ends up with the wrong # answer because we have not yet been parented to the layout. # We set this flag that we process once during our initial # showEvent(). self._adjust_columns = True return True # Qt overrides def showEvent(self, event): """Override QWidget::showEvent() to size columns when we are shown""" if self._adjust_columns: self._adjust_columns = False width = self.width() two_thirds = (width * 2) // 3 one_sixth = width // 6 self.setColumnWidth(0, two_thirds) self.setColumnWidth(1, one_sixth) self.setColumnWidth(2, one_sixth) return standard.TreeWidget.showEvent(self, event) # ViewerMixin def go_up(self): self.goto(self.itemAbove) def go_down(self): self.goto(self.itemBelow) def goto(self, finder): items = self.selected_items() item = items[0] if items else None if item is None: return found = finder(item) if found: self.select([found.commit.oid]) def selected_commit_range(self): selected_items = self.selected_items() if not selected_items: return None, None return selected_items[-1].commit.oid, selected_items[0].commit.oid def set_selecting(self, selecting): self.selecting = selecting def selection_changed(self): items = self.selected_items() if not items: return self.set_selecting(True) self.notifier.notify_observers(diff.COMMITS_SELECTED, [i.commit for i in items]) self.set_selecting(False) def commits_selected(self, commits): if self.selecting: return with qtutils.BlockSignals(self): self.select([commit.oid for commit in commits]) def select(self, oids): if not oids: return self.clearSelection() for oid in oids: try: item = self.oidmap[oid] except KeyError: continue self.scrollToItem(item) item.setSelected(True) def clear(self): QtWidgets.QTreeWidget.clear(self) self.oidmap.clear() self.commits = [] def add_commits(self, commits): self.commits.extend(commits) items = [] for c in reversed(commits): item = CommitTreeWidgetItem(c) items.append(item) self.oidmap[c.oid] = item for tag in c.tags: self.oidmap[tag] = item self.insertTopLevelItems(0, items) def create_patch(self): items = self.selectedItems() if not items: return context = self.context oids = [item.commit.oid for item in reversed(items)] all_oids = [c.oid for c in self.commits] cmds.do(cmds.FormatPatch, context, oids, all_oids) # Qt overrides def contextMenuEvent(self, event): self.context_menu_event(event) def mousePressEvent(self, event): if event.button() == Qt.RightButton: event.accept() return QtWidgets.QTreeWidget.mousePressEvent(self, event) class GitDAG(standard.MainWindow): """The git-dag widget.""" updated = Signal() def __init__(self, context, params, parent=None, settings=None): super(GitDAG, self).__init__(parent) self.setMinimumSize(420, 420) # change when widgets are added/removed self.widget_version = 2 self.context = context self.params = params self.model = context.model self.settings = settings self.commits = {} self.commit_list = [] self.selection = [] self.old_refs = set() self.old_oids = None self.old_count = 0 self.force_refresh = False self.thread = None self.revtext = completion.GitLogLineEdit(context) self.maxresults = standard.SpinBox() self.zoom_out = qtutils.create_action_button( tooltip=N_('Zoom Out'), icon=icons.zoom_out()) self.zoom_in = qtutils.create_action_button( tooltip=N_('Zoom In'), icon=icons.zoom_in()) self.zoom_to_fit = qtutils.create_action_button( tooltip=N_('Zoom to Fit'), icon=icons.zoom_fit_best()) self.notifier = notifier = observable.Observable() self.notifier.refs_updated = refs_updated = 'refs_updated' self.notifier.add_observer(refs_updated, self.display) self.notifier.add_observer(filelist.HISTORIES_SELECTED, self.histories_selected) self.notifier.add_observer(filelist.DIFFTOOL_SELECTED, self.difftool_selected) self.notifier.add_observer(diff.COMMITS_SELECTED, self.commits_selected) self.treewidget = CommitTreeWidget(context, notifier, self) self.diffwidget = diff.DiffWidget(context, notifier, self, is_commit=True) self.filewidget = filelist.FileWidget(context, notifier, self) self.graphview = GraphView(context, notifier, self) self.proxy = FocusRedirectProxy(self.treewidget, self.graphview, self.filewidget) self.viewer_actions = actions = viewer_actions(self) self.treewidget.menu_actions = actions self.graphview.menu_actions = actions self.controls_layout = qtutils.hbox(defs.no_margin, defs.spacing, self.revtext, self.maxresults) self.controls_widget = QtWidgets.QWidget() self.controls_widget.setLayout(self.controls_layout) self.log_dock = qtutils.create_dock(N_('Log'), self, stretch=False) self.log_dock.setWidget(self.treewidget) log_dock_titlebar = self.log_dock.titleBarWidget() log_dock_titlebar.add_corner_widget(self.controls_widget) self.file_dock = qtutils.create_dock(N_('Files'), self) self.file_dock.setWidget(self.filewidget) self.diff_dock = qtutils.create_dock(N_('Diff'), self) self.diff_dock.setWidget(self.diffwidget) self.graph_controls_layout = qtutils.hbox( defs.no_margin, defs.button_spacing, self.zoom_out, self.zoom_in, self.zoom_to_fit, defs.spacing) self.graph_controls_widget = QtWidgets.QWidget() self.graph_controls_widget.setLayout(self.graph_controls_layout) self.graphview_dock = qtutils.create_dock(N_('Graph'), self) self.graphview_dock.setWidget(self.graphview) graph_titlebar = self.graphview_dock.titleBarWidget() graph_titlebar.add_corner_widget(self.graph_controls_widget) self.lock_layout_action = qtutils.add_action_bool( self, N_('Lock Layout'), self.set_lock_layout, False) self.refresh_action = qtutils.add_action( self, N_('Refresh'), self.refresh, hotkeys.REFRESH) # Create the application menu self.menubar = QtWidgets.QMenuBar(self) self.setMenuBar(self.menubar) # View Menu self.view_menu = qtutils.add_menu(N_('View'), self.menubar) self.view_menu.addAction(self.refresh_action) self.view_menu.addAction(self.log_dock.toggleViewAction()) self.view_menu.addAction(self.graphview_dock.toggleViewAction()) self.view_menu.addAction(self.diff_dock.toggleViewAction()) self.view_menu.addAction(self.file_dock.toggleViewAction()) self.view_menu.addSeparator() self.view_menu.addAction(self.lock_layout_action) left = Qt.LeftDockWidgetArea right = Qt.RightDockWidgetArea self.addDockWidget(left, self.log_dock) self.addDockWidget(left, self.diff_dock) self.addDockWidget(right, self.graphview_dock) self.addDockWidget(right, self.file_dock) # Also re-loads dag.* from the saved state self.init_state(settings, self.resize_to_desktop) qtutils.connect_button(self.zoom_out, self.graphview.zoom_out) qtutils.connect_button(self.zoom_in, self.graphview.zoom_in) qtutils.connect_button(self.zoom_to_fit, self.graphview.zoom_to_fit) self.treewidget.zoom_to_fit.connect(self.graphview.zoom_to_fit) self.treewidget.diff_commits.connect(self.diff_commits) self.graphview.diff_commits.connect(self.diff_commits) self.filewidget.grab_file.connect(self.grab_file) # pylint: disable=no-member self.maxresults.editingFinished.connect(self.display) self.revtext.textChanged.connect(self.text_changed) self.revtext.activated.connect(self.display) self.revtext.enter.connect(self.display) self.revtext.down.connect(self.focus_tree) # The model is updated in another thread so use # signals/slots to bring control back to the main GUI thread self.model.add_observer(self.model.message_updated, self.updated.emit) self.updated.connect(self.model_updated, type=Qt.QueuedConnection) qtutils.add_action(self, 'Focus', self.focus_input, hotkeys.FOCUS) qtutils.add_close_action(self) self.set_params(params) def set_params(self, params): context = self.context self.params = params # Update fields affected by model self.revtext.setText(params.ref) self.maxresults.setValue(params.count) self.update_window_title() if self.thread is not None: self.thread.stop() self.thread = ReaderThread(context, params, self) thread = self.thread thread.begin.connect(self.thread_begin, type=Qt.QueuedConnection) thread.status.connect(self.thread_status, type=Qt.QueuedConnection) thread.add.connect(self.add_commits, type=Qt.QueuedConnection) thread.end.connect(self.thread_end, type=Qt.QueuedConnection) def focus_input(self): self.revtext.setFocus() def focus_tree(self): self.treewidget.setFocus() def text_changed(self, txt): self.params.ref = txt self.update_window_title() def update_window_title(self): project = self.model.project if self.params.ref: self.setWindowTitle(N_('%(project)s: %(ref)s - DAG') % dict(project=project, ref=self.params.ref)) else: self.setWindowTitle(project + N_(' - DAG')) def export_state(self): state = standard.MainWindow.export_state(self) state['count'] = self.params.count state['log'] = self.treewidget.export_state() return state def apply_state(self, state): result = standard.MainWindow.apply_state(self, state) try: count = state['count'] if self.params.overridden('count'): count = self.params.count except (KeyError, TypeError, ValueError, AttributeError): count = self.params.count result = False self.params.set_count(count) self.lock_layout_action.setChecked(state.get('lock_layout', False)) try: log_state = state['log'] except (KeyError, ValueError): log_state = None if log_state: self.treewidget.apply_state(log_state) return result def model_updated(self): self.display() self.update_window_title() def refresh(self): """Unconditionally refresh the DAG""" # self.force_refresh triggers an Unconditional redraw self.force_refresh = True cmds.do(cmds.Refresh, self.context) self.force_refresh = False def display(self): """Update the view when the Git refs change""" ref = get(self.revtext) count = get(self.maxresults) context = self.context model = self.model # The DAG tries to avoid updating when the object IDs have not # changed. Without doing this the DAG constantly redraws itself # whenever inotify sends update events, which hurts usability. # # To minimize redraws we leverage `git rev-parse`. The strategy is to # use `git rev-parse` on the input line, which converts each argument # into object IDs. From there it's a simple matter of detecting when # the object IDs changed. # # In addition to object IDs, we also need to know when the set of # named references (branches, tags) changes so that an update is # triggered when new branches and tags are created. refs = set(model.local_branches + model.remote_branches + model.tags) argv = utils.shell_split(ref or 'HEAD') oids = gitcmds.parse_refs(context, argv) update = (self.force_refresh or count != self.old_count or oids != self.old_oids or refs != self.old_refs) if update: self.thread.stop() self.params.set_ref(ref) self.params.set_count(count) self.thread.start() self.old_oids = oids self.old_count = count self.old_refs = refs def commits_selected(self, commits): if commits: self.selection = commits def clear(self): self.commits.clear() self.commit_list = [] self.graphview.clear() self.treewidget.clear() def add_commits(self, commits): self.commit_list.extend(commits) # Keep track of commits for commit_obj in commits: self.commits[commit_obj.oid] = commit_obj for tag in commit_obj.tags: self.commits[tag] = commit_obj self.graphview.add_commits(commits) self.treewidget.add_commits(commits) def thread_begin(self): self.clear() def thread_end(self): self.restore_selection() def thread_status(self, successful): self.revtext.hint.set_error(not successful) def restore_selection(self): selection = self.selection try: commit_obj = self.commit_list[-1] except IndexError: # No commits, exist, early-out return new_commits = [self.commits.get(s.oid, None) for s in selection] new_commits = [c for c in new_commits if c is not None] if new_commits: # The old selection exists in the new state self.notifier.notify_observers(diff.COMMITS_SELECTED, new_commits) else: # The old selection is now empty. Select the top-most commit self.notifier.notify_observers(diff.COMMITS_SELECTED, [commit_obj]) self.graphview.set_initial_view() def diff_commits(self, a, b): paths = self.params.paths() if paths: cmds.difftool_launch(self.context, left=a, right=b, paths=paths) else: difftool.diff_commits(self.context, self, a, b) # Qt overrides def closeEvent(self, event): self.revtext.close_popup() self.thread.stop() standard.MainWindow.closeEvent(self, event) def histories_selected(self, histories): argv = [self.model.currentbranch, '--'] argv.extend(histories) text = core.list2cmdline(argv) self.revtext.setText(text) self.display() def difftool_selected(self, files): bottom, top = self.treewidget.selected_commit_range() if not top: return cmds.difftool_launch(self.context, left=bottom, left_take_parent=True, right=top, paths=files) def grab_file(self, filename): """Save the selected file from the filelist widget""" oid = self.treewidget.selected_oid() model = browse.BrowseModel(oid, filename=filename) browse.save_path(self.context, filename, model) class ReaderThread(QtCore.QThread): begin = Signal() add = Signal(object) end = Signal() status = Signal(object) def __init__(self, context, params, parent): QtCore.QThread.__init__(self, parent) self.context = context self.params = params self._abort = False self._stop = False self._mutex = QtCore.QMutex() self._condition = QtCore.QWaitCondition() def run(self): context = self.context repo = dag.RepoReader(context, self.params) repo.reset() self.begin.emit() commits = [] for c in repo.get(): self._mutex.lock() if self._stop: self._condition.wait(self._mutex) self._mutex.unlock() if self._abort: repo.reset() return commits.append(c) if len(commits) >= 512: self.add.emit(commits) commits = [] self.status.emit(repo.returncode == 0) if commits: self.add.emit(commits) self.end.emit() def start(self): self._abort = False self._stop = False QtCore.QThread.start(self) def pause(self): self._mutex.lock() self._stop = True self._mutex.unlock() def resume(self): self._mutex.lock() self._stop = False self._mutex.unlock() self._condition.wakeOne() def stop(self): self._abort = True self.wait() class Cache(object): _label_font = None @classmethod def label_font(cls): font = cls._label_font if font is None: font = cls._label_font = QtWidgets.QApplication.font() font.setPointSize(6) return font class Edge(QtWidgets.QGraphicsItem): item_type = QtWidgets.QGraphicsItem.UserType + 1 def __init__(self, source, dest): QtWidgets.QGraphicsItem.__init__(self) self.setAcceptedMouseButtons(Qt.NoButton) self.source = source self.dest = dest self.commit = source.commit self.setZValue(-2) self.recompute_bound() self.path = None self.path_valid = False # Choose a new color for new branch edges if self.source.x() < self.dest.x(): color = EdgeColor.cycle() line = Qt.SolidLine elif self.source.x() != self.dest.x(): color = EdgeColor.current() line = Qt.SolidLine else: color = EdgeColor.current() line = Qt.SolidLine self.pen = QtGui.QPen(color, 4.0, line, Qt.SquareCap, Qt.RoundJoin) def recompute_bound(self): dest_pt = Commit.item_bbox.center() self.source_pt = self.mapFromItem(self.source, dest_pt) self.dest_pt = self.mapFromItem(self.dest, dest_pt) self.line = QtCore.QLineF(self.source_pt, self.dest_pt) width = self.dest_pt.x() - self.source_pt.x() height = self.dest_pt.y() - self.source_pt.y() rect = QtCore.QRectF(self.source_pt, QtCore.QSizeF(width, height)) self.bound = rect.normalized() def commits_were_invalidated(self): self.recompute_bound() self.prepareGeometryChange() # The path should not be recomputed immediately because just small part # of DAG is actually shown at same time. It will be recomputed on # demand in course of 'paint' method. self.path_valid = False # Hence, just queue redrawing. self.update() # Qt overrides def type(self): return self.item_type def boundingRect(self): return self.bound def recompute_path(self): QRectF = QtCore.QRectF QPointF = QtCore.QPointF arc_rect = 10 connector_length = 5 path = QtGui.QPainterPath() if self.source.x() == self.dest.x(): path.moveTo(self.source.x(), self.source.y()) path.lineTo(self.dest.x(), self.dest.y()) else: # Define points starting from source point1 = QPointF(self.source.x(), self.source.y()) point2 = QPointF(point1.x(), point1.y() - connector_length) point3 = QPointF(point2.x() + arc_rect, point2.y() - arc_rect) # Define points starting from dest point4 = QPointF(self.dest.x(), self.dest.y()) point5 = QPointF(point4.x(), point3.y() - arc_rect) point6 = QPointF(point5.x() - arc_rect, point5.y() + arc_rect) start_angle_arc1 = 180 span_angle_arc1 = 90 start_angle_arc2 = 90 span_angle_arc2 = -90 # If the dest is at the left of the source, then we # need to reverse some values if self.source.x() > self.dest.x(): point3 = QPointF(point2.x() - arc_rect, point3.y()) point6 = QPointF(point5.x() + arc_rect, point6.y()) span_angle_arc1 = 90 path.moveTo(point1) path.lineTo(point2) path.arcTo(QRectF(point2, point3), start_angle_arc1, span_angle_arc1) path.lineTo(point6) path.arcTo(QRectF(point6, point5), start_angle_arc2, span_angle_arc2) path.lineTo(point4) self.path = path self.path_valid = True def paint(self, painter, _option, _widget): if not self.path_valid: self.recompute_path() painter.setPen(self.pen) painter.drawPath(self.path) class EdgeColor(object): """An edge color factory""" current_color_index = 0 colors = [ QtGui.QColor(Qt.red), QtGui.QColor(Qt.green), QtGui.QColor(Qt.blue), QtGui.QColor(Qt.black), QtGui.QColor(Qt.darkRed), QtGui.QColor(Qt.darkGreen), QtGui.QColor(Qt.darkBlue), QtGui.QColor(Qt.cyan), QtGui.QColor(Qt.magenta), # Orange; Qt.yellow is too low-contrast qtutils.rgba(0xff, 0x66, 0x00), QtGui.QColor(Qt.gray), QtGui.QColor(Qt.darkCyan), QtGui.QColor(Qt.darkMagenta), QtGui.QColor(Qt.darkYellow), QtGui.QColor(Qt.darkGray), ] @classmethod def cycle(cls): cls.current_color_index += 1 cls.current_color_index %= len(cls.colors) color = cls.colors[cls.current_color_index] color.setAlpha(128) return color @classmethod def current(cls): return cls.colors[cls.current_color_index] @classmethod def reset(cls): cls.current_color_index = 0 class Commit(QtWidgets.QGraphicsItem): item_type = QtWidgets.QGraphicsItem.UserType + 2 commit_radius = 12.0 merge_radius = 18.0 item_shape = QtGui.QPainterPath() item_shape.addRect(commit_radius/-2.0, commit_radius/-2.0, commit_radius, commit_radius) item_bbox = item_shape.boundingRect() inner_rect = QtGui.QPainterPath() inner_rect.addRect(commit_radius/-2.0 + 2.0, commit_radius/-2.0 + 2.0, commit_radius - 4.0, commit_radius - 4.0) inner_rect = inner_rect.boundingRect() commit_color = QtGui.QColor(Qt.white) outline_color = commit_color.darker() merge_color = QtGui.QColor(Qt.lightGray) commit_selected_color = QtGui.QColor(Qt.green) selected_outline_color = commit_selected_color.darker() commit_pen = QtGui.QPen() commit_pen.setWidth(1.0) commit_pen.setColor(outline_color) def __init__(self, commit, notifier, selectable=QtWidgets.QGraphicsItem.ItemIsSelectable, cursor=Qt.PointingHandCursor, xpos=commit_radius/2.0 + 1.0, cached_commit_color=commit_color, cached_merge_color=merge_color): QtWidgets.QGraphicsItem.__init__(self) self.commit = commit self.notifier = notifier self.selected = False self.setZValue(0) self.setFlag(selectable) self.setCursor(cursor) self.setToolTip(commit.oid[:12] + ': ' + commit.summary) if commit.tags: self.label = label = Label(commit) label.setParentItem(self) label.setPos(xpos + 1, -self.commit_radius/2.0) else: self.label = None if len(commit.parents) > 1: self.brush = cached_merge_color else: self.brush = cached_commit_color self.pressed = False self.dragged = False self.edges = {} def blockSignals(self, blocked): self.notifier.notification_enabled = not blocked def itemChange(self, change, value): if change == QtWidgets.QGraphicsItem.ItemSelectedHasChanged: # Broadcast selection to other widgets selected_items = self.scene().selectedItems() commits = [item.commit for item in selected_items] self.scene().parent().set_selecting(True) self.notifier.notify_observers(diff.COMMITS_SELECTED, commits) self.scene().parent().set_selecting(False) # Cache the pen for use in paint() if value: self.brush = self.commit_selected_color color = self.selected_outline_color else: if len(self.commit.parents) > 1: self.brush = self.merge_color else: self.brush = self.commit_color color = self.outline_color commit_pen = QtGui.QPen() commit_pen.setWidth(1.0) commit_pen.setColor(color) self.commit_pen = commit_pen return QtWidgets.QGraphicsItem.itemChange(self, change, value) def type(self): return self.item_type def boundingRect(self): return self.item_bbox def shape(self): return self.item_shape def paint(self, painter, option, _widget): # Do not draw outside the exposed rect painter.setClipRect(option.exposedRect) # Draw ellipse painter.setPen(self.commit_pen) painter.setBrush(self.brush) painter.drawEllipse(self.inner_rect) def mousePressEvent(self, event): QtWidgets.QGraphicsItem.mousePressEvent(self, event) self.pressed = True self.selected = self.isSelected() def mouseMoveEvent(self, event): if self.pressed: self.dragged = True QtWidgets.QGraphicsItem.mouseMoveEvent(self, event) def mouseReleaseEvent(self, event): QtWidgets.QGraphicsItem.mouseReleaseEvent(self, event) if (not self.dragged and self.selected and event.button() == Qt.LeftButton): return self.pressed = False self.dragged = False class Label(QtWidgets.QGraphicsItem): item_type = QtWidgets.QGraphicsItem.UserType + 3 head_color = QtGui.QColor(Qt.green) other_color = QtGui.QColor(Qt.white) remote_color = QtGui.QColor(Qt.yellow) head_pen = QtGui.QPen() head_pen.setColor(head_color.darker().darker()) head_pen.setWidth(1.0) text_pen = QtGui.QPen() text_pen.setColor(QtGui.QColor(Qt.darkGray)) text_pen.setWidth(1.0) alpha = 180 head_color.setAlpha(alpha) other_color.setAlpha(alpha) remote_color.setAlpha(alpha) border = 2 item_spacing = 5 text_offset = 1 def __init__(self, commit): QtWidgets.QGraphicsItem.__init__(self) self.setZValue(-1) self.commit = commit def type(self): return self.item_type def boundingRect(self, cache=Cache): QPainterPath = QtGui.QPainterPath QRectF = QtCore.QRectF width = 72 height = 18 current_width = 0 spacing = self.item_spacing border = self.border + self.text_offset # text offset=1 in paint() font = cache.label_font() item_shape = QPainterPath() base_rect = QRectF(0, 0, width, height) base_rect = base_rect.adjusted(-border, -border, border, border) item_shape.addRect(base_rect) for tag in self.commit.tags: text_shape = QPainterPath() text_shape.addText(current_width, 0, font, tag) text_rect = text_shape.boundingRect() box_rect = text_rect.adjusted(-border, -border, border, border) item_shape.addRect(box_rect) current_width = item_shape.boundingRect().width() + spacing return item_shape.boundingRect() def paint(self, painter, _option, _widget, cache=Cache): # Draw tags and branches font = cache.label_font() painter.setFont(font) current_width = 0 border = self.border offset = self.text_offset spacing = self.item_spacing QRectF = QtCore.QRectF HEAD = 'HEAD' remotes_prefix = 'remotes/' tags_prefix = 'tags/' heads_prefix = 'heads/' remotes_len = len(remotes_prefix) tags_len = len(tags_prefix) heads_len = len(heads_prefix) for tag in self.commit.tags: if tag == HEAD: painter.setPen(self.text_pen) painter.setBrush(self.remote_color) elif tag.startswith(remotes_prefix): tag = tag[remotes_len:] painter.setPen(self.text_pen) painter.setBrush(self.other_color) elif tag.startswith(tags_prefix): tag = tag[tags_len:] painter.setPen(self.text_pen) painter.setBrush(self.remote_color) elif tag.startswith(heads_prefix): tag = tag[heads_len:] painter.setPen(self.head_pen) painter.setBrush(self.head_color) else: painter.setPen(self.text_pen) painter.setBrush(self.other_color) text_rect = painter.boundingRect( QRectF(current_width, 0, 0, 0), Qt.TextSingleLine, tag) box_rect = text_rect.adjusted(-offset, -offset, offset, offset) painter.drawRoundedRect(box_rect, border, border) painter.drawText(text_rect, Qt.TextSingleLine, tag) current_width += text_rect.width() + spacing # pylint: disable=too-many-ancestors class GraphView(QtWidgets.QGraphicsView, ViewerMixin): diff_commits = Signal(object, object) x_adjust = int(Commit.commit_radius*4/3) y_adjust = int(Commit.commit_radius*4/3) x_off = -18 y_off = -24 def __init__(self, context, notifier, parent): QtWidgets.QGraphicsView.__init__(self, parent) ViewerMixin.__init__(self) highlight = self.palette().color(QtGui.QPalette.Highlight) Commit.commit_selected_color = highlight Commit.selected_outline_color = highlight.darker() self.context = context self.columns = {} self.selection_list = [] self.menu_actions = None self.notifier = notifier self.commits = [] self.items = {} self.mouse_start = [0, 0] self.saved_matrix = self.transform() self.max_column = 0 self.min_column = 0 self.frontier = {} self.tagged_cells = set() self.x_start = 24 self.x_min = 24 self.x_offsets = collections.defaultdict(lambda: self.x_min) self.is_panning = False self.pressed = False self.selecting = False self.last_mouse = [0, 0] self.zoom = 2 self.setDragMode(self.RubberBandDrag) scene = QtWidgets.QGraphicsScene(self) scene.setItemIndexMethod(QtWidgets.QGraphicsScene.NoIndex) self.setScene(scene) self.setRenderHint(QtGui.QPainter.Antialiasing) self.setViewportUpdateMode(self.BoundingRectViewportUpdate) self.setCacheMode(QtWidgets.QGraphicsView.CacheBackground) self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse) self.setResizeAnchor(QtWidgets.QGraphicsView.NoAnchor) self.setBackgroundBrush(QtGui.QColor(Qt.white)) qtutils.add_action(self, N_('Zoom In'), self.zoom_in, hotkeys.ZOOM_IN, hotkeys.ZOOM_IN_SECONDARY) qtutils.add_action(self, N_('Zoom Out'), self.zoom_out, hotkeys.ZOOM_OUT) qtutils.add_action(self, N_('Zoom to Fit'), self.zoom_to_fit, hotkeys.FIT) qtutils.add_action(self, N_('Select Parent'), self._select_parent, hotkeys.MOVE_DOWN_TERTIARY) qtutils.add_action(self, N_('Select Oldest Parent'), self._select_oldest_parent, hotkeys.MOVE_DOWN) qtutils.add_action(self, N_('Select Child'), self._select_child, hotkeys.MOVE_UP_TERTIARY) qtutils.add_action(self, N_('Select Newest Child'), self._select_newest_child, hotkeys.MOVE_UP) notifier.add_observer(diff.COMMITS_SELECTED, self.commits_selected) def clear(self): EdgeColor.reset() self.scene().clear() self.selection_list = [] self.items.clear() self.x_offsets.clear() self.x_min = 24 self.commits = [] # ViewerMixin interface def selected_items(self): """Return the currently selected items""" return self.scene().selectedItems() def zoom_in(self): self.scale_view(1.5) def zoom_out(self): self.scale_view(1.0/1.5) def commits_selected(self, commits): if self.selecting: return self.select([commit.oid for commit in commits]) def select(self, oids): """Select the item for the oids""" self.scene().clearSelection() for oid in oids: try: item = self.items[oid] except KeyError: continue item.blockSignals(True) item.setSelected(True) item.blockSignals(False) item_rect = item.sceneTransform().mapRect(item.boundingRect()) self.ensureVisible(item_rect) def _get_item_by_generation(self, commits, criteria_fn): """Return the item for the commit matching criteria""" if not commits: return None generation = None for commit in commits: if (generation is None or criteria_fn(generation, commit.generation)): oid = commit.oid generation = commit.generation try: return self.items[oid] except KeyError: return None def _oldest_item(self, commits): """Return the item for the commit with the oldest generation number""" return self._get_item_by_generation(commits, lambda a, b: a > b) def _newest_item(self, commits): """Return the item for the commit with the newest generation number""" return self._get_item_by_generation(commits, lambda a, b: a < b) def create_patch(self): items = self.selected_items() if not items: return context = self.context selected_commits = sort_by_generation([n.commit for n in items]) oids = [c.oid for c in selected_commits] all_oids = [c.oid for c in self.commits] cmds.do(cmds.FormatPatch, context, oids, all_oids) def _select_parent(self): """Select the parent with the newest generation number""" selected_item = self.selected_item() if selected_item is None: return parent_item = self._newest_item(selected_item.commit.parents) if parent_item is None: return selected_item.setSelected(False) parent_item.setSelected(True) self.ensureVisible( parent_item.mapRectToScene(parent_item.boundingRect())) def _select_oldest_parent(self): """Select the parent with the oldest generation number""" selected_item = self.selected_item() if selected_item is None: return parent_item = self._oldest_item(selected_item.commit.parents) if parent_item is None: return selected_item.setSelected(False) parent_item.setSelected(True) scene_rect = parent_item.mapRectToScene(parent_item.boundingRect()) self.ensureVisible(scene_rect) def _select_child(self): """Select the child with the oldest generation number""" selected_item = self.selected_item() if selected_item is None: return child_item = self._oldest_item(selected_item.commit.children) if child_item is None: return selected_item.setSelected(False) child_item.setSelected(True) scene_rect = child_item.mapRectToScene(child_item.boundingRect()) self.ensureVisible(scene_rect) def _select_newest_child(self): """Select the Nth child with the newest generation number (N > 1)""" selected_item = self.selected_item() if selected_item is None: return if len(selected_item.commit.children) > 1: children = selected_item.commit.children[1:] else: children = selected_item.commit.children child_item = self._newest_item(children) if child_item is None: return selected_item.setSelected(False) child_item.setSelected(True) scene_rect = child_item.mapRectToScene(child_item.boundingRect()) self.ensureVisible(scene_rect) def set_initial_view(self): items = [] selected = self.selected_items() if selected: items.extend(selected) if not selected and self.commits: commit = self.commits[-1] items.append(self.items[commit.oid]) self.setSceneRect(self.scene().itemsBoundingRect()) self.fit_view_to_items(items) def zoom_to_fit(self): """Fit selected items into the viewport""" items = self.selected_items() self.fit_view_to_items(items) def fit_view_to_items(self, items): if not items: rect = self.scene().itemsBoundingRect() else: x_min = y_min = maxsize x_max = y_max = -maxsize for item in items: pos = item.pos() x = pos.x() y = pos.y() x_min = min(x_min, x) x_max = max(x_max, x) y_min = min(y_min, y) y_max = max(y_max, y) rect = QtCore.QRectF(x_min, y_min, abs(x_max - x_min), abs(y_max - y_min)) x_adjust = abs(GraphView.x_adjust) y_adjust = abs(GraphView.y_adjust) count = max(2.0, 10.0 - len(items)/2.0) y_offset = int(y_adjust * count) x_offset = int(x_adjust * count) rect.setX(rect.x() - x_offset//2) rect.setY(rect.y() - y_adjust//2) rect.setHeight(rect.height() + y_offset) rect.setWidth(rect.width() + x_offset) self.fitInView(rect, Qt.KeepAspectRatio) self.scene().invalidate() def save_selection(self, event): if event.button() != Qt.LeftButton: return elif Qt.ShiftModifier != event.modifiers(): return self.selection_list = self.selected_items() def restore_selection(self, event): if Qt.ShiftModifier != event.modifiers(): return for item in self.selection_list: item.setSelected(True) def handle_event(self, event_handler, event): self.save_selection(event) event_handler(self, event) self.restore_selection(event) self.update() def set_selecting(self, selecting): self.selecting = selecting def pan(self, event): pos = event.pos() dx = pos.x() - self.mouse_start[0] dy = pos.y() - self.mouse_start[1] if dx == 0 and dy == 0: return rect = QtCore.QRect(0, 0, abs(dx), abs(dy)) delta = self.mapToScene(rect).boundingRect() tx = delta.width() if dx < 0.0: tx = -tx ty = delta.height() if dy < 0.0: ty = -ty matrix = self.transform() matrix.reset() matrix *= self.saved_matrix matrix.translate(tx, ty) self.setTransformationAnchor(QtWidgets.QGraphicsView.NoAnchor) self.setTransform(matrix) def wheel_zoom(self, event): """Handle mouse wheel zooming.""" delta = qtcompat.wheel_delta(event) zoom = math.pow(2.0, delta/512.0) factor = (self.transform() .scale(zoom, zoom) .mapRect(QtCore.QRectF(0.0, 0.0, 1.0, 1.0)) .width()) if factor < 0.014 or factor > 42.0: return self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse) self.zoom = zoom self.scale(zoom, zoom) def wheel_pan(self, event): """Handle mouse wheel panning.""" unit = QtCore.QRectF(0.0, 0.0, 1.0, 1.0) factor = 1.0 / self.transform().mapRect(unit).width() tx, ty = qtcompat.wheel_translation(event) matrix = self.transform().translate(tx * factor, ty * factor) self.setTransformationAnchor(QtWidgets.QGraphicsView.NoAnchor) self.setTransform(matrix) def scale_view(self, scale): factor = (self.transform() .scale(scale, scale) .mapRect(QtCore.QRectF(0, 0, 1, 1)) .width()) if factor < 0.07 or factor > 100.0: return self.zoom = scale adjust_scrollbars = True scrollbar = self.verticalScrollBar() if scrollbar: value = get(scrollbar) min_ = scrollbar.minimum() max_ = scrollbar.maximum() range_ = max_ - min_ distance = value - min_ nonzero_range = range_ > 0.1 if nonzero_range: scrolloffset = distance/range_ else: adjust_scrollbars = False self.setTransformationAnchor(QtWidgets.QGraphicsView.NoAnchor) self.scale(scale, scale) scrollbar = self.verticalScrollBar() if scrollbar and adjust_scrollbars: min_ = scrollbar.minimum() max_ = scrollbar.maximum() range_ = max_ - min_ value = min_ + int(float(range_) * scrolloffset) scrollbar.setValue(value) def add_commits(self, commits): """Traverse commits and add them to the view.""" self.commits.extend(commits) scene = self.scene() for commit in commits: item = Commit(commit, self.notifier) self.items[commit.oid] = item for ref in commit.tags: self.items[ref] = item scene.addItem(item) self.layout_commits() self.link(commits) def link(self, commits): """Create edges linking commits with their parents""" scene = self.scene() for commit in commits: try: commit_item = self.items[commit.oid] except KeyError: # TODO - Handle truncated history viewing continue for parent in reversed(commit.parents): try: parent_item = self.items[parent.oid] except KeyError: # TODO - Handle truncated history viewing continue try: edge = parent_item.edges[commit.oid] except KeyError: edge = Edge(parent_item, commit_item) else: continue parent_item.edges[commit.oid] = edge commit_item.edges[parent.oid] = edge scene.addItem(edge) def layout_commits(self): positions = self.position_nodes() # Each edge is accounted in two commits. Hence, accumulate invalid # edges to prevent double edge invalidation. invalid_edges = set() for oid, (x, y) in positions.items(): item = self.items[oid] pos = item.pos() if pos != (x, y): item.setPos(x, y) for edge in item.edges.values(): invalid_edges.add(edge) for edge in invalid_edges: edge.commits_were_invalidated() # Commit node layout technique # # Nodes are aligned by a mesh. Columns and rows are distributed using # algorithms described below. # # Row assignment algorithm # # The algorithm aims consequent. # 1. A commit should be above all its parents. # 2. No commit should be at right side of a commit with a tag in same row. # This prevents overlapping of tag labels with commits and other labels. # 3. Commit density should be maximized. # # The algorithm requires that all parents of a commit were assigned column. # Nodes must be traversed in generation ascend order. This guarantees that all # parents of a commit were assigned row. So, the algorithm may operate in # course of column assignment algorithm. # # Row assignment uses frontier. A frontier is a dictionary that contains # minimum available row index for each column. It propagates during the # algorithm. Set of cells with tags is also maintained to meet second aim. # # Initialization is performed by reset_rows method. Each new column should # be declared using declare_column method. Getting row for a cell is # implemented in alloc_cell method. Frontier must be propagated for any child # of fork commit which occupies different column. This meets first aim. # # Column assignment algorithm # # The algorithm traverses nodes in generation ascend order. This guarantees # that a node will be visited after all its parents. # # The set of occupied columns are maintained during work. Initially it is # empty and no node occupied a column. Empty columns are allocated on demand. # Free index for column being allocated is searched in following way. # 1. Start from desired column and look towards graph center (0 column). # 2. Start from center and look in both directions simultaneously. # Desired column is defaulted to 0. Fork node should set desired column for # children equal to its one. This prevents branch from jumping too far from # its fork. # # Initialization is performed by reset_columns method. Column allocation is # implemented in alloc_column method. Initialization and main loop are in # recompute_grid method. The method also embeds row assignment algorithm by # implementation. # # Actions for each node are follow. # 1. If the node was not assigned a column then it is assigned empty one. # 2. Allocate row. # 3. Allocate columns for children. # If a child have a column assigned then it should no be overridden. One of # children is assigned same column as the node. If the node is a fork then the # child is chosen in generation descent order. This is a heuristic and it only # affects resulting appearance of the graph. Other children are assigned empty # columns in same order. It is the heuristic too. # 4. If no child occupies column of the node then leave it. # It is possible in consequent situations. # 4.1 The node is a leaf. # 4.2 The node is a fork and all its children are already assigned side # column. It is possible if all the children are merges. # 4.3 Single node child is a merge that is already assigned a column. # 5. Propagate frontier with respect to this node. # Each frontier entry corresponding to column occupied by any node's child # must be gather than node row index. This meets first aim of the row # assignment algorithm. # Note that frontier of child that occupies same row was propagated during # step 2. Hence, it must be propagated for children on side columns. def reset_columns(self): # Some children of displayed commits might not be accounted in # 'commits' list. It is common case during loading of big graph. # But, they are assigned a column that must be reseted. Hence, use # depth-first traversal to reset all columns assigned. for node in self.commits: if node.column is None: continue stack = [node] while stack: node = stack.pop() node.column = None for child in node.children: if child.column is not None: stack.append(child) self.columns = {} self.max_column = 0 self.min_column = 0 def reset_rows(self): self.frontier = {} self.tagged_cells = set() def declare_column(self, column): if self.frontier: # Align new column frontier by frontier of nearest column. If all # columns were left then select maximum frontier value. if not self.columns: self.frontier[column] = max(list(self.frontier.values())) return # This is heuristic that mostly affects roots. Note that the # frontier values for fork children will be overridden in course of # propagate_frontier. for offset in itertools.count(1): for c in [column + offset, column - offset]: if c not in self.columns: # Column 'c' is not occupied. continue try: frontier = self.frontier[c] except KeyError: # Column 'c' was never allocated. continue frontier -= 1 # The frontier of the column may be higher because of # tag overlapping prevention performed for previous head. try: if self.frontier[column] >= frontier: break except KeyError: pass self.frontier[column] = frontier break else: continue break else: # First commit must be assigned 0 row. self.frontier[column] = 0 def alloc_column(self, column=0): columns = self.columns # First, look for free column by moving from desired column to graph # center (column 0). for c in range(column, 0, -1 if column > 0 else 1): if c not in columns: if c > self.max_column: self.max_column = c elif c < self.min_column: self.min_column = c break else: # If no free column was found between graph center and desired # column then look for free one by moving from center along both # directions simultaneously. for c in itertools.count(0): if c not in columns: if c > self.max_column: self.max_column = c break c = -c if c not in columns: if c < self.min_column: self.min_column = c break self.declare_column(c) columns[c] = 1 return c def alloc_cell(self, column, tags): # Get empty cell from frontier. cell_row = self.frontier[column] if tags: # Prevent overlapping of tag with cells already allocated a row. if self.x_off > 0: can_overlap = list(range(column + 1, self.max_column + 1)) else: can_overlap = list(range(column - 1, self.min_column - 1, -1)) for c in can_overlap: frontier = self.frontier[c] if frontier > cell_row: cell_row = frontier # Avoid overlapping with tags of commits at cell_row. if self.x_off > 0: can_overlap = list(range(self.min_column, column)) else: can_overlap = list(range(self.max_column, column, -1)) for cell_row in itertools.count(cell_row): for c in can_overlap: if (c, cell_row) in self.tagged_cells: # Overlapping. Try next row. break else: # No overlapping was found. break # Note that all checks should be made for new cell_row value. if tags: self.tagged_cells.add((column, cell_row)) # Propagate frontier. self.frontier[column] = cell_row + 1 return cell_row def propagate_frontier(self, column, value): current = self.frontier[column] if current < value: self.frontier[column] = value def leave_column(self, column): count = self.columns[column] if count == 1: del self.columns[column] else: self.columns[column] = count - 1 def recompute_grid(self): self.reset_columns() self.reset_rows() for node in sort_by_generation(list(self.commits)): if node.column is None: # Node is either root or its parent is not in items. The last # happens when tree loading is in progress. Allocate new # columns for such nodes. node.column = self.alloc_column() node.row = self.alloc_cell(node.column, node.tags) # Allocate columns for children which are still without one. Also # propagate frontier for children. if node.is_fork(): sorted_children = sorted(node.children, key=lambda c: c.generation, reverse=True) citer = iter(sorted_children) for child in citer: if child.column is None: # Top most child occupies column of parent. child.column = node.column # Note that frontier is propagated in course of # alloc_cell. break else: self.propagate_frontier(child.column, node.row + 1) else: # No child occupies same column. self.leave_column(node.column) # Note that the loop below will pass no iteration. # Rest children are allocated new column. for child in citer: if child.column is None: child.column = self.alloc_column(node.column) self.propagate_frontier(child.column, node.row + 1) elif node.children: child = node.children[0] if child.column is None: child.column = node.column # Note that frontier is propagated in course of alloc_cell. elif child.column != node.column: # Child node have other parents and occupies column of one # of them. self.leave_column(node.column) # But frontier must be propagated with respect to this # parent. self.propagate_frontier(child.column, node.row + 1) else: # This is a leaf node. self.leave_column(node.column) def position_nodes(self): self.recompute_grid() x_start = self.x_start x_min = self.x_min x_off = self.x_off y_off = self.y_off positions = {} for node in self.commits: x_pos = x_start + node.column * x_off y_pos = y_off + node.row * y_off positions[node.oid] = (x_pos, y_pos) x_min = min(x_min, x_pos) self.x_min = x_min return positions # Qt overrides def contextMenuEvent(self, event): self.context_menu_event(event) def mousePressEvent(self, event): if event.button() == Qt.MidButton: pos = event.pos() self.mouse_start = [pos.x(), pos.y()] self.saved_matrix = self.transform() self.is_panning = True return if event.button() == Qt.RightButton: event.ignore() return if event.button() == Qt.LeftButton: self.pressed = True self.handle_event(QtWidgets.QGraphicsView.mousePressEvent, event) def mouseMoveEvent(self, event): pos = self.mapToScene(event.pos()) if self.is_panning: self.pan(event) return self.last_mouse[0] = pos.x() self.last_mouse[1] = pos.y() self.handle_event(QtWidgets.QGraphicsView.mouseMoveEvent, event) if self.pressed: self.viewport().repaint() def mouseReleaseEvent(self, event): self.pressed = False if event.button() == Qt.MidButton: self.is_panning = False return self.handle_event(QtWidgets.QGraphicsView.mouseReleaseEvent, event) self.selection_list = [] self.viewport().repaint() def wheelEvent(self, event): """Handle Qt mouse wheel events.""" if event.modifiers() & Qt.ControlModifier: self.wheel_zoom(event) else: self.wheel_pan(event) def fitInView(self, rect, flags=Qt.IgnoreAspectRatio): """Override fitInView to remove unwanted margins https://bugreports.qt.io/browse/QTBUG-42331 - based on QT sources """ if self.scene() is None or rect.isNull(): return unity = self.transform().mapRect(QtCore.QRectF(0, 0, 1, 1)) self.scale(1.0/unity.width(), 1.0/unity.height()) view_rect = self.viewport().rect() scene_rect = self.transform().mapRect(rect) xratio = view_rect.width() / scene_rect.width() yratio = view_rect.height() / scene_rect.height() if flags == Qt.KeepAspectRatio: xratio = yratio = min(xratio, yratio) elif flags == Qt.KeepAspectRatioByExpanding: xratio = yratio = max(xratio, yratio) self.scale(xratio, yratio) self.centerOn(rect.center()) def sort_by_generation(commits): if len(commits) < 2: return commits commits.sort(key=lambda x: x.generation) return commits # Glossary # ======== # oid -- Git objects IDs (i.e. SHA-1 IDs) # ref -- Git references that resolve to a commit-ish (HEAD, branches, tags) git-cola-3.6/cola/widgets/defs.py000066400000000000000000000015431356743264500167620ustar00rootroot00000000000000from __future__ import absolute_import, division, unicode_literals import os import math try: scale_factor = float(os.getenv('GIT_COLA_SCALE', '1')) except ValueError: scale_factor = 1.0 def scale(value, factor=scale_factor): return int(value * factor) no_margin = 0 small_margin = scale(2) margin = scale(4) large_margin = scale(12) no_spacing = 0 spacing = scale(4) titlebar_spacing = scale(8) button_spacing = scale(12) cursor_width = scale(2) handle_width = scale(4) tool_button_height = scale(28) small_icon = scale(12) medium_icon = scale(48) large_icon = scale(96) huge_icon = scale(192) max_size = scale(4096) border = max(1, scale(0.5)) checkbox = scale(12) radio = scale(22) logo_text = 24 radio_border = max(1, scale(1.0 - (1.0 / math.pi))) separator = scale(3) dialog_w = scale(720) dialog_h = scale(445) msgbox_h = scale(128) git-cola-3.6/cola/widgets/diff.py000066400000000000000000001120661356743264500167540ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals import os import re from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from qtpy.QtCore import Qt from qtpy.QtCore import Signal from ..i18n import N_ from ..interaction import Interaction from ..models import prefs from ..qtutils import get from .. import actions from .. import cmds from .. import core from .. import diffparse from .. import gitcmds from .. import gravatar from .. import hotkeys from .. import icons from .. import utils from .. import qtutils from .text import TextDecorator from .text import VimHintedPlainTextEdit from . import defs from . import imageview COMMITS_SELECTED = 'COMMITS_SELECTED' FILES_SELECTED = 'FILES_SELECTED' class DiffSyntaxHighlighter(QtGui.QSyntaxHighlighter): """Implements the diff syntax highlighting""" INITIAL_STATE = -1 DEFAULT_STATE = 0 DIFFSTAT_STATE = 1 DIFF_FILE_HEADER_STATE = 2 DIFF_STATE = 3 SUBMODULE_STATE = 4 END_STATE = 5 DIFF_FILE_HEADER_START_RGX = re.compile(r'diff --git a/.* b/.*') DIFF_HUNK_HEADER_RGX = re.compile(r'(?:@@ -[0-9,]+ \+[0-9,]+ @@)|' r'(?:@@@ (?:-[0-9,]+ ){2}\+[0-9,]+ @@@)') BAD_WHITESPACE_RGX = re.compile(r'\s+$') def __init__(self, context, doc, whitespace=True, is_commit=False): QtGui.QSyntaxHighlighter.__init__(self, doc) self.whitespace = whitespace self.enabled = True self.is_commit = is_commit QPalette = QtGui.QPalette cfg = context.cfg palette = QPalette() disabled = palette.color(QPalette.Disabled, QPalette.Text) header = qtutils.rgb_hex(disabled) dark = palette.color(QPalette.Base).lightnessF() < 0.5 self.color_text = qtutils.RGB(cfg.color('text', '030303')) self.color_add = qtutils.RGB( cfg.color('add', '77aa77' if dark else 'd2ffe4') ) self.color_remove = qtutils.RGB( cfg.color('remove', 'aa7777' if dark else 'fee0e4') ) self.color_header = qtutils.RGB(cfg.color('header', header)) self.diff_header_fmt = qtutils.make_format(fg=self.color_header) self.bold_diff_header_fmt = qtutils.make_format( fg=self.color_header, bold=True) self.diff_add_fmt = qtutils.make_format( fg=self.color_text, bg=self.color_add) self.diff_remove_fmt = qtutils.make_format( fg=self.color_text, bg=self.color_remove) self.bad_whitespace_fmt = qtutils.make_format(bg=Qt.red) self.setCurrentBlockState(self.INITIAL_STATE) def set_enabled(self, enabled): self.enabled = enabled def highlightBlock(self, text): if not self.enabled or not text: return # Aliases for quick local access initial_state = self.INITIAL_STATE default_state = self.DEFAULT_STATE diff_state = self.DIFF_STATE diffstat_state = self.DIFFSTAT_STATE diff_file_header_state = self.DIFF_FILE_HEADER_STATE submodule_state = self.SUBMODULE_STATE end_state = self.END_STATE diff_file_header_start_rgx = self.DIFF_FILE_HEADER_START_RGX diff_hunk_header_rgx = self.DIFF_HUNK_HEADER_RGX bad_whitespace_rgx = self.BAD_WHITESPACE_RGX diff_header_fmt = self.diff_header_fmt bold_diff_header_fmt = self.bold_diff_header_fmt diff_add_fmt = self.diff_add_fmt diff_remove_fmt = self.diff_remove_fmt bad_whitespace_fmt = self.bad_whitespace_fmt state = self.previousBlockState() if state == initial_state: if text.startswith('Submodule '): state = submodule_state elif text.startswith('diff --git '): state = diffstat_state elif self.is_commit: state = default_state else: state = diffstat_state if state == diffstat_state: if diff_file_header_start_rgx.match(text): state = diff_file_header_state self.setFormat(0, len(text), diff_header_fmt) elif diff_hunk_header_rgx.match(text): state = diff_state self.setFormat(0, len(text), bold_diff_header_fmt) elif '|' in text: i = text.index('|') self.setFormat(0, i, bold_diff_header_fmt) self.setFormat(i, len(text) - i, diff_header_fmt) else: self.setFormat(0, len(text), diff_header_fmt) elif state == diff_file_header_state: if diff_hunk_header_rgx.match(text): state = diff_state self.setFormat(0, len(text), bold_diff_header_fmt) else: self.setFormat(0, len(text), diff_header_fmt) elif state == diff_state: if diff_file_header_start_rgx.match(text): state = diff_file_header_state self.setFormat(0, len(text), diff_header_fmt) elif diff_hunk_header_rgx.match(text): self.setFormat(0, len(text), bold_diff_header_fmt) elif text.startswith('-'): if text == '-- ': state = end_state else: self.setFormat(0, len(text), diff_remove_fmt) elif text.startswith('+'): self.setFormat(0, len(text), diff_add_fmt) if self.whitespace: m = bad_whitespace_rgx.search(text) if m is not None: i = m.start() self.setFormat(i, len(text) - i, bad_whitespace_fmt) self.setCurrentBlockState(state) # pylint: disable=too-many-ancestors class DiffTextEdit(VimHintedPlainTextEdit): def __init__(self, context, parent, is_commit=False, whitespace=True, numbers=False): VimHintedPlainTextEdit.__init__(self, context, '', parent=parent) # Diff/patch syntax highlighter self.highlighter = DiffSyntaxHighlighter( context, self.document(), is_commit=is_commit, whitespace=whitespace) if numbers: self.numbers = DiffLineNumbers(context, self) self.numbers.hide() else: self.numbers = None self.scrollvalue = None # pylint: disable=no-member self.cursorPositionChanged.connect(self._cursor_changed) def _cursor_changed(self): """Update the line number display when the cursor changes""" line_number = max(0, self.textCursor().blockNumber()) if self.numbers: self.numbers.set_highlighted(line_number) def resizeEvent(self, event): super(DiffTextEdit, self).resizeEvent(event) if self.numbers: self.numbers.refresh_size() def save_scrollbar(self): """Save the scrollbar value, but only on the first call""" if self.scrollvalue is None: scrollbar = self.verticalScrollBar() if scrollbar: scrollvalue = get(scrollbar) else: scrollvalue = None self.scrollvalue = scrollvalue def restore_scrollbar(self): """Restore the scrollbar and clear state""" scrollbar = self.verticalScrollBar() scrollvalue = self.scrollvalue if scrollbar and scrollvalue is not None: scrollbar.setValue(scrollvalue) self.scrollvalue = None def set_loading_message(self): self.hint.set_value('+++ ' + N_('Loading...')) self.set_value('') def set_diff(self, diff): """Set the diff text, but save the scrollbar""" diff = diff.rstrip('\n') # diffs include two empty newlines self.save_scrollbar() self.hint.set_value('') if self.numbers: self.numbers.set_diff(diff) self.set_value(diff) self.restore_scrollbar() class DiffLineNumbers(TextDecorator): def __init__(self, context, parent): TextDecorator.__init__(self, parent) self.highlight_line = -1 self.lines = None self.parser = diffparse.DiffLines() self.formatter = diffparse.FormatDigits() self.setFont(qtutils.diff_font(context)) self._char_width = self.fontMetrics().width('0') QPalette = QtGui.QPalette self._palette = palette = self.palette() self._base = palette.color(QtGui.QPalette.Base) self._highlight = palette.color(QPalette.Highlight) self._highlight_text = palette.color(QPalette.HighlightedText) self._window = palette.color(QPalette.Window) self._disabled = palette.color(QPalette.Disabled, QPalette.Text) def set_diff(self, diff): parser = self.parser lines = parser.parse(diff) if parser.valid: self.lines = lines self.formatter.set_digits(self.parser.digits()) else: self.lines = None def set_lines(self, lines): self.lines = lines def width_hint(self): if not self.isVisible(): return 0 parser = self.parser if parser.merge: columns = 3 extra = 3 # one space in-between, one space after else: columns = 2 extra = 2 # one space in-between, one space after if parser.valid: digits = parser.digits() * columns else: digits = 4 return defs.margin + (self._char_width * (digits + extra)) def set_highlighted(self, line_number): """Set the line to highlight""" self.highlight_line = line_number def current_line(self): if self.lines and self.highlight_line >= 0: # Find the next valid line for line in self.lines[self.highlight_line:]: # take the "new" line number: last value in tuple line_number = line[-1] if line_number > 0: return line_number # Find the previous valid line for line in self.lines[self.highlight_line-1::-1]: # take the "new" line number: last value in tuple line_number = line[-1] if line_number > 0: return line_number return None def paintEvent(self, event): """Paint the line number""" if not self.lines: return painter = QtGui.QPainter(self) painter.fillRect(event.rect(), self._base) editor = self.editor content_offset = editor.contentOffset() block = editor.firstVisibleBlock() width = self.width() event_rect_bottom = event.rect().bottom() highlight = self._highlight highlight.setAlphaF(0.3) highlight_text = self._highlight_text disabled = self._disabled fmt = self.formatter lines = self.lines num_lines = len(self.lines) painter.setPen(disabled) text = '' while block.isValid(): block_number = block.blockNumber() if block_number >= num_lines: break block_geom = editor.blockBoundingGeometry(block) block_top = block_geom.translated(content_offset).top() if not block.isVisible() or block_top >= event_rect_bottom: break rect = block_geom.translated(content_offset).toRect() if block_number == self.highlight_line: painter.fillRect(rect.x(), rect.y(), width, rect.height(), highlight) painter.setPen(highlight_text) else: painter.setPen(disabled) line = lines[block_number] if len(line) == 2: a, b = line text = fmt.value(a, b) elif len(line) == 3: old, base, new = line text = fmt.merge_value(old, base, new) painter.drawText(rect.x(), rect.y(), self.width() - (defs.margin * 2), rect.height(), Qt.AlignRight | Qt.AlignVCenter, text) block = block.next() # pylint: disable=next-method-called class Viewer(QtWidgets.QFrame): """Text and image diff viewers""" images_changed = Signal(object) type_changed = Signal(object) def __init__(self, context, parent=None): super(Viewer, self).__init__(parent) self.context = context self.model = model = context.model self.images = [] self.pixmaps = [] self.options = options = Options(self) self.text = DiffEditor(context, options, self) self.image = imageview.ImageView(parent=self) self.image.setFocusPolicy(Qt.NoFocus) stack = self.stack = QtWidgets.QStackedWidget(self) stack.addWidget(self.text) stack.addWidget(self.image) self.main_layout = qtutils.vbox( defs.no_margin, defs.no_spacing, self.stack) self.setLayout(self.main_layout) # Observe images images_msg = model.message_images_changed model.add_observer(images_msg, self.images_changed.emit) # pylint: disable=no-member self.images_changed.connect(self.set_images, type=Qt.QueuedConnection) # Observe the diff type diff_type_msg = model.message_diff_type_changed model.add_observer(diff_type_msg, self.type_changed.emit) self.type_changed.connect(self.set_diff_type, type=Qt.QueuedConnection) # Observe the image mode combo box options.image_mode.currentIndexChanged.connect(lambda _: self.render()) options.zoom_mode.currentIndexChanged.connect(lambda _: self.render()) self.setFocusProxy(self.text) def export_state(self, state): state['show_diff_line_numbers'] = self.text.show_line_numbers() state['image_diff_mode'] = self.options.image_mode.currentIndex() state['image_zoom_mode'] = self.options.zoom_mode.currentIndex() return state def apply_state(self, state): diff_numbers = bool(state.get('show_diff_line_numbers', False)) self.text.enable_line_numbers(diff_numbers) image_mode = utils.asint(state.get('image_diff_mode', 0)) self.options.image_mode.set_index(image_mode) zoom_mode = utils.asint(state.get('image_zoom_mode', 0)) self.options.zoom_mode.set_index(zoom_mode) return True def set_diff_type(self, diff_type): """Manage the image and text diff views when selection changes""" self.options.set_diff_type(diff_type) if diff_type == 'image': self.stack.setCurrentWidget(self.image) self.render() else: self.stack.setCurrentWidget(self.text) def update_options(self): self.text.update_options() def reset(self): self.image.pixmap = QtGui.QPixmap() self.cleanup() def cleanup(self): for (image, unlink) in self.images: if unlink and core.exists(image): os.unlink(image) self.images = [] def set_images(self, images): self.images = images self.pixmaps = [] if not images: self.reset() return False # In order to comp, we first have to load all the images all_pixmaps = [QtGui.QPixmap(image[0]) for image in images] pixmaps = [pixmap for pixmap in all_pixmaps if not pixmap.isNull()] if not pixmaps: self.reset() return False self.pixmaps = pixmaps self.render() self.cleanup() return True def render(self): # Update images if self.pixmaps: mode = self.options.image_mode.currentIndex() if mode == self.options.SIDE_BY_SIDE: image = self.render_side_by_side() elif mode == self.options.DIFF: image = self.render_diff() elif mode == self.options.XOR: image = self.render_xor() elif mode == self.options.PIXEL_XOR: image = self.render_pixel_xor() else: image = self.render_side_by_side() else: image = QtGui.QPixmap() self.image.pixmap = image # Apply zoom zoom_mode = self.options.zoom_mode.currentIndex() zoom_factor = self.options.zoom_factors[zoom_mode][1] if zoom_factor > 0.0: self.image.resetTransform() self.image.scale(zoom_factor, zoom_factor) poly = self.image.mapToScene(self.image.viewport().rect()) self.image.last_scene_roi = poly.boundingRect() def render_side_by_side(self): # Side-by-side lineup comp pixmaps = self.pixmaps width = sum([pixmap.width() for pixmap in pixmaps]) height = max([pixmap.height() for pixmap in pixmaps]) image = create_image(width, height) # Paint each pixmap painter = create_painter(image) x = 0 for pixmap in pixmaps: painter.drawPixmap(x, 0, pixmap) x += pixmap.width() painter.end() return image def render_comp(self, comp_mode): # Get the max size to use as the render canvas pixmaps = self.pixmaps if len(pixmaps) == 1: return pixmaps[0] width = max([pixmap.width() for pixmap in pixmaps]) height = max([pixmap.height() for pixmap in pixmaps]) image = create_image(width, height) painter = create_painter(image) for pixmap in (pixmaps[0], pixmaps[-1]): x = (width - pixmap.width()) // 2 y = (height - pixmap.height()) // 2 painter.drawPixmap(x, y, pixmap) painter.setCompositionMode(comp_mode) painter.end() return image def render_diff(self): comp_mode = QtGui.QPainter.CompositionMode_Difference return self.render_comp(comp_mode) def render_xor(self): comp_mode = QtGui.QPainter.CompositionMode_Xor return self.render_comp(comp_mode) def render_pixel_xor(self): comp_mode = QtGui.QPainter.RasterOp_SourceXorDestination return self.render_comp(comp_mode) def create_image(width, height): size = QtCore.QSize(width, height) image = QtGui.QImage(size, QtGui.QImage.Format_ARGB32_Premultiplied) image.fill(Qt.transparent) return image def create_painter(image): painter = QtGui.QPainter(image) painter.fillRect(image.rect(), Qt.transparent) return painter class Options(QtWidgets.QWidget): """Provide the options widget used by the editor Actions are registered on the parent widget. """ # mode combobox indexes SIDE_BY_SIDE = 0 DIFF = 1 XOR = 2 PIXEL_XOR = 3 def __init__(self, parent): super(Options, self).__init__(parent) self.widget = parent self.ignore_space_at_eol = self.add_option( N_('Ignore changes in whitespace at EOL')) self.ignore_space_change = self.add_option( N_('Ignore changes in amount of whitespace')) self.ignore_all_space = self.add_option( N_('Ignore all whitespace')) self.function_context = self.add_option( N_('Show whole surrounding functions of changes')) self.show_line_numbers = self.add_option( N_('Show line numbers')) self.options = options = qtutils.create_action_button( tooltip=N_('Diff Options'), icon=icons.configure()) self.image_mode = qtutils.combo([ N_('Side by side'), N_('Diff'), N_('XOR'), N_('Pixel XOR'), ]) self.zoom_factors = ( (N_('Zoom to Fit'), 0.0), (N_('25%'), 0.25), (N_('50%'), 0.5), (N_('100%'), 1.0), (N_('200%'), 2.0), (N_('400%'), 4.0), (N_('800%'), 8.0), ) zoom_modes = [factor[0] for factor in self.zoom_factors] self.zoom_mode = qtutils.combo(zoom_modes, parent=self) self.menu = menu = qtutils.create_menu(N_('Diff Options'), options) options.setMenu(menu) menu.addAction(self.ignore_space_at_eol) menu.addAction(self.ignore_space_change) menu.addAction(self.ignore_all_space) menu.addAction(self.show_line_numbers) menu.addAction(self.function_context) layout = qtutils.hbox( defs.no_margin, defs.no_spacing, self.image_mode, defs.button_spacing, self.zoom_mode, options) self.setLayout(layout) self.image_mode.setFocusPolicy(Qt.NoFocus) self.zoom_mode.setFocusPolicy(Qt.NoFocus) self.options.setFocusPolicy(Qt.NoFocus) self.setFocusPolicy(Qt.NoFocus) def set_diff_type(self, diff_type): is_text = diff_type == 'text' is_image = diff_type == 'image' self.options.setVisible(is_text) self.image_mode.setVisible(is_image) self.zoom_mode.setVisible(is_image) def add_option(self, title): action = qtutils.add_action(self, title, self.update_options) action.setCheckable(True) return action def update_options(self): space_at_eol = get(self.ignore_space_at_eol) space_change = get(self.ignore_space_change) all_space = get(self.ignore_all_space) function_context = get(self.function_context) gitcmds.update_diff_overrides( space_at_eol, space_change, all_space, function_context) self.widget.update_options() # pylint: disable=too-many-ancestors class DiffEditor(DiffTextEdit): up = Signal() down = Signal() options_changed = Signal() updated = Signal() diff_text_updated = Signal(object) def __init__(self, context, options, parent): DiffTextEdit.__init__(self, context, parent, numbers=True) self.context = context self.model = model = context.model self.selection_model = selection_model = context.selection # "Diff Options" tool menu self.options = options self.action_apply_selection = qtutils.add_action( self, 'Apply', self.apply_selection, hotkeys.STAGE_DIFF) self.action_revert_selection = qtutils.add_action( self, 'Revert', self.revert_selection, hotkeys.REVERT) self.action_revert_selection.setIcon(icons.undo()) self.launch_editor = actions.launch_editor_at_line( context, self, *hotkeys.ACCEPT) self.launch_difftool = actions.launch_difftool(context, self) self.stage_or_unstage = actions.stage_or_unstage(context, self) # Emit up/down signals so that they can be routed by the main widget self.move_up = actions.move_up(self) self.move_down = actions.move_down(self) diff_text_updated = model.message_diff_text_updated model.add_observer(diff_text_updated, self.diff_text_updated.emit) self.diff_text_updated.connect(self.set_diff, type=Qt.QueuedConnection) selection_model.add_observer( selection_model.message_selection_changed, self.updated.emit) # pylint: disable=no-member self.updated.connect(self.refresh, type=Qt.QueuedConnection) # Update the selection model when the cursor changes self.cursorPositionChanged.connect(self._update_line_number) def refresh(self): enabled = False s = self.selection_model.selection() model = self.model if s.modified and model.stageable(): if s.modified[0] in model.submodules: pass elif s.modified[0] not in model.unstaged_deleted: enabled = True self.action_revert_selection.setEnabled(enabled) def enable_line_numbers(self, enabled): """Enable/disable the diff line number display""" self.numbers.setVisible(enabled) self.options.show_line_numbers.setChecked(enabled) def show_line_numbers(self): """Return True if we should show line numbers""" return get(self.options.show_line_numbers) def update_options(self): self.numbers.setVisible(self.show_line_numbers()) self.options_changed.emit() # Qt overrides def contextMenuEvent(self, event): """Create the context menu for the diff display.""" menu = qtutils.create_menu(N_('Actions'), self) context = self.context model = self.model s = self.selection_model.selection() filename = self.selection_model.filename() if model.stageable() or model.unstageable(): if model.stageable(): self.stage_or_unstage.setText(N_('Stage')) else: self.stage_or_unstage.setText(N_('Unstage')) menu.addAction(self.stage_or_unstage) if s.modified and model.stageable(): item = s.modified[0] if item in model.submodules: path = core.abspath(item) action = menu.addAction( icons.add(), cmds.Stage.name(), cmds.run(cmds.Stage, context, s.modified)) action.setShortcut(hotkeys.STAGE_SELECTION) menu.addAction(icons.cola(), N_('Launch git-cola'), cmds.run(cmds.OpenRepo, context, path)) elif item not in model.unstaged_deleted: if self.has_selection(): apply_text = N_('Stage Selected Lines') revert_text = N_('Revert Selected Lines...') else: apply_text = N_('Stage Diff Hunk') revert_text = N_('Revert Diff Hunk...') self.action_apply_selection.setText(apply_text) self.action_apply_selection.setIcon(icons.add()) self.action_revert_selection.setText(revert_text) menu.addAction(self.action_apply_selection) menu.addAction(self.action_revert_selection) if s.staged and model.unstageable(): item = s.staged[0] if item in model.submodules: path = core.abspath(item) action = menu.addAction( icons.remove(), cmds.Unstage.name(), cmds.run(cmds.Unstage, context, s.staged)) action.setShortcut(hotkeys.STAGE_SELECTION) menu.addAction(icons.cola(), N_('Launch git-cola'), cmds.run(cmds.OpenRepo, context, path)) elif item not in model.staged_deleted: if self.has_selection(): apply_text = N_('Unstage Selected Lines') else: apply_text = N_('Unstage Diff Hunk') self.action_apply_selection.setText(apply_text) self.action_apply_selection.setIcon(icons.remove()) menu.addAction(self.action_apply_selection) if model.stageable() or model.unstageable(): # Do not show the "edit" action when the file does not exist. # Untracked files exist by definition. if filename and core.exists(filename): menu.addSeparator() menu.addAction(self.launch_editor) # Removed files can still be diffed. menu.addAction(self.launch_difftool) # Add the Previous/Next File actions, which improves discoverability # of their associated shortcuts menu.addSeparator() menu.addAction(self.move_up) menu.addAction(self.move_down) menu.addSeparator() action = menu.addAction(icons.copy(), N_('Copy'), self.copy) action.setShortcut(QtGui.QKeySequence.Copy) action = menu.addAction(icons.select_all(), N_('Select All'), self.selectAll) action.setShortcut(QtGui.QKeySequence.SelectAll) menu.exec_(self.mapToGlobal(event.pos())) def mousePressEvent(self, event): if event.button() == Qt.RightButton: # Intercept right-click to move the cursor to the current position. # setTextCursor() clears the selection so this is only done when # nothing is selected. if not self.has_selection(): cursor = self.cursorForPosition(event.pos()) self.setTextCursor(cursor) return super(DiffEditor, self).mousePressEvent(event) def setPlainText(self, text): """setPlainText(str) while retaining scrollbar positions""" model = self.model mode = model.mode highlight = mode not in (model.mode_none, model.mode_untracked) self.highlighter.set_enabled(highlight) scrollbar = self.verticalScrollBar() if scrollbar: scrollvalue = get(scrollbar) else: scrollvalue = None if text is None: return DiffTextEdit.setPlainText(self, text) if scrollbar and scrollvalue is not None: scrollbar.setValue(scrollvalue) def selected_lines(self): cursor = self.textCursor() selection_start = cursor.selectionStart() selection_end = max(selection_start, cursor.selectionEnd() - 1) first_line_idx = -1 last_line_idx = -1 line_idx = 0 line_start = 0 for line_idx, line in enumerate(get(self).splitlines()): line_end = line_start + len(line) if line_start <= selection_start <= line_end: first_line_idx = line_idx if line_start <= selection_end <= line_end: last_line_idx = line_idx break line_start = line_end + 1 if first_line_idx == -1: first_line_idx = line_idx if last_line_idx == -1: last_line_idx = line_idx return first_line_idx, last_line_idx def apply_selection(self): model = self.model s = self.selection_model.single_selection() if model.stageable() and s.modified: self.process_diff_selection() elif model.unstageable(): self.process_diff_selection(reverse=True) def revert_selection(self): """Destructively revert selected lines or hunk from a worktree file.""" if self.has_selection(): title = N_('Revert Selected Lines?') ok_text = N_('Revert Selected Lines') else: title = N_('Revert Diff Hunk?') ok_text = N_('Revert Diff Hunk') if not Interaction.confirm( title, N_('This operation drops uncommitted changes.\n' 'These changes cannot be recovered.'), N_('Revert the uncommitted changes?'), ok_text, default=True, icon=icons.undo()): return self.process_diff_selection(reverse=True, apply_to_worktree=True) def process_diff_selection(self, reverse=False, apply_to_worktree=False): """Implement un/staging of the selected line(s) or hunk.""" if self.selection_model.is_empty(): return context = self.context first_line_idx, last_line_idx = self.selected_lines() cmds.do(cmds.ApplyDiffSelection, context, first_line_idx, last_line_idx, self.has_selection(), reverse, apply_to_worktree) def _update_line_number(self): """Update the selection model when the cursor changes""" self.selection_model.line_number = self.numbers.current_line() class DiffWidget(QtWidgets.QWidget): def __init__(self, context, notifier, parent, is_commit=False): QtWidgets.QWidget.__init__(self, parent) self.context = context self.oid = 'HEAD' author_font = QtGui.QFont(self.font()) author_font.setPointSize(int(author_font.pointSize() * 1.1)) summary_font = QtGui.QFont(author_font) summary_font.setWeight(QtGui.QFont.Bold) policy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Minimum) self.gravatar_label = gravatar.GravatarLabel() self.author_label = TextLabel() self.author_label.setTextFormat(Qt.RichText) self.author_label.setFont(author_font) self.author_label.setSizePolicy(policy) self.author_label.setAlignment(Qt.AlignBottom) self.author_label.elide() self.date_label = TextLabel() self.date_label.setTextFormat(Qt.PlainText) self.date_label.setSizePolicy(policy) self.date_label.setAlignment(Qt.AlignTop) self.date_label.hide() self.summary_label = TextLabel() self.summary_label.setTextFormat(Qt.PlainText) self.summary_label.setFont(summary_font) self.summary_label.setSizePolicy(policy) self.summary_label.setAlignment(Qt.AlignTop) self.summary_label.elide() self.oid_label = TextLabel() self.oid_label.setTextFormat(Qt.PlainText) self.oid_label.setSizePolicy(policy) self.oid_label.setAlignment(Qt.AlignTop) self.oid_label.elide() self.diff = DiffTextEdit( context, self, is_commit=is_commit, whitespace=False) self.info_layout = qtutils.vbox(defs.no_margin, defs.no_spacing, self.author_label, self.date_label, self.summary_label, self.oid_label) self.logo_layout = qtutils.hbox(defs.no_margin, defs.button_spacing, self.gravatar_label, self.info_layout) self.logo_layout.setContentsMargins(defs.margin, 0, defs.margin, 0) self.main_layout = qtutils.vbox(defs.no_margin, defs.spacing, self.logo_layout, self.diff) self.setLayout(self.main_layout) notifier.add_observer(COMMITS_SELECTED, self.commits_selected) notifier.add_observer(FILES_SELECTED, self.files_selected) self.set_tabwidth(prefs.tabwidth(context)) def set_tabwidth(self, width): self.diff.set_tabwidth(width) def set_diff_oid(self, oid, filename=None): context = self.context self.diff.save_scrollbar() self.diff.set_loading_message() task = DiffInfoTask(context, oid, filename, self) self.context.runtask.start(task, result=self.set_diff) def commits_selected(self, commits): if len(commits) != 1: return commit = commits[0] oid = self.oid = commit.oid email = commit.email or '' summary = commit.summary or '' author = commit.author or '' self.set_details(oid, author, email, '', summary) self.set_diff_oid(oid) def set_diff(self, diff): self.diff.set_diff(diff) def set_details(self, oid, author, email, date, summary): template_args = { 'author': author, 'email': email, 'summary': summary } author_text = ("""%(author)s <""" """""" """%(email)s>""" % template_args) author_template = '%(author)s <%(email)s>' % template_args self.date_label.set_text(date) self.date_label.setVisible(bool(date)) self.oid_label.set_text(oid) self.author_label.set_template(author_text, author_template) self.summary_label.set_text(summary) self.gravatar_label.set_email(email) def files_selected(self, filenames): if not filenames: return self.set_diff_oid(self.oid, filenames[0]) class TextLabel(QtWidgets.QLabel): def __init__(self, parent=None): QtWidgets.QLabel.__init__(self, parent) self.setTextInteractionFlags(Qt.TextSelectableByMouse | Qt.LinksAccessibleByMouse) self._display = '' self._template = '' self._text = '' self._elide = False self._metrics = QtGui.QFontMetrics(self.font()) self.setOpenExternalLinks(True) def elide(self): self._elide = True def set_text(self, text): self.set_template(text, text) def set_template(self, text, template): self._display = text self._text = text self._template = template self.update_text(self.width()) self.setText(self._display) def update_text(self, width): self._display = self._text if not self._elide: return text = self._metrics.elidedText(self._template, Qt.ElideRight, width-2) if text != self._template: self._display = text # Qt overrides def setFont(self, font): self._metrics = QtGui.QFontMetrics(font) QtWidgets.QLabel.setFont(self, font) def resizeEvent(self, event): if self._elide: self.update_text(event.size().width()) block = self.blockSignals(True) self.setText(self._display) self.blockSignals(block) QtWidgets.QLabel.resizeEvent(self, event) class DiffInfoTask(qtutils.Task): def __init__(self, context, oid, filename, parent): qtutils.Task.__init__(self, parent) self.context = context self.oid = oid self.filename = filename def task(self): context = self.context oid = self.oid return gitcmds.diff_info(context, oid, filename=self.filename) git-cola-3.6/cola/widgets/editremotes.py000066400000000000000000000360011356743264500203620ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals import operator from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from qtpy.QtCore import Qt from qtpy.QtCore import Signal from ..git import STDOUT from ..i18n import N_ from ..qtutils import get from .. import cmds from .. import core from .. import gitcmds from .. import icons from .. import qtutils from .. import utils from . import completion from . import defs from . import standard from . import text def editor(context, run=True): view = RemoteEditor(context, parent=qtutils.active_window()) if run: view.show() view.exec_() return view class RemoteEditor(standard.Dialog): def __init__(self, context, parent=None): standard.Dialog.__init__(self, parent) self.setWindowTitle(N_('Edit Remotes')) if parent is not None: self.setWindowModality(Qt.WindowModal) self.context = context self.current_name = '' self.current_url = '' hint = N_('Edit remotes by selecting them from the list') self.default_hint = hint self.remote_list = [] self.remotes = QtWidgets.QListWidget() self.remotes.setToolTip(N_( 'Remote git repositories - double-click to rename')) self.editor = RemoteWidget(context, self) self.save_button = qtutils.create_button( text=N_('Save'), icon=icons.save(), default=True) self.reset_button = qtutils.create_button( text=N_('Reset'), icon=icons.discard()) tooltip = N_( 'Add and remove remote repositories using the \n' 'Add(+) and Delete(-) buttons on the left-hand side.\n' '\n' 'Remotes can be renamed by selecting one from the list\n' 'and pressing "enter", or by double-clicking.') hint = self.default_hint self.info = text.VimHintedPlainTextEdit(context, hint, parent=self) self.info.setToolTip(tooltip) font = self.info.font() metrics = QtGui.QFontMetrics(font) width = metrics.width('_' * 42) height = metrics.height() * 13 self.info.setMinimumWidth(width) self.info.setMinimumHeight(height) self.info_thread = RemoteInfoThread(context, self) icon = icons.add() tooltip = N_('Add new remote git repository') self.add_button = qtutils.create_toolbutton(icon=icon, tooltip=tooltip) self.refresh_button = qtutils.create_toolbutton( icon=icons.sync(), tooltip=N_('Refresh')) self.delete_button = qtutils.create_toolbutton( icon=icons.remove(), tooltip=N_('Delete remote')) self.close_button = qtutils.close_button() self._edit_button_layout = qtutils.vbox( defs.no_margin, defs.spacing, self.save_button, self.reset_button) self._edit_layout = qtutils.hbox( defs.no_margin, defs.spacing, self.editor, self._edit_button_layout) self._display_layout = qtutils.vbox( defs.no_margin, defs.spacing, self._edit_layout, self.info) self._display_widget = QtWidgets.QWidget(self) self._display_widget.setLayout(self._display_layout) self._top_layout = qtutils.splitter( Qt.Horizontal, self.remotes, self._display_widget) width = self._top_layout.width() self._top_layout.setSizes([width//4, width*3//4]) self._button_layout = qtutils.hbox( defs.margin, defs.spacing, self.add_button, self.delete_button, self.refresh_button, qtutils.STRETCH, self.close_button) self._layout = qtutils.vbox(defs.margin, defs.spacing, self._top_layout, self._button_layout) self.setLayout(self._layout) qtutils.connect_button(self.add_button, self.add) qtutils.connect_button(self.delete_button, self.delete) qtutils.connect_button(self.refresh_button, self.refresh) qtutils.connect_button(self.close_button, self.accept) qtutils.connect_button(self.save_button, self.save) qtutils.connect_button(self.reset_button, self.reset) qtutils.add_close_action(self) thread = self.info_thread thread.result.connect(self.set_info, type=Qt.QueuedConnection) # pylint: disable=no-member self.editor.remote_name.returnPressed.connect(self.save) self.editor.remote_url.returnPressed.connect(self.save) self.editor.valid.connect(self.editor_valid) self.remotes.itemChanged.connect(self.remote_item_renamed) self.remotes.itemSelectionChanged.connect(self.selection_changed) self.disable_editor() self.init_state(None, self.resize_widget, parent) self.remotes.setFocus(Qt.OtherFocusReason) self.refresh() def reset(self): focus = self.focusWidget() if self.current_name: self.activate_remote(self.current_name, gather_info=False) restore_focus(focus) @property def changed(self): url = self.editor.url name = self.editor.name return url != self.current_url or name != self.current_name def save(self): if not self.changed: return context = self.context name = self.editor.name url = self.editor.url old_url = self.current_url old_name = self.current_name name_changed = name and name != old_name url_changed = url and url != old_url focus = self.focusWidget() name_ok = url_ok = False # Run the corresponding command if name_changed and url_changed: name_ok, url_ok = cmds.do( cmds.RemoteEdit, context, old_name, name, url) elif name_changed: result = cmds.do(cmds.RemoteRename, context, old_name, name) name_ok = result[0] elif url_changed: result = cmds.do(cmds.RemoteSetURL, context, name, url) url_ok = result[0] # Update state if the change succeeded gather = False if url_changed and url_ok: self.current_url = url gather = True # A name change requires a refresh if name_changed and name_ok: self.current_name = name self.refresh(select=False) remotes = utils.seq(self.remote_list) idx = remotes.index(name) self.select_remote(idx) gather = False # already done by select_remote() restore_focus(focus) if gather: self.gather_info() def editor_valid(self, valid): changed = self.changed self.reset_button.setEnabled(changed) self.save_button.setEnabled(changed and valid) def disable_editor(self): self.save_button.setEnabled(False) self.reset_button.setEnabled(False) self.editor.setEnabled(False) self.editor.name = '' self.editor.url = '' self.info.hint.set_value(self.default_hint) self.info.set_value('') def resize_widget(self, parent): """Set the initial size of the widget""" width, height = qtutils.default_size(parent, 720, 445) self.resize(width, height) def set_info(self, info): self.info.hint.set_value(self.default_hint) self.info.set_value(info) def select_remote(self, index): if index >= 0: item = self.remotes.item(index) if item: item.setSelected(True) def refresh(self, select=True): git = self.context.git remotes = git.remote()[STDOUT].splitlines() self.remotes.blockSignals(True) # ignore selection change signals self.remotes.clear() self.remotes.addItems(remotes) self.remote_list = remotes for idx in range(len(remotes)): item = self.remotes.item(idx) item.setFlags(item.flags() | Qt.ItemIsEditable) self.remotes.blockSignals(False) if select: if not self.current_name and remotes: # Nothing is selected; select the first item self.select_remote(0) elif self.current_name and remotes: # Reselect the previously selected item remote_seq = utils.seq(remotes) idx = remote_seq.index(self.current_name) if idx >= 0: item = self.remotes.item(idx) if item: item.setSelected(True) def add(self): if add_remote(self.context, self): self.refresh(select=False) # Newly added remote will be last; select it self.select_remote(len(self.remote_list) - 1) def delete(self): remote = qtutils.selected_item(self.remotes, self.remote_list) if not remote: return cmds.do(cmds.RemoteRemove, self.context, remote) self.refresh(select=False) def remote_item_renamed(self, item): idx = self.remotes.row(item) if idx < 0: return if idx >= len(self.remote_list): return old_name = self.remote_list[idx] new_name = item.text() if new_name == old_name: return if not new_name: item.setText(old_name) return context = self.context ok, status, _, _ = cmds.do( cmds.RemoteRename, context, old_name, new_name) if ok and status == 0: self.remote_list[idx] = new_name self.activate_remote(new_name) else: item.setText(old_name) def selection_changed(self): remote = qtutils.selected_item(self.remotes, self.remote_list) if not remote: self.disable_editor() return self.activate_remote(remote) def activate_remote(self, name, gather_info=True): url = gitcmds.remote_url(self.context, name) self.current_name = name self.current_url = url self.editor.setEnabled(True) self.editor.name = name self.editor.url = url if gather_info: self.gather_info() def gather_info(self): name = self.current_name self.info.hint.set_value(N_('Gathering info for "%s"...') % name) self.info.set_value('') self.info_thread.remote = name self.info_thread.start() def add_remote(context, parent, name='', url='', readonly_url=False): """Bring up the "Add Remote" dialog""" widget = AddRemoteDialog(context, parent, readonly_url=readonly_url) if name: widget.name = name if url: widget.url = url if widget.run(): cmds.do(cmds.RemoteAdd, context, widget.name, widget.url) result = True else: result = False return result def restore_focus(focus): if focus: focus.setFocus(Qt.OtherFocusReason) if hasattr(focus, 'selectAll'): focus.selectAll() class RemoteInfoThread(QtCore.QThread): result = Signal(object) def __init__(self, context, parent): QtCore.QThread.__init__(self, parent) self.context = context self.remote = None def run(self): remote = self.remote if remote is None: return git = self.context.git _, out, err = git.remote('show', '-n', remote) self.result.emit(out + err) class AddRemoteDialog(QtWidgets.QDialog): def __init__(self, context, parent, readonly_url=False): super(AddRemoteDialog, self).__init__(parent) self.context = context if parent: self.setWindowModality(Qt.WindowModal) self.context = context self.widget = RemoteWidget(context, self, readonly_url=readonly_url) self.add_button = qtutils.create_button( text=N_('Add Remote'), icon=icons.ok(), enabled=False) self.close_button = qtutils.close_button() self._button_layout = qtutils.hbox( defs.no_margin, defs.button_spacing, qtutils.STRETCH, self.close_button, self.add_button) self._layout = qtutils.vbox( defs.margin, defs.spacing, self.widget, self._button_layout) self.setLayout(self._layout) self.widget.valid.connect(self.add_button.setEnabled) qtutils.connect_button(self.add_button, self.accept) qtutils.connect_button(self.close_button, self.reject) def set_name(self, value): self.widget.name = value def set_url(self, value): self.widget.url = value name = property(operator.attrgetter('widget.name'), set_name) url = property(operator.attrgetter('widget.url'), set_url) def run(self): self.show() self.raise_() return self.exec_() == QtWidgets.QDialog.Accepted def lineedit(context, hint): widget = text.HintedLineEdit(context, hint) metrics = widget.fontMetrics() widget.setMinimumWidth(metrics.width('M' * 32)) return widget class RemoteWidget(QtWidgets.QWidget): name = property(lambda self: get(self.remote_name), lambda self, value: self.remote_name.set_value(value)) url = property(lambda self: get(self.remote_url), lambda self, value: self.remote_url.set_value(value)) valid = Signal(bool) def __init__(self, context, parent, readonly_url=False): super(RemoteWidget, self).__init__(parent) self.setWindowModality(Qt.WindowModal) self.context = context self.setWindowTitle(N_('Add remote')) self.remote_name = lineedit(context, N_('Name for the new remote')) self.remote_url = lineedit(context, 'git://git.example.com/repo.git') self.open_button = qtutils.create_button( text=N_('Open...'), icon=icons.folder(), tooltip=N_('Select repository')) self.url_layout = qtutils.hbox( defs.no_margin, defs.spacing, self.remote_url, self.open_button) validate_remote = completion.RemoteValidator(self.remote_name) self.remote_name.setValidator(validate_remote) self._form = qtutils.form(defs.margin, defs.spacing, (N_('Name'), self.remote_name), (N_('URL'), self.url_layout)) self._layout = qtutils.vbox(defs.margin, defs.spacing, self._form) self.setLayout(self._layout) # pylint: disable=no-member self.remote_name.textChanged.connect(self.validate) self.remote_url.textChanged.connect(self.validate) qtutils.connect_button(self.open_button, self.open_repo) if readonly_url: self.remote_url.setReadOnly(True) self.open_button.setEnabled(False) def validate(self, _text): name = self.name url = self.url self.valid.emit(bool(name) and bool(url)) def open_repo(self): git = self.context.git repo = qtutils.opendir_dialog( N_('Open Git Repository...'), core.getcwd()) if repo and git.is_git_repository(repo): self.url = repo git-cola-3.6/cola/widgets/filelist.py000066400000000000000000000102421356743264500176500ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals from qtpy import QtWidgets from qtpy.QtCore import Signal from qtpy.QtCore import QSize from .. import cmds from .. import hotkeys from .. import qtutils from ..i18n import N_ from .standard import TreeWidget from .diff import COMMITS_SELECTED from .diff import FILES_SELECTED HISTORIES_SELECTED = 'HISTORIES_SELECTED' DIFFTOOL_SELECTED = 'DIFFTOOL_SELECTED' # pylint: disable=too-many-ancestors class FileWidget(TreeWidget): grab_file = Signal(object) def __init__(self, context, notifier, parent): TreeWidget.__init__(self, parent) self.context = context self.notifier = notifier labels = [N_('Filename'), N_('Additions'), N_('Deletions')] self.setHeaderLabels(labels) notifier.add_observer(COMMITS_SELECTED, self.commits_selected) self.show_history_action = qtutils.add_action( self, N_('Show History'), self.show_history, hotkeys.HISTORY) self.launch_difftool_action = qtutils.add_action( self, N_('Launch Diff Tool'), self.show_diff) self.launch_editor_action = qtutils.add_action( self, N_('Launch Editor'), self.edit_paths, hotkeys.EDIT) self.grab_file_action = qtutils.add_action( self, N_('Grab File...'), self._grab_file) # pylint: disable=no-member self.itemSelectionChanged.connect(self.selection_changed) def selection_changed(self): items = self.selected_items() self.notifier.notify_observers( FILES_SELECTED, [i.path for i in items]) def commits_selected(self, commits): if not commits: return git = self.context.git commit = commits[0] oid = commit.oid status, out, _ = git.show(oid, z=True, numstat=True, oneline=True, no_renames=True) if status == 0: paths = [f for f in out.rstrip('\0').split('\0') if f] if paths: paths = paths[1:] else: paths = [] self.list_files(paths) def list_files(self, files_log): self.clear() if not files_log: return files = [] for f in files_log: item = FileTreeWidgetItem(f) files.append(item) self.insertTopLevelItems(0, files) def adjust_columns(self, size, old_size): if size.isValid() and old_size.isValid(): width = (self.columnWidth(0) + size.width() - old_size.width()) self.setColumnWidth(0, width) else: width = self.width() two_thirds = (width * 2) // 3 one_sixth = width // 6 self.setColumnWidth(0, two_thirds) self.setColumnWidth(1, one_sixth) self.setColumnWidth(2, one_sixth) def show(self): self.adjust_columns(QSize(), QSize()) def resizeEvent(self, e): self.adjust_columns(e.size(), e.oldSize()) def contextMenuEvent(self, event): menu = qtutils.create_menu(N_('Actions'), self) menu.addAction(self.grab_file_action) menu.addAction(self.show_history_action) menu.addAction(self.launch_difftool_action) menu.addAction(self.launch_editor_action) menu.exec_(self.mapToGlobal(event.pos())) def show_diff(self): self.notifier.notify_observers(DIFFTOOL_SELECTED, self.selected_paths()) def _grab_file(self): for path in self.selected_paths(): self.grab_file.emit(path) def selected_paths(self): return [i.path for i in self.selected_items()] def edit_paths(self): cmds.do(cmds.Edit, self.context, self.selected_paths()) def show_history(self): items = self.selected_items() paths = [i.path for i in items] self.notifier.notify_observers(HISTORIES_SELECTED, paths) class FileTreeWidgetItem(QtWidgets.QTreeWidgetItem): def __init__(self, file_log, parent=None): QtWidgets.QTreeWidgetItem.__init__(self, parent) texts = file_log.split('\t') self.path = path = texts[2] self.setText(0, path) self.setText(1, texts[0]) self.setText(2, texts[1]) git-cola-3.6/cola/widgets/filetree.py000066400000000000000000000024461356743264500176430ustar00rootroot00000000000000from __future__ import absolute_import, division, unicode_literals from qtpy import QtCore from qtpy import QtWidgets from .. import icons from . import standard # pylint: disable=too-many-ancestors class FileTree(standard.TreeWidget): def __init__(self, parent=None): standard.TreeWidget.__init__(self, parent=parent) self.setSelectionMode(self.ExtendedSelection) self.setHeaderHidden(True) def set_filenames(self, filenames, select=False): self.clear() if not filenames: return items = [] from_filename = icons.from_filename for filename in filenames: icon = from_filename(filename) item = QtWidgets.QTreeWidgetItem() item.setIcon(0, icon) item.setText(0, filename) item.setData(0, QtCore.Qt.UserRole, filename) items.append(item) self.addTopLevelItems(items) if select and items: items[0].setSelected(True) def has_selection(self): return bool(self.selectedItems()) def selected_filenames(self): items = self.selectedItems() if not items: return [] return [filename_from_item(i) for i in items] def filename_from_item(item): return item.data(0, QtCore.Qt.UserRole) git-cola-3.6/cola/widgets/finder.py000066400000000000000000000160061356743264500173100ustar00rootroot00000000000000"""File finder widgets""" from __future__ import division, absolute_import, unicode_literals import os from functools import partial from qtpy import QtCore from qtpy import QtWidgets from qtpy.QtCore import Qt from qtpy.QtCore import Signal from ..i18n import N_ from ..qtutils import get from ..utils import Group from .. import cmds from .. import core from .. import gitcmds from .. import hotkeys from .. import icons from .. import utils from .. import qtutils from . import completion from . import defs from . import filetree from . import standard from . import text def finder(context, paths=None): """Prompt and use 'git grep' to find the content.""" parent = qtutils.active_window() widget = new_finder(context, paths=paths, parent=parent) widget.show() widget.raise_() return widget def new_finder(context, paths=None, parent=None): """Create a finder widget""" widget = Finder(context, parent=parent) widget.search_for(paths or '') return widget def add_wildcards(arg): """Add "*" around user input to generate ls-files pathspecs matches >>> '*x*' == \ add_wildcards('x') == \ add_wildcards('*x') == \ add_wildcards('x*') == \ add_wildcards('*x*') True """ if not arg.startswith('*'): arg = '*' + arg if not arg.endswith('*'): arg = arg + '*' return arg def show_help(context): """Show the help page""" help_text = N_(""" Keyboard Shortcuts ------------------ J, Down = Move Down K, Up = Move Up Enter = Edit Selected Files Spacebar = Open File Using Default Application Ctrl + L = Focus Text Entry Field ? = Show Help The up and down arrows change focus between the text entry field and the results. """) title = N_('Help - Find Files') return text.text_dialog(context, help_text, title) class FindFilesThread(QtCore.QThread): """Finds files asynchronously""" result = Signal(object) def __init__(self, context, parent): QtCore.QThread.__init__(self, parent) self.context = context self.query = None def run(self): context = self.context query = self.query if query is None: args = [] else: args = [add_wildcards(arg) for arg in utils.shell_split(query)] filenames = gitcmds.tracked_files(context, *args) if query == self.query: self.result.emit(filenames) else: self.run() class Finder(standard.Dialog): """File Finder dialog""" def __init__(self, context, parent=None): standard.Dialog.__init__(self, parent) self.context = context self.setWindowTitle(N_('Find Files')) if parent is not None: self.setWindowModality(Qt.WindowModal) label = os.path.basename(core.getcwd()) + '/' self.input_label = QtWidgets.QLabel(label) self.input_txt = completion.GitTrackedLineEdit( context, hint=N_(' ...')) self.tree = filetree.FileTree(parent=self) self.edit_button = qtutils.edit_button(default=True) self.edit_button.setShortcut(hotkeys.EDIT) name = cmds.OpenDefaultApp.name() icon = icons.default_app() self.open_default_button = qtutils.create_button(text=name, icon=icon) self.open_default_button.setShortcut(hotkeys.PRIMARY_ACTION) self.button_group = Group(self.edit_button, self.open_default_button) self.button_group.setEnabled(False) self.refresh_button = qtutils.refresh_button() self.refresh_button.setShortcut(hotkeys.REFRESH) self.help_button = qtutils.create_button( text=N_('Help'), tooltip=N_('Show help\nShortcut: ?'), icon=icons.question()) self.close_button = qtutils.close_button() self.input_layout = qtutils.hbox(defs.no_margin, defs.button_spacing, self.input_label, self.input_txt) self.bottom_layout = qtutils.hbox(defs.no_margin, defs.button_spacing, self.close_button, qtutils.STRETCH, self.help_button, self.refresh_button, self.open_default_button, self.edit_button) self.main_layout = qtutils.vbox(defs.margin, defs.no_spacing, self.input_layout, self.tree, self.bottom_layout) self.setLayout(self.main_layout) self.setFocusProxy(self.input_txt) thread = self.worker_thread = FindFilesThread(context, self) thread.result.connect(self.process_result, type=Qt.QueuedConnection) # pylint: disable=no-member self.input_txt.textChanged.connect(lambda s: self.search()) self.input_txt.activated.connect(self.focus_tree) self.input_txt.down.connect(self.focus_tree) self.input_txt.enter.connect(self.focus_tree) item_selection_changed = self.tree_item_selection_changed self.tree.itemSelectionChanged.connect(item_selection_changed) self.tree.up.connect(self.focus_input) self.tree.space.connect(self.open_default) qtutils.add_action(self, 'Focus Input', self.focus_input, hotkeys.FOCUS, hotkeys.FINDER) self.show_help_action = qtutils.add_action( self, N_('Show Help'), partial(show_help, context), hotkeys.QUESTION) qtutils.connect_button(self.edit_button, self.edit) qtutils.connect_button(self.open_default_button, self.open_default) qtutils.connect_button(self.refresh_button, self.search) qtutils.connect_button(self.help_button, show_help) qtutils.connect_button(self.close_button, self.close) qtutils.add_close_action(self) self.init_size(parent=parent) def focus_tree(self): self.tree.setFocus() def focus_input(self): self.input_txt.setFocus() def search(self): self.button_group.setEnabled(False) self.refresh_button.setEnabled(False) query = get(self.input_txt) self.worker_thread.query = query self.worker_thread.start() def search_for(self, txt): self.input_txt.set_value(txt) self.focus_input() def process_result(self, filenames): self.tree.set_filenames(filenames, select=True) self.refresh_button.setEnabled(True) def edit(self): context = self.context paths = self.tree.selected_filenames() cmds.do(cmds.Edit, context, paths, background_editor=True) def open_default(self): context = self.context paths = self.tree.selected_filenames() cmds.do(cmds.OpenDefaultApp, context, paths) def tree_item_selection_changed(self): enabled = bool(self.tree.selected_item()) self.button_group.setEnabled(enabled) git-cola-3.6/cola/widgets/gitignore.py000066400000000000000000000104671356743264500200350ustar00rootroot00000000000000"""Provides the StashView dialog.""" from __future__ import division, absolute_import, unicode_literals from qtpy import QtCore from qtpy import QtWidgets from .. import cmds from .. import qtutils from ..i18n import N_ from . import defs from .standard import Dialog def gitignore_view(context): """Launches a gitignore dialog """ view = AddToGitIgnore(context, parent=qtutils.active_window()) view.show() return view class AddToGitIgnore(Dialog): def __init__(self, context, parent=None): Dialog.__init__(self, parent=parent) self.context = context self.selection = context.selection if parent is not None: self.setWindowModality(QtCore.Qt.WindowModal) self.setWindowTitle(N_('Add to exclusions')) # Create text self.text_description = QtWidgets.QLabel() self.text_description.setText(N_('Ignore filename or pattern')) # Create edit filename self.edit_filename = QtWidgets.QLineEdit() self.check_filename() self.filename_layt = qtutils.vbox(defs.no_margin, defs.spacing, self.text_description, self.edit_filename) # Create radio options self.radio_filename = qtutils.radio(text=N_('Ignore exact filename'), checked=True) self.radio_pattern = qtutils.radio(text=N_('Ignore custom pattern')) self.name_radio_group = qtutils.buttongroup(self.radio_filename, self.radio_pattern) self.name_radio_layt = qtutils.vbox(defs.no_margin, defs.spacing, self.radio_filename, self.radio_pattern) self.radio_in_repo = qtutils.radio(text=N_('Add to .gitignore'), checked=True) self.radio_local = qtutils.radio(text=N_('Add to local ' '.git/info/exclude')) self.location_radio_group = qtutils.buttongroup(self.radio_in_repo, self.radio_local) self.location_radio_layt = qtutils.vbox(defs.no_margin, defs.spacing, self.radio_in_repo, self.radio_local) # Create buttons self.button_apply = qtutils.ok_button(text=N_('Add')) self.button_close = qtutils.close_button() self.btn_layt = qtutils.hbox(defs.no_margin, defs.spacing, qtutils.STRETCH, self.button_close, self.button_apply) # Layout self.main_layout = qtutils.vbox(defs.margin, defs.spacing, self.name_radio_layt, defs.button_spacing, self.filename_layt, defs.button_spacing, self.location_radio_layt, qtutils.STRETCH, self.btn_layt) self.setLayout(self.main_layout) # Connect actions qtutils.connect_toggle(self.radio_pattern, self.check_pattern) qtutils.connect_toggle(self.radio_filename, self.check_filename) qtutils.connect_button(self.button_apply, self.apply) qtutils.connect_button(self.button_close, self.close) self.init_state(None, self.resize_widget, parent) def resize_widget(self, parent): """Set the initial size of the widget""" width, height = qtutils.default_size(parent, 720, 400) self.resize(width, max(400, height//2)) def check_pattern(self): self.edit_filename.setDisabled(False) def check_filename(self): self.edit_filename.setText('/' + ';/'.join(self.selection.untracked)) self.edit_filename.setDisabled(True) def close(self): self.reject() def apply(self): context = self.context cmds.do(cmds.Ignore, context, self.edit_filename.text().split(';'), self.radio_local.isChecked()) self.accept() git-cola-3.6/cola/widgets/grep.py000066400000000000000000000325331356743264500170010ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals from qtpy import QtCore from qtpy import QtWidgets from qtpy.QtCore import Qt from qtpy.QtCore import Signal from ..i18n import N_ from ..utils import Group from .. import cmds from .. import core from .. import hotkeys from .. import utils from .. import qtutils from ..qtutils import get from .standard import Dialog from .text import HintedLineEdit from .text import VimHintedPlainTextEdit from .text import VimTextBrowser from . import defs def grep(context): """Prompt and use 'git grep' to find the content.""" widget = new_grep(context, parent=qtutils.active_window()) widget.show() return widget def new_grep(context, text=None, parent=None): """Construct a new Grep dialog""" widget = Grep(context, parent=parent) if text: widget.search_for(text) return widget def parse_grep_line(line): """Parse a grep result line into (filename, line_number, content)""" try: filename, line_number, contents = line.split(':', 2) result = (filename, line_number, contents) except ValueError: result = None return result def goto_grep(context, line): """Called when Search -> Grep's right-click 'goto' action.""" parsed_line = parse_grep_line(line) if parsed_line: filename, line_number, _ = parsed_line cmds.do(cmds.Edit, context, [filename], line_number=line_number, background_editor=True) class GrepThread(QtCore.QThread): """Gather `git grep` results in a background thread""" result = Signal(object, object, object) def __init__(self, context, parent): QtCore.QThread.__init__(self, parent) self.context = context self.query = None self.shell = False self.regexp_mode = '--basic-regexp' def run(self): if self.query is None: return git = self.context.git query = self.query if self.shell: args = utils.shell_split(query) else: args = [query] status, out, err = git.grep(self.regexp_mode, n=True, *args) if query == self.query: self.result.emit(status, out, err) else: self.run() class Grep(Dialog): """A dialog for searching content using `git grep`""" def __init__(self, context, parent=None): Dialog.__init__(self, parent) self.context = context self.grep_result = '' self.setWindowTitle(N_('Search')) if parent is not None: self.setWindowModality(Qt.WindowModal) self.edit_action = qtutils.add_action( self, N_('Edit'), self.edit, hotkeys.EDIT) self.refresh_action = qtutils.add_action( self, N_('Refresh'), self.search, *hotkeys.REFRESH_HOTKEYS) self.input_label = QtWidgets.QLabel('git grep') self.input_label.setFont(qtutils.diff_font(context)) self.input_txt = HintedLineEdit( context, N_('command-line arguments'), parent=self) self.regexp_combo = combo = QtWidgets.QComboBox() combo.setToolTip(N_('Choose the "git grep" regular expression mode')) items = [N_('Basic Regexp'), N_('Extended Regexp'), N_('Fixed String')] combo.addItems(items) combo.setCurrentIndex(0) combo.setEditable(False) tooltip0 = N_('Search using a POSIX basic regular expression') tooltip1 = N_('Search using a POSIX extended regular expression') tooltip2 = N_('Search for a fixed string') combo.setItemData(0, tooltip0, Qt.ToolTipRole) combo.setItemData(1, tooltip1, Qt.ToolTipRole) combo.setItemData(2, tooltip2, Qt.ToolTipRole) combo.setItemData(0, '--basic-regexp', Qt.UserRole) combo.setItemData(1, '--extended-regexp', Qt.UserRole) combo.setItemData(2, '--fixed-strings', Qt.UserRole) self.result_txt = GrepTextView(context, N_('grep result...'), self) self.preview_txt = PreviewTextView(context, self) self.preview_txt.setFocusProxy(self.result_txt) self.edit_button = qtutils.edit_button(default=True) qtutils.button_action(self.edit_button, self.edit_action) self.refresh_button = qtutils.refresh_button() qtutils.button_action(self.refresh_button, self.refresh_action) text = N_('Shell arguments') tooltip = N_('Parse arguments using a shell.\n' 'Queries with spaces will require "double quotes".') self.shell_checkbox = qtutils.checkbox(text=text, tooltip=tooltip, checked=False) self.close_button = qtutils.close_button() self.refresh_group = Group(self.refresh_action, self.refresh_button) self.refresh_group.setEnabled(False) self.edit_group = Group(self.edit_action, self.edit_button) self.edit_group.setEnabled(False) self.input_layout = qtutils.hbox(defs.no_margin, defs.button_spacing, self.input_label, self.input_txt, self.regexp_combo) self.bottom_layout = qtutils.hbox(defs.no_margin, defs.button_spacing, self.close_button, qtutils.STRETCH, self.shell_checkbox, self.refresh_button, self.edit_button) self.splitter = qtutils.splitter(Qt.Vertical, self.result_txt, self.preview_txt) self.mainlayout = qtutils.vbox(defs.margin, defs.no_spacing, self.input_layout, self.splitter, self.bottom_layout) self.setLayout(self.mainlayout) thread = self.worker_thread = GrepThread(context, self) thread.result.connect(self.process_result, type=Qt.QueuedConnection) # pylint: disable=no-member self.input_txt.textChanged.connect(lambda s: self.search()) self.regexp_combo.currentIndexChanged.connect(lambda x: self.search()) self.result_txt.leave.connect(self.input_txt.setFocus) self.result_txt.cursorPositionChanged.connect(self.update_preview) qtutils.add_action(self.input_txt, 'Focus Results', self.focus_results, hotkeys.DOWN, *hotkeys.ACCEPT) qtutils.add_action(self, 'Focus Input', self.focus_input, hotkeys.FOCUS) qtutils.connect_toggle(self.shell_checkbox, lambda x: self.search()) qtutils.connect_button(self.close_button, self.close) qtutils.add_close_action(self) self.init_size(parent=parent) def focus_input(self): """Focus the grep input field and select the text""" self.input_txt.setFocus() self.input_txt.selectAll() def focus_results(self): """Give focus to the results window""" self.result_txt.setFocus() def regexp_mode(self): """Return the selected grep regex mode""" idx = self.regexp_combo.currentIndex() return self.regexp_combo.itemData(idx, Qt.UserRole) def search(self): """Initiate a search by starting the GrepThread""" self.edit_group.setEnabled(False) self.refresh_group.setEnabled(False) query = get(self.input_txt) if len(query) < 2: self.result_txt.clear() self.preview_txt.clear() return self.worker_thread.query = query self.worker_thread.shell = get(self.shell_checkbox) self.worker_thread.regexp_mode = self.regexp_mode() self.worker_thread.start() def search_for(self, txt): """Set the initial value of the input text""" self.input_txt.set_value(txt) def text_scroll(self): """Return the scrollbar value for the results window""" scrollbar = self.result_txt.verticalScrollBar() if scrollbar: return get(scrollbar) return None def set_text_scroll(self, scroll): """Set the scrollbar value for the results window""" scrollbar = self.result_txt.verticalScrollBar() if scrollbar and scroll is not None: scrollbar.setValue(scroll) def text_offset(self): """Return the cursor's offset within the result text""" return self.result_txt.textCursor().position() def set_text_offset(self, offset): """Set the text cursor from an offset""" cursor = self.result_txt.textCursor() cursor.setPosition(offset) self.result_txt.setTextCursor(cursor) def process_result(self, status, out, err): """Apply the results from grep to the widgets""" if status == 0: value = out + err elif out + err: value = 'git grep: ' + out + err else: value = '' # save scrollbar and text cursor scroll = self.text_scroll() offset = min(len(value), self.text_offset()) self.grep_result = value self.result_txt.set_value(value) # restore self.set_text_scroll(scroll) self.set_text_offset(offset) enabled = status == 0 self.edit_group.setEnabled(enabled) self.refresh_group.setEnabled(True) if not value: self.preview_txt.clear() def update_preview(self): """Update the file preview window""" parsed_line = parse_grep_line(self.result_txt.selected_line()) if parsed_line: filename, line_number, _ = parsed_line self.preview_txt.preview(filename, line_number) def edit(self): """Launch an editor on the currently selected line""" goto_grep(self.context, self.result_txt.selected_line()) def export_state(self): """Export persistent settings""" state = super(Grep, self).export_state() state['sizes'] = get(self.splitter) return state def apply_state(self, state): """Apply persistent settings""" result = super(Grep, self).apply_state(state) try: self.splitter.setSizes(state['sizes']) except (AttributeError, KeyError, ValueError, TypeError): result = False return result # pylint: disable=too-many-ancestors class GrepTextView(VimHintedPlainTextEdit): """A text view with hotkeys for launching editors""" def __init__(self, context, hint, parent): VimHintedPlainTextEdit.__init__(self, context, hint, parent=parent) self.context = context self.goto_action = qtutils.add_action(self, 'Launch Editor', self.edit) self.goto_action.setShortcut(hotkeys.EDIT) def contextMenuEvent(self, event): menu = self.createStandardContextMenu(event.pos()) menu.addSeparator() menu.addAction(self.goto_action) menu.exec_(self.mapToGlobal(event.pos())) def edit(self): goto_grep(self.context, self.selected_line()) class PreviewTask(qtutils.Task): """Asynchronous task for loading file content""" def __init__(self, parent, filename, line_number): qtutils.Task.__init__(self, parent) self.content = '' self.filename = filename self.line_number = line_number def task(self): try: self.content = core.read(self.filename, errors='ignore') except IOError: pass return (self.filename, self.content, self.line_number) # pylint: disable=too-many-ancestors class PreviewTextView(VimTextBrowser): """Preview window for file contents""" def __init__(self, context, parent): VimTextBrowser.__init__(self, context, parent) self.filename = None self.content = None self.runtask = qtutils.RunTask(parent=self) def preview(self, filename, line_number): """Preview the a file at the specified line number""" if filename != self.filename: request = PreviewTask(self, filename, line_number) self.runtask.start(request, finish=self.show_preview) else: self.scroll_to_line(line_number) def clear(self): self.filename = '' self.content = '' super(PreviewTextView, self).clear() def show_preview(self, task): """Show the results of the asynchronous file read""" filename = task.filename content = task.content line_number = task.line_number if filename != self.filename: self.filename = filename self.content = content self.set_value(content) self.scroll_to_line(line_number) def scroll_to_line(self, line_number): """Scroll to the specified line number""" try: line_num = int(line_number) - 1 except ValueError: return self.numbers.set_highlighted(line_num) cursor = self.textCursor() cursor.setPosition(0) self.setTextCursor(cursor) self.ensureCursorVisible() cursor.movePosition(cursor.Down, cursor.MoveAnchor, line_num) cursor.movePosition(cursor.EndOfLine, cursor.KeepAnchor) self.setTextCursor(cursor) self.ensureCursorVisible() scrollbar = self.verticalScrollBar() step = scrollbar.pageStep() // 2 position = scrollbar.sliderPosition() + step scrollbar.setSliderPosition(position) self.ensureCursorVisible() git-cola-3.6/cola/widgets/highlighter.py000066400000000000000000000064441356743264500203440ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets have_pygments = True try: from pygments.styles import get_style_by_name from pygments import lex from pygments.util import ClassNotFound from pygments.lexers import get_lexer_for_filename except ImportError: have_pygments = False def highlight_document(edit, filename): if not have_pygments: return doc = edit.document() try: lexer = get_lexer_for_filename(filename, stripnl=False) except ClassNotFound: return style = get_style_by_name('default') font = doc.defaultFont() base_format = QtGui.QTextCharFormat() base_format.setFont(font) token_formats = {} window = edit.window() if hasattr(window, 'processEvents'): processEvents = window.processEvents else: processEvents = QtCore.QCoreApplication.processEvents def get_token_format(token): if token in token_formats: return token_formats[token] if token.parent: parent_format = get_token_format(token.parent) else: parent_format = base_format fmt = QtGui.QTextCharFormat(parent_format) font = fmt.font() if style.styles_token(token): tstyle = style.style_for_token(token) if tstyle['color']: fmt.setForeground(QtGui.QColor('#' + tstyle['color'])) if tstyle['bold']: font.setWeight(QtGui.QFont.Bold) if tstyle['italic']: font.setItalic(True) if tstyle['underline']: fmt.setFontUnderline(True) if tstyle['bgcolor']: fmt.setBackground(QtGui.QColor('#' + tstyle['bgcolor'])) token_formats[token] = fmt return fmt text = doc.toPlainText() block_count = 0 block = doc.firstBlock() assert isinstance(block, QtGui.QTextBlock) block_pos = 0 block_len = block.length() block_formats = [] for token, ttext in lex(text, lexer): format_len = len(ttext) fmt = get_token_format(token) while format_len > 0: format_range = QtGui.QTextLayout.FormatRange() format_range.start = block_pos format_range.length = min(format_len, block_len) format_range.format = fmt block_formats.append(format_range) block_len -= format_range.length format_len -= format_range.length block_pos += format_range.length if block_len == 0: block.layout().setAdditionalFormats(block_formats) doc.markContentsDirty(block.position(), block.length()) block = block.next() # pylint: disable=next-method-called block_pos = 0 block_len = block.length() block_formats = [] block_count += 1 if block_count % 100 == 0: processEvents() if __name__ == '__main__': app = QtWidgets.QApplication([]) python = QtWidgets.QPlainTextEdit() f = open(__file__, 'r') python.setPlainText(f.read()) f.close() python.setWindowTitle('python') python.show() highlight_document(python, __file__) app.exec_() git-cola-3.6/cola/widgets/imageview.py000066400000000000000000000376451356743264500200320ustar00rootroot00000000000000# Copyright (c) 2018 David Aguilar # # Git Cola is GPL licensed, but this file has a more permissive license. # This file is dual-licensed Git Cola GPL + pyqimageview MIT. # imageview.py was originally based on the pyqimageview: # https://github.com/nevion/pyqimageview/ # # The MIT License (MIT) # # Copyright (c) 2014 Jason Newton # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. from __future__ import absolute_import, division, unicode_literals import argparse import os import sys from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from qtpy.QtCore import Qt from qtpy.QtCore import Signal try: import numpy as np have_numpy = True except ImportError: have_numpy = False from .. import qtcompat main_loop_type = 'qt' def clamp(x, lo, hi): return max(min(x, hi), lo) class ImageView(QtWidgets.QGraphicsView): image_changed = Signal() def __init__(self, parent=None): super(ImageView, self).__init__(parent) scene = QtWidgets.QGraphicsScene(self) self.graphics_pixmap = QtWidgets.QGraphicsPixmapItem() scene.addItem(self.graphics_pixmap) self.setScene(scene) self.zoom_factor = 1.125 self.rubberband = None self.panning = False self.first_show_occured = False self.last_scene_roi = None self.start_drag = QtCore.QPoint() self.checkerboard = None CHECK_MEDIUM = 8 CHECK_GRAY = 0x80 CHECK_LIGHT = 0xcc check_pattern = QtGui.QImage(CHECK_MEDIUM * 2, CHECK_MEDIUM * 2, QtGui.QImage.Format_RGB888) color_gray = QtGui.QColor(CHECK_GRAY, CHECK_GRAY, CHECK_GRAY) color_light = QtGui.QColor(CHECK_LIGHT, CHECK_LIGHT, CHECK_LIGHT) painter = QtGui.QPainter(check_pattern) painter.fillRect(0, 0, CHECK_MEDIUM, CHECK_MEDIUM, color_gray) painter.fillRect(CHECK_MEDIUM, CHECK_MEDIUM, CHECK_MEDIUM, CHECK_MEDIUM, color_gray) painter.fillRect(0, CHECK_MEDIUM, CHECK_MEDIUM, CHECK_MEDIUM, color_light) painter.fillRect(CHECK_MEDIUM, 0, CHECK_MEDIUM, CHECK_MEDIUM, color_light) self.check_pattern = check_pattern self.check_brush = QtGui.QBrush(check_pattern) def load(self, filename): image = QtGui.QImage() image.load(filename) ok = not image.isNull() if ok: self.pixmap = image return ok @property def pixmap(self): return self.graphics_pixmap.pixmap() @pixmap.setter def pixmap(self, image, image_format=None): pixmap = None if have_numpy and isinstance(image, np.ndarray): if image.ndim == 3: if image.shape[2] == 3: if image_format is None: image_format = QtGui.QImage.Format_RGB888 q_image = QtGui.QImage( image.data, image.shape[1], image.shape[0], image_format) pixmap = QtGui.QPixmap.fromImage(q_image) elif image.shape[2] == 4: if image_format is None: image_format = QtGui.QImage.Format_RGB32 q_image = QtGui.QImage( image.data, image.shape[1], image.shape[0], image_format) pixmap = QtGui.QPixmap.fromImage(q_image) else: raise TypeError(image) elif image.ndim == 2: if image_format is None: image_format = QtGui.QImage.Format_RGB888 q_image = QtGui.QImage(image.data, image.shape[1], image.shape[0], image_format) pixmap = QtGui.QPixmap.fromImage(q_image) else: raise ValueError(image) elif isinstance(image, QtGui.QImage): pixmap = QtGui.QPixmap.fromImage(image) elif isinstance(image, QtGui.QPixmap): pixmap = image else: raise TypeError(image) if pixmap.hasAlpha(): checkerboard = QtGui.QImage(pixmap.width(), pixmap.height(), QtGui.QImage.Format_ARGB32) self.checkerboard = checkerboard painter = QtGui.QPainter(checkerboard) painter.fillRect(checkerboard.rect(), self.check_brush) painter.drawPixmap(0, 0, pixmap) pixmap = QtGui.QPixmap.fromImage(checkerboard) self.graphics_pixmap.setPixmap(pixmap) self.update_scene_rect() self.fitInView(self.image_scene_rect, flags=Qt.KeepAspectRatio) self.graphics_pixmap.update() self.image_changed.emit() # image property alias @property def image(self): return self.pixmap @image.setter def image(self, image): self.pixmap = image def update_scene_rect(self): pixmap = self.pixmap self.setSceneRect(QtCore.QRectF( QtCore.QPointF(0, 0), QtCore.QPointF(pixmap.width(), pixmap.height()))) @property def image_scene_rect(self): return QtCore.QRectF( self.graphics_pixmap.pos(), QtCore.QSizeF(self.pixmap.size())) def resizeEvent(self, event): super(ImageView, self).resizeEvent(event) self.update_scene_rect() event.accept() self.fitInView(self.last_scene_roi, Qt.KeepAspectRatio) self.update() def zoomROICentered(self, p, zoom_level_delta): roi = self.current_scene_ROI roi_dims = QtCore.QPointF(roi.width(), roi.height()) roi_scalef = 1 if zoom_level_delta > 0: roi_scalef = 1.0/self.zoom_factor elif zoom_level_delta < 0: roi_scalef = self.zoom_factor nroi_dims = roi_dims * roi_scalef nroi_dims.setX(max(nroi_dims.x(), 1)) nroi_dims.setY(max(nroi_dims.y(), 1)) nroi_center = p nroi_dimsh = nroi_dims / 2.0 nroi_topleft = nroi_center - nroi_dimsh nroi = QtCore.QRectF( nroi_topleft.x(), nroi_topleft.y(), nroi_dims.x(), nroi_dims.y()) self.fitInView(nroi, Qt.KeepAspectRatio) self.update() def zoomROITo(self, p, zoom_level_delta): roi = self.current_scene_ROI roi_dims = QtCore.QPointF(roi.width(), roi.height()) roi_topleft = roi.topLeft() roi_scalef = 1.0 if zoom_level_delta > 0: roi_scalef = 1.0 / self.zoom_factor elif zoom_level_delta < 0: roi_scalef = self.zoom_factor nroi_dims = roi_dims * roi_scalef nroi_dims.setX(max(nroi_dims.x(), 1.0)) nroi_dims.setY(max(nroi_dims.y(), 1.0)) prel_scaled_x = (p.x() - roi_topleft.x()) / roi_dims.x() prel_scaled_y = (p.y() - roi_topleft.y()) / roi_dims.y() nroi_topleft_x = p.x() - prel_scaled_x * nroi_dims.x() nroi_topleft_y = p.y() - prel_scaled_y * nroi_dims.y() nroi = QtCore.QRectF( nroi_topleft_x, nroi_topleft_y, nroi_dims.x(), nroi_dims.y()) self.fitInView(nroi, Qt.KeepAspectRatio) self.update() def _scene_ROI(self, geometry): return QtCore.QRectF( self.mapToScene(geometry.topLeft()), self.mapToScene(geometry.bottomRight())) @property def current_scene_ROI(self): return self.last_scene_roi def mousePressEvent(self, event): super(ImageView, self).mousePressEvent(event) button = event.button() modifier = event.modifiers() # pan if modifier == Qt.ControlModifier and button == Qt.LeftButton: self.start_drag = event.pos() self.panning = True # initiate/show ROI selection if modifier == Qt.ShiftModifier and button == Qt.LeftButton: self.start_drag = event.pos() if self.rubberband is None: self.rubberband = QtWidgets.QRubberBand( QtWidgets.QRubberBand.Rectangle, self.viewport()) self.rubberband.setGeometry( QtCore.QRect(self.start_drag, QtCore.QSize())) self.rubberband.show() def mouseMoveEvent(self, event): super(ImageView, self).mouseMoveEvent(event) # update selection display if self.rubberband is not None: self.rubberband.setGeometry( QtCore.QRect(self.start_drag, event.pos()).normalized()) if self.panning: end_drag = event.pos() pan_vector = end_drag - self.start_drag scene2view = self.transform() # skip shear sx = scene2view.m11() sy = scene2view.m22() scene_pan_x = pan_vector.x() / sx scene_pan_y = pan_vector.y() / sy scene_pan_vector = QtCore.QPointF(scene_pan_x, scene_pan_y) roi = self.current_scene_ROI top_left = roi.topLeft() new_top_left = top_left - scene_pan_vector scene_rect = self.sceneRect() new_top_left.setX(clamp(new_top_left.x(), scene_rect.left(), scene_rect.right())) new_top_left.setY(clamp(new_top_left.y(), scene_rect.top(), scene_rect.bottom())) nroi = QtCore.QRectF(new_top_left, roi.size()) self.fitInView(nroi, Qt.KeepAspectRatio) self.start_drag = end_drag self.update() def mouseReleaseEvent(self, event): super(ImageView, self).mouseReleaseEvent(event) # consume rubber band selection if self.rubberband is not None: self.rubberband.hide() # set view to ROI rect = self.rubberband.geometry().normalized() if rect.width() > 5 and rect.height() > 5: roi = QtCore.QRectF( self.mapToScene(rect.topLeft()), self.mapToScene(rect.bottomRight())) self.fitInView(roi, Qt.KeepAspectRatio) self.rubberband = None if self.panning: self.panning = False self.update() def wheelEvent(self, event): delta = qtcompat.wheel_delta(event) # adjust zoom if abs(delta) > 0: scene_pos = self.mapToScene(event.pos()) if delta >= 0: sign = 1 else: sign = -1 self.zoomROITo(scene_pos, sign) def reset(self): self.update_scene_rect() self.fitInView(self.image_scene_rect, flags=Qt.KeepAspectRatio) self.update() # override arbitrary and unwanted margins: # https://bugreports.qt.io/browse/QTBUG-42331 - based on QT sources def fitInView(self, rect, flags=Qt.IgnoreAspectRatio): if self.scene() is None or not rect or rect.isNull(): return self.last_scene_roi = rect unity = self.transform().mapRect(QtCore.QRectF(0.0, 0.0, 1.0, 1.0)) self.scale(1.0/unity.width(), 1.0/unity.height()) viewrect = self.viewport().rect() scene_rect = self.transform().mapRect(rect) xratio = viewrect.width() / scene_rect.width() yratio = viewrect.height() / scene_rect.height() if flags == Qt.KeepAspectRatio: xratio = yratio = min(xratio, yratio) elif flags == Qt.KeepAspectRatioByExpanding: xratio = yratio = max(xratio, yratio) self.scale(xratio, yratio) self.centerOn(rect.center()) class AppImageView(ImageView): def __init__(self, parent=None): ImageView.__init__(self, parent=parent) self.main_widget = None def mousePressEvent(self, event): ImageView.mousePressEvent(self, event) def mouseMoveEvent(self, event): ImageView.mouseMoveEvent(self, event) pos = event.pos() scene_pos = self.mapToScene(pos) msg = ('ui: %d, %d image: %d, %d' % (pos.y(), pos.x(), int(scene_pos.y()), int(scene_pos.x()))) self.main_widget.statusBar().showMessage(msg) class ImageViewerWindow(QtWidgets.QMainWindow): def __init__(self, image, input_path): QtWidgets.QMainWindow.__init__(self) self.image = image self.input_path = input_path self.image_view = AppImageView(parent=self) self.image_view.main_widget = self self.statusBar().showMessage('') padding = self.frameGeometry().size() - self.geometry().size() self.resize(image.size() + padding) central = QtWidgets.QWidget(self) self.vbox = QtWidgets.QVBoxLayout(central) self.vbox.setContentsMargins(0, 0, 0, 0) self.setCentralWidget(central) self.layout().setContentsMargins(0, 0, 0, 0) Expanding = QtWidgets.QSizePolicy.Expanding height_for_width = self.image_view.sizePolicy().hasHeightForWidth() policy = QtWidgets.QSizePolicy(Expanding, Expanding) policy.setHorizontalStretch(1) policy.setVerticalStretch(1) policy.setHeightForWidth(height_for_width) self.image_view.setSizePolicy(policy) self.image_view.setMouseTracking(True) self.image_view.setFocusPolicy(Qt.NoFocus) self.image_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.image_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.vbox.addWidget(self.image_view) screen = QtWidgets.QDesktopWidget().screenGeometry(self) size = self.geometry() self.move((screen.width() - size.width()) // 4, (screen.height() - size.height()) // 4) self.update_view() self.image_view.reset() def hideEvent(self, _event): QtWidgets.QMainWindow.hide(self) def update_view(self): self.image_view.image = self.image self.setWindowTitle(self.make_window_title()) def make_window_title(self): return os.path.basename(self.input_path) def keyPressEvent(self, event): key = event.key() global main_loop_type # pylint: disable=global-statement if key == Qt.Key_Escape: if main_loop_type == 'qt': QtWidgets.QApplication.quit() elif main_loop_type == 'ipython': self.hide() # import IPython # IPython.get_ipython().ask_exit() # pylint: disable=unused-argument def sigint_handler(*args): """Handler for the SIGINT signal.""" sys.stderr.write('\r') QtWidgets.QApplication.quit() def main(): parser = argparse.ArgumentParser(description='image viewer') parser.add_argument('image', help='path to the image') opts = parser.parse_args() input_image = opts.image image = QtGui.QImage() image.load(input_image) app = QtWidgets.QApplication(sys.argv) try: import signal signal.signal(signal.SIGINT, sigint_handler) except ImportError: pass window = ImageViewerWindow(image, input_image) window.show() app.exec_() if __name__ == '__main__': main() git-cola-3.6/cola/widgets/log.py000066400000000000000000000051401356743264500166170ustar00rootroot00000000000000from __future__ import absolute_import, division, unicode_literals import time from qtpy import QtGui from qtpy import QtWidgets from qtpy.QtCore import Qt from qtpy.QtCore import Signal from .. import core from .. import qtutils from ..i18n import N_ from . import defs from .text import VimTextEdit class LogWidget(QtWidgets.QFrame): """A simple dialog to display command logs.""" channel = Signal(object) def __init__(self, context, parent=None, output=None): QtWidgets.QFrame.__init__(self, parent) self.output_text = VimTextEdit(context, parent=self) self.highlighter = LogSyntaxHighlighter(self.output_text.document()) if output: self.set_output(output) self.main_layout = qtutils.vbox(defs.no_margin, defs.spacing, self.output_text) self.setLayout(self.main_layout) self.channel.connect(self.append, type=Qt.QueuedConnection) def clear(self): self.output_text.clear() def set_output(self, output): self.output_text.set_value(output) def log_status(self, status, out, err=None): msg = [] if out: msg.append(out) if err: msg.append(err) if status: msg.append(N_('exit code %s') % status) self.log('\n'.join(msg)) def append(self, msg): """Append to the end of the log message""" if not msg: return msg = core.decode(msg) cursor = self.output_text.textCursor() cursor.movePosition(cursor.End) text = self.output_text # NOTE: the ': ' colon-SP-SP suffix is for the syntax highlighter prefix = core.decode(time.strftime('%Y-%m-%d %H:%M:%S: ')) # ISO-8601 for line in msg.split('\n'): cursor.insertText(prefix + line + '\n') cursor.movePosition(cursor.End) text.setTextCursor(cursor) def log(self, msg): """Add output to the log window""" # Funnel through a Qt queued to allow thread-safe logging from # asynchronous QRunnables, filesystem notification, etc. self.channel.emit(msg) class LogSyntaxHighlighter(QtGui.QSyntaxHighlighter): """Implements the log syntax highlighting""" def __init__(self, doc): QtGui.QSyntaxHighlighter.__init__(self, doc) palette = QtGui.QPalette() QPalette = QtGui.QPalette self.disabled_color = palette.color(QPalette.Disabled, QPalette.Text) def highlightBlock(self, text): end = text.find(': ') if end > 0: self.setFormat(0, end + 1, self.disabled_color) git-cola-3.6/cola/widgets/main.py000066400000000000000000001172601356743264500167710ustar00rootroot00000000000000"""This view provides the main git-cola user interface. """ from __future__ import division, absolute_import, unicode_literals import os from functools import partial from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from qtpy.QtCore import Qt from qtpy.QtCore import Signal from ..compat import uchr from ..compat import WIN32 from ..i18n import N_ from ..interaction import Interaction from ..models import prefs from ..qtutils import get from ..settings import Settings from .. import cmds from .. import core from .. import guicmds from .. import git from .. import gitcmds from .. import hotkeys from .. import icons from .. import qtutils from .. import resources from .. import utils from .. import version from . import about from . import action from . import archive from . import bookmarks from . import branch from . import submodules from . import browse from . import cfgactions from . import clone from . import commitmsg from . import compare from . import createbranch from . import createtag from . import dag from . import defs from . import diff from . import finder from . import editremotes from . import grep from . import log from . import merge from . import patch from . import prefs as prefs_widget from . import recent from . import remote from . import search from . import standard from . import status from . import stash from . import toolbar class MainView(standard.MainWindow): config_actions_changed = Signal(object) updated = Signal() def __init__(self, context, parent=None, settings=None): standard.MainWindow.__init__(self, parent) self.setAttribute(Qt.WA_DeleteOnClose) self.context = context self.git = context.git self.dag = None self.model = model = context.model self.settings = settings self.prefs_model = prefs_model = prefs.PreferencesModel(context) self.toolbar_state = toolbar.ToolBarState(context, self) # The widget version is used by import/export_state(). # Change this whenever dockwidgets are removed. self.widget_version = 2 create_dock = qtutils.create_dock cfg = context.cfg self.browser_dockable = cfg.get('cola.browserdockable') if self.browser_dockable: browser = browse.worktree_browser(context, parent=self, show=False, update=False) self.browserdock = create_dock(N_('Browser'), self, widget=browser) # "Actions" widget self.actionsdock = create_dock( N_('Actions'), self, widget=action.ActionButtons(context, self)) qtutils.hide_dock(self.actionsdock) # "Repository Status" widget self.statusdock = create_dock( N_('Status'), self, fn=lambda dock: status.StatusWidget( context, dock.titleBarWidget(), dock)) self.statuswidget = self.statusdock.widget() # "Switch Repository" widgets self.bookmarksdock = create_dock( N_('Favorites'), self, fn=lambda dock: bookmarks.bookmark(context, dock)) bookmarkswidget = self.bookmarksdock.widget() qtutils.hide_dock(self.bookmarksdock) self.recentdock = create_dock( N_('Recent'), self, fn=lambda dock: bookmarks.recent(context, dock)) recentwidget = self.recentdock.widget() qtutils.hide_dock(self.recentdock) bookmarkswidget.connect_to(recentwidget) # "Branch" widgets self.branchdock = create_dock( N_('Branches'), self, fn=partial(branch.BranchesWidget, context)) self.branchwidget = self.branchdock.widget() titlebar = self.branchdock.titleBarWidget() titlebar.add_corner_widget(self.branchwidget.filter_button) titlebar.add_corner_widget(self.branchwidget.sort_order_button) # "Submodule" widgets self.submodulesdock = create_dock( N_('Submodules'), self, fn=partial(submodules.SubmodulesWidget, context)) self.submoduleswidget = self.submodulesdock.widget() # "Commit Message Editor" widget self.position_label = QtWidgets.QLabel() self.position_label.setAlignment(Qt.AlignCenter) font = qtutils.default_monospace_font() font.setPointSize(int(font.pointSize() * 0.8)) self.position_label.setFont(font) # make the position label fixed size to avoid layout issues fm = self.position_label.fontMetrics() width = fm.width('99:999') + defs.spacing self.position_label.setMinimumWidth(width) editor = commitmsg.CommitMessageEditor(context, self) self.commiteditor = editor self.commitdock = create_dock(N_('Commit'), self, widget=editor) titlebar = self.commitdock.titleBarWidget() titlebar.add_corner_widget(self.position_label) # "Console" widget self.logwidget = log.LogWidget(context) self.logdock = create_dock(N_('Console'), self, widget=self.logwidget) qtutils.hide_dock(self.logdock) # "Diff Viewer" widget self.diffdock = create_dock( N_('Diff'), self, fn=lambda dock: diff.Viewer(context, parent=dock)) self.diffviewer = self.diffdock.widget() self.diffviewer.set_diff_type(self.model.diff_type) self.diffeditor = self.diffviewer.text titlebar = self.diffdock.titleBarWidget() titlebar.add_corner_widget(self.diffviewer.options) # All Actions add_action = qtutils.add_action add_action_bool = qtutils.add_action_bool self.commit_amend_action = add_action_bool( self, N_('Amend Last Commit'), partial(cmds.do, cmds.AmendMode, context), False) self.commit_amend_action.setShortcut(hotkeys.AMEND) self.commit_amend_action.setShortcutContext(Qt.WidgetShortcut) self.unstage_all_action = add_action( self, N_('Unstage All'), cmds.run(cmds.UnstageAll, context)) self.unstage_all_action.setIcon(icons.remove()) self.unstage_selected_action = add_action( self, N_('Unstage From Commit'), cmds.run(cmds.UnstageSelected, context)) self.unstage_selected_action.setIcon(icons.remove()) self.show_diffstat_action = add_action( self, N_('Diffstat'), self.statuswidget.select_header, hotkeys.DIFFSTAT) self.stage_modified_action = add_action( self, N_('Stage Changed Files To Commit'), cmds.run(cmds.StageModified, context), hotkeys.STAGE_MODIFIED) self.stage_modified_action.setIcon(icons.add()) self.stage_untracked_action = add_action( self, N_('Stage All Untracked'), cmds.run(cmds.StageUntracked, context), hotkeys.STAGE_UNTRACKED) self.stage_untracked_action.setIcon(icons.add()) self.apply_patches_action = add_action( self, N_('Apply Patches...'), partial(patch.apply_patches, context)) self.export_patches_action = add_action( self, N_('Export Patches...'), partial(guicmds.export_patches, context), hotkeys.EXPORT) self.new_repository_action = add_action( self, N_('New Repository...'), partial(guicmds.open_new_repo, context)) self.new_repository_action.setIcon(icons.new()) self.new_bare_repository_action = add_action( self, N_('New Bare Repository...'), partial(guicmds.new_bare_repo, context)) self.new_bare_repository_action.setIcon(icons.new()) prefs_fn = partial( prefs_widget.preferences, context, parent=self, model=prefs_model) self.preferences_action = add_action( self, N_('Preferences'), prefs_fn, QtGui.QKeySequence.Preferences) self.edit_remotes_action = add_action( self, N_('Edit Remotes...'), partial(editremotes.editor, context)) self.rescan_action = add_action( self, cmds.Refresh.name(), cmds.run(cmds.Refresh, context), *hotkeys.REFRESH_HOTKEYS) self.rescan_action.setIcon(icons.sync()) self.find_files_action = add_action( self, N_('Find Files'), partial(finder.finder, context), hotkeys.FINDER, hotkeys.FINDER_SECONDARY) self.find_files_action.setIcon(icons.zoom_in()) self.browse_recently_modified_action = add_action( self, N_('Recently Modified Files...'), partial(recent.browse_recent_files, context), hotkeys.EDIT_SECONDARY) self.cherry_pick_action = add_action( self, N_('Cherry-Pick...'), partial(guicmds.cherry_pick, context), hotkeys.CHERRY_PICK) self.load_commitmsg_action = add_action( self, N_('Load Commit Message...'), partial(guicmds.load_commitmsg, context)) self.prepare_commitmsg_hook_action = add_action( self, N_('Prepare Commit Message'), cmds.run(cmds.PrepareCommitMessageHook, context), hotkeys.PREPARE_COMMIT_MESSAGE) self.save_tarball_action = add_action( self, N_('Save As Tarball/Zip...'), partial(archive.save_archive, context)) self.quit_action = add_action( self, N_('Quit'), self.close, hotkeys.QUIT) self.grep_action = add_action( self, N_('Grep'), partial(grep.grep, context), hotkeys.GREP) self.merge_local_action = add_action( self, N_('Merge...'), partial(merge.local_merge, context), hotkeys.MERGE) self.merge_abort_action = add_action( self, N_('Abort Merge...'), cmds.run(cmds.AbortMerge, context)) self.update_submodules_action = add_action( self, N_('Update All Submodules...'), cmds.run(cmds.SubmodulesUpdate, context)) self.fetch_action = add_action( self, N_('Fetch...'), partial(remote.fetch, context), hotkeys.FETCH) self.push_action = add_action( self, N_('Push...'), partial(remote.push, context), hotkeys.PUSH) self.pull_action = add_action( self, N_('Pull...'), partial(remote.pull, context), hotkeys.PULL) self.open_repo_action = add_action( self, N_('Open...'), partial(guicmds.open_repo, context), hotkeys.OPEN) self.open_repo_action.setIcon(icons.folder()) self.open_repo_new_action = add_action( self, N_('Open in New Window...'), partial(guicmds.open_repo_in_new_window, context)) self.open_repo_new_action.setIcon(icons.folder()) self.stash_action = add_action( self, N_('Stash...'), partial(stash.view, context), hotkeys.STASH) self.reset_branch_head_action = add_action( self, N_('Reset Branch Head'), partial(guicmds.reset_branch_head, context)) self.reset_worktree_action = add_action( self, N_('Reset Worktree'), partial(guicmds.reset_worktree, context)) self.clone_repo_action = add_action( self, N_('Clone...'), partial(clone.clone, context, settings=settings)) self.clone_repo_action.setIcon(icons.repo()) self.help_docs_action = add_action( self, N_('Documentation'), resources.show_html_docs, QtGui.QKeySequence.HelpContents) self.help_shortcuts_action = add_action( self, N_('Keyboard Shortcuts'), about.show_shortcuts, hotkeys.QUESTION) self.visualize_current_action = add_action( self, N_('Visualize Current Branch...'), cmds.run(cmds.VisualizeCurrent, context)) self.visualize_all_action = add_action( self, N_('Visualize All Branches...'), cmds.run(cmds.VisualizeAll, context)) self.search_commits_action = add_action( self, N_('Search...'), partial(search.search, context)) self.browse_branch_action = add_action( self, N_('Browse Current Branch...'), partial(guicmds.browse_current, context)) self.browse_other_branch_action = add_action( self, N_('Browse Other Branch...'), partial(guicmds.browse_other, context)) self.load_commitmsg_template_action = add_action( self, N_('Get Commit Message Template'), cmds.run(cmds.LoadCommitMessageFromTemplate, context)) self.help_about_action = add_action( self, N_('About'), partial(about.about_dialog, context)) self.diff_expression_action = add_action( self, N_('Expression...'), partial(guicmds.diff_expression, context)) self.branch_compare_action = add_action( self, N_('Branches...'), partial(compare.compare_branches, context)) self.create_tag_action = add_action( self, N_('Create Tag...'), partial(createtag.create_tag, context, settings=settings)) self.create_branch_action = add_action( self, N_('Create...'), partial(createbranch.create_new_branch, context, settings=settings), hotkeys.BRANCH) self.create_branch_action.setIcon(icons.branch()) self.delete_branch_action = add_action( self, N_('Delete...'), partial(guicmds.delete_branch, context)) self.delete_remote_branch_action = add_action( self, N_('Delete Remote Branch...'), partial(guicmds.delete_remote_branch, context)) self.rename_branch_action = add_action( self, N_('Rename Branch...'), partial(guicmds.rename_branch, context)) self.checkout_branch_action = add_action( self, N_('Checkout...'), partial(guicmds.checkout_branch, context), hotkeys.CHECKOUT) self.branch_review_action = add_action( self, N_('Review...'), partial(guicmds.review_branch, context)) self.browse_action = add_action( self, N_('File Browser...'), partial(browse.worktree_browser, context)) self.browse_action.setIcon(icons.cola()) self.dag_action = add_action(self, N_('DAG...'), self.git_dag) self.dag_action.setIcon(icons.cola()) self.rebase_start_action = add_action( self, N_('Start Interactive Rebase...'), cmds.run(cmds.Rebase, context), hotkeys.REBASE_START_AND_CONTINUE) self.rebase_edit_todo_action = add_action( self, N_('Edit...'), cmds.run(cmds.RebaseEditTodo, context)) self.rebase_continue_action = add_action( self, N_('Continue'), cmds.run(cmds.RebaseContinue, context), hotkeys.REBASE_START_AND_CONTINUE) self.rebase_skip_action = add_action( self, N_('Skip Current Patch'), cmds.run(cmds.RebaseSkip, context)) self.rebase_abort_action = add_action( self, N_('Abort'), cmds.run(cmds.RebaseAbort, context)) # For "Start Rebase" only, reverse the first argument to setEnabled() # so that we can operate on it as a group. # We can do this because can_rebase == not is_rebasing self.rebase_start_action_proxy = utils.Proxy( self.rebase_start_action, setEnabled=lambda x: self.rebase_start_action.setEnabled(not x)) self.rebase_group = utils.Group(self.rebase_start_action_proxy, self.rebase_edit_todo_action, self.rebase_continue_action, self.rebase_skip_action, self.rebase_abort_action) self.annex_init_action = qtutils.add_action( self, N_('Initialize Git Annex'), cmds.run(cmds.AnnexInit, context)) self.lfs_init_action = qtutils.add_action( self, N_('Initialize Git LFS'), cmds.run(cmds.LFSInstall, context)) self.lock_layout_action = add_action_bool( self, N_('Lock Layout'), self.set_lock_layout, False) self.reset_layout_action = add_action( self, N_('Reset Layout'), self.reset_layout) # Create the application menu self.menubar = QtWidgets.QMenuBar(self) self.setMenuBar(self.menubar) # File Menu add_menu = qtutils.add_menu self.file_menu = add_menu(N_('&File'), self.menubar) # File->Open Recent menu self.open_recent_menu = self.file_menu.addMenu(N_('Open Recent')) self.open_recent_menu.setIcon(icons.folder()) self.file_menu.addAction(self.open_repo_action) self.file_menu.addAction(self.open_repo_new_action) self.file_menu.addSeparator() self.file_menu.addAction(self.new_repository_action) self.file_menu.addAction(self.new_bare_repository_action) self.file_menu.addAction(self.clone_repo_action) self.file_menu.addSeparator() self.file_menu.addAction(self.rescan_action) self.file_menu.addAction(self.find_files_action) self.file_menu.addAction(self.edit_remotes_action) self.file_menu.addAction(self.browse_recently_modified_action) self.file_menu.addSeparator() self.file_menu.addAction(self.apply_patches_action) self.file_menu.addAction(self.export_patches_action) self.file_menu.addAction(self.save_tarball_action) # Git Annex / Git LFS annex = core.find_executable('git-annex') lfs = core.find_executable('git-lfs') if annex or lfs: self.file_menu.addSeparator() if annex: self.file_menu.addAction(self.annex_init_action) if lfs: self.file_menu.addAction(self.lfs_init_action) self.file_menu.addSeparator() self.file_menu.addAction(self.preferences_action) self.file_menu.addAction(self.quit_action) # Edit Menu self.edit_proxy = edit_proxy = ( FocusProxy(editor, editor.summary, editor.description)) copy_widgets = ( self, editor.summary, editor.description, self.diffeditor, bookmarkswidget.tree, recentwidget.tree, ) edit_proxy.override('copy', copy_widgets) edit_proxy.override('selectAll', copy_widgets) edit_menu = self.edit_menu = add_menu(N_('&Edit'), self.menubar) add_action(edit_menu, N_('Undo'), edit_proxy.undo, hotkeys.UNDO) add_action(edit_menu, N_('Redo'), edit_proxy.redo, hotkeys.REDO) edit_menu.addSeparator() add_action(edit_menu, N_('Cut'), edit_proxy.cut, hotkeys.CUT) add_action(edit_menu, N_('Copy'), edit_proxy.copy, hotkeys.COPY) add_action(edit_menu, N_('Paste'), edit_proxy.paste, hotkeys.PASTE) add_action(edit_menu, N_('Delete'), edit_proxy.delete, hotkeys.DELETE) edit_menu.addSeparator() add_action(edit_menu, N_('Select All'), edit_proxy.selectAll, hotkeys.SELECT_ALL) edit_menu.addSeparator() commitmsg.add_menu_actions(edit_menu, self.commiteditor.menu_actions) # Actions menu self.actions_menu = add_menu(N_('Actions'), self.menubar) self.actions_menu.addAction(self.fetch_action) self.actions_menu.addAction(self.push_action) self.actions_menu.addAction(self.pull_action) self.actions_menu.addAction(self.stash_action) self.actions_menu.addSeparator() self.actions_menu.addAction(self.create_tag_action) self.actions_menu.addAction(self.cherry_pick_action) self.actions_menu.addAction(self.merge_local_action) self.actions_menu.addAction(self.merge_abort_action) self.actions_menu.addSeparator() self.actions_menu.addAction(self.update_submodules_action) self.actions_menu.addSeparator() self.actions_reset_menu = self.actions_menu.addMenu(N_('Reset')) self.actions_reset_menu.addAction(self.reset_branch_head_action) self.actions_reset_menu.addAction(self.reset_worktree_action) self.actions_menu.addSeparator() self.actions_menu.addAction(self.grep_action) self.actions_menu.addAction(self.search_commits_action) # Commit Menu self.commit_menu = add_menu(N_('Commit@@verb'), self.menubar) self.commit_menu.setTitle(N_('Commit@@verb')) self.commit_menu.addAction(self.commiteditor.commit_action) self.commit_menu.addAction(self.commit_amend_action) self.commit_menu.addSeparator() self.commit_menu.addAction(self.stage_modified_action) self.commit_menu.addAction(self.stage_untracked_action) self.commit_menu.addSeparator() self.commit_menu.addAction(self.unstage_all_action) self.commit_menu.addAction(self.unstage_selected_action) self.commit_menu.addSeparator() self.commit_menu.addAction(self.load_commitmsg_action) self.commit_menu.addAction(self.load_commitmsg_template_action) self.commit_menu.addAction(self.prepare_commitmsg_hook_action) # Diff Menu self.diff_menu = add_menu(N_('Diff'), self.menubar) self.diff_menu.addAction(self.diff_expression_action) self.diff_menu.addAction(self.branch_compare_action) self.diff_menu.addSeparator() self.diff_menu.addAction(self.show_diffstat_action) # Branch Menu self.branch_menu = add_menu(N_('Branch'), self.menubar) self.branch_menu.addAction(self.branch_review_action) self.branch_menu.addSeparator() self.branch_menu.addAction(self.create_branch_action) self.branch_menu.addAction(self.checkout_branch_action) self.branch_menu.addAction(self.delete_branch_action) self.branch_menu.addAction(self.delete_remote_branch_action) self.branch_menu.addAction(self.rename_branch_action) self.branch_menu.addSeparator() self.branch_menu.addAction(self.browse_branch_action) self.branch_menu.addAction(self.browse_other_branch_action) self.branch_menu.addSeparator() self.branch_menu.addAction(self.visualize_current_action) self.branch_menu.addAction(self.visualize_all_action) # Rebase menu self.rebase_menu = add_menu(N_('Rebase'), self.actions_menu) self.rebase_menu.addAction(self.rebase_start_action) self.rebase_menu.addAction(self.rebase_edit_todo_action) self.rebase_menu.addSeparator() self.rebase_menu.addAction(self.rebase_continue_action) self.rebase_menu.addAction(self.rebase_skip_action) self.rebase_menu.addSeparator() self.rebase_menu.addAction(self.rebase_abort_action) # View Menu self.view_menu = add_menu(N_('View'), self.menubar) # pylint: disable=no-member self.view_menu.aboutToShow.connect( lambda: self.build_view_menu(self.view_menu)) self.setup_dockwidget_view_menu() if utils.is_darwin(): # TODO or self.menubar.setNativeMenuBar(False) # Since native OSX menu doesn't show empty entries self.build_view_menu(self.view_menu) # Help Menu self.help_menu = add_menu(N_('Help'), self.menubar) self.help_menu.addAction(self.help_docs_action) self.help_menu.addAction(self.help_shortcuts_action) self.help_menu.addAction(self.help_about_action) # Arrange dock widgets bottom = Qt.BottomDockWidgetArea top = Qt.TopDockWidgetArea self.addDockWidget(top, self.statusdock) self.addDockWidget(top, self.commitdock) if self.browser_dockable: self.addDockWidget(top, self.browserdock) self.tabifyDockWidget(self.browserdock, self.commitdock) self.addDockWidget(top, self.branchdock) self.addDockWidget(top, self.submodulesdock) self.addDockWidget(top, self.bookmarksdock) self.addDockWidget(top, self.recentdock) self.tabifyDockWidget(self.branchdock, self.submodulesdock) self.tabifyDockWidget(self.submodulesdock, self.bookmarksdock) self.tabifyDockWidget(self.bookmarksdock, self.recentdock) self.branchdock.raise_() self.addDockWidget(bottom, self.diffdock) self.addDockWidget(bottom, self.actionsdock) self.addDockWidget(bottom, self.logdock) self.tabifyDockWidget(self.actionsdock, self.logdock) # Listen for model notifications model.add_observer(model.message_updated, self.updated.emit) model.add_observer(model.message_mode_changed, lambda mode: self.updated.emit()) prefs_model.add_observer(prefs_model.message_config_updated, self._config_updated) # Set a default value self.show_cursor_position(1, 0) self.commit_menu.aboutToShow.connect(self.update_menu_actions) self.open_recent_menu.aboutToShow.connect(self.build_recent_menu) self.commiteditor.cursor_changed.connect(self.show_cursor_position) self.diffeditor.options_changed.connect(self.statuswidget.refresh) self.diffeditor.up.connect(self.statuswidget.move_up) self.diffeditor.down.connect(self.statuswidget.move_down) self.commiteditor.up.connect(self.statuswidget.move_up) self.commiteditor.down.connect(self.statuswidget.move_down) self.updated.connect(self.refresh, type=Qt.QueuedConnection) self.config_actions_changed.connect(self._install_config_actions, type=Qt.QueuedConnection) self.init_state(settings, self.set_initial_size) # Route command output here Interaction.log_status = self.logwidget.log_status Interaction.log = self.logwidget.log # Focus the status widget; this must be deferred QtCore.QTimer.singleShot(0, self.initialize) def initialize(self): context = self.context git_version = version.git_version_str(context) if git_version: ok = True Interaction.log(git_version + '\n' + N_('git cola version %s') % version.version()) else: ok = False error_msg = N_('error: unable to execute git') Interaction.log(error_msg) if ok: self.statuswidget.setFocus() else: title = N_('error: unable to execute git') msg = title details = '' if WIN32: details = git.win32_git_error_hint() Interaction.critical(title, message=msg, details=details) self.context.app.exit(2) def set_initial_size(self): # Default size; this is thrown out when save/restore is used width, height = qtutils.desktop_size() self.resize((width*3)//4, height) self.statuswidget.set_initial_size() self.commiteditor.set_initial_size() def set_filter(self, txt): self.statuswidget.set_filter(txt) # Qt overrides def closeEvent(self, event): """Save state in the settings""" commit_msg = self.commiteditor.commit_message(raw=True) self.model.save_commitmsg(msg=commit_msg) standard.MainWindow.closeEvent(self, event) def create_view_menu(self): menu = qtutils.create_menu(N_('View'), self) self.build_view_menu(menu) return menu def build_view_menu(self, menu): menu.clear() menu.addAction(self.browse_action) menu.addAction(self.dag_action) menu.addSeparator() popup_menu = self.createPopupMenu() for menu_action in popup_menu.actions(): menu_action.setParent(menu) menu.addAction(menu_action) menu.addSeparator() context = self.context menu_action = menu.addAction( N_('Add Toolbar'), partial(toolbar.add_toolbar, context, self)) menu_action.setIcon(icons.add()) dockwidgets = [ self.logdock, self.commitdock, self.statusdock, self.diffdock, self.actionsdock, self.bookmarksdock, self.recentdock, self.branchdock, self.submodulesdock ] if self.browser_dockable: dockwidgets.append(self.browserdock) for dockwidget in dockwidgets: # Associate the action with the shortcut toggleview = dockwidget.toggleViewAction() menu.addAction(toggleview) menu.addSeparator() menu.addAction(self.lock_layout_action) menu.addAction(self.reset_layout_action) return menu def contextMenuEvent(self, event): menu = self.create_view_menu() menu.exec_(event.globalPos()) def build_recent_menu(self): settings = Settings() settings.load() cmd = cmds.OpenRepo context = self.context menu = self.open_recent_menu menu.clear() worktree = self.git.worktree() for entry in settings.recent: directory = entry['path'] if directory == worktree: # Omit the current worktree from the "Open Recent" menu. continue name = entry['name'] text = '%s %s %s' % (name, uchr(0x2192), directory) menu.addAction(text, cmds.run(cmd, context, directory)) # Accessors mode = property(lambda self: self.model.mode) def _config_updated(self, _source, config, value): if config == prefs.FONTDIFF: # The diff font font = QtGui.QFont() if not font.fromString(value): return self.logwidget.setFont(font) self.diffeditor.setFont(font) self.commiteditor.setFont(font) elif config == prefs.TABWIDTH: # This can be set locally or globally, so we have to use the # effective value otherwise we'll update when we shouldn't. # For example, if this value is overridden locally, and the # global value is tweaked, we should not update. value = prefs.tabwidth(self.context) self.diffeditor.set_tabwidth(value) self.commiteditor.set_tabwidth(value) elif config == prefs.EXPANDTAB: self.commiteditor.set_expandtab(value) elif config == prefs.LINEBREAK: # enables automatic line breaks self.commiteditor.set_linebreak(value) elif config == prefs.SORT_BOOKMARKS: self.bookmarksdock.widget().reload_bookmarks() elif config == prefs.TEXTWIDTH: # Use the effective value for the same reason as tabwidth. value = prefs.textwidth(self.context) self.commiteditor.set_textwidth(value) elif config == prefs.SHOW_PATH: # the path in the window title was toggled self.refresh_window_title() def start(self, context): """Do the expensive "get_config_actions()" call in the background""" # Install .git-config-defined actions task = qtutils.SimpleTask(self, self.get_config_actions) context.runtask.start(task) def get_config_actions(self): actions = cfgactions.get_config_actions(self.context) self.config_actions_changed.emit(actions) def _install_config_actions(self, names_and_shortcuts): """Install .gitconfig-defined actions""" if not names_and_shortcuts: return context = self.context menu = self.actions_menu menu.addSeparator() for (name, shortcut) in names_and_shortcuts: callback = cmds.run(cmds.RunConfigAction, context, name) menu_action = menu.addAction(name, callback) if shortcut: menu_action.setShortcut(shortcut) def refresh(self): """Update the title with the current branch and directory name.""" curbranch = self.model.currentbranch curdir = core.getcwd() is_merging = self.model.is_merging is_rebasing = self.model.is_rebasing msg = N_('Repository: %s') % curdir msg += '\n' msg += N_('Branch: %s') % curbranch if is_rebasing: msg += '\n\n' msg += N_('This repository is currently being rebased.\n' 'Resolve conflicts, commit changes, and run:\n' ' Rebase > Continue') elif is_merging: msg += '\n\n' msg += N_('This repository is in the middle of a merge.\n' 'Resolve conflicts and commit changes.') self.refresh_window_title() if self.mode == self.model.mode_amend: self.commit_amend_action.setChecked(True) else: self.commit_amend_action.setChecked(False) self.commitdock.setToolTip(msg) self.commiteditor.set_mode(self.mode) self.update_actions() def refresh_window_title(self): """Refresh the window title when state changes""" alerts = [] project = self.model.project curbranch = self.model.currentbranch is_merging = self.model.is_merging is_rebasing = self.model.is_rebasing prefix = uchr(0xab) suffix = uchr(0xbb) if is_rebasing: alerts.append(N_('Rebasing')) elif is_merging: alerts.append(N_('Merging')) if self.mode == self.model.mode_amend: alerts.append(N_('Amending')) if alerts: alert_text = (prefix + ' %s ' + suffix + ' ') % ', '.join(alerts) else: alert_text = '' if self.model.cfg.get(prefs.SHOW_PATH, True): path_text = self.git.worktree() else: path_text = '' title = '%s: %s %s%s' % (project, curbranch, alert_text, path_text) self.setWindowTitle(title) def update_actions(self): is_rebasing = self.model.is_rebasing self.rebase_group.setEnabled(is_rebasing) enabled = not self.model.is_empty_repository() self.rename_branch_action.setEnabled(enabled) self.delete_branch_action.setEnabled(enabled) self.annex_init_action.setEnabled(not self.model.annex) self.lfs_init_action.setEnabled(not self.model.lfs) def update_menu_actions(self): # Enable the Prepare Commit Message action if the hook exists hook = gitcmds.prepare_commit_message_hook(self.context) enabled = os.path.exists(hook) self.prepare_commitmsg_hook_action.setEnabled(enabled) def export_state(self): state = standard.MainWindow.export_state(self) show_status_filter = self.statuswidget.filter_widget.isVisible() state['show_status_filter'] = show_status_filter state['toolbars'] = self.toolbar_state.export_state() state['ref_sort'] = self.model.ref_sort self.diffviewer.export_state(state) return state def apply_state(self, state): """Imports data for save/restore""" base_ok = standard.MainWindow.apply_state(self, state) lock_layout = state.get('lock_layout', False) self.lock_layout_action.setChecked(lock_layout) show_status_filter = state.get('show_status_filter', False) self.statuswidget.filter_widget.setVisible(show_status_filter) toolbars = state.get('toolbars', []) self.toolbar_state.apply_state(toolbars) sort_key = state.get('ref_sort', 0) self.model.set_ref_sort(sort_key) diff_ok = self.diffviewer.apply_state(state) return base_ok and diff_ok def setup_dockwidget_view_menu(self): # Hotkeys for toggling the dock widgets if utils.is_darwin(): optkey = 'Meta' else: optkey = 'Ctrl' dockwidgets = ( (optkey + '+0', self.logdock), (optkey + '+1', self.commitdock), (optkey + '+2', self.statusdock), (optkey + '+3', self.diffdock), (optkey + '+4', self.actionsdock), (optkey + '+5', self.bookmarksdock), (optkey + '+6', self.recentdock), (optkey + '+7', self.branchdock), (optkey + '+8', self.submodulesdock) ) for shortcut, dockwidget in dockwidgets: # Associate the action with the shortcut toggleview = dockwidget.toggleViewAction() toggleview.setShortcut('Shift+' + shortcut) def showdock(show, dockwidget=dockwidget): if show: dockwidget.raise_() dockwidget.widget().setFocus() else: self.setFocus() self.addAction(toggleview) qtutils.connect_action_bool(toggleview, showdock) # Create a new shortcut Shift+ that gives focus toggleview = QtWidgets.QAction(self) toggleview.setShortcut(shortcut) def focusdock(dockwidget=dockwidget): focus_dock(dockwidget) self.addAction(toggleview) qtutils.connect_action(toggleview, focusdock) # These widgets warrant home-row hotkey status qtutils.add_action(self, 'Focus Commit Message', lambda: focus_dock(self.commitdock), hotkeys.FOCUS) qtutils.add_action(self, 'Focus Status Window', lambda: focus_dock(self.statusdock), hotkeys.FOCUS_STATUS) qtutils.add_action(self, 'Focus Diff Editor', lambda: focus_dock(self.diffdock), hotkeys.FOCUS_DIFF) def git_dag(self): self.dag = dag.git_dag(self.context, existing_view=self.dag) def show_cursor_position(self, rows, cols): display = '%02d:%02d' % (rows, cols) css = """ """ if cols > 78: cls = 'error' elif cols > 72: cls = 'second-warning' elif cols > 64: cls = 'first-warning' else: cls = 'good' div = ('
%s
' % (cls, display)) self.position_label.setText(css + div) class FocusProxy(object): """Proxy over child widgets and operate on the focused widget""" def __init__(self, *widgets): self.widgets = widgets self.overrides = {} def override(self, name, widgets): self.overrides[name] = widgets def focus(self, name): """Return the currently focused widget""" widgets = self.overrides.get(name, self.widgets) # The parent must be the parent of all the proxied widgets parent = widgets[0] # The first widget is used as a fallback fallback = widgets[1] # We ignore the parent when delegating to child widgets widgets = widgets[1:] focus = parent.focusWidget() if focus not in widgets: focus = fallback return focus def __getattr__(self, name): """Return a callback that calls a common child method""" def callback(): focus = self.focus(name) fn = getattr(focus, name, None) if fn: fn() return callback def delete(self): """Specialized delete() to deal with QLineEdit vs QTextEdit""" focus = self.focus('delete') if hasattr(focus, 'del_'): focus.del_() elif hasattr(focus, 'textCursor'): focus.textCursor().deleteChar() def show_dock(dockwidget): dockwidget.raise_() dockwidget.widget().setFocus() def focus_dock(dockwidget): if get(dockwidget.toggleViewAction()): show_dock(dockwidget) else: dockwidget.toggleViewAction().trigger() git-cola-3.6/cola/widgets/merge.py000066400000000000000000000214431356743264500171410ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals from qtpy import QtWidgets from qtpy.QtCore import Qt from ..i18n import N_ from ..interaction import Interaction from ..qtutils import get from .. import cmds from .. import icons from .. import qtutils from . import completion from . import standard from . import defs def local_merge(context): """Provides a dialog for merging branches""" view = Merge(context, qtutils.active_window()) view.show() view.raise_() return view class Merge(standard.Dialog): """Provides a dialog for merging branches.""" def __init__(self, context, parent=None, ref=None): standard.Dialog.__init__(self, parent=parent) self.context = context self.cfg = cfg = context.cfg self.model = model = context.model if parent is not None: self.setWindowModality(Qt.WindowModal) # Widgets self.title_label = QtWidgets.QLabel() self.revision_label = QtWidgets.QLabel() self.revision_label.setText(N_('Revision to Merge')) self.revision = completion.GitRefLineEdit(context) self.revision.setToolTip(N_('Revision to Merge')) if ref: self.revision.set_value(ref) self.radio_local = qtutils.radio(text=N_('Local Branch'), checked=True) self.radio_remote = qtutils.radio(text=N_('Tracking Branch')) self.radio_tag = qtutils.radio(text=N_('Tag')) self.revisions = QtWidgets.QListWidget() self.revisions.setAlternatingRowColors(True) self.button_viz = qtutils.create_button(text=N_('Visualize'), icon=icons.visualize()) tooltip = N_('Squash the merged commits into a single commit') self.checkbox_squash = qtutils.checkbox(text=N_('Squash'), tooltip=tooltip) tooltip = N_('Always create a merge commit when enabled, ' 'even when the merge is a fast-forward update') self.checkbox_noff = qtutils.checkbox(text=N_('No fast forward'), tooltip=tooltip, checked=False) self.checkbox_noff_state = False tooltip = N_('Commit the merge if there are no conflicts. ' 'Uncheck to leave the merge uncommitted') self.checkbox_commit = qtutils.checkbox(text=N_('Commit'), tooltip=tooltip, checked=True) self.checkbox_commit_state = True text = N_('Create Signed Commit') checked = cfg.get('cola.signcommits', False) tooltip = N_('GPG-sign the merge commit') self.checkbox_sign = qtutils.checkbox(text=text, checked=checked, tooltip=tooltip) self.button_close = qtutils.close_button() icon = icons.merge() self.button_merge = qtutils.create_button(text=N_('Merge'), icon=icon, default=True) # Layouts self.revlayt = qtutils.hbox(defs.no_margin, defs.spacing, self.revision_label, self.revision, qtutils.STRETCH, self.title_label) self.radiolayt = qtutils.hbox(defs.no_margin, defs.spacing, self.radio_local, self.radio_remote, self.radio_tag) self.buttonlayt = qtutils.hbox(defs.no_margin, defs.button_spacing, self.button_close, qtutils.STRETCH, self.checkbox_squash, self.checkbox_noff, self.checkbox_commit, self.checkbox_sign, self.button_viz, self.button_merge) self.mainlayt = qtutils.vbox(defs.margin, defs.spacing, self.radiolayt, self.revisions, self.revlayt, self.buttonlayt) self.setLayout(self.mainlayt) # Signal/slot connections # pylint: disable=no-member self.revision.textChanged.connect(self.update_title) self.revision.enter.connect(self.merge_revision) self.revisions.itemSelectionChanged.connect(self.revision_selected) qtutils.connect_released(self.radio_local, self.update_revisions) qtutils.connect_released(self.radio_remote, self.update_revisions) qtutils.connect_released(self.radio_tag, self.update_revisions) qtutils.connect_button(self.button_merge, self.merge_revision) qtutils.connect_button(self.checkbox_squash, self.toggle_squash) qtutils.connect_button(self.button_viz, self.viz_revision) qtutils.connect_button(self.button_close, self.reject) # Observer messages model.add_observer(model.message_updated, self.update_all) self.update_all() self.init_size(parent=parent) self.revision.setFocus() def update_all(self): """Set the branch name for the window title and label.""" self.update_title() self.update_revisions() def update_title(self, _txt=None): branch = self.model.currentbranch revision = self.revision.text() if revision: txt = (N_('Merge "%(revision)s" into "%(branch)s"') % dict(revision=revision, branch=branch)) else: txt = N_('Merge into "%s"') % branch self.button_merge.setEnabled(bool(revision)) self.title_label.setText(txt) self.setWindowTitle(txt) def toggle_squash(self): """Toggles the commit checkbox based on the squash checkbox.""" if get(self.checkbox_squash): self.checkbox_commit_state = self.checkbox_commit.checkState() self.checkbox_commit.setCheckState(Qt.Unchecked) self.checkbox_commit.setDisabled(True) self.checkbox_noff_state = self.checkbox_noff.checkState() self.checkbox_noff.setCheckState(Qt.Unchecked) self.checkbox_noff.setDisabled(True) else: self.checkbox_noff.setDisabled(False) oldstateff = self.checkbox_noff_state self.checkbox_noff.setCheckState(oldstateff) self.checkbox_commit.setDisabled(False) oldstate = self.checkbox_commit_state self.checkbox_commit.setCheckState(oldstate) def update_revisions(self): """Update the revision list whenever a radio button is clicked""" self.revisions.clear() self.revisions.addItems(self.current_revisions()) def revision_selected(self): """Update the revision field when a list item is selected""" revlist = self.current_revisions() widget = self.revisions revision = qtutils.selected_item(widget, revlist) if revision is not None: self.revision.setText(revision) def current_revisions(self): """Retrieve candidate items to merge""" if get(self.radio_local): return self.model.local_branches elif get(self.radio_remote): return self.model.remote_branches elif get(self.radio_tag): return self.model.tags return [] def viz_revision(self): """Launch a gitk-like viewer on the selection revision""" revision = self.revision.text() if not revision: Interaction.information( N_('No Revision Specified'), N_('You must specify a revision to view.')) return cmds.do(cmds.VisualizeRevision, self.context, revision) def merge_revision(self): """Merge the selected revision/branch""" revision = self.revision.text() if not revision: Interaction.information( N_('No Revision Specified'), N_('You must specify a revision to merge.')) return noff = get(self.checkbox_noff) no_commit = not get(self.checkbox_commit) squash = get(self.checkbox_squash) sign = get(self.checkbox_sign) context = self.context cmds.do(cmds.Merge, context, revision, no_commit, squash, noff, sign) self.accept() def export_state(self): """Export persistent settings""" state = super(Merge, self).export_state() state['no-ff'] = get(self.checkbox_noff) state['sign'] = get(self.checkbox_sign) state['commit'] = get(self.checkbox_commit) return state def apply_state(self, state): """Apply persistent settings""" result = super(Merge, self).apply_state(state) self.checkbox_noff.setChecked(state.get('no-ff', False)) self.checkbox_sign.setChecked(state.get('sign', False)) self.checkbox_commit.setChecked(state.get('commit', True)) return result git-cola-3.6/cola/widgets/patch.py000066400000000000000000000214211356743264500171350ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals import os import re from qtpy import QtWidgets from qtpy.QtCore import Qt from ..i18n import N_ from ..qtutils import get from .. import core from .. import cmds from .. import hotkeys from .. import observable from .. import icons from .. import qtutils from .standard import Dialog from .standard import DraggableTreeWidget from . import defs from . import diff def apply_patches(context): parent = qtutils.active_window() dlg = new_apply_patches(context, parent=parent) dlg.show() dlg.raise_() return dlg def new_apply_patches(context, patches=None, parent=None): dlg = ApplyPatches(context, parent=parent) if patches: dlg.add_paths(patches) return dlg def get_patches_from_paths(paths): paths = [core.decode(p) for p in paths] patches = [p for p in paths if core.isfile(p) and (p.endswith('.patch') or p.endswith('.mbox'))] dirs = [p for p in paths if core.isdir(p)] dirs.sort() for d in dirs: patches.extend(get_patches_from_dir(d)) return patches def get_patches_from_mimedata(mimedata): urls = mimedata.urls() if not urls: return [] paths = [x.path() for x in urls] return get_patches_from_paths(paths) def get_patches_from_dir(path): """Find patches in a subdirectory""" patches = [] for root, _, files in core.walk(path): for name in [f for f in files if f.endswith('.patch')]: patches.append(core.decode(os.path.join(root, name))) return patches class ApplyPatches(Dialog): def __init__(self, context, parent=None): super(ApplyPatches, self).__init__(parent=parent) self.context = context self.setWindowTitle(N_('Apply Patches')) self.setAcceptDrops(True) if parent is not None: self.setWindowModality(Qt.WindowModal) self.curdir = core.getcwd() self.inner_drag = False self.usage = QtWidgets.QLabel() self.usage.setText(N_("""

Drag and drop or use the Add button to add patches to the list

""")) self.tree = PatchTreeWidget(parent=self) self.tree.setHeaderHidden(True) # pylint: disable=no-member self.tree.itemSelectionChanged.connect(self._tree_selection_changed) self.notifier = notifier = observable.Observable() self.diffwidget = diff.DiffWidget(context, notifier, self, is_commit=True) self.add_button = qtutils.create_toolbutton( text=N_('Add'), icon=icons.add(), tooltip=N_('Add patches (+)')) self.remove_button = qtutils.create_toolbutton( text=N_('Remove'), icon=icons.remove(), tooltip=N_('Remove selected (Delete)')) self.apply_button = qtutils.create_button( text=N_('Apply'), icon=icons.ok()) self.close_button = qtutils.close_button() self.add_action = qtutils.add_action( self, N_('Add'), self.add_files, hotkeys.ADD_ITEM) self.remove_action = qtutils.add_action( self, N_('Remove'), self.tree.remove_selected, hotkeys.DELETE, hotkeys.BACKSPACE, hotkeys.REMOVE_ITEM) self.top_layout = qtutils.hbox(defs.no_margin, defs.button_spacing, self.add_button, self.remove_button, qtutils.STRETCH, self.usage) self.bottom_layout = qtutils.hbox(defs.no_margin, defs.button_spacing, self.close_button, qtutils.STRETCH, self.apply_button) self.splitter = qtutils.splitter(Qt.Vertical, self.tree, self.diffwidget) self.main_layout = qtutils.vbox(defs.margin, defs.spacing, self.top_layout, self.splitter, self.bottom_layout) self.setLayout(self.main_layout) qtutils.connect_button(self.add_button, self.add_files) qtutils.connect_button(self.remove_button, self.tree.remove_selected) qtutils.connect_button(self.apply_button, self.apply_patches) qtutils.connect_button(self.close_button, self.close) self.init_state(None, self.resize, 666, 420) def apply_patches(self): items = self.tree.items() if not items: return context = self.context patches = [i.data(0, Qt.UserRole) for i in items] cmds.do(cmds.ApplyPatches, context, patches) self.accept() def add_files(self): files = qtutils.open_files(N_('Select patch file(s)...'), directory=self.curdir, filters='Patches (*.patch *.mbox)') if not files: return self.curdir = os.path.dirname(files[0]) self.add_paths([core.relpath(f) for f in files]) def dragEnterEvent(self, event): """Accepts drops if the mimedata contains patches""" super(ApplyPatches, self).dragEnterEvent(event) patches = get_patches_from_mimedata(event.mimeData()) if patches: event.acceptProposedAction() def dropEvent(self, event): """Add dropped patches""" event.accept() patches = get_patches_from_mimedata(event.mimeData()) if not patches: return self.add_paths(patches) def add_paths(self, paths): self.tree.add_paths(paths) def _tree_selection_changed(self): items = self.tree.selected_items() if not items: return item = items[-1] # take the last item path = item.data(0, Qt.UserRole) if not core.exists(path): return commit = parse_patch(path) self.diffwidget.set_details(commit.oid, commit.author, commit.email, commit.date, commit.summary) self.diffwidget.set_diff(commit.diff) def export_state(self): """Export persistent settings""" state = super(ApplyPatches, self).export_state() state['sizes'] = get(self.splitter) return state def apply_state(self, state): """Apply persistent settings""" result = super(ApplyPatches, self).apply_state(state) try: self.splitter.setSizes(state['sizes']) except (AttributeError, KeyError, ValueError, TypeError): pass return result # pylint: disable=too-many-ancestors class PatchTreeWidget(DraggableTreeWidget): def add_paths(self, paths): patches = get_patches_from_paths(paths) if not patches: return items = [] icon = icons.file_text() for patch in patches: item = QtWidgets.QTreeWidgetItem() flags = item.flags() & ~Qt.ItemIsDropEnabled item.setFlags(flags) item.setIcon(0, icon) item.setText(0, os.path.basename(patch)) item.setData(0, Qt.UserRole, patch) item.setToolTip(0, patch) items.append(item) self.addTopLevelItems(items) def remove_selected(self): idxs = self.selectedIndexes() rows = [idx.row() for idx in idxs] for row in reversed(sorted(rows)): self.invisibleRootItem().takeChild(row) class Commit(object): """Container for commit details""" def __init__(self): self.content = '' self.author = '' self.email = '' self.oid = '' self.summary = '' self.diff = '' self.date = '' def parse_patch(path): content = core.read(path) commit = Commit() parse(content, commit) return commit def parse(content, commit): """Parse commit details from a patch""" from_rgx = re.compile(r'^From (?P[a-f0-9]{40}) .*$') author_rgx = re.compile(r'^From: (?P[^<]+) <(?P[^>]+)>$') date_rgx = re.compile(r'^Date: (?P.*)$') subject_rgx = re.compile(r'^Subject: (?P.*)$') commit.content = content lines = content.splitlines() for idx, line in enumerate(lines): match = from_rgx.match(line) if match: commit.oid = match.group('oid') continue match = author_rgx.match(line) if match: commit.author = match.group('author') commit.email = match.group('email') continue match = date_rgx.match(line) if match: commit.date = match.group('date') continue match = subject_rgx.match(line) if match: commit.summary = match.group('summary') commit.diff = '\n'.join(lines[idx + 1:]) break git-cola-3.6/cola/widgets/prefs.py000066400000000000000000000364651356743264500171730ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals import os from qtpy import QtCore from qtpy import QtWidgets from . import defs from . import standard from .. import cmds from .. import hidpi from .. import icons from .. import qtutils from .. import themes from ..compat import ustr from ..i18n import N_ from ..models import prefs from ..models.prefs import Defaults def preferences(context, model=None, parent=None): if model is None: model = prefs.PreferencesModel(context) view = PreferencesView(context, model, parent=parent) view.show() view.raise_() return view class FormWidget(QtWidgets.QWidget): def __init__(self, context, model, parent, source='user'): QtWidgets.QWidget.__init__(self, parent) self.context = context self.cfg = context.cfg self.model = model self.config_to_widget = {} self.widget_to_config = {} self.source = source self.defaults = {} self.setLayout(QtWidgets.QFormLayout()) def add_row(self, label, widget): self.layout().addRow(label, widget) def set_config(self, config_dict): self.config_to_widget.update(config_dict) for config, (widget, default) in config_dict.items(): self.widget_to_config[config] = widget self.defaults[config] = default self.connect_widget_to_config(widget, config) def connect_widget_to_config(self, widget, config): if isinstance(widget, QtWidgets.QSpinBox): widget.valueChanged.connect(self._int_config_changed(config)) elif isinstance(widget, QtWidgets.QCheckBox): widget.toggled.connect(self._bool_config_changed(config)) elif isinstance(widget, QtWidgets.QLineEdit): widget.editingFinished.connect( self._text_config_changed(config, widget)) widget.returnPressed.connect( self._text_config_changed(config, widget)) elif isinstance(widget, qtutils.ComboBox): widget.currentIndexChanged.connect( self._item_config_changed(config, widget)) def _int_config_changed(self, config): def runner(value): cmds.do(prefs.SetConfig, self.model, self.source, config, value) return runner def _bool_config_changed(self, config): def runner(value): cmds.do(prefs.SetConfig, self.model, self.source, config, value) return runner def _text_config_changed(self, config, widget): def runner(): value = widget.text() cmds.do(prefs.SetConfig, self.model, self.source, config, value) return runner def _item_config_changed(self, config, widget): def runner(): value = widget.current_data() cmds.do(prefs.SetConfig, self.model, self.source, config, value) return runner def update_from_config(self): if self.source == 'user': getter = self.cfg.get_user_or_system else: getter = self.cfg.get for config, widget in self.widget_to_config.items(): value = getter(config) if value is None: value = self.defaults[config] set_widget_value(widget, value) def set_widget_value(widget, value): widget.blockSignals(True) if isinstance(widget, QtWidgets.QSpinBox): widget.setValue(value) elif isinstance(widget, QtWidgets.QLineEdit): widget.setText(value) elif isinstance(widget, QtWidgets.QCheckBox): widget.setChecked(value) elif isinstance(widget, qtutils.ComboBox): widget.set_value(value) widget.blockSignals(False) class RepoFormWidget(FormWidget): def __init__(self, context, model, parent, source): FormWidget.__init__(self, context, model, parent, source=source) self.name = QtWidgets.QLineEdit() self.email = QtWidgets.QLineEdit() self.diff_context = standard.SpinBox(value=5, mini=2, maxi=9995) self.merge_verbosity = standard.SpinBox(value=5, maxi=5) self.merge_summary = qtutils.checkbox(checked=True) self.autotemplate = qtutils.checkbox(checked=False) self.merge_diffstat = qtutils.checkbox(checked=True) self.display_untracked = qtutils.checkbox(checked=True) self.show_path = qtutils.checkbox(checked=True) self.tabwidth = standard.SpinBox(value=8, maxi=42) self.textwidth = standard.SpinBox(value=72, maxi=150) tooltip = N_('Detect conflict markers in unmerged files') self.check_conflicts = qtutils.checkbox(checked=True, tooltip=tooltip) tooltip = N_( 'Prevent "Stage" from staging all files when nothing is selected') self.safe_mode = qtutils.checkbox(checked=False, tooltip=tooltip) tooltip = N_('Enable path autocompletion in tools') self.autocomplete_paths = qtutils.checkbox( checked=True, tooltip=tooltip) self.add_row(N_('User Name'), self.name) self.add_row(N_('Email Address'), self.email) self.add_row(N_('Tab Width'), self.tabwidth) self.add_row(N_('Text Width'), self.textwidth) self.add_row(N_('Merge Verbosity'), self.merge_verbosity) self.add_row(N_('Number of Diff Context Lines'), self.diff_context) self.add_row(N_('Summarize Merge Commits'), self.merge_summary) self.add_row(N_('Automatically Load Commit Message Template'), self.autotemplate) self.add_row(N_('Show Full Paths in the Window Title'), self.show_path) self.add_row(N_('Show Diffstat After Merge'), self.merge_diffstat) self.add_row(N_('Display Untracked Files'), self.display_untracked) self.add_row(N_('Detect Conflict Markers'), self.check_conflicts) self.add_row(N_('Safe Mode'), self.safe_mode) self.add_row(N_('Autocomplete Paths'), self.autocomplete_paths) self.set_config({ prefs.AUTOTEMPLATE: (self.autotemplate, Defaults.autotemplate), prefs.CHECKCONFLICTS: (self.check_conflicts, Defaults.check_conflicts), prefs.DIFFCONTEXT: (self.diff_context, Defaults.diff_context), prefs.DISPLAY_UNTRACKED: (self.display_untracked, Defaults.display_untracked), prefs.USER_NAME: (self.name, ''), prefs.USER_EMAIL: (self.email, ''), prefs.MERGE_DIFFSTAT: (self.merge_diffstat, Defaults.merge_diffstat), prefs.MERGE_SUMMARY: (self.merge_summary, Defaults.merge_summary), prefs.MERGE_VERBOSITY: (self.merge_verbosity, Defaults.merge_verbosity), prefs.SAFE_MODE: (self.safe_mode, Defaults.safe_mode), prefs.AUTOCOMPLETE_PATHS: ( self.autocomplete_paths, Defaults.autocomplete_paths), prefs.SHOW_PATH: (self.show_path, Defaults.show_path), prefs.TABWIDTH: (self.tabwidth, Defaults.tabwidth), prefs.TEXTWIDTH: (self.textwidth, Defaults.textwidth), }) class SettingsFormWidget(FormWidget): def __init__(self, context, model, parent): FormWidget.__init__(self, context, model, parent) self.fixed_font = QtWidgets.QFontComboBox() self.font_size = standard.SpinBox(value=12, mini=8, maxi=192) self.maxrecent = standard.SpinBox(maxi=99) self.tabwidth = standard.SpinBox(maxi=42) self.textwidth = standard.SpinBox(maxi=150) self.editor = QtWidgets.QLineEdit() self.historybrowser = QtWidgets.QLineEdit() self.blameviewer = QtWidgets.QLineEdit() self.difftool = QtWidgets.QLineEdit() self.mergetool = QtWidgets.QLineEdit() self.linebreak = qtutils.checkbox() self.keep_merge_backups = qtutils.checkbox() self.sort_bookmarks = qtutils.checkbox() self.save_window_settings = qtutils.checkbox() self.check_spelling = qtutils.checkbox() self.expandtab = qtutils.checkbox() self.add_row(N_('Fixed-Width Font'), self.fixed_font) self.add_row(N_('Font Size'), self.font_size) self.add_row(N_('Editor'), self.editor) self.add_row(N_('History Browser'), self.historybrowser) self.add_row(N_('Blame Viewer'), self.blameviewer) self.add_row(N_('Diff Tool'), self.difftool) self.add_row(N_('Merge Tool'), self.mergetool) self.add_row(N_('Recent repository count'), self.maxrecent) self.add_row(N_('Auto-Wrap Lines'), self.linebreak) self.add_row(N_('Insert spaces instead of tabs'), self.expandtab) self.add_row(N_('Sort bookmarks alphabetically'), self.sort_bookmarks) self.add_row(N_('Keep *.orig Merge Backups'), self.keep_merge_backups) self.add_row(N_('Save GUI Settings'), self.save_window_settings) self.add_row(N_('Check spelling'), self.check_spelling) self.set_config({ prefs.SAVEWINDOWSETTINGS: (self.save_window_settings, Defaults.save_window_settings), prefs.TABWIDTH: (self.tabwidth, Defaults.tabwidth), prefs.EXPANDTAB: (self.expandtab, Defaults.expandtab), prefs.TEXTWIDTH: (self.textwidth, Defaults.textwidth), prefs.LINEBREAK: (self.linebreak, Defaults.linebreak), prefs.MAXRECENT: (self.maxrecent, Defaults.maxrecent), prefs.SORT_BOOKMARKS: (self.sort_bookmarks, Defaults.sort_bookmarks), prefs.DIFFTOOL: (self.difftool, Defaults.difftool), prefs.EDITOR: (self.editor, os.getenv('VISUAL', Defaults.editor)), prefs.HISTORY_BROWSER: (self.historybrowser, prefs.default_history_browser()), prefs.BLAME_VIEWER: (self.blameviewer, Defaults.blame_viewer), prefs.MERGE_KEEPBACKUP: (self.keep_merge_backups, Defaults.merge_keep_backup), prefs.MERGETOOL: (self.mergetool, Defaults.mergetool), prefs.SPELL_CHECK: (self.check_spelling, Defaults.spellcheck), }) # pylint: disable=no-member self.fixed_font.currentFontChanged.connect(self.current_font_changed) self.font_size.valueChanged.connect(self.font_size_changed) def update_from_config(self): FormWidget.update_from_config(self) context = self.context block = self.fixed_font.blockSignals(True) font = qtutils.diff_font(context) self.fixed_font.setCurrentFont(font) self.fixed_font.blockSignals(block) block = self.font_size.blockSignals(True) font_size = font.pointSize() self.font_size.setValue(font_size) self.font_size.blockSignals(block) def font_size_changed(self, size): font = self.fixed_font.currentFont() font.setPointSize(size) cmds.do(prefs.SetConfig, self.model, 'user', prefs.FONTDIFF, font.toString()) def current_font_changed(self, font): cmds.do(prefs.SetConfig, self.model, 'user', prefs.FONTDIFF, font.toString()) class AppearanceFormWidget(FormWidget): def __init__(self, context, model, parent): FormWidget.__init__(self, context, model, parent) # Theme selectors self.theme = qtutils.combo_mapped(themes.options()) self.icon_theme = qtutils.combo_mapped(icons.icon_themes()) # The transform to ustr is needed because the config reader will convert # "0", "1", and "2" into integers. The "1.5" value, though, is # parsed as a string, so the transform is effectively a no-op. self.high_dpi = qtutils.combo_mapped(hidpi.options(), transform=ustr) self.high_dpi.setEnabled(hidpi.is_supported()) self.bold_headers = qtutils.checkbox() self.status_show_totals = qtutils.checkbox() self.status_indent = qtutils.checkbox() self.add_row(N_('GUI theme'), self.theme) self.add_row(N_('Icon theme'), self.icon_theme) self.add_row(N_('High DPI'), self.high_dpi) self.add_row(N_('Bold on dark headers instead of italic'), self.bold_headers) self.add_row(N_('Show file counts in Status titles'), self.status_show_totals) self.add_row(N_('Indent Status paths'), self.status_indent) self.set_config({ prefs.BOLD_HEADERS: (self.bold_headers, Defaults.bold_headers), prefs.HIDPI: (self.high_dpi, Defaults.hidpi), prefs.STATUS_SHOW_TOTALS: (self.status_show_totals, Defaults.status_show_totals), prefs.STATUS_INDENT: (self.status_indent, Defaults.status_indent), prefs.THEME: (self.theme, Defaults.theme), prefs.ICON_THEME: (self.icon_theme, Defaults.icon_theme), }) class AppearanceWidget(QtWidgets.QWidget): def __init__(self, form, parent): QtWidgets.QWidget.__init__(self, parent) self.form = form self.label = QtWidgets.QLabel( '
' + N_('Restart the application after changing appearance settings.') + '
') layout = qtutils.vbox(defs.margin, defs.spacing, self.form, defs.spacing * 4, self.label, qtutils.STRETCH) self.setLayout(layout) def update_from_config(self): self.form.update_from_config() class PreferencesView(standard.Dialog): def __init__(self, context, model, parent=None): standard.Dialog.__init__(self, parent=parent) self.context = context self.setWindowTitle(N_('Preferences')) if parent is not None: self.setWindowModality(QtCore.Qt.WindowModal) self.resize(600, 360) self.tab_bar = QtWidgets.QTabBar() self.tab_bar.setDrawBase(False) self.tab_bar.addTab(N_('All Repositories')) self.tab_bar.addTab(N_('Current Repository')) self.tab_bar.addTab(N_('Settings')) self.tab_bar.addTab(N_('Appearance')) self.user_form = RepoFormWidget(context, model, self, source='user') self.repo_form = RepoFormWidget(context, model, self, source='repo') self.options_form = SettingsFormWidget(context, model, self) self.appearance_form = AppearanceFormWidget(context, model, self) self.appearance = AppearanceWidget(self.appearance_form, self) self.stack_widget = QtWidgets.QStackedWidget() self.stack_widget.addWidget(self.user_form) self.stack_widget.addWidget(self.repo_form) self.stack_widget.addWidget(self.options_form) self.stack_widget.addWidget(self.appearance) self.close_button = qtutils.close_button() self.button_layout = qtutils.hbox(defs.no_margin, defs.spacing, qtutils.STRETCH, self.close_button) self.main_layout = qtutils.vbox(defs.margin, defs.spacing, self.tab_bar, self.stack_widget, self.button_layout) self.setLayout(self.main_layout) # pylint: disable=no-member self.tab_bar.currentChanged.connect(self.stack_widget.setCurrentIndex) self.stack_widget.currentChanged.connect(self.update_widget) qtutils.connect_button(self.close_button, self.accept) qtutils.add_close_action(self) self.update_widget(0) def update_widget(self, idx): widget = self.stack_widget.widget(idx) widget.update_from_config() git-cola-3.6/cola/widgets/recent.py000066400000000000000000000120131356743264500173130ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals from qtpy import QtCore from qtpy import QtWidgets from qtpy.QtCore import Qt from qtpy.QtCore import Signal from ..i18n import N_ from ..qtutils import get from .. import cmds from .. import gitcmds from .. import hotkeys from .. import icons from .. import qtutils from .browse import GitTreeWidget from .browse import GitFileTreeModel from . import defs from . import standard def browse_recent_files(context): dialog = RecentFiles(context, parent=qtutils.active_window()) dialog.show() return dialog class UpdateFileListThread(QtCore.QThread): result = Signal(object) def __init__(self, context, count): QtCore.QThread.__init__(self) self.context = context self.count = count def run(self): context = self.context ref = 'HEAD~%d' % self.count filenames = gitcmds.diff_index_filenames(context, ref) self.result.emit(filenames) class RecentFiles(standard.Dialog): def __init__(self, context, parent=None): standard.Dialog.__init__(self, parent=parent) self.context = context self.setWindowTitle(N_('Recently Modified Files')) if parent is not None: self.setWindowModality(Qt.WindowModal) count = 8 self.update_thread = UpdateFileListThread(context, count) self.count = standard.SpinBox(value=count, maxi=10000, suffix=N_(' commits ago')) self.count_label = QtWidgets.QLabel() self.count_label.setText(N_('Showing changes since')) self.refresh_button = qtutils.refresh_button(enabled=False) self.tree = GitTreeWidget(parent=self) self.tree_model = GitFileTreeModel(self) self.tree.setModel(self.tree_model) self.expand_button = qtutils.create_button(text=N_('Expand all'), icon=icons.unfold()) self.collapse_button = qtutils.create_button(text=N_('Collapse all'), icon=icons.fold()) self.edit_button = qtutils.edit_button(enabled=False, default=True) self.close_button = qtutils.close_button() self.top_layout = qtutils.hbox(defs.no_margin, defs.spacing, self.count_label, self.count, qtutils.STRETCH, self.refresh_button) self.button_layout = qtutils.hbox(defs.no_margin, defs.spacing, self.close_button, qtutils.STRETCH, self.expand_button, self.collapse_button, self.edit_button) self.main_layout = qtutils.vbox(defs.margin, defs.spacing, self.top_layout, self.tree, self.button_layout) self.setLayout(self.main_layout) # pylint: disable=no-member self.tree.selection_changed.connect(self.tree_selection_changed) self.tree.path_chosen.connect(self.edit_file) self.count.valueChanged.connect(self.count_changed) self.count.editingFinished.connect(self.refresh) thread = self.update_thread thread.result.connect(self.set_filenames, type=Qt.QueuedConnection) qtutils.connect_button(self.refresh_button, self.refresh) qtutils.connect_button(self.expand_button, self.tree.expandAll) qtutils.connect_button(self.collapse_button, self.tree.collapseAll) qtutils.connect_button(self.close_button, self.accept) qtutils.connect_button(self.edit_button, self.edit_selected) qtutils.add_action(self, N_('Refresh'), self.refresh, hotkeys.REFRESH) self.update_thread.start() self.init_size(parent=parent) def edit_selected(self): filenames = self.tree.selected_files() if not filenames: return self.edit_files(filenames) def edit_files(self, filenames): cmds.do(cmds.Edit, self.context, filenames) def edit_file(self, filename): self.edit_files([filename]) def refresh(self): self.refresh_button.setEnabled(False) self.count.setEnabled(False) self.tree_model.clear() self.tree.setEnabled(False) self.update_thread.count = get(self.count) self.update_thread.start() def count_changed(self, _value): self.refresh_button.setEnabled(True) def tree_selection_changed(self): """Update actions based on the current selection""" filenames = self.tree.selected_files() self.edit_button.setEnabled(bool(filenames)) def set_filenames(self, filenames): self.count.setEnabled(True) self.tree.setEnabled(True) self.tree_model.clear() self.tree_model.add_files(filenames) self.tree.expandAll() self.tree.select_first_file() self.tree.setFocus() git-cola-3.6/cola/widgets/remote.py000066400000000000000000000614211356743264500173350ustar00rootroot00000000000000"""Widgets for Fetch, Push, and Pull""" from __future__ import division, absolute_import, unicode_literals import fnmatch from qtpy import QtGui from qtpy import QtWidgets from qtpy.QtCore import Qt from ..i18n import N_ from ..interaction import Interaction from ..qtutils import connect_button from ..qtutils import get from .. import gitcmds from .. import icons from .. import qtutils from .. import utils from . import defs from . import standard FETCH = 'FETCH' PUSH = 'PUSH' PULL = 'PULL' def fetch(context): """Fetch from remote repositories""" return run(context, Fetch) def push(context): """Push to remote repositories""" return run(context, Push) def pull(context): """Pull from remote repositories""" return run(context, Pull) def run(context, RemoteDialog): """Launches fetch/push/pull dialogs.""" # Copy global stuff over to speedup startup parent = qtutils.active_window() view = RemoteDialog(context, parent=parent) view.show() return view def combine(result, prev): """Combine multiple (status, out, err) tuples into a combined tuple The current state is passed in via `prev`. The status code is a max() over all the subprocess status codes. Individual (out, err) strings are sequentially concatenated together. """ if isinstance(prev, (tuple, list)): if len(prev) != 3: raise AssertionError('combine() with length %d' % len(prev)) combined = (max(prev[0], result[0]), combine(prev[1], result[1]), combine(prev[2], result[2])) elif prev and result: combined = prev + '\n\n' + result elif prev: combined = prev else: combined = result return combined def uncheck(value, *checkboxes): """Uncheck the specified checkboxes if value is True""" if value: for checkbox in checkboxes: checkbox.setChecked(False) def strip_remotes(remote_branches): """Strip the / prefixes from branches e.g. "origin/master" becomes "master". """ branches = [utils.strip_one(branch) for branch in remote_branches] return [branch for branch in branches if branch != 'HEAD'] class ActionTask(qtutils.Task): """Run actions asynchronously""" def __init__(self, parent, model_action, remote, kwargs): qtutils.Task.__init__(self, parent) self.model_action = model_action self.remote = remote self.kwargs = kwargs def task(self): """Runs the model action and captures the result""" return self.model_action(self.remote, **self.kwargs) class RemoteActionDialog(standard.Dialog): """Interface for performing remote operations""" def __init__(self, context, action, title, parent=None, icon=None): """Customize the dialog based on the remote action""" standard.Dialog.__init__(self, parent=parent) self.setWindowTitle(title) if parent is not None: self.setWindowModality(Qt.WindowModal) self.context = context self.model = model = context.model self.action = action self.filtered_remote_branches = [] self.selected_remotes = [] self.runtask = qtutils.RunTask(parent=self) self.progress = standard.progress(title, N_('Updating'), self) self.local_label = QtWidgets.QLabel() self.local_label.setText(N_('Local Branch')) self.local_branch = QtWidgets.QLineEdit() qtutils.add_completer(self.local_branch, model.local_branches) self.local_branches = QtWidgets.QListWidget() self.local_branches.addItems(model.local_branches) self.remote_label = QtWidgets.QLabel() self.remote_label.setText(N_('Remote')) self.remote_name = QtWidgets.QLineEdit() qtutils.add_completer(self.remote_name, model.remotes) # pylint: disable=no-member self.remote_name.editingFinished.connect(self.remote_name_edited) self.remote_name.textEdited.connect(lambda x: self.remote_name_edited()) self.remotes = QtWidgets.QListWidget() if action == PUSH: mode = QtWidgets.QAbstractItemView.ExtendedSelection self.remotes.setSelectionMode(mode) self.remotes.addItems(model.remotes) self.remote_branch_label = QtWidgets.QLabel() self.remote_branch_label.setText(N_('Remote Branch')) self.remote_branch = QtWidgets.QLineEdit() remote_branches = strip_remotes(model.remote_branches) qtutils.add_completer(self.remote_branch, remote_branches) self.remote_branches = QtWidgets.QListWidget() self.remote_branches.addItems(model.remote_branches) text = N_('Prompt on creation') tooltip = N_('Prompt when pushing creates new remote branches') self.prompt_checkbox = qtutils.checkbox(checked=True, text=text, tooltip=tooltip) text = N_('Fast-forward only') tooltip = N_('Refuse to merge unless the current HEAD is already up-' 'to-date or the merge can be resolved as a fast-forward') self.ff_only_checkbox = qtutils.checkbox(checked=True, text=text, tooltip=tooltip) text = N_('No fast-forward') tooltip = N_('Create a merge commit even when the merge resolves as a ' 'fast-forward') self.no_ff_checkbox = qtutils.checkbox(checked=False, text=text, tooltip=tooltip) text = N_('Force') tooltip = N_('Allow non-fast-forward updates. Using "force" can ' 'cause the remote repository to lose commits; ' 'use it with care') self.force_checkbox = qtutils.checkbox(checked=False, text=text, tooltip=tooltip) self.tags_checkbox = qtutils.checkbox(text=N_('Include tags ')) tooltip = N_('Remove remote-tracking branches that no longer ' 'exist on the remote') self.prune_checkbox = qtutils.checkbox(text=N_('Prune '), tooltip=tooltip) tooltip = N_('Rebase the current branch instead of merging') self.rebase_checkbox = qtutils.checkbox(text=N_('Rebase'), tooltip=tooltip) text = N_('Set upstream') tooltip = N_('Configure the remote branch as the the new upstream') self.upstream_checkbox = qtutils.checkbox(text=text, tooltip=tooltip) self.action_button = qtutils.ok_button(title, icon=icon) self.close_button = qtutils.close_button() self.buttons = utils.Group(self.action_button, self.close_button) self.local_branch_layout = qtutils.hbox( defs.small_margin, defs.spacing, self.local_label, self.local_branch) self.remote_layout = qtutils.hbox( defs.small_margin, defs.spacing, self.remote_label, self.remote_name) self.remote_branch_layout = qtutils.hbox( defs.small_margin, defs.spacing, self.remote_branch_label, self.remote_branch) self.options_layout = qtutils.hbox( defs.no_margin, defs.button_spacing, self.close_button, qtutils.STRETCH, self.force_checkbox, self.ff_only_checkbox, self.no_ff_checkbox, self.tags_checkbox, self.prune_checkbox, self.rebase_checkbox, self.upstream_checkbox, self.prompt_checkbox, self.action_button) self.remote_input_layout = qtutils.vbox( defs.no_margin, defs.spacing, self.remote_layout, self.remotes) self.local_branch_input_layout = qtutils.vbox( defs.no_margin, defs.spacing, self.local_branch_layout, self.local_branches) self.remote_branch_input_layout = qtutils.vbox( defs.no_margin, defs.spacing, self.remote_branch_layout, self.remote_branches) if action == PUSH: widgets = ( self.remote_input_layout, self.local_branch_input_layout, self.remote_branch_input_layout) else: # fetch and pull widgets = ( self.remote_input_layout, self.remote_branch_input_layout, self.local_branch_input_layout) self.top_layout = qtutils.hbox(defs.no_margin, defs.spacing, *widgets) self.main_layout = qtutils.vbox( defs.margin, defs.spacing, self.top_layout, self.options_layout) self.setLayout(self.main_layout) default_remote = gitcmds.upstream_remote(context) or 'origin' remotes = model.remotes if default_remote in remotes: idx = remotes.index(default_remote) if self.select_remote(idx): self.set_remote_name(default_remote) else: if self.select_first_remote(): self.set_remote_name(remotes[0]) # Trim the remote list to just the default remote self.update_remotes() self.set_field_defaults() # Setup signals and slots # pylint: disable=no-member self.remotes.itemSelectionChanged.connect(self.update_remotes) local = self.local_branches local.itemSelectionChanged.connect(self.update_local_branches) remote = self.remote_branches remote.itemSelectionChanged.connect(self.update_remote_branches) self.no_ff_checkbox.toggled.connect( lambda x: uncheck(x, self.ff_only_checkbox, self.rebase_checkbox)) self.ff_only_checkbox.toggled.connect( lambda x: uncheck(x, self.no_ff_checkbox, self.rebase_checkbox)) self.rebase_checkbox.toggled.connect( lambda x: uncheck(x, self.no_ff_checkbox, self.ff_only_checkbox)) connect_button(self.action_button, self.action_callback) connect_button(self.close_button, self.close) qtutils.add_action(self, N_('Close'), self.close, QtGui.QKeySequence.Close, 'Esc') if action != FETCH: self.prune_checkbox.hide() if action != PUSH: # Push-only options self.upstream_checkbox.hide() self.prompt_checkbox.hide() if action == PULL: # Fetch and Push-only options self.force_checkbox.hide() self.tags_checkbox.hide() self.local_label.hide() self.local_branch.hide() self.local_branches.hide() else: # Pull-only options self.rebase_checkbox.hide() self.no_ff_checkbox.hide() self.ff_only_checkbox.hide() self.init_size(parent=parent) def set_rebase(self, value): """Check the rebase checkbox""" self.rebase_checkbox.setChecked(value) def set_field_defaults(self): """Set sensible initial defaults""" # Default to "git fetch origin master" action = self.action if action in (FETCH, PULL): self.local_branch.setText('') self.remote_branch.setText('') return # Select the current branch by default for push if action == PUSH: branch = self.model.currentbranch try: idx = self.model.local_branches.index(branch) except ValueError: return if self.select_local_branch(idx): self.set_local_branch(branch) self.set_remote_branch('') def set_remote_name(self, remote_name): """Set the remote name""" self.remote_name.setText(remote_name) def set_local_branch(self, branch): """Set the local branch name""" self.local_branch.setText(branch) if branch: self.local_branch.selectAll() def set_remote_branch(self, branch): """Set the remote branch name""" self.remote_branch.setText(branch) if branch: self.remote_branch.selectAll() def set_remote_branches(self, branches): """Set the list of remote branches""" self.remote_branches.clear() self.remote_branches.addItems(branches) self.filtered_remote_branches = branches qtutils.add_completer(self.remote_branch, strip_remotes(branches)) def select_first_remote(self): """Select the first remote in the list view""" return self.select_remote(0) def select_remote(self, idx): """Select a remote by index""" item = self.remotes.item(idx) if item: item.setSelected(True) self.remotes.setCurrentItem(item) self.set_remote_name(item.text()) result = True else: result = False return result def select_remote_by_name(self, remote): """Select a remote by name""" remotes = self.model.remotes if remote in remotes: idx = remotes.index(remote) result = self.select_remote(idx) else: result = False return result def set_selected_remotes(self, remotes): """Set the list of selected remotes Return True if all remotes were found and selected. """ # Invalid remote names are ignored. # This handles a remote going away between sessions. # The selection is unchanged when none of the specified remotes exist. found = False for remote in remotes: if remote in self.model.remotes: found = True break if found: # Only clear the selection if the specified remotes exist self.remotes.clearSelection() found = all([self.select_remote_by_name(x) for x in remotes]) return found def select_local_branch(self, idx): """Selects a local branch by index in the list view""" item = self.local_branches.item(idx) if item: item.setSelected(True) self.local_branches.setCurrentItem(item) self.local_branch.setText(item.text()) result = True else: result = False return result def display_remotes(self, widget): """Display the available remotes in a listwidget""" displayed = [] for remote_name in self.model.remotes: url = self.model.remote_url(remote_name, self.action) display = ('%s\t(%s)' % (remote_name, N_('URL: %s') % url)) displayed.append(display) qtutils.set_items(widget, displayed) def update_remotes(self): """Update the remote name when a remote from the list is selected""" widget = self.remotes remotes = self.model.remotes selection = qtutils.selected_item(widget, remotes) if not selection: self.selected_remotes = [] return self.set_remote_name(selection) self.selected_remotes = qtutils.selected_items(self.remotes, self.model.remotes) self.set_remote_to(selection, self.selected_remotes) def set_remote_to(self, _remote, selected_remotes): context = self.context all_branches = gitcmds.branch_list(context, remote=True) branches = [] patterns = [] for remote_name in selected_remotes: patterns.append(remote_name + '/*') for branch in all_branches: for pat in patterns: if fnmatch.fnmatch(branch, pat): branches.append(branch) break if branches: self.set_remote_branches(branches) else: self.set_remote_branches(all_branches) self.set_remote_branch('') def remote_name_edited(self): """Update the current remote when the remote name is typed manually""" remote = self.remote_name.text() self.set_remote_to(remote, [remote]) def update_local_branches(self): """Update the local/remote branch names when a branch is selected""" branches = self.model.local_branches widget = self.local_branches selection = qtutils.selected_item(widget, branches) if not selection: return self.set_local_branch(selection) self.set_remote_branch(selection) def update_remote_branches(self): """Update the remote branch name when a branch is selected""" widget = self.remote_branches branches = self.filtered_remote_branches selection = qtutils.selected_item(widget, branches) if not selection: return branch = utils.strip_one(selection) if branch == 'HEAD': return self.set_remote_branch(branch) def common_args(self): """Returns git arguments common to fetch/push/pull""" remote_name = self.remote_name.text() local_branch = self.local_branch.text() remote_branch = self.remote_branch.text() ff_only = get(self.ff_only_checkbox) force = get(self.force_checkbox) no_ff = get(self.no_ff_checkbox) rebase = get(self.rebase_checkbox) set_upstream = get(self.upstream_checkbox) tags = get(self.tags_checkbox) prune = get(self.prune_checkbox) return (remote_name, { 'ff_only': ff_only, 'force': force, 'local_branch': local_branch, 'no_ff': no_ff, 'rebase': rebase, 'remote_branch': remote_branch, 'set_upstream': set_upstream, 'tags': tags, 'prune': prune, }) # Actions def push_to_all(self, _remote, *args, **kwargs): """Push to all selected remotes""" selected_remotes = self.selected_remotes all_results = None for remote in selected_remotes: result = self.model.push(remote, *args, **kwargs) all_results = combine(result, all_results) return all_results def action_callback(self): """Perform the actual fetch/push/pull operation""" action = self.action if action == FETCH: model_action = self.model.fetch elif action == PUSH: model_action = self.push_to_all else: # if action == PULL: model_action = self.model.pull remote_name = self.remote_name.text() if not remote_name: errmsg = N_('No repository selected.') Interaction.log(errmsg) return remote, kwargs = self.common_args() self.selected_remotes = qtutils.selected_items(self.remotes, self.model.remotes) # Check if we're about to create a new branch and warn. remote_branch = self.remote_branch.text() local_branch = self.local_branch.text() if action == PUSH and not remote_branch: branch = local_branch candidate = '%s/%s' % (remote, branch) prompt = get(self.prompt_checkbox) if prompt and candidate not in self.model.remote_branches: title = N_('Push') args = dict(branch=branch, remote=remote) msg = N_('Branch "%(branch)s" does not exist in "%(remote)s".\n' 'A new remote branch will be published.') % args info_txt = N_('Create a new remote branch?') ok_text = N_('Create Remote Branch') if not Interaction.confirm(title, msg, info_txt, ok_text, icon=icons.cola()): return if get(self.force_checkbox): if action == FETCH: title = N_('Force Fetch?') msg = N_('Non-fast-forward fetch overwrites local history!') info_txt = N_('Force fetching from %s?') % remote ok_text = N_('Force Fetch') elif action == PUSH: title = N_('Force Push?') msg = N_('Non-fast-forward push overwrites published ' 'history!\n(Did you pull first?)') info_txt = N_('Force push to %s?') % remote ok_text = N_('Force Push') else: # pull: shouldn't happen since the controls are hidden return if not Interaction.confirm(title, msg, info_txt, ok_text, default=False, icon=icons.discard()): return # Disable the GUI by default self.buttons.setEnabled(False) # Use a thread to update in the background task = ActionTask(self, model_action, remote, kwargs) self.runtask.start(task, progress=self.progress, finish=self.action_completed) def action_completed(self, task): """Grab the results of the action and finish up""" status, out, err = task.result self.buttons.setEnabled(True) command = 'git %s' % self.action.lower() message = Interaction.format_command_status(command, status) details = Interaction.format_out_err(out, err) log_message = message if details: log_message += '\n\n' + details Interaction.log(log_message) if status == 0: self.accept() return if self.action == PUSH: message += '\n\n' message += N_('Have you rebased/pulled lately?') Interaction.critical(self.windowTitle(), message=message, details=details) # Use distinct classes so that each saves its own set of preferences class Fetch(RemoteActionDialog): """Fetch from remote repositories""" def __init__(self, context, parent=None): super(Fetch, self).__init__( context, FETCH, N_('Fetch'), parent=parent, icon=icons.repo()) def export_state(self): """Export persistent settings""" state = RemoteActionDialog.export_state(self) state['tags'] = get(self.tags_checkbox) state['prune'] = get(self.prune_checkbox) return state def apply_state(self, state): """Apply persistent settings""" result = RemoteActionDialog.apply_state(self, state) tags = bool(state.get('tags', False)) self.tags_checkbox.setChecked(tags) prune = bool(state.get('prune', False)) self.prune_checkbox.setChecked(prune) return result class Push(RemoteActionDialog): """Push to remote repositories""" def __init__(self, context, parent=None): super(Push, self).__init__( context, PUSH, N_('Push'), parent=parent, icon=icons.push()) def export_state(self): """Export persistent settings""" state = RemoteActionDialog.export_state(self) state['prompt'] = get(self.prompt_checkbox) state['tags'] = get(self.tags_checkbox) return state def apply_state(self, state): """Apply persistent settings""" result = RemoteActionDialog.apply_state(self, state) # Restore the "prompt on creation" checkbox prompt = bool(state.get('prompt', True)) self.prompt_checkbox.setChecked(prompt) # Restore the "tags" checkbox tags = bool(state.get('tags', False)) self.tags_checkbox.setChecked(tags) return result class Pull(RemoteActionDialog): """Pull from remote repositories""" def __init__(self, context, parent=None): super(Pull, self).__init__( context, PULL, N_('Pull'), parent=parent, icon=icons.pull()) def apply_state(self, state): """Apply persistent settings""" result = RemoteActionDialog.apply_state(self, state) # Rebase has the highest priority rebase = bool(state.get('rebase', False)) ff_only = not rebase and bool(state.get('ff_only', False)) no_ff = not rebase and not ff_only and bool(state.get('no_ff', False)) self.rebase_checkbox.setChecked(rebase) self.no_ff_checkbox.setChecked(no_ff) # Allow users coming from older versions that have rebase=False to # pickup the new ff_only=True default by only setting ff_only False # when it either exists in the config or when rebase=True. if 'ff_only' in state or rebase: self.ff_only_checkbox.setChecked(ff_only) return result def export_state(self): """Export persistent settings""" state = RemoteActionDialog.export_state(self) state['ff_only'] = get(self.ff_only_checkbox) state['no_ff'] = get(self.no_ff_checkbox) state['rebase'] = get(self.rebase_checkbox) return state git-cola-3.6/cola/widgets/search.py000066400000000000000000000266251356743264500173160ustar00rootroot00000000000000"""A widget for searching git commits""" from __future__ import division, absolute_import, unicode_literals import time from qtpy import QtCore from qtpy import QtWidgets from qtpy.QtCore import Qt from ..i18n import N_ from ..interaction import Interaction from ..git import STDOUT from ..qtutils import connect_button from ..qtutils import create_toolbutton from ..qtutils import get from .. import core from .. import gitcmds from .. import icons from .. import utils from .. import qtutils from . import diff from . import defs from . import standard def mkdate(timespec): return '%04d-%02d-%02d' % time.localtime(timespec)[:3] class SearchOptions(object): def __init__(self): self.query = '' self.max_count = 500 self.start_date = '' self.end_date = '' class SearchWidget(standard.Dialog): def __init__(self, context, parent): standard.Dialog.__init__(self, parent) self.context = context self.setWindowTitle(N_('Search')) self.mode_combo = QtWidgets.QComboBox() self.browse_button = create_toolbutton(icon=icons.folder(), tooltip=N_('Browse...')) self.query = QtWidgets.QLineEdit() self.start_date = QtWidgets.QDateEdit() self.start_date.setCurrentSection(QtWidgets.QDateTimeEdit.YearSection) self.start_date.setCalendarPopup(True) self.start_date.setDisplayFormat(N_('yyyy-MM-dd')) self.end_date = QtWidgets.QDateEdit() self.end_date.setCurrentSection(QtWidgets.QDateTimeEdit.YearSection) self.end_date.setCalendarPopup(True) self.end_date.setDisplayFormat(N_('yyyy-MM-dd')) icon = icons.search() self.search_button = qtutils.create_button(text=N_('Search'), icon=icon, default=True) self.max_count = standard.SpinBox(value=500, mini=5, maxi=9995, step=5) self.commit_list = QtWidgets.QListWidget() self.commit_list.setMinimumSize(QtCore.QSize(1, 1)) self.commit_list.setAlternatingRowColors(True) selection_mode = QtWidgets.QAbstractItemView.SingleSelection self.commit_list.setSelectionMode(selection_mode) self.commit_text = diff.DiffTextEdit(context, self, whitespace=False) self.button_export = qtutils.create_button(text=N_('Export Patches'), icon=icons.diff()) self.button_cherrypick = qtutils.create_button(text=N_('Cherry Pick'), icon=icons.save()) self.button_close = qtutils.close_button() self.top_layout = qtutils.hbox(defs.no_margin, defs.button_spacing, self.query, self.start_date, self.end_date, self.browse_button, self.search_button, qtutils.STRETCH, self.mode_combo, self.max_count) self.splitter = qtutils.splitter(Qt.Vertical, self.commit_list, self.commit_text) self.bottom_layout = qtutils.hbox(defs.no_margin, defs.spacing, self.button_close, qtutils.STRETCH, self.button_export, self.button_cherrypick) self.main_layout = qtutils.vbox(defs.margin, defs.spacing, self.top_layout, self.splitter, self.bottom_layout) self.setLayout(self.main_layout) self.init_size(parent=parent) def search(context): """Return a callback to handle various search actions.""" return search_commits(context, qtutils.active_window()) class SearchEngine(object): def __init__(self, context, model): self.context = context self.model = model def rev_args(self): max_count = self.model.max_count return { 'no_color': True, 'max-count': max_count, 'pretty': 'format:%H %aN - %s - %ar', } def common_args(self): return (self.model.query, self.rev_args()) def search(self): if self.validate(): return self.results() return [] def validate(self): return len(self.model.query) > 1 def revisions(self, *args, **kwargs): git = self.context.git revlist = git.log(*args, **kwargs)[STDOUT] return gitcmds.parse_rev_list(revlist) def results(self): pass class RevisionSearch(SearchEngine): def results(self): query, opts = self.common_args() args = utils.shell_split(query) return self.revisions(*args, **opts) class PathSearch(SearchEngine): def results(self): query, args = self.common_args() paths = ['--'] + utils.shell_split(query) return self.revisions(all=True, *paths, **args) class MessageSearch(SearchEngine): def results(self): query, kwargs = self.common_args() return self.revisions(all=True, grep=query, **kwargs) class AuthorSearch(SearchEngine): def results(self): query, kwargs = self.common_args() return self.revisions(all=True, author=query, **kwargs) class CommitterSearch(SearchEngine): def results(self): query, kwargs = self.common_args() return self.revisions(all=True, committer=query, **kwargs) class DiffSearch(SearchEngine): def results(self): git = self.context.git query, kwargs = self.common_args() return gitcmds.parse_rev_list( git.log('-S'+query, all=True, **kwargs)[STDOUT]) class DateRangeSearch(SearchEngine): def validate(self): return self.model.start_date < self.model.end_date def results(self): kwargs = self.rev_args() start_date = self.model.start_date end_date = self.model.end_date return self.revisions(date='iso', all=True, after=start_date, before=end_date, **kwargs) class Search(SearchWidget): def __init__(self, context, model, parent): """ Search diffs and commit logs :param model: SearchOptions instance """ SearchWidget.__init__(self, context, parent) self.model = model self.EXPR = N_('Search by Expression') self.PATH = N_('Search by Path') self.MESSAGE = N_('Search Commit Messages') self.DIFF = N_('Search Diffs') self.AUTHOR = N_('Search Authors') self.COMMITTER = N_('Search Committers') self.DATE_RANGE = N_('Search Date Range') self.results = [] # Each search type is handled by a distinct SearchEngine subclass self.engines = { self.EXPR: RevisionSearch, self.PATH: PathSearch, self.MESSAGE: MessageSearch, self.DIFF: DiffSearch, self.AUTHOR: AuthorSearch, self.COMMITTER: CommitterSearch, self.DATE_RANGE: DateRangeSearch, } self.modes = (self.EXPR, self.PATH, self.DATE_RANGE, self.DIFF, self.MESSAGE, self.AUTHOR, self.COMMITTER) self.mode_combo.addItems(self.modes) connect_button(self.search_button, self.search_callback) connect_button(self.browse_button, self.browse_callback) connect_button(self.button_export, self.export_patch) connect_button(self.button_cherrypick, self.cherry_pick) connect_button(self.button_close, self.accept) # pylint: disable=no-member self.mode_combo.currentIndexChanged.connect(self.mode_changed) self.commit_list.itemSelectionChanged.connect(self.display) self.set_start_date(mkdate(time.time()-(87640*31))) self.set_end_date(mkdate(time.time()+87640)) self.set_mode(self.EXPR) self.query.setFocus() def mode_changed(self, _idx): mode = self.mode() self.update_shown_widgets(mode) if mode == self.PATH: self.browse_callback() def set_commits(self, commits): widget = self.commit_list widget.clear() widget.addItems(commits) def set_start_date(self, datestr): set_date(self.start_date, datestr) def set_end_date(self, datestr): set_date(self.end_date, datestr) def set_mode(self, mode): idx = self.modes.index(mode) self.mode_combo.setCurrentIndex(idx) self.update_shown_widgets(mode) def update_shown_widgets(self, mode): date_shown = mode == self.DATE_RANGE browse_shown = mode == self.PATH self.query.setVisible(not date_shown) self.browse_button.setVisible(browse_shown) self.start_date.setVisible(date_shown) self.end_date.setVisible(date_shown) def mode(self): return self.mode_combo.currentText() # pylint: disable=unused-argument def search_callback(self, *args): engineclass = self.engines[self.mode()] self.model.query = get(self.query) self.model.max_count = get(self.max_count) self.model.start_date = get(self.start_date) self.model.end_date = get(self.end_date) self.results = engineclass(self.context, self.model).search() if self.results: self.display_results() else: self.commit_list.clear() self.commit_text.setText('') def browse_callback(self): paths = qtutils.open_files(N_('Choose Paths')) if not paths: return filepaths = [] curdir = core.getcwd() prefix_len = len(curdir) + 1 for path in paths: if not path.startswith(curdir): continue relpath = path[prefix_len:] if relpath: filepaths.append(relpath) query = core.list2cmdline(filepaths) self.query.setText(query) if query: self.search_callback() def display_results(self): commits = [result[1] for result in self.results] self.set_commits(commits) def selected_revision(self): result = qtutils.selected_item(self.commit_list, self.results) return result[0] if result else None # pylint: disable=unused-argument def display(self, *args): context = self.context revision = self.selected_revision() if revision is None: self.commit_text.setText('') else: qtutils.set_clipboard(revision) diff_text = gitcmds.commit_diff(context, revision) self.commit_text.setText(diff_text) def export_patch(self): context = self.context revision = self.selected_revision() if revision is not None: Interaction.log_status(*gitcmds.export_patchset( context, revision, revision)) def cherry_pick(self): git = self.context.git revision = self.selected_revision() if revision is not None: Interaction.log_status(*git.cherry_pick(revision)) def set_date(widget, datestr): fmt = Qt.ISODate date = QtCore.QDate.fromString(datestr, fmt) if date: widget.setDate(date) def search_commits(context, parent): opts = SearchOptions() widget = Search(context, opts, parent) widget.show() return widget git-cola-3.6/cola/widgets/selectcommits.py000066400000000000000000000137011356743264500207130ustar00rootroot00000000000000"""A GUI for selecting commits""" from __future__ import division, absolute_import, unicode_literals from qtpy import QtWidgets from qtpy.QtCore import Qt from .. import gitcmds from .. import qtutils from ..i18n import N_ from ..icons import folder from ..interaction import Interaction from . import defs from .diff import DiffTextEdit from .standard import Dialog def select_commits(context, title, revs, summaries, multiselect=True): """Use the SelectCommits to select commits from a list.""" model = Model(revs, summaries) parent = qtutils.active_window() dialog = SelectCommits( context, model, parent, title, multiselect=multiselect) return dialog.select_commits() def select_commits_and_output(context, title, revs, summaries, multiselect=True): """Select commits from a list and output path""" model = Model(revs, summaries) parent = qtutils.active_window() dialog = SelectCommitsAndOutput(context, model, parent, title, multiselect=multiselect) return dialog.select_commits_and_output() class Model(object): def __init__(self, revs, summaries): self.revisions = revs self.summaries = summaries class SelectCommits(Dialog): def __init__(self, context, model, parent=None, title=None, multiselect=True): Dialog.__init__(self, parent) self.context = context self.model = model if title: self.setWindowTitle(title) if multiselect: mode = QtWidgets.QAbstractItemView.ExtendedSelection else: mode = QtWidgets.QAbstractItemView.SingleSelection commits = self.commits = QtWidgets.QListWidget() commits.setSelectionMode(mode) commits.setAlternatingRowColors(True) self.commit_text = DiffTextEdit(context, self, whitespace=False) self.label = QtWidgets.QLabel() self.label.setText(N_('Revision Expression:')) self.revision = QtWidgets.QLineEdit() self.revision.setReadOnly(True) self.select_button = qtutils.ok_button(N_('Select'), enabled=False) self.close_button = qtutils.close_button() # Make the list widget slightly larger self.splitter = qtutils.splitter(Qt.Vertical, self.commits, self.commit_text) self.splitter.setSizes([100, 150]) self.input_layout = qtutils.hbox(defs.no_margin, defs.button_spacing, self.close_button, qtutils.STRETCH, self.label, self.revision, self.select_button) self.main_layout = qtutils.vbox(defs.margin, defs.margin, self.splitter, self.input_layout) self.setLayout(self.main_layout) # pylint: disable=no-member commits.itemSelectionChanged.connect(self.commit_oid_selected) commits.itemDoubleClicked.connect(self.commit_oid_double_clicked) qtutils.connect_button(self.select_button, self.accept) qtutils.connect_button(self.close_button, self.reject) self.init_state(None, self.resize_widget, parent) def resize_widget(self, parent): """Set the initial size of the widget""" width, height = qtutils.default_size(parent, 720, 480) self.resize(width, height) def selected_commit(self): return qtutils.selected_item(self.commits, self.model.revisions) def selected_commits(self): return qtutils.selected_items(self.commits, self.model.revisions) def select_commits(self): summaries = self.model.summaries if not summaries: msg = N_('No commits exist in this branch.') Interaction.log(msg) return [] qtutils.set_items(self.commits, summaries) self.show() if self.exec_() != QtWidgets.QDialog.Accepted: return [] return self.selected_commits() def commit_oid_selected(self): context = self.context oid = self.selected_commit() selected = oid is not None self.select_button.setEnabled(selected) if not selected: self.commit_text.set_value('') self.revision.setText('') return self.revision.setText(oid) self.revision.selectAll() # Display the oid's commit commit_diff = gitcmds.commit_diff(context, oid) self.commit_text.setText(commit_diff) def commit_oid_double_clicked(self, _item): oid = self.selected_commit() if oid: self.accept() class SelectCommitsAndOutput(SelectCommits): def __init__(self, context, model, parent=None, title=None, multiselect=True): SelectCommits.__init__( self, context, model, parent, title, multiselect) self.output_dir = 'output' self.select_output = qtutils.create_button( tooltip=N_('Select output dir'), icon=folder()) self.output_text = QtWidgets.QLineEdit() self.output_text.setReadOnly(True) self.output_text.setText(self.output_dir) output_layout = qtutils.hbox(defs.no_margin, defs.no_spacing, self.select_output, self.output_text) self.input_layout.insertLayout(1, output_layout) qtutils.connect_button(self.select_output, self.show_output_dialog) def select_commits_and_output(self): to_export = SelectCommits.select_commits(self) output = self.output_dir return {'to_export': to_export, 'output': output} def show_output_dialog(self): self.output_dir = qtutils.opendir_dialog(N_('Select output directory'), self.output_dir) if not self.output_dir: return self.output_text.setText(self.output_dir) git-cola-3.6/cola/widgets/spellcheck.py000066400000000000000000000100541356743264500201530ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import division, absolute_import, unicode_literals import re from qtpy.QtCore import Qt from qtpy.QtCore import QEvent from qtpy.QtCore import Signal from qtpy.QtGui import QMouseEvent from qtpy.QtGui import QSyntaxHighlighter from qtpy.QtGui import QTextCharFormat from qtpy.QtGui import QTextCursor from qtpy.QtWidgets import QAction from .. import qtutils from .. import spellcheck from ..i18n import N_ from .text import HintedTextEdit # pylint: disable=too-many-ancestors class SpellCheckTextEdit(HintedTextEdit): def __init__(self, context, hint, parent=None): HintedTextEdit.__init__(self, context, hint, parent) # Default dictionary based on the current locale. self.spellcheck = spellcheck.NorvigSpellCheck() self.highlighter = Highlighter(self.document(), self.spellcheck) def set_dictionary(self, dictionary): self.spellcheck.set_dictionary(dictionary) def mousePressEvent(self, event): if event.button() == Qt.RightButton: # Rewrite the mouse event to a left button event so the cursor is # moved to the location of the pointer. event = QMouseEvent(QEvent.MouseButtonPress, event.pos(), Qt.LeftButton, Qt.LeftButton, Qt.NoModifier) HintedTextEdit.mousePressEvent(self, event) def context_menu(self): popup_menu = HintedTextEdit.createStandardContextMenu(self) # Select the word under the cursor. cursor = self.textCursor() cursor.select(QTextCursor.WordUnderCursor) self.setTextCursor(cursor) # Check if the selected word is misspelled and offer spelling # suggestions if it is. spell_menu = None if self.textCursor().hasSelection(): text = self.textCursor().selectedText() if not self.spellcheck.check(text): title = N_('Spelling Suggestions') spell_menu = qtutils.create_menu(title, self) for word in self.spellcheck.suggest(text): action = SpellAction(word, spell_menu) action.result.connect(self.correct) spell_menu.addAction(action) # Only add the spelling suggests to the menu if there are # suggestions. if spell_menu.actions(): popup_menu.addSeparator() popup_menu.addMenu(spell_menu) return popup_menu, spell_menu def contextMenuEvent(self, event): popup_menu, _ = self.context_menu() popup_menu.exec_(self.mapToGlobal(event.pos())) def correct(self, word): """Replaces the selected text with word.""" cursor = self.textCursor() cursor.beginEditBlock() cursor.removeSelectedText() cursor.insertText(word) cursor.endEditBlock() class Highlighter(QSyntaxHighlighter): WORDS = r"(?iu)[\w']+" def __init__(self, doc, spellcheck_widget): QSyntaxHighlighter.__init__(self, doc) self.spellcheck = spellcheck_widget self.enabled = False def enable(self, enabled): self.enabled = enabled self.rehighlight() def highlightBlock(self, text): if not self.enabled: return fmt = QTextCharFormat() fmt.setUnderlineColor(Qt.red) fmt.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline) for word_object in re.finditer(self.WORDS, text): if not self.spellcheck.check(word_object.group()): self.setFormat(word_object.start(), word_object.end() - word_object.start(), fmt) class SpellAction(QAction): """QAction that returns the text in a signal. """ result = Signal(object) def __init__(self, *args): QAction.__init__(self, *args) # pylint: disable=no-member self.triggered.connect(self.correct) def correct(self): self.result.emit(self.text()) git-cola-3.6/cola/widgets/standard.py000066400000000000000000000744341356743264500176520ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals import time from functools import partial from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from qtpy.QtCore import Qt from qtpy.QtCore import Signal from qtpy.QtWidgets import QDockWidget from ..i18n import N_ from ..interaction import Interaction from ..settings import Settings, mklist from ..models import prefs from .. import core from .. import hotkeys from .. import icons from .. import qtcompat from .. import qtutils from .. import utils from . import defs class WidgetMixin(object): """Mix-in for common utilities and serialization of widget state""" def __init__(self): self._unmaximized_rect = {} def center(self): parent = self.parent() if parent is None: return left = parent.x() width = parent.width() center_x = left + width//2 x = center_x - self.width()//2 y = parent.y() self.move(x, y) def resize_to_desktop(self): desktop = QtWidgets.QApplication.instance().desktop() width = desktop.width() height = desktop.height() if utils.is_darwin(): self.resize(width, height) else: shown = self.isVisible() # earlier show() fools Windows focus stealing prevention. the main # window is blocked for the duration of "git rebase" and we don't # want to present a blocked window with git-xbase hidden somewhere. self.show() self.setWindowState(Qt.WindowMaximized) if not shown: self.hide() def name(self): """Returns the name of the view class""" return self.__class__.__name__.lower() def save_state(self, settings=None): save = True context = getattr(self, 'context', None) if context: cfg = context.cfg save = cfg.get('cola.savewindowsettings', default=True) if save: if settings is None: settings = Settings() settings.load() settings.save_gui_state(self) def restore_state(self, settings=None): if settings is None: settings = Settings() settings.load() state = settings.get_gui_state(self) if state: result = self.apply_state(state) else: result = False return result def apply_state(self, state): """Imports data for view save/restore""" width = utils.asint(state.get('width')) height = utils.asint(state.get('height')) x = utils.asint(state.get('x')) y = utils.asint(state.get('y')) geometry = state.get('geometry', '') if geometry: from_base64 = QtCore.QByteArray.fromBase64 result = self.restoreGeometry(from_base64(core.encode(geometry))) elif width and height: # Users migrating from older versions won't have 'geometry'. # They'll be upgraded to the new format on shutdown. self.resize(width, height) self.move(x, y) result = True else: result = False return result def export_state(self): """Exports data for view save/restore""" state = {} geometry = self.saveGeometry() state['geometry'] = geometry.toBase64().data().decode('ascii') # Until 2020: co-exist with older versions state['width'] = self.width() state['height'] = self.height() state['x'] = self.x() state['y'] = self.y() return state def save_settings(self, settings=None): return self.save_state(settings=settings) def closeEvent(self, event): self.save_settings() self.Base.closeEvent(self, event) def init_size(self, parent=None, settings=None, width=0, height=0): if not width: width = defs.dialog_w if not height: height = defs.dialog_h self.init_state(settings, self.resize_to_parent, parent, width, height) def init_state(self, settings, callback, *args, **kwargs): """Restore saved settings or set the initial location""" if not self.restore_state(settings=settings): callback(*args, **kwargs) self.center() def resize_to_parent(self, parent, w, h): """Set the initial size of the widget""" width, height = qtutils.default_size(parent, w, h) self.resize(width, height) class MainWindowMixin(WidgetMixin): def __init__(self): WidgetMixin.__init__(self) # Dockwidget options self.dockwidgets = [] self.lock_layout = False self.widget_version = 0 qtcompat.set_common_dock_options(self) self.default_state = None def init_state(self, settings, callback, *args, **kwargs): """Save the initial state before calling the parent initializer""" self.default_state = self.saveState(self.widget_version) super(MainWindowMixin, self).init_state(settings, callback, *args, **kwargs) def export_state(self): """Exports data for save/restore""" state = WidgetMixin.export_state(self) windowstate = self.saveState(self.widget_version) state['lock_layout'] = self.lock_layout state['windowstate'] = windowstate.toBase64().data().decode('ascii') return state def save_settings(self, settings=None): if settings is None: context = getattr(self, 'context', None) settings = Settings() settings.load() settings.add_recent(core.getcwd(), prefs.maxrecent(context)) return WidgetMixin.save_settings(self, settings=settings) def apply_state(self, state): result = WidgetMixin.apply_state(self, state) windowstate = state.get('windowstate', '') if windowstate: from_base64 = QtCore.QByteArray.fromBase64 result = self.restoreState( from_base64(core.encode(windowstate)), self.widget_version) and result else: result = False self.lock_layout = state.get('lock_layout', self.lock_layout) self.update_dockwidget_lock_state() self.update_dockwidget_tooltips() return result def reset_layout(self): self.restoreState(self.default_state, self.widget_version) def set_lock_layout(self, lock_layout): self.lock_layout = lock_layout self.update_dockwidget_lock_state() def update_dockwidget_lock_state(self): if self.lock_layout: features = (QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetFloatable) else: features = (QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) for widget in self.dockwidgets: widget.titleBarWidget().update_tooltips() widget.setFeatures(features) def update_dockwidget_tooltips(self): for widget in self.dockwidgets: widget.titleBarWidget().update_tooltips() # pylint: disable=too-many-ancestors class ListWidget(QtWidgets.QListWidget): """QListWidget with vim j/k navigation hotkeys""" def __init__(self, parent=None): super(ListWidget, self).__init__(parent) self.up_action = qtutils.add_action( self, N_('Move Up'), self.move_up, hotkeys.MOVE_UP, hotkeys.MOVE_UP_SECONDARY) self.down_action = qtutils.add_action( self, N_('Move Down'), self.move_down, hotkeys.MOVE_DOWN, hotkeys.MOVE_DOWN_SECONDARY) def selected_item(self): return self.currentItem() def selected_items(self): return self.selectedItems() def move_up(self): self.move(-1) def move_down(self): self.move(1) def move(self, direction): item = self.selected_item() if item: row = (self.row(item) + direction) % self.count() elif self.count() > 0: row = (self.count() + direction) % self.count() else: return new_item = self.item(row) if new_item: self.setCurrentItem(new_item) class TreeMixin(object): def __init__(self, widget, Base): self.widget = widget self.Base = Base widget.setAlternatingRowColors(True) widget.setUniformRowHeights(True) widget.setAllColumnsShowFocus(True) widget.setAnimated(True) widget.setRootIsDecorated(False) def keyPressEvent(self, event): """ Make LeftArrow to work on non-directories. When LeftArrow is pressed on a file entry or an unexpanded directory, then move the current index to the parent directory. This simplifies navigation using the keyboard. For power-users, we support Vim keybindings ;-P """ # Check whether the item is expanded before calling the base class # keyPressEvent otherwise we end up collapsing and changing the # current index in one shot, which we don't want to do. widget = self.widget index = widget.currentIndex() was_expanded = widget.isExpanded(index) was_collapsed = not was_expanded # Vim keybindings... # Rewrite the event before marshalling to QTreeView.event() key = event.key() # Remap 'H' to 'Left' if key == Qt.Key_H: event = QtGui.QKeyEvent(event.type(), Qt.Key_Left, event.modifiers()) # Remap 'J' to 'Down' elif key == Qt.Key_J: event = QtGui.QKeyEvent(event.type(), Qt.Key_Down, event.modifiers()) # Remap 'K' to 'Up' elif key == Qt.Key_K: event = QtGui.QKeyEvent(event.type(), Qt.Key_Up, event.modifiers()) # Remap 'L' to 'Right' elif key == Qt.Key_L: event = QtGui.QKeyEvent(event.type(), Qt.Key_Right, event.modifiers()) # Re-read the event key to take the remappings into account key = event.key() if key == Qt.Key_Up: idxs = widget.selectedIndexes() rows = [idx.row() for idx in idxs] if len(rows) == 1 and rows[0] == 0: # The cursor is at the beginning of the line. # If we have selection then simply reset the cursor. # Otherwise, emit a signal so that the parent can # change focus. widget.up.emit() elif key == Qt.Key_Space: widget.space.emit() result = self.Base.keyPressEvent(widget, event) # Let others hook in here before we change the indexes widget.index_about_to_change.emit() # Automatically select the first entry when expanding a directory if (key == Qt.Key_Right and was_collapsed and widget.isExpanded(index)): index = widget.moveCursor(widget.MoveDown, event.modifiers()) widget.setCurrentIndex(index) # Process non-root entries with valid parents only. elif key == Qt.Key_Left and index.parent().isValid(): # File entries have rowCount() == 0 model = widget.model() if (hasattr(model, 'itemFromIndex') and model.itemFromIndex(index).rowCount() == 0): widget.setCurrentIndex(index.parent()) # Otherwise, do this for collapsed directories only elif was_collapsed: widget.setCurrentIndex(index.parent()) # If it's a movement key ensure we have a selection elif key in (Qt.Key_Left, Qt.Key_Up, Qt.Key_Right, Qt.Key_Down): # Try to select the first item if the model index is invalid item = self.selected_item() if item is None or not index.isValid(): index = widget.model().index(0, 0, QtCore.QModelIndex()) if index.isValid(): widget.setCurrentIndex(index) return result def item_from_index(self, item): """Return a QModelIndex from the provided item""" if hasattr(self, 'itemFromIndex'): index = self.itemFromIndex(item) else: index = self.model().itemFromIndex() return index def items(self): root = self.widget.invisibleRootItem() child = root.child count = root.childCount() return [child(i) for i in range(count)] def selected_items(self): """Return all selected items""" widget = self.widget if hasattr(widget, 'selectedItems'): return widget.selectedItems() else: if hasattr(widget, 'itemFromIndex'): item_from_index = widget.itemFromIndex else: item_from_index = widget.model().itemFromIndex return [item_from_index(i) for i in widget.selectedIndexes()] def selected_item(self): """Return the first selected item""" selected_items = self.selected_items() if not selected_items: return None return selected_items[0] def current_item(self): item = None widget = self.widget if hasattr(widget, 'currentItem'): item = widget.currentItem() else: index = widget.currentIndex() if index.isValid(): item = widget.model().itemFromIndex(index) return item def column_widths(self): """Return the tree's column widths""" widget = self.widget count = widget.header().count() return [widget.columnWidth(i) for i in range(count)] def set_column_widths(self, widths): """Set the tree's column widths""" if widths: widget = self.widget count = widget.header().count() if len(widths) > count: widths = widths[:count] for idx, value in enumerate(widths): widget.setColumnWidth(idx, value) class DraggableTreeMixin(TreeMixin): """A tree widget with internal drag+drop reordering of rows Expects that the widget provides an `items_moved` signal. """ def __init__(self, widget, Base): super(DraggableTreeMixin, self).__init__(widget, Base) self._inner_drag = False widget.setAcceptDrops(True) widget.setSelectionMode(widget.SingleSelection) widget.setDragEnabled(True) widget.setDropIndicatorShown(True) widget.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove) widget.setSortingEnabled(False) def dragEnterEvent(self, event): """Accept internal drags only""" widget = self.widget self.Base.dragEnterEvent(widget, event) self._inner_drag = event.source() == widget if self._inner_drag: event.acceptProposedAction() else: event.ignore() def dragLeaveEvent(self, event): widget = self.widget self.Base.dragLeaveEvent(widget, event) if self._inner_drag: event.accept() else: event.ignore() self._inner_drag = False def dropEvent(self, event): """Re-select selected items after an internal move""" if not self._inner_drag: event.ignore() return widget = self.widget clicked_items = self.selected_items() event.setDropAction(Qt.MoveAction) self.Base.dropEvent(widget, event) if clicked_items: widget.clearSelection() for item in clicked_items: item.setSelected(True) widget.items_moved.emit(clicked_items) self._inner_drag = False event.accept() # must be called after dropEvent() def mousePressEvent(self, event): """Clear the selection when a mouse click hits no item""" widget = self.widget clicked_item = widget.itemAt(event.pos()) if clicked_item is None: widget.clearSelection() return self.Base.mousePressEvent(widget, event) class Widget(WidgetMixin, QtWidgets.QWidget): Base = QtWidgets.QWidget def __init__(self, parent=None): QtWidgets.QWidget.__init__(self, parent) WidgetMixin.__init__(self) class Dialog(WidgetMixin, QtWidgets.QDialog): Base = QtWidgets.QDialog def __init__(self, parent=None): QtWidgets.QDialog.__init__(self, parent) WidgetMixin.__init__(self) # Disable the Help button hint on Windows if hasattr(Qt, 'WindowContextHelpButtonHint'): help_hint = Qt.WindowContextHelpButtonHint flags = self.windowFlags() & ~help_hint self.setWindowFlags(flags) def accept(self): self.save_settings() self.dispose() return self.Base.accept(self) def reject(self): self.save_settings() self.dispose() return self.Base.reject(self) # pylint: disable=no-self-use def dispose(self): """Extension method for model deregistration in sub-classes""" return def close(self): """save_settings() is handled by accept() and reject()""" self.dispose() self.Base.close(self) def closeEvent(self, event): """save_settings() is handled by accept() and reject()""" self.dispose() self.Base.closeEvent(self, event) class MainWindow(MainWindowMixin, QtWidgets.QMainWindow): Base = QtWidgets.QMainWindow def __init__(self, parent=None): QtWidgets.QMainWindow.__init__(self, parent) MainWindowMixin.__init__(self) # pylint: disable=too-many-ancestors class TreeView(QtWidgets.QTreeView): Mixin = TreeMixin up = Signal() space = Signal() index_about_to_change = Signal() def __init__(self, parent=None): QtWidgets.QTreeView.__init__(self, parent) self._mixin = self.Mixin(self, QtWidgets.QTreeView) def keyPressEvent(self, event): return self._mixin.keyPressEvent(event) def current_item(self): return self._mixin.current_item() def selected_item(self): return self._mixin.selected_item() def selected_items(self): return self._mixin.selected_items() def items(self): return self._mixin.items() def column_widths(self): return self._mixin.column_widths() def set_column_widths(self, widths): return self._mixin.set_column_widths(widths) # pylint: disable=too-many-ancestors class TreeWidget(QtWidgets.QTreeWidget): Mixin = TreeMixin up = Signal() space = Signal() index_about_to_change = Signal() def __init__(self, parent=None): super(TreeWidget, self).__init__(parent) self._mixin = self.Mixin(self, QtWidgets.QTreeWidget) def keyPressEvent(self, event): return self._mixin.keyPressEvent(event) def current_item(self): return self._mixin.current_item() def selected_item(self): return self._mixin.selected_item() def selected_items(self): return self._mixin.selected_items() def items(self): return self._mixin.items() def column_widths(self): return self._mixin.column_widths() def set_column_widths(self, widths): return self._mixin.set_column_widths(widths) # pylint: disable=too-many-ancestors class DraggableTreeWidget(TreeWidget): Mixin = DraggableTreeMixin items_moved = Signal(object) def mousePressEvent(self, event): return self._mixin.mousePressEvent(event) def dropEvent(self, event): return self._mixin.dropEvent(event) def dragLeaveEvent(self, event): return self._mixin.dragLeaveEvent(event) def dragEnterEvent(self, event): return self._mixin.dragEnterEvent(event) class ProgressDialog(QtWidgets.QProgressDialog): """Custom progress dialog This dialog ignores the ESC key so that it is not prematurely closed. A thread is spawned to animate the progress label text. """ def __init__(self, title, label, parent): QtWidgets.QProgressDialog.__init__(self, parent) if parent is not None: self.setWindowModality(Qt.WindowModal) self.reset() self.setRange(0, 0) self.setMinimumDuration(0) self.setCancelButton(None) self.setFont(qtutils.default_monospace_font()) self.thread = ProgressAnimationThread(label, self) self.thread.updated.connect(self.refresh, type=Qt.QueuedConnection) self.set_details(title, label) def set_details(self, title, label): self.setWindowTitle(title) self.setLabelText(label + ' ') self.thread.set_text(label) def refresh(self, txt): self.setLabelText(txt) def keyPressEvent(self, event): if event.key() != Qt.Key_Escape: super(ProgressDialog, self).keyPressEvent(event) def show(self): QtWidgets.QApplication.setOverrideCursor(Qt.WaitCursor) super(ProgressDialog, self).show() self.thread.start() def hide(self): QtWidgets.QApplication.restoreOverrideCursor() self.thread.stop() self.thread.wait() super(ProgressDialog, self).hide() class ProgressAnimationThread(QtCore.QThread): """Emits a pseudo-animated text stream for progress bars """ updated = Signal(object) def __init__(self, txt, parent, timeout=0.1): QtCore.QThread.__init__(self, parent) self.running = False self.txt = txt self.timeout = timeout self.symbols = [ '. ..', '.. .', '... ', ' ... ', ' ...', ] self.idx = -1 def set_text(self, txt): self.txt = txt def cycle(self): self.idx = (self.idx + 1) % len(self.symbols) return self.txt + self.symbols[self.idx] def stop(self): self.running = False def run(self): self.running = True while self.running: self.updated.emit(self.cycle()) time.sleep(self.timeout) class SpinBox(QtWidgets.QSpinBox): def __init__(self, parent=None, value=None, mini=1, maxi=99999, step=0, prefix='', suffix=''): QtWidgets.QSpinBox.__init__(self, parent) self.setPrefix(prefix) self.setSuffix(suffix) self.setWrapping(True) self.setMinimum(mini) self.setMaximum(maxi) if step: self.setSingleStep(step) if value is not None: self.setValue(value) font = self.font() metrics = QtGui.QFontMetrics(font) width = max(self.minimumWidth(), metrics.width('XXXXXX')) self.setMinimumWidth(width) def export_header_columns(widget, state): """Save QHeaderView column sizes""" columns = [] header = widget.horizontalHeader() for idx in range(header.count()): columns.append(header.sectionSize(idx)) state['columns'] = columns def apply_header_columns(widget, state): """Apply QHeaderView column sizes""" columns = mklist(state.get('columns', [])) header = widget.horizontalHeader() if header.stretchLastSection(): # Setting the size will make the section wider than necessary, which # defeats the purpose of the stretch flag. Skip the last column when # it's stretchy so that it retains the stretchy behavior. columns = columns[:-1] for idx, size in enumerate(columns): header.resizeSection(idx, size) class MessageBox(Dialog): """Improved QMessageBox replacement QMessageBox has a lot of usability issues. It sometimes cannot be resized, and it brings along a lots of annoying properties that we'd have to workaround, so we use a simple custom dialog instead. """ def __init__(self, parent=None, title='', text='', info='', details='', logo=None, default=False, ok_icon=None, ok_text='', cancel_text=None, cancel_icon=None): Dialog.__init__(self, parent=parent) if parent: self.setWindowModality(Qt.WindowModal) if title: self.setWindowTitle(title) self.logo_label = QtWidgets.QLabel() if logo: # Render into a 1-inch wide pixmap pixmap = logo.pixmap(defs.large_icon) self.logo_label.setPixmap(pixmap) else: self.logo_label.hide() self.text_label = QtWidgets.QLabel() self.text_label.setText(text) self.info_label = QtWidgets.QLabel() if info: self.info_label.setText(info) else: self.info_label.hide() ok_icon = icons.mkicon(ok_icon, icons.ok) self.button_ok = qtutils.create_button(text=ok_text, icon=ok_icon) self.button_close = qtutils.close_button( text=cancel_text, icon=cancel_icon) if ok_text: self.button_ok.setText(ok_text) else: self.button_ok.hide() self.details_text = QtWidgets.QPlainTextEdit() self.details_text.setReadOnly(True) if details: self.details_text.setFont(qtutils.default_monospace_font()) self.details_text.setPlainText(details) else: self.details_text.hide() self.info_layout = qtutils.vbox( defs.large_margin, defs.button_spacing, self.text_label, self.info_label, qtutils.STRETCH) self.top_layout = qtutils.hbox( defs.large_margin, defs.button_spacing, self.logo_label, self.info_layout, qtutils.STRETCH) self.buttons_layout = qtutils.hbox( defs.no_margin, defs.button_spacing, qtutils.STRETCH, self.button_close, self.button_ok) self.main_layout = qtutils.vbox( defs.margin, defs.button_spacing, self.top_layout, self.buttons_layout, self.details_text) self.main_layout.setStretchFactor(self.details_text, 2) self.setLayout(self.main_layout) if default: self.button_ok.setDefault(True) self.button_ok.setFocus() else: self.button_close.setDefault(True) self.button_close.setFocus() qtutils.connect_button(self.button_ok, self.accept) qtutils.connect_button(self.button_close, self.reject) self.init_state(None, self.set_initial_size) def set_initial_size(self): width = defs.dialog_w height = defs.msgbox_h self.resize(width, height) def keyPressEvent(self, event): """Handle Y/N hotkeys""" key = event.key() if key == Qt.Key_Y: QtCore.QTimer.singleShot(0, self.accept) elif key in (Qt.Key_N, Qt.Key_Q): QtCore.QTimer.singleShot(0, self.reject) elif key == Qt.Key_Tab: if self.button_ok.isVisible(): event.accept() if self.focusWidget() == self.button_close: self.button_ok.setFocus() else: self.button_close.setFocus() return Dialog.keyPressEvent(self, event) def run(self): self.show() return self.exec_() def confirm(title, text, informative_text, ok_text, icon=None, default=True, cancel_text=None, cancel_icon=None): """Confirm that an action should take place""" cancel_text = cancel_text or N_('Cancel') logo = icons.from_style(QtWidgets.QStyle.SP_MessageBoxQuestion) mbox = MessageBox( parent=qtutils.active_window(), title=title, text=text, info=informative_text, ok_text=ok_text, ok_icon=icon, cancel_text=cancel_text, cancel_icon=cancel_icon, logo=logo, default=default) return mbox.run() == mbox.Accepted def critical(title, message=None, details=None): """Show a warning with the provided title and message.""" if message is None: message = title logo = icons.from_style(QtWidgets.QStyle.SP_MessageBoxCritical) mbox = MessageBox( parent=qtutils.active_window(), title=title, text=message, details=details, logo=logo) mbox.run() def command_error(title, cmd, status, out, err): """Report an error message about a failed command""" details = Interaction.format_out_err(out, err) message = Interaction.format_command_status(cmd, status) critical(title, message=message, details=details) def information(title, message=None, details=None, informative_text=None): """Show information with the provided title and message.""" if message is None: message = title mbox = MessageBox( parent=qtutils.active_window(), title=title, text=message, info=informative_text, details=details, logo=icons.cola()) mbox.run() def progress(title, text, parent): """Create a new ProgressDialog""" return ProgressDialog(title, text, parent) def question(title, text, default=True): """Launches a QMessageBox question with the provided title and message. Passing "default=False" will make "No" the default choice.""" parent = qtutils.active_window() logo = icons.from_style(QtWidgets.QStyle.SP_MessageBoxQuestion) msgbox = MessageBox( parent=parent, title=title, text=text, default=default, logo=logo, ok_text=N_('Yes'), cancel_text=N_('No')) return msgbox.run() == msgbox.Accepted def save_as(filename, title): return qtutils.save_as(filename, title=title) def async_command(title, cmd, runtask): parent = qtutils.active_window() task = qtutils.SimpleTask(parent, partial(core.run_command, cmd)) task.connect(partial(async_command_result, title, cmd)) runtask.start(task) def async_command_result(title, cmd, result): status, out, err = result cmd_string = core.list2cmdline(cmd) Interaction.command(title, cmd_string, status, out, err) def install(): """Install the GUI-model interaction hooks""" Interaction.critical = staticmethod(critical) Interaction.confirm = staticmethod(confirm) Interaction.question = staticmethod(question) Interaction.information = staticmethod(information) Interaction.command_error = staticmethod(command_error) Interaction.save_as = staticmethod(save_as) Interaction.async_command = staticmethod(async_command) git-cola-3.6/cola/widgets/startup.py000066400000000000000000000146641356743264500175530ustar00rootroot00000000000000"""Provides the git-cola startup dialog The startup dialog is presented when no repositories can be found at startup. """ from __future__ import division, absolute_import, unicode_literals from qtpy.QtCore import Qt from qtpy import QtGui from qtpy import QtWidgets from ..i18n import N_ from ..settings import Settings from .. import core from .. import guicmds from .. import icons from .. import qtutils from .. import version from . import clone from . import defs from . import standard class StartupDialog(standard.Dialog): """Provides a GUI to Open or Clone a git repository.""" def __init__(self, context, parent=None, settings=None): standard.Dialog.__init__(self, parent) self.context = context self.setWindowTitle(N_('git-cola')) # Top-most large icon logo_pixmap = icons.cola().pixmap(defs.huge_icon, defs.huge_icon) self.logo_label = QtWidgets.QLabel() self.logo_label.setPixmap(logo_pixmap) self.logo_label.setAlignment(Qt.AlignCenter) self.logo_text_label = qtutils.label(text=version.cola_version()) self.logo_text_label.setAlignment(Qt.AlignCenter) self.repodir = None if context.runtask: self.runtask = context.runtask else: self.runtask = context.runtask = qtutils.RunTask(parent=self) self.new_button = qtutils.create_button( text=N_('New...'), icon=icons.new()) self.open_button = qtutils.create_button( text=N_('Open...'), icon=icons.folder()) self.clone_button = qtutils.create_button( text=N_('Clone...'), icon=icons.cola()) self.close_button = qtutils.close_button() if settings is None: settings = Settings() settings.load() self.settings = settings self.bookmarks_label = qtutils.label(text=N_('Select Repository...')) self.bookmarks_label.setAlignment(Qt.AlignCenter) self.bookmarks_model = QtGui.QStandardItemModel() item = QtGui.QStandardItem(N_('Select manually...')) item.setEditable(False) self.bookmarks_model.appendRow(item) # Bookmarks/"Favorites" and Recent are lists of {name,path: str} bookmarks = [i['path'] for i in settings.bookmarks] recent = [i['path'] for i in settings.recent] all_repos = bookmarks + recent added = set() for repo in sorted(all_repos, key=lambda x: x.lower()): if repo in added: continue added.add(repo) item = QtGui.QStandardItem(repo) item.setEditable(False) self.bookmarks_model.appendRow(item) selection_mode = QtWidgets.QAbstractItemView.SingleSelection self.bookmarks = QtWidgets.QListView() self.bookmarks.setSelectionMode(selection_mode) self.bookmarks.setAlternatingRowColors(True) self.bookmarks.setModel(self.bookmarks_model) self.logo_layout = qtutils.vbox(defs.no_margin, defs.spacing, self.logo_label, self.logo_text_label, defs.button_spacing, qtutils.STRETCH) self.button_layout = qtutils.hbox(defs.no_margin, defs.spacing, self.open_button, self.clone_button, self.new_button, qtutils.STRETCH, self.close_button) self.center_layout = qtutils.hbox(defs.no_margin, defs.button_spacing, self.logo_layout, self.bookmarks) self.main_layout = qtutils.vbox(defs.margin, defs.spacing, self.bookmarks_label, self.center_layout, self.button_layout) self.setLayout(self.main_layout) qtutils.connect_button(self.open_button, self.open_repo) qtutils.connect_button(self.clone_button, self.clone_repo) qtutils.connect_button(self.new_button, self.new_repo) qtutils.connect_button(self.close_button, self.reject) # pylint: disable=no-member self.bookmarks.activated.connect(self.open_bookmark) self.init_state(settings, self.resize_widget) self.setFocusProxy(self.bookmarks) self.bookmarks.setFocus() def resize_widget(self): screen = QtWidgets.QApplication.instance().desktop() self.setGeometry(screen.width() // 4, screen.height() // 4, screen.width() // 2, screen.height() // 2) def find_git_repo(self): """ Return a path to a git repository This is the entry point for external callers. This method finds a git repository by allowing the user to browse to one on the filesystem or by creating a new one with git-clone. """ self.show() self.raise_() if self.exec_() == QtWidgets.QDialog.Accepted: return self.repodir return None def open_repo(self): self.repodir = self.get_selected_bookmark() if not self.repodir: self.repodir = qtutils.opendir_dialog(N_('Open Git Repository...'), core.getcwd()) if self.repodir: self.accept() def clone_repo(self): context = self.context settings = self.settings progress = standard.progress('', '', self) clone.clone_repo(context, self, True, settings, progress, self.clone_repo_done, False) def clone_repo_done(self, task): if task.cmd and task.cmd.status == 0: self.repodir = task.destdir self.accept() else: clone.task_finished(task) def new_repo(self): context = self.context repodir = guicmds.new_repo(context) if repodir: self.repodir = repodir self.accept() def open_bookmark(self, index): if index.row() == 0: self.open_repo() else: self.repodir = self.bookmarks_model.data(index) if self.repodir: self.accept() def get_selected_bookmark(self): selected = self.bookmarks.selectedIndexes() if selected and selected[0].row() != 0: return self.bookmarks_model.data(selected[0]) return None git-cola-3.6/cola/widgets/stash.py000066400000000000000000000216431356743264500171660ustar00rootroot00000000000000"""Widgets for manipulating git stashes""" from __future__ import division, absolute_import, unicode_literals from qtpy import QtCore from qtpy.QtCore import Qt from ..i18n import N_ from ..interaction import Interaction from ..models import stash from ..qtutils import get from .. import cmds from .. import icons from .. import qtutils from .. import utils from . import defs from . import diff from . import standard def view(context, show=True): """Launches a stash dialog using the provided model + view """ model = stash.StashModel(context) stash_view = StashView(context, model, parent=qtutils.active_window()) if show: stash_view.show() stash_view.raise_() return stash_view class StashView(standard.Dialog): def __init__(self, context, model, parent=None): standard.Dialog.__init__(self, parent=parent) self.context = context self.model = model self.stashes = [] self.revids = [] self.names = [] self.setWindowTitle(N_('Stash')) if parent is not None: self.setWindowModality(Qt.WindowModal) self.stash_list = standard.ListWidget(parent=self) self.stash_text = diff.DiffTextEdit(context, self) self.button_apply = qtutils.create_button( text=N_('Apply'), tooltip=N_('Apply the selected stash'), icon=icons.ok()) self.button_save = qtutils.create_button( text=N_('Save'), tooltip=N_('Save modified state to new stash'), icon=icons.save(), default=True) self.button_drop = qtutils.create_button( text=N_('Drop'), tooltip=N_('Drop the selected stash'), icon=icons.discard()) self.button_pop = qtutils.create_button( text=N_('Pop'), tooltip=N_('Apply and drop the selected stash (git stash pop)'), icon=icons.discard()) self.button_close = qtutils.close_button() self.keep_index = qtutils.checkbox( text=N_('Keep Index'), checked=True, tooltip=N_('Stash unstaged changes only, keeping staged changes')) self.stash_index = qtutils.checkbox( text=N_('Stash Index'), tooltip=N_('Stash staged changes only')) # Arrange layouts self.splitter = qtutils.splitter(Qt.Horizontal, self.stash_list, self.stash_text) self.splitter.setChildrenCollapsible(False) self.btn_layt = qtutils.hbox( defs.no_margin, defs.button_spacing, self.button_close, qtutils.STRETCH, self.stash_index, self.keep_index, self.button_save, self.button_apply, self.button_pop, self.button_drop) self.main_layt = qtutils.vbox(defs.margin, defs.spacing, self.splitter, self.btn_layt) self.setLayout(self.main_layt) self.splitter.setSizes([self.width()//3, self.width()*2//3]) # pylint: disable=no-member self.stash_list.itemSelectionChanged.connect(self.item_selected) qtutils.connect_button(self.button_save, self.stash_save) qtutils.connect_button(self.button_apply, self.stash_apply) qtutils.connect_button(self.button_pop, self.stash_pop) qtutils.connect_button(self.button_drop, self.stash_drop) qtutils.connect_button(self.button_close, self.close_and_rescan) qtutils.connect_checkbox(self.stash_index, self.stash_index_clicked) qtutils.connect_checkbox(self.keep_index, self.keep_index_clicked) self.init_size(parent=parent) self.update_from_model() self.update_actions() def close_and_rescan(self): cmds.do(cmds.Rescan, self.context) self.reject() # "stash" and "keep" index are mutually disable, but we don't # want a radio button because we'd have to add a 3rd "default" option. def stash_index_clicked(self, clicked): if clicked: self.keep_index.setChecked(False) def keep_index_clicked(self, clicked): if clicked: self.stash_index.setChecked(False) def selected_stash(self): """Returns the stash name of the currently selected stash """ list_widget = self.stash_list stash_list = self.revids return qtutils.selected_item(list_widget, stash_list) def selected_name(self): list_widget = self.stash_list stash_list = self.names return qtutils.selected_item(list_widget, stash_list) def item_selected(self): """Shows the current stash in the main view.""" self.update_actions() selection = self.selected_stash() if not selection: return diff_text = self.model.stash_diff(selection) self.stash_text.setPlainText(diff_text) def update_actions(self): is_staged = self.model.is_staged() is_changed = self.model.is_changed() is_selected = bool(self.selected_stash()) self.stash_index.setEnabled(is_staged) self.keep_index.setEnabled(is_changed) self.button_save.setEnabled(is_changed) self.button_apply.setEnabled(is_selected) self.button_drop.setEnabled(is_selected) self.button_pop.setEnabled(is_selected) def update_from_model(self): """Initiates git queries on the model and updates the view """ stashes, revids, author_dates, names = self.model.stash_info() self.stashes = stashes self.revids = revids self.names = names self.stash_list.clear() self.stash_list.addItems(self.stashes) if self.stash_list.count() > 0: for i in range(self.stash_list.count()): self.stash_list.item(i).setToolTip(author_dates[i]) item = self.stash_list.item(0) self.stash_list.setCurrentItem(item) # "Stash Index" depends on staged changes, so disable this option # if there are no staged changes. is_staged = self.model.is_staged() if get(self.stash_index) and not is_staged: self.stash_index.setChecked(False) def stash_pop(self): self.stash_apply(pop=True) def stash_apply(self, pop=False): """Applies the currently selected stash """ selection = self.selected_stash() if not selection: return context = self.context index = get(self.keep_index) cmds.do(stash.ApplyStash, context, selection, index, pop) QtCore.QTimer.singleShot(1, self.accept) def stash_save(self): """Saves the worktree in a stash This prompts the user for a stash name and creates a git stash named accordingly. """ stash_name, ok = qtutils.prompt( N_('Enter a name for the stash'), title=N_('Save Stash'), parent=self) if not ok or not stash_name: return # Sanitize the stash name stash_name = utils.sanitize(stash_name) if stash_name in self.names: Interaction.critical( N_('Error: Stash exists'), N_('A stash named "%s" already exists') % stash_name) return context = self.context keep_index = get(self.keep_index) stash_index = get(self.stash_index) if stash_index: cmds.do(stash.StashIndex, context, stash_name) else: cmds.do(stash.SaveStash, context, stash_name, keep_index) QtCore.QTimer.singleShot(1, self.accept) def stash_drop(self): """Drops the currently selected stash """ selection = self.selected_stash() name = self.selected_name() if not selection: return if not Interaction.confirm( N_('Drop Stash?'), N_('Recovering a dropped stash is not possible.'), N_('Drop the "%s" stash?') % name, N_('Drop Stash'), default=True, icon=icons.discard()): return cmds.do(stash.DropStash, self.context, selection) self.update_from_model() self.stash_text.setPlainText('') def export_state(self): """Export persistent settings""" state = super(StashView, self).export_state() state['keep_index'] = get(self.keep_index) state['stash_index'] = get(self.stash_index) state['sizes'] = get(self.splitter) return state def apply_state(self, state): """Apply persistent settings""" result = super(StashView, self).apply_state(state) keep_index = bool(state.get('keep_index', True)) stash_index = bool(state.get('stash_index', False)) self.keep_index.setChecked(keep_index) self.stash_index.setChecked(stash_index) try: self.splitter.setSizes(state['sizes']) except (KeyError, ValueError, AttributeError): pass return result git-cola-3.6/cola/widgets/status.py000066400000000000000000001322671356743264500173740ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals import itertools import os from functools import partial from qtpy.QtCore import Qt from qtpy.QtCore import Signal from qtpy import QtCore from qtpy import QtWidgets from ..i18n import N_ from ..models import prefs from ..models import selection from ..widgets import gitignore from ..widgets import standard from ..qtutils import get from .. import actions from .. import cmds from .. import core from .. import hotkeys from .. import icons from .. import qtutils from .. import settings from .. import utils from . import common from . import completion from . import defs from . import text class StatusWidget(QtWidgets.QFrame): """ Provides a git-status-like repository widget. This widget observes the main model and broadcasts Qt signals. """ def __init__(self, context, titlebar, parent): QtWidgets.QFrame.__init__(self, parent) self.context = context tooltip = N_('Toggle the paths filter') icon = icons.ellipsis() self.filter_button = qtutils.create_action_button(tooltip=tooltip, icon=icon) self.filter_widget = StatusFilterWidget(context) self.filter_widget.hide() self.tree = StatusTreeWidget(context, parent=self) self.setFocusProxy(self.tree) self.main_layout = qtutils.vbox(defs.no_margin, defs.no_spacing, self.filter_widget, self.tree) self.setLayout(self.main_layout) self.toggle_action = qtutils.add_action( self, tooltip, self.toggle_filter, hotkeys.FILTER) titlebar.add_corner_widget(self.filter_button) qtutils.connect_button(self.filter_button, self.toggle_filter) def toggle_filter(self): shown = not self.filter_widget.isVisible() self.filter_widget.setVisible(shown) if shown: self.filter_widget.setFocus() else: self.tree.setFocus() def set_initial_size(self): self.setMaximumWidth(222) QtCore.QTimer.singleShot( 1, lambda: self.setMaximumWidth(2 ** 13)) def refresh(self): self.tree.show_selection() def set_filter(self, txt): self.filter_widget.setVisible(True) self.filter_widget.text.set_value(txt) self.filter_widget.apply_filter() def move_up(self): self.tree.move_up() def move_down(self): self.tree.move_down() def select_header(self): self.tree.select_header() # pylint: disable=too-many-ancestors class StatusTreeWidget(QtWidgets.QTreeWidget): # Signals about_to_update = Signal() updated = Signal() diff_text_changed = Signal() # Item categories idx_header = -1 idx_staged = 0 idx_unmerged = 1 idx_modified = 2 idx_untracked = 3 idx_end = 4 # Read-only access to the mode state mode = property(lambda self: self.m.mode) def __init__(self, context, parent=None): QtWidgets.QTreeWidget.__init__(self, parent) self.context = context self.selection_model = context.selection self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) self.headerItem().setHidden(True) self.setAllColumnsShowFocus(True) self.setSortingEnabled(False) self.setUniformRowHeights(True) self.setAnimated(True) self.setRootIsDecorated(False) self.setDragEnabled(True) self.setAutoScroll(False) if not prefs.status_indent(context): self.setIndentation(0) ok = icons.ok() compare = icons.compare() question = icons.question() self._add_toplevel_item(N_('Staged'), ok, hide=True) self._add_toplevel_item(N_('Unmerged'), compare, hide=True) self._add_toplevel_item(N_('Modified'), compare, hide=True) self._add_toplevel_item(N_('Untracked'), question, hide=True) # Used to restore the selection self.old_vscroll = None self.old_hscroll = None self.old_selection = None self.old_contents = None self.old_current_item = None self.was_visible = True self.expanded_items = set() self.image_formats = qtutils.ImageFormats() self.process_selection_action = qtutils.add_action( self, cmds.StageOrUnstage.name(), self._stage_selection, hotkeys.STAGE_SELECTION) self.revert_unstaged_edits_action = qtutils.add_action( self, cmds.RevertUnstagedEdits.name(), cmds.run(cmds.RevertUnstagedEdits, context), hotkeys.REVERT) self.revert_unstaged_edits_action.setIcon(icons.undo()) self.launch_difftool_action = qtutils.add_action( self, cmds.LaunchDifftool.name(), cmds.run(cmds.LaunchDifftool, context), hotkeys.DIFF) self.launch_difftool_action.setIcon(icons.diff()) self.launch_editor_action = actions.launch_editor( context, self, *hotkeys.ACCEPT) if not utils.is_win32(): self.default_app_action = common.default_app_action( context, self, self.selected_group) self.parent_dir_action = common.parent_dir_action( context, self, self.selected_group) self.terminal_action = common.terminal_action( context, self, self.selected_group) self.up_action = qtutils.add_action( self, N_('Move Up'), self.move_up, hotkeys.MOVE_UP, hotkeys.MOVE_UP_SECONDARY) self.down_action = qtutils.add_action( self, N_('Move Down'), self.move_down, hotkeys.MOVE_DOWN, hotkeys.MOVE_DOWN_SECONDARY) self.copy_path_action = qtutils.add_action( self, N_('Copy Path to Clipboard'), partial(copy_path, context), hotkeys.COPY) self.copy_path_action.setIcon(icons.copy()) self.copy_relpath_action = qtutils.add_action( self, N_('Copy Relative Path to Clipboard'), partial(copy_relpath, context), hotkeys.CUT) self.copy_relpath_action.setIcon(icons.copy()) self.copy_leading_path_action = qtutils.add_action( self, N_('Copy Leading Path to Clipboard'), partial(copy_leading_path, context)) self.copy_leading_path_action.setIcon(icons.copy()) self.copy_basename_action = qtutils.add_action( self, N_('Copy Basename to Clipboard'), partial(copy_basename, context)) self.copy_basename_action.setIcon(icons.copy()) self.copy_customize_action = qtutils.add_action( self, N_('Customize...'), partial(customize_copy_actions, context, self)) self.copy_customize_action.setIcon(icons.configure()) self.view_history_action = qtutils.add_action( self, N_('View History...'), partial(view_history, context), hotkeys.HISTORY) self.view_blame_action = qtutils.add_action( self, N_('Blame...'), partial(view_blame, context), hotkeys.BLAME) self.annex_add_action = qtutils.add_action( self, N_('Add to Git Annex'), cmds.run(cmds.AnnexAdd, context)) self.lfs_track_action = qtutils.add_action( self, N_('Add to Git LFS'), cmds.run(cmds.LFSTrack, context)) # MoveToTrash and Delete use the same shortcut. # We will only bind one of them, depending on whether or not the # MoveToTrash command is available. When available, the hotkey # is bound to MoveToTrash, otherwise it is bound to Delete. if cmds.MoveToTrash.AVAILABLE: self.move_to_trash_action = qtutils.add_action( self, N_('Move files to trash'), self._trash_untracked_files, hotkeys.TRASH) self.move_to_trash_action.setIcon(icons.discard()) delete_shortcut = hotkeys.DELETE_FILE else: self.move_to_trash_action = None delete_shortcut = hotkeys.DELETE_FILE_SECONDARY self.delete_untracked_files_action = qtutils.add_action( self, N_('Delete Files...'), self._delete_untracked_files, delete_shortcut) self.delete_untracked_files_action.setIcon(icons.discard()) about_to_update = self._about_to_update self.about_to_update.connect(about_to_update, type=Qt.QueuedConnection) self.updated.connect(self.refresh, type=Qt.QueuedConnection) self.diff_text_changed.connect( self._make_current_item_visible, type=Qt.QueuedConnection) self.m = context.model self.m.add_observer(self.m.message_about_to_update, self.about_to_update.emit) self.m.add_observer(self.m.message_updated, self.updated.emit) self.m.add_observer(self.m.message_diff_text_changed, self.diff_text_changed.emit) # pylint: disable=no-member self.itemSelectionChanged.connect(self.show_selection) self.itemDoubleClicked.connect(self._double_clicked) self.itemCollapsed.connect(lambda x: self._update_column_widths()) self.itemExpanded.connect(lambda x: self._update_column_widths()) def _make_current_item_visible(self): item = self.currentItem() if item: self.scroll_to_item(item) def _add_toplevel_item(self, txt, icon, hide=False): context = self.context font = self.font() if prefs.bold_headers(context): font.setBold(True) else: font.setItalic(True) item = QtWidgets.QTreeWidgetItem(self) item.setFont(0, font) item.setText(0, txt) item.setIcon(0, icon) if prefs.bold_headers(context): item.setBackground(0, self.palette().midlight()) if hide: item.setHidden(True) def _restore_selection(self): if not self.old_selection or not self.old_contents: return old_c = self.old_contents old_s = self.old_selection new_c = self.contents() def mkselect(lst, widget_getter): def select(item, current=False): idx = lst.index(item) item = widget_getter(idx) if current: self.setCurrentItem(item) item.setSelected(True) return select select_staged = mkselect(new_c.staged, self._staged_item) select_unmerged = mkselect(new_c.unmerged, self._unmerged_item) select_modified = mkselect(new_c.modified, self._modified_item) select_untracked = mkselect(new_c.untracked, self._untracked_item) saved_selection = [ (set(new_c.staged), old_c.staged, set(old_s.staged), select_staged), (set(new_c.unmerged), old_c.unmerged, set(old_s.unmerged), select_unmerged), (set(new_c.modified), old_c.modified, set(old_s.modified), select_modified), (set(new_c.untracked), old_c.untracked, set(old_s.untracked), select_untracked), ] # Restore the current item if self.old_current_item: category, idx = self.old_current_item if category == self.idx_header: item = self.invisibleRootItem().child(idx) if item is not None: self.blockSignals(True) self.setCurrentItem(item) item.setSelected(True) self.blockSignals(False) self.show_selection() return # Reselect the current item selection_info = saved_selection[category] new = selection_info[0] old = selection_info[1] reselect = selection_info[3] try: item = old[idx] except IndexError: return if item in new: reselect(item, current=True) # Restore selection # When reselecting we only care that the items are selected; # we do not need to rerun the callbacks which were triggered # above. Block signals to skip the callbacks. self.blockSignals(True) for (new, old, sel, reselect) in saved_selection: for item in sel: if item in new: reselect(item, current=False) self.blockSignals(False) for (new, old, sel, reselect) in saved_selection: # When modified is staged, select the next modified item # When unmerged is staged, select the next unmerged item # When unstaging, select the next staged item # When staging untracked files, select the next untracked item if len(new) >= len(old): # The list did not shrink so it is not one of these cases. continue for item in sel: # The item still exists so ignore it if item in new or item not in old: continue # The item no longer exists in this list so search for # its nearest neighbors and select them instead. idx = old.index(item) for j in itertools.chain(old[idx+1:], reversed(old[:idx])): if j in new: reselect(j, current=True) return def _restore_scrollbars(self): vscroll = self.verticalScrollBar() if vscroll and self.old_vscroll is not None: vscroll.setValue(self.old_vscroll) self.old_vscroll = None hscroll = self.horizontalScrollBar() if hscroll and self.old_hscroll is not None: hscroll.setValue(self.old_hscroll) self.old_hscroll = None def _stage_selection(self): """Stage or unstage files according to the selection""" context = self.context selected_indexes = self.selected_indexes() if selected_indexes: category, idx = selected_indexes[0] # A header item e.g. 'Staged', 'Modified', etc. if category == self.idx_header: if idx == self.idx_staged: cmds.do(cmds.UnstageAll, context) elif idx == self.idx_modified: cmds.do(cmds.StageModified, context) elif idx == self.idx_untracked: cmds.do(cmds.StageUntracked, context) else: pass # Do nothing for unmerged items, by design return cmds.do(cmds.StageOrUnstage, context) def _staged_item(self, itemidx): return self._subtree_item(self.idx_staged, itemidx) def _modified_item(self, itemidx): return self._subtree_item(self.idx_modified, itemidx) def _unmerged_item(self, itemidx): return self._subtree_item(self.idx_unmerged, itemidx) def _untracked_item(self, itemidx): return self._subtree_item(self.idx_untracked, itemidx) def _unstaged_item(self, itemidx): # is it modified? item = self.topLevelItem(self.idx_modified) count = item.childCount() if itemidx < count: return item.child(itemidx) # is it unmerged? item = self.topLevelItem(self.idx_unmerged) count += item.childCount() if itemidx < count: return item.child(itemidx) # is it untracked? item = self.topLevelItem(self.idx_untracked) count += item.childCount() if itemidx < count: return item.child(itemidx) # Nope.. return None def _subtree_item(self, idx, itemidx): parent = self.topLevelItem(idx) return parent.child(itemidx) def _about_to_update(self): self._save_scrollbars() self._save_selection() def _save_scrollbars(self): vscroll = self.verticalScrollBar() if vscroll: self.old_vscroll = get(vscroll) hscroll = self.horizontalScrollBar() if hscroll: self.old_hscroll = get(hscroll) def current_item(self): s = self.selected_indexes() if not s: return None current = self.currentItem() if not current: return None idx = self.indexFromItem(current, 0) if idx.parent().isValid(): parent_idx = idx.parent() entry = (parent_idx.row(), idx.row()) else: entry = (self.idx_header, idx.row()) return entry def _save_selection(self): self.old_contents = self.contents() self.old_selection = self.selection() self.old_current_item = self.current_item() def refresh(self): self._set_staged(self.m.staged) self._set_modified(self.m.modified) self._set_unmerged(self.m.unmerged) self._set_untracked(self.m.untracked) self._update_column_widths() self._update_actions() self._restore_selection() self._restore_scrollbars() def _update_actions(self, selected=None): if selected is None: selected = self.selection_model.selection() can_revert_edits = bool(selected.staged or selected.modified) self.revert_unstaged_edits_action.setEnabled(can_revert_edits) def _set_staged(self, items): """Adds items to the 'Staged' subtree.""" self._set_subtree(items, self.idx_staged, N_('Staged'), staged=True, deleted_set=self.m.staged_deleted) def _set_modified(self, items): """Adds items to the 'Modified' subtree.""" self._set_subtree(items, self.idx_modified, N_('Modified'), deleted_set=self.m.unstaged_deleted) def _set_unmerged(self, items): """Adds items to the 'Unmerged' subtree.""" deleted_set = set([path for path in items if not core.exists(path)]) self._set_subtree(items, self.idx_unmerged, N_('Unmerged'), deleted_set=deleted_set) def _set_untracked(self, items): """Adds items to the 'Untracked' subtree.""" self._set_subtree(items, self.idx_untracked, N_('Untracked'), untracked=True) def _set_subtree(self, items, idx, parent_title, staged=False, untracked=False, deleted_set=None): """Add a list of items to a treewidget item.""" self.blockSignals(True) parent = self.topLevelItem(idx) hide = not bool(items) parent.setHidden(hide) # sip v4.14.7 and below leak memory in parent.takeChildren() # so we use this backwards-compatible construct instead while parent.takeChild(0) is not None: pass for item in items: deleted = (deleted_set is not None and item in deleted_set) treeitem = qtutils.create_treeitem(item, staged=staged, deleted=deleted, untracked=untracked) parent.addChild(treeitem) self._expand_items(idx, items) self.blockSignals(False) if prefs.status_show_totals(self.context): parent.setText(0, '%s (%s)' % (parent_title, len(items))) def _update_column_widths(self): self.resizeColumnToContents(0) def _expand_items(self, idx, items): """Expand the top-level category "folder" once and only once.""" # Don't do this if items is empty; this makes it so that we # don't add the top-level index into the expanded_items set # until an item appears in a particular category. if not items: return # Only run this once; we don't want to re-expand items that # we've clicked on to re-collapse on updated(). if idx in self.expanded_items: return self.expanded_items.add(idx) item = self.topLevelItem(idx) if item: self.expandItem(item) def contextMenuEvent(self, event): """Create context menus for the repo status tree.""" menu = self._create_context_menu() menu.exec_(self.mapToGlobal(event.pos())) def _create_context_menu(self): """Set up the status menu for the repo status tree.""" s = self.selection() menu = qtutils.create_menu('Status', self) selected_indexes = self.selected_indexes() if selected_indexes: category, idx = selected_indexes[0] # A header item e.g. 'Staged', 'Modified', etc. if category == self.idx_header: return self._create_header_context_menu(menu, idx) if s.staged: self._create_staged_context_menu(menu, s) elif s.unmerged: self._create_unmerged_context_menu(menu, s) else: self._create_unstaged_context_menu(menu, s) if not utils.is_win32(): if not menu.isEmpty(): menu.addSeparator() if not self.selection_model.is_empty(): menu.addAction(self.default_app_action) menu.addAction(self.parent_dir_action) if self.terminal_action is not None: menu.addAction(self.terminal_action) self._add_copy_actions(menu) return menu def _add_copy_actions(self, menu): """Add the "Copy" sub-menu""" enabled = self.selection_model.filename() is not None self.copy_path_action.setEnabled(enabled) self.copy_relpath_action.setEnabled(enabled) self.copy_leading_path_action.setEnabled(enabled) self.copy_basename_action.setEnabled(enabled) copy_icon = icons.copy() menu.addSeparator() copy_menu = QtWidgets.QMenu(N_('Copy...'), menu) menu.addMenu(copy_menu) copy_menu.setIcon(copy_icon) copy_menu.addAction(self.copy_path_action) copy_menu.addAction(self.copy_relpath_action) copy_menu.addAction(self.copy_leading_path_action) copy_menu.addAction(self.copy_basename_action) current_settings = settings.Settings() current_settings.load() copy_formats = current_settings.copy_formats if copy_formats: copy_menu.addSeparator() context = self.context for entry in copy_formats: name = entry.get('name', '') fmt = entry.get('format', '') if name and fmt: action = copy_menu.addAction( name, partial(copy_format, context, fmt)) action.setIcon(copy_icon) action.setEnabled(enabled) copy_menu.addSeparator() copy_menu.addAction(self.copy_customize_action) def _create_header_context_menu(self, menu, idx): context = self.context if idx == self.idx_staged: menu.addAction(icons.remove(), N_('Unstage All'), cmds.run(cmds.UnstageAll, context)) elif idx == self.idx_unmerged: action = menu.addAction(icons.add(), cmds.StageUnmerged.name(), cmds.run(cmds.StageUnmerged, context)) action.setShortcut(hotkeys.STAGE_SELECTION) elif idx == self.idx_modified: action = menu.addAction(icons.add(), cmds.StageModified.name(), cmds.run(cmds.StageModified, context)) action.setShortcut(hotkeys.STAGE_SELECTION) elif idx == self.idx_untracked: action = menu.addAction(icons.add(), cmds.StageUntracked.name(), cmds.run(cmds.StageUntracked, context)) action.setShortcut(hotkeys.STAGE_SELECTION) return menu def _create_staged_context_menu(self, menu, s): if s.staged[0] in self.m.submodules: return self._create_staged_submodule_context_menu(menu, s) context = self.context if self.m.unstageable(): action = menu.addAction( icons.remove(), N_('Unstage Selected'), cmds.run(cmds.Unstage, context, self.staged())) action.setShortcut(hotkeys.STAGE_SELECTION) menu.addAction(self.launch_editor_action) # Do all of the selected items exist? all_exist = all(i not in self.m.staged_deleted and core.exists(i) for i in self.staged()) if all_exist: menu.addAction(self.launch_difftool_action) if self.m.undoable(): menu.addAction(self.revert_unstaged_edits_action) menu.addAction(self.view_history_action) menu.addAction(self.view_blame_action) return menu def _create_staged_submodule_context_menu(self, menu, s): context = self.context path = core.abspath(s.staged[0]) if len(self.staged()) == 1: menu.addAction(icons.cola(), N_('Launch git-cola'), cmds.run(cmds.OpenRepo, context, path)) menu.addSeparator() action = menu.addAction( icons.remove(), N_('Unstage Selected'), cmds.run(cmds.Unstage, context, self.staged())) action.setShortcut(hotkeys.STAGE_SELECTION) menu.addAction(self.view_history_action) return menu def _create_unmerged_context_menu(self, menu, _s): context = self.context menu.addAction(self.launch_difftool_action) action = menu.addAction( icons.add(), N_('Stage Selected'), cmds.run(cmds.Stage, context, self.unstaged())) action.setShortcut(hotkeys.STAGE_SELECTION) menu.addAction(self.launch_editor_action) menu.addAction(self.view_history_action) menu.addAction(self.view_blame_action) return menu def _create_unstaged_context_menu(self, menu, s): context = self.context modified_submodule = (s.modified and s.modified[0] in self.m.submodules) if modified_submodule: return self._create_modified_submodule_context_menu(menu, s) if self.m.stageable(): action = menu.addAction( icons.add(), N_('Stage Selected'), cmds.run(cmds.Stage, context, self.unstaged())) action.setShortcut(hotkeys.STAGE_SELECTION) if not self.selection_model.is_empty(): menu.addAction(self.launch_editor_action) # Do all of the selected items exist? all_exist = all(i not in self.m.unstaged_deleted and core.exists(i) for i in self.staged()) if all_exist and s.modified and self.m.stageable(): menu.addAction(self.launch_difftool_action) if s.modified and self.m.stageable(): if self.m.undoable(): menu.addSeparator() menu.addAction(self.revert_unstaged_edits_action) if all_exist and s.untracked: # Git Annex / Git LFS annex = self.m.annex lfs = core.find_executable('git-lfs') if annex or lfs: menu.addSeparator() if annex: menu.addAction(self.annex_add_action) if lfs: menu.addAction(self.lfs_track_action) menu.addSeparator() if self.move_to_trash_action is not None: menu.addAction(self.move_to_trash_action) menu.addAction(self.delete_untracked_files_action) menu.addSeparator() menu.addAction(icons.edit(), N_('Ignore...'), partial(gitignore.gitignore_view, self.context)) if not self.selection_model.is_empty(): menu.addAction(self.view_history_action) menu.addAction(self.view_blame_action) return menu def _create_modified_submodule_context_menu(self, menu, s): context = self.context path = core.abspath(s.modified[0]) if len(self.unstaged()) == 1: menu.addAction(icons.cola(), N_('Launch git-cola'), cmds.run(cmds.OpenRepo, context, path)) menu.addAction(icons.pull(), N_('Update this submodule'), cmds.run(cmds.SubmoduleUpdate, context, path)) menu.addSeparator() if self.m.stageable(): menu.addSeparator() action = menu.addAction( icons.add(), N_('Stage Selected'), cmds.run(cmds.Stage, context, self.unstaged())) action.setShortcut(hotkeys.STAGE_SELECTION) menu.addAction(self.view_history_action) return menu def _delete_untracked_files(self): cmds.do(cmds.Delete, self.context, self.untracked()) def _trash_untracked_files(self): cmds.do(cmds.MoveToTrash, self.context, self.untracked()) def selected_path(self): s = self.single_selection() return s.staged or s.unmerged or s.modified or s.untracked or None def single_selection(self): """Scan across staged, modified, etc. and return a single item.""" staged = None unmerged = None modified = None untracked = None s = self.selection() if s.staged: staged = s.staged[0] elif s.unmerged: unmerged = s.unmerged[0] elif s.modified: modified = s.modified[0] elif s.untracked: untracked = s.untracked[0] return selection.State(staged, unmerged, modified, untracked) def selected_indexes(self): """Returns a list of (category, row) representing the tree selection.""" selected = self.selectedIndexes() result = [] for idx in selected: if idx.parent().isValid(): parent_idx = idx.parent() entry = (parent_idx.row(), idx.row()) else: entry = (self.idx_header, idx.row()) result.append(entry) return result def selection(self): """Return the current selection in the repo status tree.""" return selection.State(self.staged(), self.unmerged(), self.modified(), self.untracked()) def contents(self): return selection.State(self.m.staged, self.m.unmerged, self.m.modified, self.m.untracked) def all_files(self): c = self.contents() return c.staged + c.unmerged + c.modified + c.untracked def selected_group(self): """A list of selected files in various states of being""" return selection.pick(self.selection()) def selected_idx(self): c = self.contents() s = self.single_selection() offset = 0 for content, sel in zip(c, s): if not content: continue if sel is not None: return offset + content.index(sel) offset += len(content) return None def select_by_index(self, idx): c = self.contents() to_try = [ (c.staged, self.idx_staged), (c.unmerged, self.idx_unmerged), (c.modified, self.idx_modified), (c.untracked, self.idx_untracked), ] for content, toplevel_idx in to_try: if not content: continue if idx < len(content): parent = self.topLevelItem(toplevel_idx) item = parent.child(idx) if item is not None: self.select_item(item) return idx -= len(content) def scroll_to_item(self, item): # First, scroll to the item, but keep the original hscroll hscroll = None hscrollbar = self.horizontalScrollBar() if hscrollbar: hscroll = get(hscrollbar) self.scrollToItem(item) if hscroll is not None: hscrollbar.setValue(hscroll) def select_item(self, item): self.scroll_to_item(item) self.setCurrentItem(item) item.setSelected(True) def staged(self): return self._subtree_selection(self.idx_staged, self.m.staged) def unstaged(self): return self.unmerged() + self.modified() + self.untracked() def modified(self): return self._subtree_selection(self.idx_modified, self.m.modified) def unmerged(self): return self._subtree_selection(self.idx_unmerged, self.m.unmerged) def untracked(self): return self._subtree_selection(self.idx_untracked, self.m.untracked) def staged_items(self): return self._subtree_selection_items(self.idx_staged) def unstaged_items(self): return (self.unmerged_items() + self.modified_items() + self.untracked_items()) def modified_items(self): return self._subtree_selection_items(self.idx_modified) def unmerged_items(self): return self._subtree_selection_items(self.idx_unmerged) def untracked_items(self): return self._subtree_selection_items(self.idx_untracked) def _subtree_selection(self, idx, items): item = self.topLevelItem(idx) return qtutils.tree_selection(item, items) def _subtree_selection_items(self, idx): item = self.topLevelItem(idx) return qtutils.tree_selection_items(item) def _double_clicked(self, _item, _idx): """Called when an item is double-clicked in the repo status tree.""" cmds.do(cmds.StageOrUnstage, self.context) def show_selection(self): """Show the selected item.""" context = self.context self.scroll_to_item(self.currentItem()) # Sync the selection model selected = self.selection() selection_model = self.selection_model selection_model.set_selection(selected) self._update_actions(selected=selected) selected_indexes = self.selected_indexes() if not selected_indexes: if self.m.amending(): cmds.do(cmds.SetDiffText, context, '') else: cmds.do(cmds.ResetMode, context) return # A header item e.g. 'Staged', 'Modified', etc. category, idx = selected_indexes[0] header = category == self.idx_header if header: cls = { self.idx_staged: cmds.DiffStagedSummary, self.idx_modified: cmds.Diffstat, # TODO implement UnmergedSummary # self.idx_unmerged: cmds.UnmergedSummary, self.idx_untracked: cmds.UntrackedSummary, }.get(idx, cmds.Diffstat) cmds.do(cls, context) return staged = category == self.idx_staged modified = category == self.idx_modified unmerged = category == self.idx_unmerged untracked = category == self.idx_untracked if staged: item = self.staged_items()[0] elif unmerged: item = self.unmerged_items()[0] elif modified: item = self.modified_items()[0] elif untracked: item = self.unstaged_items()[0] else: item = None # this shouldn't happen assert item is not None path = item.path deleted = item.deleted image = self.image_formats.ok(path) # Images are diffed differently if image: cmds.do(cmds.DiffImage, context, path, deleted, staged, modified, unmerged, untracked) elif staged: cmds.do(cmds.DiffStaged, context, path, deleted=deleted) elif modified: cmds.do(cmds.Diff, context, path, deleted=deleted) elif unmerged: cmds.do(cmds.Diff, context, path) elif untracked: cmds.do(cmds.ShowUntracked, context, path) def select_header(self): """Select an active header, which triggers a diffstat""" for idx in (self.idx_staged, self.idx_unmerged, self.idx_modified, self.idx_untracked): item = self.topLevelItem(idx) if item.childCount() > 0: self.clearSelection() self.setCurrentItem(item) return def move_up(self): idx = self.selected_idx() all_files = self.all_files() if idx is None: selected_indexes = self.selected_indexes() if selected_indexes: category, toplevel_idx = selected_indexes[0] if category == self.idx_header: item = self.itemAbove(self.topLevelItem(toplevel_idx)) if item is not None: self.select_item(item) return if all_files: self.select_by_index(len(all_files) - 1) return if idx - 1 >= 0: self.select_by_index(idx - 1) else: self.select_by_index(len(all_files) - 1) def move_down(self): idx = self.selected_idx() all_files = self.all_files() if idx is None: selected_indexes = self.selected_indexes() if selected_indexes: category, toplevel_idx = selected_indexes[0] if category == self.idx_header: item = self.itemBelow(self.topLevelItem(toplevel_idx)) if item is not None: self.select_item(item) return if all_files: self.select_by_index(0) return if idx + 1 < len(all_files): self.select_by_index(idx + 1) else: self.select_by_index(0) def mimeData(self, items): """Return a list of absolute-path URLs""" context = self.context paths = qtutils.paths_from_items(items, item_filter=_item_filter) return qtutils.mimedata_from_paths(context, paths) # pylint: disable=no-self-use def mimeTypes(self): return qtutils.path_mimetypes() def _item_filter(item): return not item.deleted and core.exists(item.path) def view_blame(context): """Signal that we should view blame for paths.""" cmds.do(cmds.BlamePaths, context) def view_history(context): """Signal that we should view history for paths.""" cmds.do(cmds.VisualizePaths, context, context.selection.union()) def copy_path(context, absolute=True): """Copy a selected path to the clipboard""" filename = context.selection.filename() qtutils.copy_path(filename, absolute=absolute) def copy_relpath(context): """Copy a selected relative path to the clipboard""" copy_path(context, absolute=False) def copy_basename(context): filename = os.path.basename(context.selection.filename()) basename, _ = os.path.splitext(filename) qtutils.copy_path(basename, absolute=False) def copy_leading_path(context): """Copy the selected leading path to the clipboard""" filename = context.selection.filename() dirname = os.path.dirname(filename) qtutils.copy_path(dirname, absolute=False) def copy_format(context, fmt): values = {} values['path'] = path = context.selection.filename() values['abspath'] = abspath = os.path.abspath(path) values['absdirname'] = os.path.dirname(abspath) values['dirname'] = os.path.dirname(path) values['filename'] = os.path.basename(path) values['basename'], values['ext'] = ( os.path.splitext(os.path.basename(path))) qtutils.set_clipboard(fmt % values) def show_help(context): help_text = N_(r""" Format String Variables ----------------------- %(path)s = relative file path %(abspath)s = absolute file path %(dirname)s = relative directory path %(absdirname)s = absolute directory path %(filename)s = file basename %(basename)s = file basename without extension %(ext)s = file extension """) title = N_('Help - Custom Copy Actions') return text.text_dialog(context, help_text, title) class StatusFilterWidget(QtWidgets.QWidget): def __init__(self, context, parent=None): QtWidgets.QWidget.__init__(self, parent) self.context = context hint = N_('Filter paths...') self.text = completion.GitStatusFilterLineEdit( context, hint=hint, parent=self) self.text.setToolTip(hint) self.setFocusProxy(self.text) self._filter = None self.main_layout = qtutils.hbox(defs.no_margin, defs.spacing, self.text) self.setLayout(self.main_layout) widget = self.text # pylint: disable=no-member widget.changed.connect(self.apply_filter) widget.cleared.connect(self.apply_filter) widget.enter.connect(self.apply_filter) widget.editingFinished.connect(self.apply_filter) def apply_filter(self): value = get(self.text) if value == self._filter: return self._filter = value paths = utils.shell_split(value) self.context.model.update_path_filter(paths) def customize_copy_actions(context, parent): """Customize copy actions""" dialog = CustomizeCopyActions(context, parent) dialog.show() dialog.exec_() class CustomizeCopyActions(standard.Dialog): def __init__(self, context, parent): standard.Dialog.__init__(self, parent=parent) self.setWindowTitle(N_('Custom Copy Actions')) self.table = QtWidgets.QTableWidget(self) self.table.setColumnCount(2) self.table.setHorizontalHeaderLabels([ N_('Action Name'), N_('Format String'), ]) self.table.setSortingEnabled(False) self.table.verticalHeader().hide() self.table.horizontalHeader().setStretchLastSection(True) self.add_button = qtutils.create_button(N_('Add')) self.remove_button = qtutils.create_button(N_('Remove')) self.remove_button.setEnabled(False) self.show_help_button = qtutils.create_button(N_('Show Help')) self.show_help_button.setShortcut(hotkeys.QUESTION) self.close_button = qtutils.close_button() self.save_button = qtutils.ok_button(N_('Save')) self.buttons = qtutils.hbox(defs.no_margin, defs.button_spacing, self.add_button, self.remove_button, self.show_help_button, qtutils.STRETCH, self.close_button, self.save_button) layout = qtutils.vbox(defs.margin, defs.spacing, self.table, self.buttons) self.setLayout(layout) qtutils.connect_button(self.add_button, self.add) qtutils.connect_button(self.remove_button, self.remove) qtutils.connect_button( self.show_help_button, partial(show_help, context)) qtutils.connect_button(self.close_button, self.reject) qtutils.connect_button(self.save_button, self.save) qtutils.add_close_action(self) # pylint: disable=no-member self.table.itemSelectionChanged.connect(self.table_selection_changed) self.init_size(parent=parent) self.settings = settings.Settings() QtCore.QTimer.singleShot(0, self.reload_settings) def reload_settings(self): # Called once after the GUI is initialized self.settings.load() table = self.table for entry in self.settings.copy_formats: name_string = entry.get('name', '') format_string = entry.get('format', '') if name_string and format_string: name = QtWidgets.QTableWidgetItem(name_string) fmt = QtWidgets.QTableWidgetItem(format_string) rows = table.rowCount() table.setRowCount(rows + 1) table.setItem(rows, 0, name) table.setItem(rows, 1, fmt) def export_state(self): state = super(CustomizeCopyActions, self).export_state() standard.export_header_columns(self.table, state) return state def apply_state(self, state): result = super(CustomizeCopyActions, self).apply_state(state) standard.apply_header_columns(self.table, state) return result def add(self): self.table.setFocus() rows = self.table.rowCount() self.table.setRowCount(rows + 1) name = QtWidgets.QTableWidgetItem(N_('Name')) fmt = QtWidgets.QTableWidgetItem(r'%(path)s') self.table.setItem(rows, 0, name) self.table.setItem(rows, 1, fmt) self.table.setCurrentCell(rows, 0) self.table.editItem(name) def remove(self): """Remove selected items""" # Gather a unique set of rows and remove them in reverse order rows = set() items = self.table.selectedItems() for item in items: rows.add(self.table.row(item)) for row in reversed(sorted(rows)): self.table.removeRow(row) def save(self): copy_formats = [] for row in range(self.table.rowCount()): name = self.table.item(row, 0) fmt = self.table.item(row, 1) if name and fmt: entry = { 'name': name.text(), 'format': fmt.text(), } copy_formats.append(entry) while self.settings.copy_formats: self.settings.copy_formats.pop() self.settings.copy_formats.extend(copy_formats) self.settings.save() self.accept() def table_selection_changed(self): items = self.table.selectedItems() self.remove_button.setEnabled(bool(items)) git-cola-3.6/cola/widgets/submodules.py000066400000000000000000000077541356743264500202350ustar00rootroot00000000000000"""Provides widgets related to submodules""" from __future__ import absolute_import from qtpy import QtWidgets from qtpy.QtCore import Qt from qtpy.QtCore import Signal from .. import cmds from .. import core from .. import qtutils from .. import icons from ..i18n import N_ from ..widgets import defs from ..widgets import standard class SubmodulesWidget(QtWidgets.QFrame): def __init__(self, context, parent): QtWidgets.QFrame.__init__(self, parent) self.setToolTip(N_('Submodules')) self.tree = SubmodulesTreeWidget(context, parent=self) self.setFocusProxy(self.tree) self.main_layout = qtutils.vbox(defs.no_margin, defs.spacing, self.tree) self.setLayout(self.main_layout) # Titlebar buttons self.refresh_button = qtutils.create_action_button( tooltip=N_('Refresh'), icon=icons.sync()) self.open_parent_button = qtutils.create_action_button( tooltip=N_('Open Parent'), icon=icons.repo()) self.button_layout = qtutils.hbox(defs.no_margin, defs.spacing, self.open_parent_button, self.refresh_button) self.corner_widget = QtWidgets.QWidget(self) self.corner_widget.setLayout(self.button_layout) titlebar = parent.titleBarWidget() titlebar.add_corner_widget(self.corner_widget) # Connections qtutils.connect_button(self.refresh_button, context.model.update_submodules_list) qtutils.connect_button(self.open_parent_button, cmds.run(cmds.OpenParentRepo, context)) # pylint: disable=too-many-ancestors class SubmodulesTreeWidget(standard.TreeWidget): updated = Signal() def __init__(self, context, parent=None): standard.TreeWidget.__init__(self, parent=parent) model = context.model self.context = context self.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) self.setHeaderHidden(True) # UI self._active = False self.list_helper = BuildItem() # Connections # pylint: disable=no-member self.itemDoubleClicked.connect(self.tree_double_clicked) self.updated.connect(self.refresh, type=Qt.QueuedConnection) model.add_observer(model.message_submodules_changed, self.updated.emit) def refresh(self): if not self._active: return submodules = self.context.model.submodules_list items = [self.list_helper.get(entry) for entry in submodules] self.clear() if items: self.addTopLevelItems(items) def showEvent(self, event): """Defer updating widgets until the widget is visible""" if not self._active: self._active = True self.refresh() return super(SubmodulesTreeWidget, self).showEvent(event) def tree_double_clicked(self, item, _column): path = core.abspath(item.path) cmds.do(cmds.OpenRepo, self.context, path) class BuildItem(object): def __init__(self): self.state_folder_map = {} self.state_folder_map[''] = icons.folder() self.state_folder_map['+'] = icons.staged() self.state_folder_map['-'] = icons.modified() self.state_folder_map['U'] = icons.merge() def get(self, entry): """entry: same as returned from list_submodule""" name = entry[2] path = entry[2] # TODO better tip tip = path + '\n' + entry[1] if entry[3]: tip += '\n({0})'.format(entry[3]) icon = self.state_folder_map[entry[0]] return SubmodulesTreeWidgetItem(name, path, tip, icon) class SubmodulesTreeWidgetItem(QtWidgets.QTreeWidgetItem): def __init__(self, name, path, tip, icon): QtWidgets.QTreeWidgetItem.__init__(self) self.path = path self.setIcon(0, icon) self.setText(0, name) self.setToolTip(0, tip) git-cola-3.6/cola/widgets/text.py000066400000000000000000000674751356743264500170450ustar00rootroot00000000000000"""Text widgets""" # pylint: disable=unexpected-keyword-arg from __future__ import division, absolute_import, unicode_literals import math from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from qtpy.QtCore import Qt from qtpy.QtCore import Signal from ..models import prefs from ..qtutils import get from .. import hotkeys from .. import qtutils from ..i18n import N_ from . import defs def get_stripped(widget): return widget.get().strip() class LineEdit(QtWidgets.QLineEdit): cursor_changed = Signal(int, int) def __init__(self, parent=None, row=1, get_value=None, clear_button=False): QtWidgets.QLineEdit.__init__(self, parent) self._row = row if get_value is None: get_value = get_stripped self._get_value = get_value self.cursor_position = LineEditCursorPosition(self, row) if clear_button and hasattr(self, 'setClearButtonEnabled'): self.setClearButtonEnabled(True) def get(self): """Return the raw unicode value from Qt""" return self.text() def value(self): """Return the processed value, e.g. stripped""" return self._get_value(self) def set_value(self, value, block=False): if block: blocksig = self.blockSignals(True) pos = self.cursorPosition() self.setText(value) self.setCursorPosition(pos) if block: self.blockSignals(blocksig) class LineEditCursorPosition(object): """Translate cursorPositionChanged(int,int) into cursorPosition(int,int) """ def __init__(self, widget, row): self._widget = widget self._row = row # Translate cursorPositionChanged into cursor_changed(int, int) widget.cursorPositionChanged.connect(lambda old, new: self.emit()) def emit(self): widget = self._widget row = self._row col = widget.cursorPosition() widget.cursor_changed.emit(row, col) def reset(self): self._widget.setCursorPosition(0) class BaseTextEditExtension(QtCore.QObject): def __init__(self, widget, get_value, readonly): QtCore.QObject.__init__(self, widget) self.widget = widget self.cursor_position = TextEditCursorPosition(widget, self) if get_value is None: get_value = get_stripped self._get_value = get_value self._tabwidth = 8 self._readonly = readonly self._init_flags() self.init() def _init_flags(self): widget = self.widget widget.setMinimumSize(QtCore.QSize(1, 1)) widget.setWordWrapMode(QtGui.QTextOption.WordWrap) widget.setLineWrapMode(widget.NoWrap) if self._readonly: widget.setReadOnly(True) widget.setAcceptDrops(False) widget.setTabChangesFocus(True) widget.setUndoRedoEnabled(False) widget.setTextInteractionFlags(Qt.TextSelectableByKeyboard | Qt.TextSelectableByMouse) def get(self): """Return the raw unicode value from Qt""" return self.widget.toPlainText() def value(self): """Return a safe value, e.g. a stripped value""" return self._get_value(self.widget) def set_value(self, value, block=False): if block: blocksig = self.widget.blockSignals(True) # Save cursor position offset, selection_text = self.offset_and_selection() old_value = get(self.widget) # Update text self.widget.setPlainText(value) # Restore cursor if selection_text and selection_text in value: # If the old selection exists in the new text then re-select it. idx = value.index(selection_text) cursor = self.widget.textCursor() cursor.setPosition(idx) cursor.setPosition(idx + len(selection_text), QtGui.QTextCursor.KeepAnchor) self.widget.setTextCursor(cursor) elif value == old_value: # Otherwise, if the text is identical and there is no selection # then restore the cursor position. cursor = self.widget.textCursor() cursor.setPosition(offset) self.widget.setTextCursor(cursor) else: # If none of the above applied then restore the cursor position. position = max(0, min(offset, len(value) - 1)) cursor = self.widget.textCursor() cursor.setPosition(position) self.widget.setTextCursor(cursor) cursor = self.widget.textCursor() cursor.movePosition(QtGui.QTextCursor.StartOfLine) self.widget.setTextCursor(cursor) if block: self.widget.blockSignals(blocksig) def set_cursor_position(self, new_position): cursor = self.widget.textCursor() cursor.setPosition(new_position) self.widget.setTextCursor(cursor) def tabwidth(self): return self._tabwidth def set_tabwidth(self, width): self._tabwidth = width font = self.widget.font() fm = QtGui.QFontMetrics(font) pixels = fm.width('M' * width) self.widget.setTabStopWidth(pixels) def selected_line(self): contents = self.value() cursor = self.widget.textCursor() offset = min(cursor.position(), len(contents)-1) while (offset >= 1 and contents[offset-1] and contents[offset-1] != '\n'): offset -= 1 data = contents[offset:] if '\n' in data: line, _ = data.split('\n', 1) else: line = data return line def cursor(self): return self.widget.textCursor() def has_selection(self): return self.cursor().hasSelection() def offset_and_selection(self): cursor = self.cursor() offset = cursor.selectionStart() selection_text = cursor.selection().toPlainText() return offset, selection_text def mouse_press_event(self, event): # Move the text cursor so that the right-click events operate # on the current position, not the last left-clicked position. widget = self.widget if event.button() == Qt.RightButton: if not widget.textCursor().hasSelection(): cursor = widget.cursorForPosition(event.pos()) widget.setTextCursor(cursor) # For extension by sub-classes # pylint: disable=no-self-use def init(self): """Called during init for class-specific settings""" return # pylint: disable=no-self-use,unused-argument def set_textwidth(self, width): """Set the text width""" return # pylint: disable=no-self-use,unused-argument def set_linebreak(self, brk): """Enable word wrapping""" return class PlainTextEditExtension(BaseTextEditExtension): def set_linebreak(self, brk): if brk: wrapmode = QtWidgets.QPlainTextEdit.WidgetWidth else: wrapmode = QtWidgets.QPlainTextEdit.NoWrap self.widget.setLineWrapMode(wrapmode) class PlainTextEdit(QtWidgets.QPlainTextEdit): cursor_changed = Signal(int, int) leave = Signal() def __init__(self, parent=None, get_value=None, readonly=False): QtWidgets.QPlainTextEdit.__init__(self, parent) self.ext = PlainTextEditExtension(self, get_value, readonly) self.cursor_position = self.ext.cursor_position def get(self): """Return the raw unicode value from Qt""" return self.ext.get() # For compatibility with QTextEdit def setText(self, value): self.set_value(value) def value(self): """Return a safe value, e.g. a stripped value""" return self.ext.value() def set_value(self, value, block=False): self.ext.set_value(value, block=block) def has_selection(self): return self.ext.has_selection() def selected_line(self): return self.ext.selected_line() def set_tabwidth(self, width): self.ext.set_tabwidth(width) def set_textwidth(self, width): self.ext.set_textwidth(width) def set_linebreak(self, brk): self.ext.set_linebreak(brk) def mousePressEvent(self, event): self.ext.mouse_press_event(event) super(PlainTextEdit, self).mousePressEvent(event) def wheelEvent(self, event): """Disable control+wheelscroll text resizing""" if event.modifiers() & Qt.ControlModifier: event.ignore() return super(PlainTextEdit, self).wheelEvent(event) class TextEditExtension(BaseTextEditExtension): def init(self): widget = self.widget widget.setAcceptRichText(False) def set_linebreak(self, brk): if brk: wrapmode = QtWidgets.QTextEdit.FixedColumnWidth else: wrapmode = QtWidgets.QTextEdit.NoWrap self.widget.setLineWrapMode(wrapmode) def set_textwidth(self, width): self.widget.setLineWrapColumnOrWidth(width) class TextEdit(QtWidgets.QTextEdit): cursor_changed = Signal(int, int) leave = Signal() def __init__(self, parent=None, get_value=None, readonly=False): QtWidgets.QTextEdit.__init__(self, parent) self.ext = TextEditExtension(self, get_value, readonly) self.cursor_position = self.ext.cursor_position self.expandtab_enabled = False def get(self): """Return the raw unicode value from Qt""" return self.ext.get() def value(self): """Return a safe value, e.g. a stripped value""" return self.ext.value() def set_value(self, value, block=False): self.ext.set_value(value, block=block) def selected_line(self): return self.ext.selected_line() def set_tabwidth(self, width): self.ext.set_tabwidth(width) def set_textwidth(self, width): self.ext.set_textwidth(width) def set_linebreak(self, brk): self.ext.set_linebreak(brk) def set_expandtab(self, value): self.expandtab_enabled = value def mousePressEvent(self, event): self.ext.mouse_press_event(event) super(TextEdit, self).mousePressEvent(event) def wheelEvent(self, event): """Disable control+wheelscroll text resizing""" if event.modifiers() & Qt.ControlModifier: event.ignore() return super(TextEdit, self).wheelEvent(event) def should_expandtab(self, event): return event.key() == Qt.Key_Tab and self.expandtab_enabled def expandtab(self): tabwidth = max(self.ext.tabwidth(), 1) cursor = self.textCursor() cursor.insertText(' ' * tabwidth) def keyPressEvent(self, event): expandtab = self.should_expandtab(event) if expandtab: self.expandtab() event.accept() else: QtWidgets.QTextEdit.keyPressEvent(self, event) def keyReleaseEvent(self, event): expandtab = self.should_expandtab(event) if expandtab: event.ignore() else: QtWidgets.QTextEdit.keyReleaseEvent(self, event) class TextEditCursorPosition(object): def __init__(self, widget, ext): self._widget = widget self._ext = ext widget.cursorPositionChanged.connect(self.emit) def emit(self): widget = self._widget ext = self._ext cursor = widget.textCursor() position = cursor.position() txt = widget.get() before = txt[:position] row = before.count('\n') line = before.split('\n')[row] col = cursor.columnNumber() col += line[:col].count('\t') * (ext.tabwidth() - 1) widget.cursor_changed.emit(row+1, col) def reset(self): widget = self._widget cursor = widget.textCursor() cursor.setPosition(0) widget.setTextCursor(cursor) class MonoTextEdit(PlainTextEdit): def __init__(self, context, parent=None, readonly=False): PlainTextEdit.__init__(self, parent=parent, readonly=readonly) self.setFont(qtutils.diff_font(context)) def get_value_hinted(widget): text = get_stripped(widget) hint = get(widget.hint) if text == hint: return '' return text class HintWidget(QtCore.QObject): """Extend a widget to provide hint messages This primarily exists because setPlaceholderText() is only available in Qt5, so this class provides consistent behavior across versions. """ def __init__(self, widget, hint): QtCore.QObject.__init__(self, widget) self._widget = widget self._hint = hint self._is_error = False self.modern = modern = hasattr(widget, 'setPlaceholderText') if modern: widget.setPlaceholderText(hint) # Palette for normal text QPalette = QtGui.QPalette palette = widget.palette() hint_color = palette.color(QPalette.Disabled, QPalette.Text) error_bg_color = QtGui.QColor(Qt.red).darker() error_fg_color = QtGui.QColor(Qt.white) hint_rgb = qtutils.rgb_css(hint_color) error_bg_rgb = qtutils.rgb_css(error_bg_color) error_fg_rgb = qtutils.rgb_css(error_fg_color) env = dict(name=widget.__class__.__name__, error_fg_rgb=error_fg_rgb, error_bg_rgb=error_bg_rgb, hint_rgb=hint_rgb) self._default_style = '' self._hint_style = """ %(name)s { color: %(hint_rgb)s; } """ % env self._error_style = """ %(name)s { color: %(error_fg_rgb)s; background-color: %(error_bg_rgb)s; } """ % env def init(self): """Defered initialization""" if self.modern: self.widget().setPlaceholderText(self.value()) else: self.widget().installEventFilter(self) self.enable(True) def widget(self): """Return the parent text widget""" return self._widget def active(self): """Return True when hint-mode is active""" return self.value() == get_stripped(self._widget) def value(self): """Return the current hint text""" return self._hint def set_error(self, is_error): """Enable/disable error mode""" self._is_error = is_error self.refresh() def set_value(self, hint): """Change the hint text""" if self.modern: self._hint = hint self._widget.setPlaceholderText(hint) else: # If hint-mode is currently active, re-activate it active = self.active() self._hint = hint if active or self.active(): self.enable(True) def enable(self, enable): """Enable/disable hint-mode""" if not self.modern: if enable and self._hint: self._widget.set_value(self._hint, block=True) self._widget.cursor_position.reset() else: self._widget.clear() self._update_palette(enable) def refresh(self): """Update the palette to match the current mode""" self._update_palette(self.active()) def _update_palette(self, hint): """Update to palette for normal/error/hint mode""" if self._is_error: style = self._error_style elif not self.modern and hint: style = self._hint_style else: style = self._default_style QtCore.QTimer.singleShot( 0, lambda: self._widget.setStyleSheet(style)) def eventFilter(self, _obj, event): """Enable/disable hint-mode when focus changes""" etype = event.type() if etype == QtCore.QEvent.FocusIn: self.focus_in() elif etype == QtCore.QEvent.FocusOut: self.focus_out() return False def focus_in(self): """Disable hint-mode when focused""" widget = self.widget() if self.active(): self.enable(False) widget.cursor_position.emit() def focus_out(self): """Re-enable hint-mode when losing focus""" widget = self.widget() if not get(widget): self.enable(True) class HintedPlainTextEdit(PlainTextEdit): """A hinted plain text edit""" def __init__(self, context, hint, parent=None, readonly=False): PlainTextEdit.__init__(self, parent=parent, get_value=get_value_hinted, readonly=readonly) self.hint = HintWidget(self, hint) self.hint.init() self.setFont(qtutils.diff_font(context)) self.set_tabwidth(prefs.tabwidth(context)) # Refresh palettes when text changes # pylint: disable=no-member self.textChanged.connect(self.hint.refresh) def set_value(self, value, block=False): """Set the widget text or enable hint mode when empty""" if value or self.hint.modern: PlainTextEdit.set_value(self, value, block=block) else: self.hint.enable(True) class HintedTextEdit(TextEdit): """A hinted text edit""" def __init__(self, context, hint, parent=None, readonly=False): TextEdit.__init__(self, parent=parent, get_value=get_value_hinted, readonly=readonly) self.hint = HintWidget(self, hint) self.hint.init() # Refresh palettes when text changes # pylint: disable=no-member self.textChanged.connect(self.hint.refresh) self.setFont(qtutils.diff_font(context)) def set_value(self, value, block=False): """Set the widget text or enable hint mode when empty""" if value or self.hint.modern: TextEdit.set_value(self, value, block=block) else: self.hint.enable(True) # The vim-like read-only text view class VimMixin(object): def __init__(self, widget): self.widget = widget self.Base = widget.Base # Common vim/unix-ish keyboard actions self.add_navigation('Up', hotkeys.MOVE_UP, shift=hotkeys.MOVE_UP_SHIFT) self.add_navigation('Down', hotkeys.MOVE_DOWN, shift=hotkeys.MOVE_DOWN_SHIFT) self.add_navigation('Left', hotkeys.MOVE_LEFT, shift=hotkeys.MOVE_LEFT_SHIFT) self.add_navigation('Right', hotkeys.MOVE_RIGHT, shift=hotkeys.MOVE_RIGHT_SHIFT) self.add_navigation('WordLeft', hotkeys.WORD_LEFT) self.add_navigation('WordRight', hotkeys.WORD_RIGHT) self.add_navigation('StartOfLine', hotkeys.START_OF_LINE) self.add_navigation('EndOfLine', hotkeys.END_OF_LINE) qtutils.add_action(widget, 'PageUp', lambda: widget.page(-widget.height()//2), hotkeys.SECONDARY_ACTION) qtutils.add_action(widget, 'PageDown', lambda: widget.page(widget.height()//2), hotkeys.PRIMARY_ACTION) def add_navigation(self, name, hotkey, shift=None): """Add a hotkey along with a shift-variant""" widget = self.widget direction = getattr(QtGui.QTextCursor, name) qtutils.add_action(widget, name, lambda: self.move(direction), hotkey) if shift: qtutils.add_action(widget, 'Shift' + name, lambda: self.move(direction, True), shift) def move(self, direction, select=False, n=1): widget = self.widget cursor = widget.textCursor() if select: mode = QtGui.QTextCursor.KeepAnchor else: mode = QtGui.QTextCursor.MoveAnchor if cursor.movePosition(direction, mode, n): self.set_text_cursor(cursor) def page(self, offset): widget = self.widget rect = widget.cursorRect() x = rect.x() y = rect.y() + offset new_cursor = widget.cursorForPosition(QtCore.QPoint(x, y)) if new_cursor is not None: self.set_text_cursor(new_cursor) def set_text_cursor(self, cursor): widget = self.widget widget.setTextCursor(cursor) widget.ensureCursorVisible() widget.viewport().update() def keyPressEvent(self, event): """Custom keyboard behaviors The leave() signal is emitted when `Up` is pressed and we're already at the beginning of the text. This allows the parent widget to orchestrate some higher-level interaction, such as giving focus to another widget. When in the middle of the first line and `Up` is pressed, the cursor is moved to the beginning of the line. """ widget = self.widget if event.key() == Qt.Key_Up: cursor = widget.textCursor() position = cursor.position() if position == 0: # The cursor is at the beginning of the line. # Emit a signal so that the parent can e.g. change focus. widget.leave.emit() elif get(widget)[:position].count('\n') == 0: # The cursor is in the middle of the first line of text. # We can't go up ~ jump to the beginning of the line. # Select the text if shift is pressed. if event.modifiers() & Qt.ShiftModifier: mode = QtGui.QTextCursor.KeepAnchor else: mode = QtGui.QTextCursor.MoveAnchor cursor.movePosition(QtGui.QTextCursor.StartOfLine, mode) widget.setTextCursor(cursor) return self.Base.keyPressEvent(widget, event) # pylint: disable=too-many-ancestors class VimHintedPlainTextEdit(HintedPlainTextEdit): """HintedPlainTextEdit with vim hotkeys This can only be used in read-only mode. """ Base = HintedPlainTextEdit Mixin = VimMixin def __init__(self, context, hint, parent=None): HintedPlainTextEdit.__init__( self, context, hint, parent=parent, readonly=True) self._mixin = self.Mixin(self) def move(self, direction, select=False, n=1): return self._mixin.page(direction, select=select, n=n) def page(self, offset): return self._mixin.page(offset) def keyPressEvent(self, event): return self._mixin.keyPressEvent(event) # pylint: disable=too-many-ancestors class VimTextEdit(MonoTextEdit): """Text viewer with vim-like hotkeys This can only be used in read-only mode. """ Base = MonoTextEdit Mixin = VimMixin def __init__(self, context, parent=None, readonly=True): MonoTextEdit.__init__(self, context, parent=None, readonly=readonly) self._mixin = self.Mixin(self) def move(self, direction, select=False, n=1): return self._mixin.page(direction, select=select, n=n) def page(self, offset): return self._mixin.page(offset) def keyPressEvent(self, event): return self._mixin.keyPressEvent(event) class HintedLineEdit(LineEdit): def __init__(self, context, hint, parent=None): LineEdit.__init__(self, parent=parent, get_value=get_value_hinted) self.hint = HintWidget(self, hint) self.hint.init() self.setFont(qtutils.diff_font(context)) # pylint: disable=no-member self.textChanged.connect(lambda text: self.hint.refresh()) def text_dialog(context, text, title): """Show a wall of text in a dialog""" parent = qtutils.active_window() label = QtWidgets.QLabel(parent) label.setFont(qtutils.diff_font(context)) label.setText(text) label.setMargin(defs.large_margin) text_flags = Qt.TextSelectableByKeyboard | Qt.TextSelectableByMouse label.setTextInteractionFlags(text_flags) widget = QtWidgets.QDialog(parent) widget.setWindowModality(Qt.WindowModal) widget.setWindowTitle(title) scroll = QtWidgets.QScrollArea() scroll.setWidget(label) layout = qtutils.hbox(defs.margin, defs.spacing, scroll) widget.setLayout(layout) qtutils.add_action(widget, N_('Close'), widget.accept, Qt.Key_Question, Qt.Key_Enter, Qt.Key_Return) widget.show() return widget class VimTextBrowser(VimTextEdit): """Text viewer with line number annotations""" def __init__(self, context, parent=None, readonly=True): VimTextEdit.__init__(self, context, parent=parent, readonly=readonly) self.numbers = LineNumbers(self) def resizeEvent(self, event): super(VimTextBrowser, self).resizeEvent(event) self.numbers.refresh_size() class TextDecorator(QtWidgets.QWidget): """Common functionality for providing line numbers in text widgets""" def __init__(self, parent): QtWidgets.QWidget.__init__(self, parent) self.editor = parent parent.blockCountChanged.connect(lambda x: self._refresh_viewport()) parent.cursorPositionChanged.connect(self.refresh) parent.updateRequest.connect(self._refresh_rect) def refresh(self): """Refresh the numbers display""" rect = self.editor.viewport().rect() self._refresh_rect(rect, 0) def _refresh_rect(self, rect, dy): if dy: self.scroll(0, dy) else: self.update(0, rect.y(), self.width(), rect.height()) if rect.contains(self.editor.viewport().rect()): self._refresh_viewport() def _refresh_viewport(self): self.editor.setViewportMargins(self.width_hint(), 0, 0, 0) def refresh_size(self): rect = self.editor.contentsRect() geom = QtCore.QRect(rect.left(), rect.top(), self.width_hint(), rect.height()) self.setGeometry(geom) def sizeHint(self): return QtCore.QSize(self.width_hint(), 0) class LineNumbers(TextDecorator): """Provide line numbers for QPlainTextEdit widgets""" def __init__(self, parent): TextDecorator.__init__(self, parent) self.highlight_line = -1 def width_hint(self): document = self.editor.document() digits = int(math.log(max(1, document.blockCount()), 10)) + 2 return defs.large_margin + self.fontMetrics().width('0') * digits def set_highlighted(self, line_number): """Set the line to highlight""" self.highlight_line = line_number def paintEvent(self, event): """Paint the line number""" QPalette = QtGui.QPalette painter = QtGui.QPainter(self) editor = self.editor palette = editor.palette() painter.fillRect(event.rect(), palette.color(QPalette.Base)) content_offset = editor.contentOffset() block = editor.firstVisibleBlock() width = self.width() event_rect_bottom = event.rect().bottom() highlight = palette.color(QPalette.Highlight) highlighted_text = palette.color(QPalette.HighlightedText) disabled = palette.color(QPalette.Disabled, QPalette.Text) while block.isValid(): block_geom = editor.blockBoundingGeometry(block) block_top = block_geom.translated(content_offset).top() if not block.isVisible() or block_top >= event_rect_bottom: break rect = block_geom.translated(content_offset).toRect() block_number = block.blockNumber() if block_number == self.highlight_line: painter.fillRect(rect.x(), rect.y(), width, rect.height(), highlight) painter.setPen(highlighted_text) else: painter.setPen(disabled) number = '%s' % (block_number + 1) painter.drawText(rect.x(), rect.y(), self.width() - defs.large_margin, rect.height(), Qt.AlignRight | Qt.AlignVCenter, number) block = block.next() # pylint: disable=next-method-called git-cola-3.6/cola/widgets/toolbar.py000066400000000000000000000362601356743264500175070ustar00rootroot00000000000000from __future__ import division, absolute_import, unicode_literals from functools import partial from qtpy import QtGui from qtpy.QtCore import Qt from qtpy import QtWidgets from ..i18n import N_ from ..widgets import standard from ..qtutils import get from .. import icons from .. import qtutils from .toolbarcmds import COMMANDS from . import defs TREE_LAYOUT = { 'Others': [ 'Others::LaunchEditor', 'Others::RevertUnstagedEdits' ], 'File': [ 'File::NewRepo', 'File::OpenRepo', 'File::OpenRepoNewWindow', 'File::Refresh', 'File::EditRemotes', 'File::RecentModified', 'File::SaveAsTarZip', 'File::ApplyPatches', 'File::ExportPatches', ], 'Actions': [ 'Actions::Fetch', 'Actions::Pull', 'Actions::Push', 'Actions::Stash', 'Actions::CreateTag', 'Actions::CherryPick', 'Actions::Merge', 'Actions::AbortMerge', 'Actions::UpdateSubmodules', 'Actions::ResetBranchHead', 'Actions::ResetWorktree', 'Actions::Grep', 'Actions::Search' ], 'Commit@@verb': [ 'Commit::Stage', 'Commit::AmendLast', 'Commit::StageAll', 'Commit::UnstageAll', 'Commit::Unstage', 'Commit::LoadCommitMessage', 'Commit::GetCommitMessageTemplate', ], 'Diff': [ 'Diff::Difftool', 'Diff::Expression', 'Diff::Branches', 'Diff::Diffstat' ], 'Branch': [ 'Branch::Review', 'Branch::Create', 'Branch::Checkout', 'Branch::Delete', 'Branch::DeleteRemote', 'Branch::Rename', 'Branch::BrowseCurrent', 'Branch::BrowseOther', 'Branch::VisualizeCurrent', 'Branch::VisualizeAll' ], 'View': [ 'View::DAG', 'View::FileBrowser', ] } def configure(toolbar, parent=None): """Launches the Toolbar configure dialog""" view = ToolbarView(toolbar, parent if parent else qtutils.active_window()) view.show() return view def get_toolbars(widget): return widget.findChildren(ToolBar) def add_toolbar(context, widget): toolbars = get_toolbars(widget) name = 'ToolBar%d' % (len(toolbars) + 1) toolbar = ToolBar.create(context, name) widget.addToolBar(toolbar) configure(toolbar) class ToolBarState(object): """export_state() and apply_state() providers for toolbars""" def __init__(self, context, widget): """widget must be a QMainWindow for toolBarArea(), etc.""" self.context = context self.widget = widget def apply_state(self, toolbars): context = self.context widget = self.widget for data in toolbars: toolbar = ToolBar.create(context, data['name']) toolbar.load_items(data['items']) toolbar.set_show_icons(data['show_icons']) toolbar.setVisible(data['visible']) toolbar_area = decode_toolbar_area(data['area']) if data['break']: widget.addToolBarBreak(toolbar_area) widget.addToolBar(toolbar_area, toolbar) # floating toolbars must be set after added if data['float']: toolbar.setWindowFlags(Qt.Tool | Qt.FramelessWindowHint) toolbar.move(data['x'], data['y']) # TODO: handle changed width when exists more than one toolbar in # an area def export_state(self): result = [] widget = self.widget toolbars = widget.findChildren(ToolBar) for toolbar in toolbars: toolbar_area = widget.toolBarArea(toolbar) if toolbar_area == Qt.NoToolBarArea: continue # filter out removed toolbars items = [x.data() for x in toolbar.actions()] result.append({ 'name': toolbar.windowTitle(), 'area': encode_toolbar_area(toolbar_area), 'break': widget.toolBarBreak(toolbar), 'float': toolbar.isFloating(), 'x': toolbar.pos().x(), 'y': toolbar.pos().y(), 'width': toolbar.width(), 'height': toolbar.height(), 'show_icons': toolbar.show_icons(), 'visible': toolbar.isVisible(), 'items': items, }) return result class ToolBar(QtWidgets.QToolBar): SEPARATOR = 'Separator' @staticmethod def create(context, name): return ToolBar(context, name, TREE_LAYOUT, COMMANDS) def __init__(self, context, title, tree_layout, toolbar_commands): QtWidgets.QToolBar.__init__(self) self.setWindowTitle(title) self.setObjectName(title) self.context = context self.tree_layout = tree_layout self.commands = toolbar_commands def set_show_icons(self, show_icons): if show_icons: self.setToolButtonStyle(Qt.ToolButtonIconOnly) else: self.setToolButtonStyle(Qt.ToolButtonTextOnly) def show_icons(self): return self.toolButtonStyle() == Qt.ToolButtonIconOnly def load_items(self, items): for data in items: self.add_action_from_data(data) def add_action_from_data(self, data): parent = data['parent'] child = data['child'] if child == self.SEPARATOR: toolbar_action = self.addSeparator() toolbar_action.setData(data) return tree_items = self.tree_layout.get(parent, []) if child in tree_items and child in self.commands: command = self.commands[child] title = N_(command['title']) callback = partial(command['action'], self.context) icon = None command_icon = command.get('icon', None) if command_icon: icon = getattr(icons, command_icon, None) if callable(icon): icon = icon() if icon: toolbar_action = self.addAction(icon, title, callback) else: toolbar_action = self.addAction(title, callback) toolbar_action.setData(data) def delete_toolbar(self): self.parent().removeToolBar(self) def contextMenuEvent(self, event): menu = QtWidgets.QMenu() menu.addAction(N_('Configure toolbar'), partial(configure, self)) menu.addAction(N_('Delete toolbar'), self.delete_toolbar) menu.exec_(event.globalPos()) def encode_toolbar_area(toolbar_area): """Encode a Qt::ToolBarArea as a string""" if toolbar_area == Qt.LeftToolBarArea: result = 'left' elif toolbar_area == Qt.RightToolBarArea: result = 'right' elif toolbar_area == Qt.TopToolBarArea: result = 'top' elif toolbar_area == Qt.BottomToolBarArea: result = 'bottom' else: # fallback to "bottom" result = 'bottom' return result def decode_toolbar_area(string): """Decode an encoded toolbar area string into a Qt::ToolBarArea""" if string == 'left': result = Qt.LeftToolBarArea elif string == 'right': result = Qt.RightToolBarArea elif string == 'top': result = Qt.TopToolBarArea elif string == 'bottom': result = Qt.BottomToolBarArea else: result = Qt.BottomToolBarArea return result class ToolbarView(standard.Dialog): """Provides the git-cola 'ToolBar' configure dialog""" SEPARATOR_TEXT = '----------------------------' def __init__(self, toolbar, parent=None): standard.Dialog.__init__(self, parent) self.setWindowTitle(N_('Configure toolbar')) self.toolbar = toolbar self.left_list = ToolbarTreeWidget(self) self.right_list = DraggableListWidget(self) self.text_toolbar_name = QtWidgets.QLabel() self.text_toolbar_name.setText(N_('Name')) self.toolbar_name = QtWidgets.QLineEdit() self.toolbar_name.setText(toolbar.windowTitle()) self.add_separator = qtutils.create_button(N_('Add Separator')) self.remove_item = qtutils.create_button(N_('Remove Element')) checked = toolbar.show_icons() checkbox_text = N_('Show icon? (if available)') self.show_icon = qtutils.checkbox( checkbox_text, checkbox_text, checked) self.apply_button = qtutils.ok_button(N_('Apply')) self.close_button = qtutils.close_button() self.close_button.setDefault(True) self.right_actions = qtutils.hbox( defs.no_margin, defs.spacing, self.add_separator, self.remove_item) self.name_layout = qtutils.hbox( defs.no_margin, defs.spacing, self.text_toolbar_name, self.toolbar_name) self.left_layout = qtutils.vbox( defs.no_margin, defs.spacing, self.left_list) self.right_layout = qtutils.vbox( defs.no_margin, defs.spacing, self.right_list, self.right_actions) self.top_layout = qtutils.hbox( defs.no_margin, defs.spacing, self.left_layout, self.right_layout) self.actions_layout = qtutils.hbox( defs.no_margin, defs.spacing, self.show_icon, qtutils.STRETCH, self.close_button, self.apply_button) self.main_layout = qtutils.vbox( defs.margin, defs.spacing, self.name_layout, self.top_layout, self.actions_layout) self.setLayout(self.main_layout) qtutils.connect_button(self.add_separator, self.add_separator_action) qtutils.connect_button(self.remove_item, self.remove_item_action) qtutils.connect_button(self.apply_button, self.apply_action) qtutils.connect_button(self.close_button, self.accept) self.load_right_items() self.load_left_items() self.init_size(parent=parent) def load_right_items(self): for action in self.toolbar.actions(): data = action.data() if data['child'] == self.toolbar.SEPARATOR: self.add_separator_action() else: command = self.toolbar.commands[data['child']] title = command['title'] icon = command['icon'] self.right_list.add_item(title, data, icon) def load_left_items(self): # def current_children(actions): # result = [] # for action in actions: # data = action.data() # if data['child'] != self.toolbar.SEPARATOR: # result.append(data['child']) # return result for parent in self.toolbar.tree_layout: top = self.left_list.insert_top(parent) # current_items = current_children(self.toolbar.actions()) for item in self.toolbar.tree_layout[parent]: command = self.toolbar.commands[item] child = create_child(parent, item, command['title'], command['icon']) top.appendRow(child) top.sortChildren(0, Qt.AscendingOrder) def add_separator_action(self): data = {'parent': None, 'child': self.toolbar.SEPARATOR} self.right_list.add_separator(self.SEPARATOR_TEXT, data) def remove_item_action(self): items = self.right_list.selectedItems() for item in items: self.right_list.takeItem(self.right_list.row(item)) def apply_action(self): self.toolbar.clear() self.toolbar.set_show_icons(get(self.show_icon)) self.toolbar.setWindowTitle(self.toolbar_name.text()) for item in self.right_list.get_items(): data = item.data(Qt.UserRole) self.toolbar.add_action_from_data(data) class DraggableListMixin(object): items = [] def __init__(self, widget, Base): self.widget = widget self.Base = Base widget.setAcceptDrops(True) widget.setSelectionMode(widget.SingleSelection) widget.setDragEnabled(True) widget.setDropIndicatorShown(True) def dragEnterEvent(self, event): widget = self.widget self.Base.dragEnterEvent(widget, event) def dragMoveEvent(self, event): widget = self.widget self.Base.dragMoveEvent(widget, event) def dragLeaveEvent(self, event): widget = self.widget self.Base.dragLeaveEvent(widget, event) def dropEvent(self, event): widget = self.widget event.setDropAction(Qt.MoveAction) self.Base.dropEvent(widget, event) def get_items(self): widget = self.widget base = self.Base items = [base.item(widget, i) for i in range(base.count(widget))] return items # pylint: disable=too-many-ancestors class DraggableListWidget(QtWidgets.QListWidget): Mixin = DraggableListMixin def __init__(self, parent=None): QtWidgets.QListWidget.__init__(self, parent) self.setAcceptDrops(True) self.setSelectionMode(self.SingleSelection) self.setDragEnabled(True) self.setDropIndicatorShown(True) self._mixin = self.Mixin(self, QtWidgets.QListWidget) def dragEnterEvent(self, event): return self._mixin.dragEnterEvent(event) def dragMoveEvent(self, event): return self._mixin.dragMoveEvent(event) def dropEvent(self, event): return self._mixin.dropEvent(event) def add_separator(self, title, data): item = QtWidgets.QListWidgetItem() item.setText(title) item.setData(Qt.UserRole, data) self.addItem(item) def add_item(self, title, data, icon_text=None): item = QtWidgets.QListWidgetItem() item.setText(N_(title)) item.setData(Qt.UserRole, data) if icon_text is not None: icon = getattr(icons, icon_text, None) item.setIcon(icon()) self.addItem(item) def get_items(self): return self._mixin.get_items() # pylint: disable=too-many-ancestors class ToolbarTreeWidget(standard.TreeView): def __init__(self, parent): standard.TreeView.__init__(self, parent) self.setDragEnabled(True) self.setDragDropMode(QtWidgets.QAbstractItemView.DragOnly) self.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) self.setDropIndicatorShown(True) self.setRootIsDecorated(True) self.setHeaderHidden(True) self.setAlternatingRowColors(False) self.setSortingEnabled(False) self.setModel(QtGui.QStandardItemModel()) def insert_top(self, title): item = create_item(title, title) item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.model().insertRow(0, item) self.model().sort(0) return item def create_child(parent, child, title, icon_text=None): data = {'parent': parent, 'child': child} item = create_item(title, data) if icon_text is not None: icon = getattr(icons, icon_text, None) item.setIcon(icon()) return item def create_item(name, data): item = QtGui.QStandardItem() item.setEditable(False) item.setDragEnabled(True) item.setText(N_(name)) item.setData(data, Qt.UserRole) return item git-cola-3.6/cola/widgets/toolbarcmds.py000066400000000000000000000175601356743264500203600ustar00rootroot00000000000000from __future__ import absolute_import, division, unicode_literals from .. import cmds from .. import guicmds from ..widgets import archive from ..widgets import browse from ..widgets import compare from ..widgets import createbranch from ..widgets import createtag from ..widgets import dag from ..widgets import editremotes from ..widgets import finder from ..widgets import grep from ..widgets import merge from ..widgets import patch from ..widgets import recent from ..widgets import remote from ..widgets import search from ..widgets import stash COMMANDS = { 'Others::LaunchEditor': { 'title': 'Launch Editor', 'action': cmds.run(cmds.LaunchEditor), 'icon': 'edit' }, 'Others::RevertUnstagedEdits': { 'title': 'Revert Unstaged Edits...', 'action': cmds.run(cmds.RevertUnstagedEdits), 'icon': 'undo' }, 'File::NewRepo': { 'title': 'New Repository...', 'action': guicmds.open_new_repo, 'icon': 'new' }, 'File::OpenRepo': { 'title': 'Open...', 'action': guicmds.open_repo, 'icon': 'folder' }, 'File::OpenRepoNewWindow': { 'title': 'Open in New Window...', 'action': guicmds.open_repo_in_new_window, 'icon': 'folder' }, # 'File::CloneRepo': { # 'title': 'Clone...', # 'action': guicmds.spawn_clone, # 'icon': 'repo' # }, 'File::Refresh': { 'title': 'Refresh...', 'action': cmds.run(cmds.Refresh), 'icon': 'sync' }, 'File::FindFiles': { 'title': 'Find Files', 'action': finder.finder, 'icon': 'zoom_in' }, 'File::EditRemotes': { 'title': 'Edit Remotes...', 'action': editremotes.editor, 'icon': None }, 'File::RecentModified': { 'title': 'Recently Modified Files...', 'action': recent.browse_recent_files, 'icon': None }, 'File::ApplyPatches': { 'title': 'Apply Patches...', 'action': patch.apply_patches, 'icon': None }, 'File::ExportPatches': { 'title': 'Export Patches...', 'action': guicmds.export_patches, 'icon': None }, 'File::SaveAsTarZip': { 'title': 'Save As Tarball/Zip...', 'action': archive.save_archive, 'icon': 'file_zip' }, # 'File::Preferences': { # 'title': 'Preferences', # 'action': prefs.preferences, # 'icon': 'configure' # }, 'Actions::Fetch': { 'title': 'Fetch...', 'action': remote.fetch, 'icon': None }, 'Actions::Pull': { 'title': 'Pull...', 'action': remote.pull, 'icon': 'pull' }, 'Actions::Push': { 'title': 'Push...', 'action': remote.push, 'icon': 'push' }, 'Actions::Stash': { 'title': 'Stash...', 'action': stash.view, 'icon': None }, 'Actions::CreateTag': { 'title': 'Create Tag...', 'action': createtag.create_tag, 'icon': 'tag' }, 'Actions::CherryPick': { 'title': 'Cherry-Pick...', 'action': guicmds.cherry_pick, 'icon': None }, 'Actions::Merge': { 'title': 'Merge...', 'action': merge.local_merge, 'icon': 'merge' }, 'Actions::AbortMerge': { 'title': 'Abort Merge...', 'action': cmds.run(cmds.AbortMerge), 'icon': None }, 'Actions::UpdateSubmodules': { 'title': 'Update All Submodules...', 'action': cmds.run(cmds.SubmodulesUpdate), 'icon': None }, 'Actions::ResetBranchHead': { 'title': 'Reset Branch Head', 'action': guicmds.reset_branch_head, 'icon': None }, 'Actions::ResetWorktree': { 'title': 'Reset Worktree', 'action': guicmds.reset_worktree, 'icon': None }, 'Actions::Grep': { 'title': 'Grep', 'action': grep.grep, 'icon': None }, 'Actions::Search': { 'title': 'Search...', 'action': search.search, 'icon': 'search' }, 'Commit::Stage': { 'title': 'Stage', 'action': cmds.run(cmds.StageOrUnstage), 'icon': 'add' }, 'Commit::AmendLast': { 'title': 'Amend Last Commit', 'action': cmds.run(cmds.AmendMode), 'icon': None }, 'Commit::StageAll': { 'title': 'Stage All Untracked', 'action': cmds.run(cmds.StageUntracked), 'icon': None }, 'Commit::UnstageAll': { 'title': 'Unstage All', 'action': cmds.run(cmds.UnstageAll), 'icon': None }, 'Commit::Unstage': { 'title': 'Unstage', 'action': cmds.run(cmds.UnstageSelected), 'icon': 'remove' }, 'Commit::LoadCommitMessage': { 'title': 'Load Commit Message...', 'action': guicmds.load_commitmsg, 'icon': None }, 'Commit::GetCommitMessageTemplate': { 'title': 'Get Commit Message Template', 'action': cmds.run(cmds.LoadCommitMessageFromTemplate), 'icon': None }, 'Diff::Difftool': { 'title': 'Launch Diff tool', 'action': cmds.run(cmds.LaunchDifftool), 'icon': 'diff' }, 'Diff::Expression': { 'title': 'Expression...', 'action': guicmds.diff_expression, 'icon': None }, 'Diff::Branches': { 'title': 'Branches...', 'action': compare.compare_branches, 'icon': None }, 'Diff::Diffstat': { 'title': 'Diffstat', 'action': cmds.run(cmds.Diffstat), 'icon': None }, 'Branch::Review': { 'title': 'Review...', 'action': guicmds.review_branch, 'icon': None }, 'Branch::Create': { 'title': 'Create...', 'action': createbranch.create_new_branch, 'icon': None }, 'Branch::Checkout': { 'title': 'Checkout...', 'action': guicmds.checkout_branch, 'icon': None }, 'Branch::Delete': { 'title': 'Delete...', 'action': guicmds.delete_branch, 'icon': None }, 'Branch::DeleteRemote': { 'title': 'Delete Remote Branch...', 'action': guicmds.delete_remote_branch, 'icon': None }, 'Branch::Rename': { 'title': 'Rename Branch...', 'action': guicmds.rename_branch, 'icon': None }, 'Branch::BrowseCurrent': { 'title': 'Browse Current Branch...', 'action': guicmds.browse_current, 'icon': None }, 'Branch::BrowseOther': { 'title': 'Browse Other Branch...', 'action': guicmds.browse_other, 'icon': None }, 'Branch::VisualizeCurrent': { 'title': 'Visualize Current Branch...', 'action': cmds.run(cmds.VisualizeCurrent), 'icon': None }, 'Branch::VisualizeAll': { 'title': 'Visualize All Branches...', 'action': cmds.run(cmds.VisualizeAll), 'icon': None }, 'View::FileBrowser': { 'title': 'File Browser...', 'action': browse.worktree_browser, 'icon': 'cola' }, 'View::DAG': { 'title': 'DAG...', 'action': dag.git_dag, 'icon': 'cola' }, } # 'Rebase::StartInteractive': { # 'title': 'Start Interactive Rebase...', # 'action': lambda: app().activeWindow().rebase_start(), # 'icon': None # }, # 'Rebase::Edit': { # 'title': 'Edit...', # 'action': lambda: cmds.rebase_edit_todo(), # 'icon': None # }, # 'Rebase::Continue': { # 'title': 'Continue', # 'action': lambda: cmds.rebase_continue(), # 'icon': None # }, # 'Rebase::SkipCurrentPatch': { # 'title': 'Skip Current Patch', # 'action': lambda: cmds.rebase_skip(), # 'icon': None # }, # 'Rebase::Abort': { # 'title': 'Abort', # 'action': lambda: cmds.rebase_abort(), # 'icon': None # } git-cola-3.6/contrib/000077500000000000000000000000001356743264500145405ustar00rootroot00000000000000git-cola-3.6/contrib/README.md000066400000000000000000000036361356743264500160270ustar00rootroot00000000000000Miscellaneous git-cola utilities ================================ The [git-cola bash completion script](git-cola-complation.bash) can be sourced by `.bashrc` or `/etc/bash_completion.d` to provide completion for `git cola` on the command-line. The [travis-build script](travis-build) lets you execute git-cola's [travis build script](../.travis.yml) locally. This makes it possible to debug the travis build on your local machine. e.g. you can execute the python2.7 integration tests in .travis.yaml using your system-default python2.7 inside a virtualenv: $ virtualenv --python /usr/bin/python2.7 env27 $ source env27/bin/activate $ pip install pyyaml $ ./contrib/travis-build -V 2.7 .travis.yaml This script can run any travis-like build.yaml file, so we use it to provide a [python2.6 build script](build-python2.6.sh) and accompanying [yaml build config](build-python2.6.yaml) that bootstraps a python2.6 virtualenv in the `env26` directory for running the .travis.yaml unit tests. `build-python2.6.sh` was developed on Debian/sid, where python2.6 is not available and SSLv3 has been removed. This allows us to run the unittests for compatibility testing. This script uses your existing Qt library, and rebuilds Python, sip, and PyQt4. [build-git-cola.sh](build-git-cola.sh) shows how to build git-cola on an older Unix/Linux OS, such as RHEL5, where Python 2.6 or newer is not available, and we want to use a newer version of Qt4 than what is provided on the system. This script rebuilds all of Qt4, Python, and PyQt4. The [darwin](darwin) directory contains resources for creating Mac OS X git-cola.app application bundles. The [win32](win32) directory contains packaging-related utilities and resources for the Windows installer. If you're developing git-cola on Windows then you can use the `cola` and `dag` helper scripts to launch git-cola from your source tree without needing to have python.exe in your path. git-cola-3.6/contrib/build-git-cola.sh000077500000000000000000000004531356743264500176750ustar00rootroot00000000000000#!/bin/sh # Build a complete Python 2.7, Qt4, PyQt4, and git-cola development # environment from scratch. This can be used on e.g. RHEL5 where the # system-provided versions are too old. # See contrib/build-git-cola.yaml for more details ./contrib/travis-build ./contrib/build-git-cola.yaml "$@" git-cola-3.6/contrib/build-git-cola.yaml000066400000000000000000000040211356743264500202150ustar00rootroot00000000000000# Based on a script originally by Aaron Cook # This script will build git-cola on an older Linux distribution, e.g. RHEL 5. # Replace COLA_PREFIX with your path to install somewhere else. # Set NUM_JOBS to control the number of cores used to build. # This script defaults to 2. # # To run git cola, use it directly through $COLA_PREFIX/bin/git-cola. # There is also a softlink at $COLA_PREFIX/bin/cola. # You can add the $COLA_PREFIX/bin to your PATH or softlink git-cola (or cola) # from a directory that is already in your PATH. # language: python python: - "2.7" env: - PATH="$PWD/local/git-cola/bin":"$PATH" COLA_PREFIX="$PWD/local/git-cola" NUM_JOBS=4 install: - mkdir -p local/git-cola - mkdir -p local/sandbox - cd local/sandbox # Python - wget https://www.python.org/ftp/python/2.7.11/Python-2.7.11.tgz - tar xzf Python-2.7.11.tgz - cd Python-2.7.11 - ./configure --prefix=$COLA_PREFIX --enable-unicode=ucs4 - make -j $NUM_JOBS - make install - cd .. # Qt4 - wget https://download.qt.io/archive/qt/4.8/4.8.6/qt-everywhere-opensource-src-4.8.6.tar.gz - tar xzf qt-everywhere-opensource-src-4.8.6.tar.gz - cd qt-everywhere-opensource-src-4.8.6 - echo yes | ./configure -prefix "$COLA_PREFIX" -opensource -no-qt3support -qt-zlib -qt-libtiff -qt-libpng -qt-libmng -qt-libjpeg - make -j $NUM_JOBS - make install - cd .. # SIP - wget "http://sourceforge.net/projects/pyqt/files/sip/sip-4.16.5/sip-4.16.5.tar.gz" - tar xzf sip-4.16.5.tar.gz - cd sip-4.16.5 - python ./configure.py - make -j $NUM_JOBS - make install - cd .. # PyQt4 - wget "http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.11.3/PyQt-x11-gpl-4.11.3.tar.gz" - tar xzf PyQt-x11-gpl-4.11.3.tar.gz - cd PyQt-x11-gpl-4.11.3 - python ./configure.py -q "$COLA_PREFIX/bin/qmake" --confirm-license --no-designer-plugin --no-qsci-api --no-timestamp - make -j $NUM_JOBS - make install - cd .. # Git Cola - cd ../.. - make all - make doc - make prefix="$COLA_PREFIX" install install-doc git-cola-3.6/contrib/darwin/000077500000000000000000000000001356743264500160245ustar00rootroot00000000000000git-cola-3.6/contrib/darwin/.gitignore000066400000000000000000000000151356743264500200100ustar00rootroot00000000000000/git-cola.py git-cola-3.6/contrib/darwin/Info.plist000066400000000000000000000027151356743264500200010ustar00rootroot00000000000000 CFBundleDevelopmentRegion English CFBundleDisplayName git-cola CFBundleDocumentTypes CFBundleTypeOSTypes **** fold disk CFBundleTypeRole Viewer CFBundleExecutable git-cola CFBundleIconFile git-cola.icns CFBundleIdentifier com.justroots.git-cola CFBundleInfoDictionaryVersion 6.0 CFBundleName git-cola CFBundlePackageType APPL CFBundleShortVersionString 0.0.0 CFBundleSignature ???? CFBundleVersion 0.0.0 LSHasLocalizedDisplayName NSAppleScriptEnabled NSHumanReadableCopyright Copyright 2007-2017 David Aguilar and contributors NSMainNibFile MainMenu NSPrincipalClass NSApplication NSHighResolutionCapable True git-cola-3.6/contrib/darwin/PkgInfo000066400000000000000000000000101356743264500172730ustar00rootroot00000000000000APPL????git-cola-3.6/contrib/darwin/git-cola000077500000000000000000000004141356743264500174500ustar00rootroot00000000000000#!/bin/sh # Setup PATH for git-osx-installer and other common locations PATH="$PATH":/usr/local/bin:/usr/local/git/bin export PATH # $0 = Contents/MacOS/git-cola macos="$(dirname "$0")" contents="$(dirname "$macos")" exec "$contents/Resources/bin/git-cola" --prompt git-cola-3.6/contrib/darwin/git-cola.icns000066400000000000000000006161131356743264500204110ustar00rootroot00000000000000icnsKTOC His32s8mkil32 vl8mkit32F(t8mk@ic08ic09is32܀ f  T V " ]9 [ +1e ޠm6u WO|s & 1@1 B5=1 1 ?8>1{3?9 (9=32>6>A6<1,?8:;2 A:=1>Z2=;:: 1+9=1 vkU57:9 9-97@6t{`V4< 37":=1=fqC6: 5==;=1;i_>5<1 ?}D#"<<3 *::8:=12=7=10@1"*" ,"(" # +%)"{$(' &(##($),#(#*%&'" ,&(#0G)'&' # &("d]C!"&& & '$*(cnNE ) #&''"0Tc0!($()'(#-WuL *#'" 1n1''$%'(#$'$'#"*"s8mk%- t3v;|V5)}8COҢ-"7Y+zpil32 v#e  ?-@+K+]+'X+;W+>P+>w+>"+>+>]+>k ]+>^[+?M(++ UeV RTy)S{F+*Q+*IU+* +*0!'+*+*` O+)t9k,*,)+)+),*, ,.0 >;= >8:9= >9:;:9=$>8;:9=#>899;:9=A."?=<9;:9=?7>/*2=9;:9=>8<8=/*>9;:9=>8;:;8> ;:9=>8;: 9< =9;:9=?8;: ;9=,$>8; :9=@6;:;8?(%>788;:9=;5?8;:;9<,!2#@>=9;:9=5DF.>7;:(;9=+A,+=9;:9=5ae.@9:9:;9=,<<,/<9;:9=5,H2f:97;=9;9=+>:2?8;;9;2pBQ<;3=:9=+>:6)>8;:9<B=UME4>7=,?7>* <9;:9=,iJUG<99<*=9:=;8>:B9=5^AO97>7?- @7<8::8::9=27?6L/?2 1<9;::;:9=<_On[4<9;:9=-WLM8 ;:9=9YM,B!>8;:9=9-5@8=(&;9;:9=C;8;9>?>9::9=<::;8::9==9:;:9= =9:;:9==9=<;<* +%+ +$'$+ *%'&'%+)%'&&'%+)$%&''$+-#*('%&'%++#($ %)%&'%++$(%(% (%&'$++$'%'$* )%&&'$++$'&&'%* *$'&&'$++$'&%("*$('&'%+,"(&'%) )$%%''%+' ,$'&'!'+*(%&'%+!13+#'&O'%(!+"!(%&'%+!OT-%&%&&%'!('"#'&&'$+/5V&%#')%'%'!*%%*%&t_}.?(')%&'!)%'(%&'$+0)C:2 *$(!*$)! (%&'%+Y7D4(%&' )%&()()%&'%+"M.=% #*$)#+$'%&'$*#+"w9*$ %'&'%+)M=_J)%'&&'%+F::% )%&&'%*&G:-)%''%+&!,#) )%&'$+1'%'%(+(%&'$+*%''%&'$++$'$+ +$'&'$+ +%&$++&+l8mk X; |a a  a a d&a  ya  {a  |a  |P<=:;==:9;:;9<-:9:;::3  '&7<9:;9<-:9:;::3  %:;9<-:9:;::4 9:;9<-:9:;::3 9:;9<-:9:;::3 !<9:;9<-:9:;:;34:;9<-:9:;0=9;:;9<-:9:;9=";9:;9<-:9:;9= 8:;9<-:9:;9=3:;9<-:9:;9=6:;9<-:9:;9=:;9<-:9:9<-=8;:;9=-:9:99 4;:;:;9=-:9:9<* 4;:;:;9=-:;9; 4::;:;9<-:9: 4::;:;9<-:9:9;(  4;:;:;9<-:9:   4::;:;9<-:9:;8=3 3::;:;9=-:9:;9=>. 4:;9<-:9:;9==:0 4::;:;9<-:9:;9=>8<. 4::;:;9<-:9:;9==9:;. 4;:;:;9<-:9:;9==8;9<- 4::;9:;:;9<-:9:;:;9==9:;9<-  4::<<;<;99;:;9<-:9:;979;:;9==9;:;9<-  37.**.5<<9:;9<-:9;:;97=?@?;7:;9=>9;::;9<, -<:;9<-:9::;9;@3..07?9: ;9==9;:;9<- 9:;9=-:9::;9=8-WxrK.;;9: ;9==9;:;9<-8:;9<- 9:;9=4F99:9: ;9==9;:;9<,;9:;8=)+<9;:9<5MȒ8<: ;9==9;:;9<-*<9:;9< 9:9;9u2..;->8;: ;9==9;:;8>:9:<-;9:;7@,h&A>@;4p2>8;: ;9==9;:9 0;9:;7.9::;8>4*E594>5Z/>6;;: ;9==9;:9<1&=9;:779:9;;g1=8<;8;7J3>;:7: ;9==9;:9<.!>8;:8': 9<9V4;:;:90><66;@9: ;9==9;:9<-!=8;:;7<9;;7?1~,C3::;9<>,0['69<3PÄ:9>9:;: ;9==9;:;9=:9: ;9<*=9;:6G97H=5@/?7;:9=1;:9;: ;9=>9;:;2'<9;:;8=(&-<9;9::3D=0a);<:5Q6<9:<3k?8<8;: ;9==9;:9=!9:/;9<.-<9;99?*P<44`k*D95B.v/@5?0s1=<9;: ;9==9;:;9;7;:;9<.%-<9;:8@79C,-C4=7=-|.@7;9G27: ;9==9;:9:"8:;9<-&-<9;;7<7>.x/;889<=i0>8:;3=?;9: ;9==9;:;:<0*;:;9<.'-<9;;:7@.|.D8>@(A9::;6D*j0>8;: ;9==9;: 9;=4+$"*3;<9:;9<.%-<9;;9=3[6472/,@8;7@).>8;: ;9==9;: ;:9;<=><;99;:9<.#-<9;:8?0WIb/>8;8@++@8;: ;9==9;:;:9889:;:;9;-!-<9;::;70<::8@+*A7;: ;9==9;:;;:;9<.-<9;9;:2vЧ_,=::8@+*A6;: ;9==9;:;9<.-<9;9:>//76-2@9:8?+)A6;: ;9==9;:9<.-<9;:8??<=@=8;8@+)A6;: 9=>9;:;9<.-<9;:779879;7@,)A6;::;: ;8=<9;:;9<.-<9;:;::;;9A,)A6;:;:879;: ;:@8:;9<.-<9;:8=()A6;:;79>@;7:;9;) 9:;9<.-<9;:;8?/~,@7;::7?;0.7?8:;9<5;:;9<.-<9;:8=3]3=8;:9?-9d|K.=9:9< 9:9<.-<9;:8>&w^2=9:=-u1=7:9<,<9:;9<.-<9;;8C,rQ6:<0饋,B9:9:1;9:;9<.'-<9;;5C(~7;>-B/-.H'=8;::9<-=9;:;9<.&-<9;;8=4/5?.q+:?@@5E6<9:;9=":9:;9<.%-<9;:8=@9>2->963;5K:;9:;9=7:;9<.$-<9;:97:9@y4?7=C4KC6;9:;9<3:;9<-#-<9;:;9;:~"?77)MD6=9;:;9=6:;9<."-<9;;7@-uE@QqE5=8;::;9=!;9:;9<.-<9;::;9C5=7;:97<:;9< 8:;9<.-<9;;6>&~*B6<:;9< 6:;9<.-<9;::=34<8;:9;,  :;9;/ -<9;:9>=9;: ;9;9* #5<9:;9<0 -<9;:89;: 99<=;::<=:9;:;9;/-<9;:;:9:9:;:;9;/-<9;:;;:;:;9;0-<9;:9p Tpp  p   kp ~ Np   xp xQp Ҭp p p o p n q }^ 0Y ]SKm *b } 'YS W  \>ˁ\?Jl joic08PNG  IHDR\rf$iCCPICC Profile8UoT>oR? XGůUS[IJ*$:7鶪O{7@Hkk?<kktq݋m6nƶد-mR;`zv x#=\% oYRڱ#&?>ҹЪn_;j;$}*}+(}'}/LtY"$].9⦅%{_a݊]hk5'SN{<_ t jM{-4%TńtY۟R6#v\喊x:'HO3^&0::m,L%3:qVE t]~Iv6Wٯ) |ʸ2]G4(6w‹$"AEv m[D;Vh[}چN|3HS:KtxU'D;77;_"e?Yqxl+@IDATx mGU&}{Iޔ),6a#ڦE$l_ #;ahKTN/(!y 2psjT}yȩUkZUvq42bdP^_R*GQqڵ7رmv n,Ņ/|h\|taᓝNxE0+zv3 kd. @G⑀SBCף۷K~arzF4Y(WַZnq4E-bTdӱp{mqj0ځ^|G$0j.BLv}l>a  ޕnn'*q{GJ}P-`Z:zz}xrHv^{bnB]vq)Lzt*pczv1d>Zb#RcjiP*k_}ѣ6uF…nF ^_n]J?WoJ׎;%(~ %^(ԟ9^Vxllө}_qȑ?@Dy /?ړz~)e]+vzW ZrӉCPnYa(?ѽߌτJ~]l\eז,,-}`N#s!J`\fiN)?{ݗzbz凣Fh_X BQ1y릛Fn`1nƅ֍.n7z͙nZ\ h4i⼠~G U\:g/ae۶uΝZ@jz1>Aq}Z \H0 FGm)uJ7#>7 dwaG U^Lm_9Ǟ *?z7ݸ7$y;9({cv.J5ڙ4G#D5j.K)ߍo~7?bs.TНrab,l0[KkH^[kaq4B fwTFyO~$z4'p*"?Seߵ]ejl=9/fi9pNv$Ձќ@_ب8&klW83GxhP9!@u=n8@s>/N1jκWaJ:?\K`s6OեZ7r05Riد ^ lyh$0L|_Ԥ}'ɇM>Æ7KCV#N >bXX7}ю|5C)48:?=v_J)[|6,6#!Bըp${9ps , H=jΟBnï_Ɯ:Z&3J<@y}!|H ƎA(4g׌v :ܣ(tϟsj== hRphf<y }xs6~mC Du}YQpnOʯ^[ISF Egȗ0fď9tO3jm<p{K3! <^3)I?!f#8^&)s<;8:E9s$xDRY_xO>NWRR^d4k{_I);c8ᜧ儑m@Ձht0y5Rʿ=('KV^3>->T>fW{5(y 7jk?;'}Hgh$u\>w&KZ?`oIyI STc6L T %4m# Ĕv8'7p;GӒ=QpveNT6&6zg@ǾN$yd 05u Ep 2t ?lc H]#S1gt@ l=;=) Ӹk7|R&NQqC}&LS<4?$p|LF{>4 G<;`lugZu#oqrOqj۷m{e;w?T_)/U:ScS'y)h^Xw`!~s#^YVcv G {2֨rtn\|~ !Ɖ?2gVΏ<T̿Sj/{6ي{?/MYMZ79 /n(|}t0Nή>~:F \$ѣ[7n@kwW71C#/4pYh6hұ1y)-9'0'3!v fu}G o.skcrqas6hv61)}“2Ofp#՛Ajך8 Kn@ :o7st;/a+?&0 MsYM#Env4Fe|rQprr0?ͯ]R[PH'R lF4ՌDU/PrB1%Wﷳ* $lȗCG ˌM.H۱}[fiwڋD^Flup#40OFW`$p% `LÌ~#U&rֲi04}>,7a~Ձ=fU)B/t\KXn],`yn-ͬp>h$iF7ۆmP#NVVV!mHG vI 8BEMBx6 'I#䜀19-*1WFw xOw^dN.C{.߉;͕s+Nga~~8'}sHoVD˦R`o4i3B1{TtlF/puaC^Zm5WwNHP$ svWe+T6^RL)Bh+Ta~n!aF穭iw; ` "\;:EoQR:qՇc%Y6h*bi Lb$p l>pbQbò*oW%!6_@:LOO1S~{;hUQq~$zriP;g֬q müT#*$rF+3*C]/ley(vC0xz+Kr )aqw>cpO f{ŒR~ DDŽ&xz~^}X= H&1189yxObNW( Sa+[ݦ\pT!hfco5/J)|w@@:[^ 4K1zڣ|J9ۿ{w-z~hGX= s+%׭[H:PMcv;$q61271 {JRNE hCy0<)yJ1%Dq&, qYHF03jL2)Cor۰UrJ,RځM +su ~pihc'"Df0TlzM +['HoRBün>M؜_%LK4F @:nfǰp0Տ50rʦ`OM %cmrxgI:o۲azLIHoTjl.B=e *ن+tF^ȯB18zw -+ 7_(\ݮb&3[IC?zUs`4N j$Qb[d3M8nwİ ψAg{,w>F#/; S~=ԉo}MqϞ~~p^LU= L]}:z1;Jlz"D: q\-_;3~# O`F#ܡ!6>KLmlX}݁ۆGw >j?R?33{n焟~=9R 鱬z2RBmçppsWz+1b qܹȕ p| L$ f P߀K BqF?!_O9Os ĵAk G3Kf{yK}Vjj +]VITŤMBQ IűMX+e2<ֺFu /;<F-cٸJ~"z}NI{sAψk׾h֭?MM_W[u#XCps5I0Pӈ|҄𬛴ƔwH8QN8pφ`Ttjb򪏵KbB5r3ATp̕6HC+KK'|/.~M~Sb{s<3j@)Ъ0AY0,} )0~Fd [kpX#F{bmʯ;`~Wlţ, ÑCqFbx%9F6. ;zm4Sh#xx /tkx-L0f)0bMXGҠqBe+IHqm#1x m BcB*\hXULQ2CUAVnk9Cz _EJ_4npDUNjskݺ}Sh_QJT rhQNpMnYZ \8Y;FmH1o~o&Kge+**JvXGY/ #~'3sn6VwrNRp=idڳtVRz`M/g ]^eɚ[!!4i輽RaA^ .)?Ïyh{J{}%JVR 5d%\r^a{&M sZ:ρ01G_0.@=[e#Nbrc_Z^h2Pv,9aJr CX<@B m; Ub"\sq.)?ak`=U  [>|0T*Cwug~$Vz?^ΐݙ2t6>>;T ~T|RSϗՑsV,KiVNYCnKbIhC/p WK:\sCRb`{1)?$]HM>"d4'' E"zt&bW׬T*_z?CWE9t8jZߘ^ћZi<)-!K pǏ O p13ln.-G榑WŃ'cy@t7)w:ꖮ El*3Tls0Z ֜1|_n⑵q(\pfݏSJwk/b{&Yb.` 1 vGx{( ̽r$9gOCaƌmƥF%&W‚ϯ %m .95dRϞ%[f{+2݌V/e31TmhboGQegmՊX\m̆eJ:|_ը8|l~-ύ11FsG~E3RL~̗Mp M^N&;aL͗Ř'SQk~ w%s([.^B(S`+ ,L=U8˃=:'H˦(V 9 ] m:b>M> AawEyq1*4`8 sBϤInڇfn%HQN'|2iZ А|#lK~_شY&zRرc7l2"+$0Z_K}tc&H;,hj#٪i0#GMLSx؈s=$p^9J>ܬLb7jsrdM\Jl C$$r?S6pFZ* 4.{\Ͽ=rz~^ ?3UU1XtNJCn'XHoqfc Wvȣٳq=  ,HKCT,֑JiB{WZMK8&?ӱd,VxJCȅ0i$p4p# `$ \ @J=?` .[0}0 V0ųjJ1ȋW V -=;ѫ 1,ra[ 9kwmq)ncRe*i+J,̰r0!/827gH2xqz x 7\s{R~ ]\Y0Y#B!0☒z.!\ Q/NEMP D@=lZ.danݱKŔ3RˇZ^MuChMlb(VN ߴ qT̟znufjg V \翚^; <:YѯW(UtHj+ax?9G' ͆x r!r9ttRwUϩesl|bJkx?I״, &oNXXS>24wK@(>ڒ+K+ ;޽a fu|mRϽp<{dϥ>~5V{.U6+Qh`U |uü˨7ʰ .+M~X)C0]? tqL*5+̹ k3<7HxŐ=<>y8<a g!i\FZO|\"(g['+/\-e<Pc,f IX!\pd>1 kmqXwvE8 3OOrr|zb{;K[^ l/&,Ldx&ٓ&Uii 'QNS#}v>Op8u~w|gRQ V_X* '+]AoTV BE̐#Q_jR7K\kZ>k2EX06^|0Q& 9]B( fC=mK&DZ , 9Yj6'}c V0'=w OgH/_ٽˎ7lztBTeSqK!pU!jx!7Gw%qS BiEAhz Q%F^y\Ӏg0P?k:n'V[{o6ZNag+ qAfÌJ2/aaZJŠ8Yy>xt;ڛ,t!"TlR/7o{UTA)CӟWYash[faąᄧKR*Aӿ@<IhhgJCR J@=Mμ$`ZF ?i+!F`p'X : P}( F19j#{0H)z~Ï*`NX`r[aL*4j}k!ɧ5/HS|iO>zL>Bx;\Lp+0"ɇ&ǟ؛cxI^nsX#K3K>$_-uG sFB Sdd>;1}n 6מ7  \K}6MV.tAd/bӊwȢkV>/h Q%^|Wм<>6㸮V̛R΋g1%P<9}G<w^t)1w60o%rrXG\B:qa>&ʆN xNF#p0ĿJwq8υ欻eR~շM>N Th+A o.<Ŗb 'my)fz7~UhML\C|3lW^Fvj~4$w:5l&|#-r%)O^"\G׏Θx 'v~zWw#:7"ܟͥZv([& <[x\SĽ5W#`„P|'ɸ2 ťe6?b4mgyk-eӥR0pц 5lJhC^ܤ՜qs% f1h`$P?#8Rf2[{ +alUPŐW`Ƌ*z m b)Fa 7! Qc =vgJ7p]xY8>?IYF %Axb9'h$%hц =Ⳙ_>)dBHKvǠnފ9s{lumouuaJu`輀U# &fXX>Sy4a< ej`p{VxEiÒx T}{3Cp|s3_~tu'fe|@#69"< ;8!/s>YAz 0|&{(móh9ff=:83tK*p0\De}Qy@Rd L0G7 th0;QOM`$0vCp%"rh   m~u D2„aw &ta8iqZs1W6NƪF$ s*hRo\p{+,A1Z/m9wV) SJaLE~<~:$l/O8}p 'Ya e`B cMv̗&piL[Z UHxv  '_K}ԡ]P툓G+>pr";x6"(\Y-G Ix N|gU؋DRu-[{ne`fW\7oS_XX4*H [42g_$p KI' UZ1dh&\c WП Ä`x^ :S @J?қ2yjl:xRw[P C0%;[M:ӎ4,o)!<9QXoCFr]S5*/.ZaLMM=u޽oǧa+[x#,t(i9`#KAM B<'lLvX 'Xiϗ1\&/U[h/ DF\Lɚ_K}Cr{Z\D.U,҄w y #QxZBjwfx 5!-qh q -}>% 0^6C~Ӊ.-Fe<u;9➀qa0Y[Zv߲ukЕ20,YaŤ4;*V&~^]X)ueganC0Aiﳲ5c_L㠛#6̋FmxvMT9%t7No~䳀_|l^Y}aXP 3N\/RTT=0&i'c <0UO˃O c ^WWlXqsdJ%:Vo|Ǯ[6f9pS3\#PH1tgF 5`#er /9f ~C YB_qBwҊ>4y|6(' D3{:T8:7؋=o : ZrX(nE.iRt⪢/+lni1'PxSEӧ42>7;&vضc.A#kNr$89 4I#H N5&W.dҐpB _4 f%P&72Xa|@sa\:̑oHa;,tFp{>>a{o~v\+6i"4M;C0=L4!OKQ)|a$~ӡO EXW zDz^bηnI7,F,l$ρ T'~#~?80ơvr1yL\p[d KKxrQf1c-O3yh{bOr'yaM@ 0fT4#.cXai_Bv^&_0/rtJB8B7)ײ^+`  =ohMi6`$@8$ʲo88F2j瀟uFYMDg.%Z4 f&{! c5;F D-B{ 7y8)& ^N"Q>)AQ7~ki{U Ő&4(̥_C8+[,T )%{6vLce|<W!q u:h&6^1+ %50G#`6'095"P_RK[B-]Z˦?)q1j,'hȁFe-B6\9Ex8|~^]\,񛟭De>/0B"6xA QfmU,mPKrNlT cV .aZYޞ6ˆ A`v|0>l9HyZM퉣];߶a㆗`WC#0`,ɒ,kb+X`#.ausw`bpgsړR1b7aXsPJlX^ lCpIØ,7rPF@*qͽJ|G'q껹ҫ%eԋ H$YIZ Vያ} 4\ӡ5a9/sGol9$_yg>aH\ؐAcz>/߱] 6X7,+L%R|cblssu tq6f ALI/9Z"&9t*N`'4QX͉91h/%#o$p2 @J_{R~l) #+&½1 &r(&t y[ ` hR~sKB7a?XQ/Aif1a£,+>}*05bm4IGX|Il:EE­ℐEiYb 9T`#ZZwa܈5 %-1j$:5d,"%p (,(CFk%#0Ͱp O|CHx]N i$ם['Rg=?|8o8-P 3,K4f*t( (T|B>Y^l0SL|#X--f~eKCHT[᫰GpP7Mvg:оbǎ_ɱ:Zg221 FA#B%r ϑ <€E%@D1xD0n/QҖC< 8>ģiO&m @_%&aGia~y~wׯb2m-X(S#(Y&4?}C:_ p::FmG0 -c UGfă>bk)/^AUPj . t0,-j|O^EKap@D l0GDp94Y1;?>VH7 D&k0,G>I̛/c̽_ ZR38{7!omboo2 H)so Gz{y~&04Lϒ YCiJ *e[Ca1³i$oE'\btLig4|q VܲCzrfSJme>&1za}`$p徽N]{K4OLZ/עbw[(ֱDUfX,w: 8rێvB\g[aP)w”IG0\OxP,4DL;;[͐7 yCή(~vۥޛ^Lg,WfaV zM(ED(Mh"|@IDATO h$<}KCig4VJfӦ4e:lyxji4y^YүR ; ;URP#^![wz-F;}G>9du&wXxlxK5B#Za\]MIvX4ZCdToX-}m|l 3f=Uת7YhG(tbr*fF3zX CO~`T)4P>. zKZ܈;v|7R7,z~lxǒJl VKˬ=5L- (,<0l2F0ږ?`_a0a,>̱ HŸy e= <4>aކLxh Q=.`$Jsg:t)x4*/gC?v]_('˥F_p`Z .NoV+ZsOB$nn(4-*U8nE>y |.M96<:/4/B@#po77HGEp5),ݑ^QR~ +ZL,) % (~RAe\Wlnn>Ց ]ﮯ}%l?{O;J<.ӹ ^~ݺui֖~n 78l%l̕˳rIs- '(!\257*Y>"2Fͨ} FT87f9췽󳠳Ner *h㈩3 N.a,~%ZuL~jB!FaK atdIS4ͤc!S-F|KSv.]FV ޲v~8+ȼb6pNzaY]D5F][>'g9z 1wX@c<СCKw՗Vz06d,v9IuU>o^u7)_+&o*`ف_֫W1=Ņަmý;s$ž_ 2>*3;ҟp|.\X/™jHa oi,ć~HOcar{[x-$eH ̦[$_hӽRKrvdօڿ+kfBظS c6߾|"~xy6ަ[o6{2O1N /s.>BϝH$̅$qtDCYZkoۥB{z]hX!q˕L)Ǘ4~*FzB<ń{w@WyoxTW~7ۏS}nnA+pt&*S|$iUC1GE~p4&aBe_~<n2&x //= 3I ,4qm%m ݏOGPis?q1dzmک6j$8G$pB8 wx0^UFZv -NRPJxOzQ0G#9{s}QTMTذlS^:<5?5?(FQA@9l/+BXH!b ZJ@| 7€!LCXIDɇzy µl}S@5{~pTZeqHDá0JFfEWQ葨'D3Z4)*^ B5ll[4 0!*_h.5Sx*at3^^xeWsC| QCފ1/c3/jYV& NrF3n16,-LG<qN=S=395KxS@GCiFlKNy '.![~ݰWxB`Vv`\?Zꗬ]wá#sh?PD{]qBz[(½Y%3?Ma+`Q&_rc?z5؜"&&P?^ KEV4F'QiǥQopDfJ4je~E&~͐4Ug,/ij|e)T(&K| c dFmqx)/L²u"ao,1 .6~/C nsю-[^h~eSķCS*/jf)?&ݣsċo&~u8z8{hw#QD0X,LODkMk׀v)*l;7D).:!T /t20. ѣH)N=|#,|Hf!aa+ GC,{yOǦa1:5<.]dH&z&n,ð6Q{]w=#); Ƨv9BpRp#_:>w[_fuNuI5&ۼ$yw ,nv$V~ HC[䦒78KJ/%[6CՉ'cs[2d3蹻ǣʷ<6~*?7@[h-7!L̬ 6D[ =ёٿAÁKm1*`$ >hL @ژi0C)O'EI@ ZTs[͟lq6.X fc6 Ni4+R>!l'0tQa4/ªuvp|CHM;Y!;zg٨W &bTybE<vz21aXƳ0`r_߻~r;ģ? 3Bh:'aXk9R舘N\}Df}GCr_Ywqdήqcڿu? ,g}[hb> ld|ʽ\#W#7'&r/&}?8&=Њ /-LOM>Un #C[IP䌂ߔnX>YQqZ0,㵿/4Uoَ@%4h hŨco~m;vꂙE۰_OSr 5`68n(<]O(Dk~A|Xȉ-xڄ KClbx4bQ)>dWHA'kU"bid 9PfsSȇSSG3 1ASo.tZ3MAu}2 ~۳Y,2!(zw%&`iCaxFIFhx4#;;-ȐA!! 㱸W4>[,uc3xPG dy#Y?>wM.^4v:#qCRM^{ZcH 6H1̄XOHPᢐg@m{[wal?*GG|"/^v9^ AhiиJcɦ׻3CG ǗuQ<>8ϐe\н?NޢW$hzn jf P]^yaxTĒa/0:xr.G@xIJ=Be9eZe—Mhbpqg)ܻ2+z~ӕ+9d+pu\ԴfU/a˗|e-eQB # {Qjyj/.S[X\l ] e_CrxnIKG4f;!e\ $2 .`Ss1ys9pq7Ӫs"Iy,}7̋hE a!OKCq)vpxXah}r0c0<RxP+BBDmx#3LͧtgÌ!>L ߐAt=7{=/\@бP^Tb_b"Dֈ4ql:=Lu3fϖS&J qFfEc`.>sce,qmeCZuҰ-?ZMW$۰ *,1̅"ɩ9J WSJ!M}6Aj,#rFRN_Qz|CZ3-L{*Qs~ X^rpv!GCʨiz}XSܶ}hTܤ]8ba!$򥂳ᆠ"sq.;a\:C2yJRm60*=Q;GDo1DGaZ.`eяy&naV87 /i`-'xx*>ڟ8x\ҌR-Nrn2Bc! CP0ccս E29nƋ*JMX+ߺm.C\;O.v3"(S0mDT?^cP>N5S3їGﻣEsek&cJ {[7D?3w *\ w/_gp˕lI0ySp/R-\ل7paXNq&yx7[)'h`*t'9 Z< ˗A!JŢq8ɑ0vVMOM=;Ʒ lPM^Z!'XMjI"LT) X=gKoiJR~? :/Vjv(?8likP&g67D/1>M ᱭy@{ 3DLJGGc~fF/p--A6 qcpqa%?[7Fjw @($a:UL:@)v* 1ti0\G8q0ensدύK-7j篥I[@+]i4PY;=4`J(]g$+~xFvxOlܛ_0KKaX6Uq˂NiX!n@|ϬoE|ԾyO\hUu| 04_$@LLFSxe4ߋ [vO xb ௌ,/!x }?Ja*ӤH,ؙ7 qnШ(.92?Yn⥼Y\}XX)7y( nػhxd -V)?S4!{9Ii2ôrióSaIv3dq_Ʈ5ɧm&<Эa hf"uĉ4AsINْdrKي/tC_~]mCD\w ӥw?kK_loljc#ko+KbQsׂEm78?7G~w]8sm rp׉h±hc/"4|$:WEs/}^4#/>Zo81G}3o q F&;`ʝ+PVxn7T7QȶJ@x($&! Q,SǢ₯1O_Gʰ 7imTwV<ͳ%SOAz+ξAܨx-ÛA'G6qsQ}ba~GC;+½dF;%Fz=̄ =_4n=~OҸ;øz2 Ԗ^{}4~Y>U{0 !t̀O,#p1st1:ZI7l@Ohe h-l|ն"w񓍀DIXv6.s~fB<{^ѝf~hN~V\81xPyv/e X^La"rfxxNU0pM6CfjW&;pɣ֠z7~;/ƥ_m5:4lA8xĽ@Wp{l):/ @;38chNTXm]Iy,'vƞ^F7%=67C܏ pFw(,߈C3:SsxATZsiޅt ܡb!1׀ IrT`Vð‚q֟<rq H(OP}WH aP,7daX" нܪV;/7X/.i9OݱepCg[E<Ԅ&LHSUaXxDpr#P+tPq7/{~*˵ 4d_>pn<\XԱh`>`x +ͱQPBsPqx>W`k0ܨ 8o:' k&cc 0䰿?+{df68\"JDoWиw[qT!Z1BNFcQiO"Ӏ>Dndpm=hh b0 +g@(\:kVR.~ "Ġ LQ{-5{bm oxI˽\\MB%1-FF~5$VKOЭĊZ~3 _aPy_I|lЂhM'cKccw;zq;p-% Klx5q xCH- 2lsi- 4- ϣ#?;>tOt柌5R]Wco}1oB`o6h ?F!lФ.:!='x11w-`#f@8py׀|,\JN%ұ_&!.5\DX;㿈ϔ V_q5,5}!9n{25B[1 B>0\)(?hͯ5o}v4F ûw $uq2^A1GڥҁTȲG{ynGgLT0=j\>f`Q12:_sC^rQ8ڍwq< c5mM:aKcxxȕ8육Zp^{Cc6{畸jYɶlZu_1Xɑ@>i% ^pJw=OH/\&^<Lw"1)(=™|ŧ'LDf :ayaaMOÃt2dGp>,p)VOzV4'u Adp J,e0Y9y ҈N;D 0 ʦr( J`dcirOT ~0i8*__ [{lre2+ .jYM/@jY51⧘՟n’Rh}u6};1Xo46m{#8(k<+$:?rh`Om v35l ЪPrt LV'#9kȯ[ tl$MίAuHG(uv 2`p5FO#iÕA~1 X!V"GSԴ2Jn]Hj_BҸP0 `a2i˯qWpꯦ|h\*!bKÎy^͚twky\QOtʫ֟{ҹ\A|N_āDxrb嫟ng?7[o3;0ɍ0ΥȑN`崬LPԐ5\CU?XezN;±0rώ_ȿQF޴gOȹı4pC]}fvc0^ Dr>FmH dr &`͟qĎj~3PO"0?2j?b)\xbaM&= /pc1747oǑfJ8Zr> &nxL:#f++>rҥyUq O&,~EZ&@DZj!;1H6p(;cP-hz!JOZ°u ճj{̌L[#y@p5jGtE/^f)%v (9\A]J,b%#%e J?Gc0qGӀGjŗAG|^$ ؒMP7/9fNysиJO>O:CbG @/&A%_,6x)2'k/(c1v0CΎf4wh)W( [@ ղ:81ۧ-*MI?c!?1s~smT.7od(02_0h5,0FǙ'V1yܛk [~ bE 6L+Q'+]v~ Fk<2#C0Y@}{ X>}Ȍͦ+d?Y-%,$9 83EJ'5633WwqO()t ׀0tkЦD _$ҡ4mhqn8mhhy# 5(#n3/[mߋgE}sS1+:XY՞f.6:Un }<VGJ4^mMJD mo+VO.SC?w3w`4юn54N8x^}p&rr*I/3#cyMkpLK}3 ؗAw4-s"%7^g7"6x[pشg|"uT͢U+g$=f f#`Kߜ1Soy5N J/_+IeZ/aԮyP?~i4\] ?4%~8"E) 'ײYĉG]&k?ʬŵ =/6 $`eJ9 纹Q݁l99W Яfi>=i\#!1%F~ X޼i3F=alx,jT}1ߘ `ƍ"'A3+EHZ)e dO#*; );N3xa#9(eӻN7)a:M4;nf/ 7n O(C"_ )sk5~ iW `lFa!IO\~8Gp߽/ow=kL@Tar"c7/_nno"GnP_wYϙ64FzSP9>Z2Cؘ? |%ZGܸ#Ao!RMy`bj1Iv&pJߠ4#R!謄4TcP>D؁V}%j`mG 6n^_}$͇KRsؼSKxxI<? _U'  {5,X@| =̄0Sє4 ʍ* SWH- ]c~ (p/vHl ?އ 41(40WpQE姝e]$LͲ~o9?kOrv,9p-%-a#:=RTfC=? S_(b8b|W[t5? (]G1%!\up&ə4yUhAXZl̑ &u_:r $ee+b,NihW87Hj.nk=? ģ0jW7[B>n?k&?N8<^1r !38vmEV(a.9]zّϑ>ڈ[.:I#%溿 aQ,*hM[0kQ_/C\>__k^Ks&}EA O֏ft*|i8qMB~L? $.!~_T*q~a_>%2]tGq>\%/Q p#/n%DPs _ZQ `Y a{cr3!ܳf"`\T7 S+K|OeG~3 6 I.绥_[7B~IjX5h $mU|8s8h-m[|٫ݚk\?_z"33x3Wz="g:m% d$؃{~K򒗙O^ns0j+Ʒa +xB HQX٩/MI{X$I iLa_k%~7kW1KJ+)) Wx4B 8J!EѼؒŭyp-"q&}$dděq?*90~.ES/j:ZK #1()O^󜿂f=s~,g8' 83e+ڵ3Uv$}AwxrnNfɨ1!?;{D=3:n8 +OD?`M̦n??!~ܴI9K4CK 4N6w6qpRM0j'BPi! 1ώN48].M> _Alj, xzz ImFq9έUC@;H6Ln?Q65Ge1(X}U0x3v2[$f?!<ܺ[f3XI7#(0Rղ?~Qnyk~Bڜ.aȷش9xw驏b>ّ9x ځCpW:(7?thOcd^l 4./#~@~X[ óKH ,z1 V+/L!@%w tL>l79s(j\ӑ)ˆ$)JOMAF gG 7)eNa|83ܕSi$dT0$#;^ c:.;sIH)v 1(d/߇yqЅ"q>XT #w]Nm0 89lYJE*-xT{,l'@Y{5 ဍzO ~AdO=#C¯Ƒ݆DFNkh? &.p'$Y}\OA/1̀-a:<CpMŇ ԍ[;IDAT1Ő?$LyNbH;7^mq1G0FOˁ/RbQu-ap^6%J^nY^_'k^F~&Fֆv%oƥq0$ ɩ$4N0&HȎ2g~9$^,S諹ĤZr*.c|3\0:ICRquHd<-ae,_p?iFs i.|$vz$G~ϑb0;6\ˁ^b-JVf}aX~v2#$wG^;G~_7,h'/ظNvu'/a4C|4ӸXN_6?/YSK"^2I>Kk<%S-I֯'n)q?t;K.-Bd(s#_bt(- '8ɥ& jДsF_(_ I&"''/\I5WȴK?~qkbO_ۯ/iH*`iIWNR] as#HQX\B ⾒s;c'uˆ')j\.RO΃r>;e۶mWݻn_E$|fe?ub۲ͭlk%.V>5rQGCu$ɰd^$\cJs 햴ӭFa+hg[qO~le~AOg}[߰|@'T]&G0,e1Xh429>v--0=3ӶLr= Ƶh8j}ۮ.0H> bOʚ%nqiy%@?oi:^_(:h>5Ը[.Cm}ݎ|ܷ( &/ћoA 6C#.fol+Il0ǡxF!;_8M25Isx\h>ߖOr"o P[^&o}njnϱ 0]3՘ |3<Ȁdofʍ^=(+c׼# ~eG r(Ĉct^iz” ձdd {m!Q']flƼ{GPMbwѡvTgp/4mxN'hl}SS_􉉗[|R8o[Gɽ+#2bL1LG&I_zTmXgi|SATyύfm.03Gp"xjU*Bxh= 2o]b?q)^z}$;KK3n(>z Wޯ_^ %af^׬7u } -/Wz3)LG-42I26 8P8wb~όCޥxk5&>$ˡ _ &xF?, r$}S-'g17sxl1L6 UU9+emA\VS0F>,^ӡ+/l 6u73@ H k5EPE_@ãcAZiq_ro [EO 2jq)]xC6rggO}?#Mh-O,!Fk>S\w.3?ZKt ø7`Gx8&l!;/x%UY]߆,!rmO;{۶{)xLEeƏkjrEx^vE~>)N|;kćPI1_?o׸0 6c( !~Ş{k`^b&=J.%}!Xlk~hspOM>8CH/ e`x{Y&@9H RXHיi}vc&p f`oq!߈Q|a3DmBƜ;kF渑,rVcNqϛM7%x-h$fmpe`ESf+CTc! XG\$q,ۖ 쏴+6Lvk6[Čs#h[IcG"Ziʗ|,5HyZJ粩P n.7!>'K9?Fkm{k=_tdXǓaIU D|P5 鞀yK0$RŁ|s^yYQ Lf[of.6PeybƬL_zN1棣 z29&'_}͢yڛcf|d!"lL;A,J<ڟ?N;;?37W!GbɁ2BG`o3`fۭ]bq yg p˪ao.A`Q#04̥B9d%'#O3-*L`"1fRCw7wd*Wn9k[۵97)+LTWb*JE X`-l݁r&~CbOM } ϓ.#6~YËGw~&˰,0J'WDjrn.o6۱"ȣMBdl#å♭᱋6Ӳ eB>*a*F?ͺ MOtqdj [tcn$]im#`Nc&=MK {݁au'w[|@wۗN`F񶧰YG~}|,fx-٤"R? t Gm:1 $isinj5BFg]v%Ҏɂ#xJ~ܻk%\>G:siA(IWˀUtۭCL\\r"g0I,Rhؼ'#~߭dIFG}zMg֭oך?Y0ĞNƬDm Ġߨ @xg#.6TloSˆ؟ˆ@ث~OGz총 v禞O8NL)^l0>`2l?:֏!@FBm J䯎;[axong_EܖQ9e=cuoҍX,)" Do67epK8l*$oz&$FF~s]8燐kdyt<vloO 'o",vWd*69N^LbPۮLLL3NAC/P1NxB Q{Lf*09'n?GNR;S_i?S:>dY_v'L[+RLIC]eNݘmr57exy(MUМs*_dꔎ@DC;JDc+*auf7rz Q)OE.FC#r al|FP~{44HX€ fț s/lݶ*Bg8j\nUxGd1*wv?h/bs~PнI,!ϵ]fW,C|2##`>pwqi b(#7Fy?ȥkY k@J\iƥaY* kGpѥpQzj- ~.v 2"L(=Hv0(e@=k^oFn|P3൯7sEc{"~B4cXru\Բ0PKƯGC]\Ec F\+M.!^_ٿG{:Vow4Ra ;xpM&`Uwj462[:\XN=`2H C)>*)kG7 r טK a7M7IO0{LEI4x3I U6HǑ__}߇U`.VTRWaFɨVp2 矌K7{޻っÏ=f)1; t:6 }^l4H{l60:3֦%l p߀8s2_I)AHBi{OI} ӓ(sdC=+>2:kƇծi2PΏx/"~/ZR{\$2% Nvsn#U?JJ~|NK_l=%?5\س$db[ 9Ü 6@sN!8u9F޾ɴwl¨̵:@p@iә!c'? )XE mt]׾ Ϸ?2aIG{iMU:= f"H؏MRM #u2qHM+dѹ{߇0 d1eʟUC^]SꫳOmܴ#[kۏ>4xB9݁& d8<{e `Xn!f ;zSX{$6"|NCQ $4Yׄ1.7Wb@";?i?F .(;(麻KQamߜsNf޽""0iD"_KOXx||g&O;m'jE\xb"`OF/IRn?GRO& !w~\'XGe~aI6GsL1X7_wTKf d ~I@ɯ QJ D{7}wC駐ȭ>dO?چNBEs_o].?WvWoCb ojw-{,Z-)c/Y6V> L\q/Nd:%b]$aHEӡUq5?5l5_'bL^.t{bOէ^Ub^ ڏ@v-k4S3?1K~֍lbcf_BGۑ7/<(Fa7V(9ӓH+1֎"*pbbUM]iBR0;>i.WX| %t(~/&cͯB>[]͛7SSluI/_i4~YKnr@ Ic$; d Wtvg@"6JB.|sn?(;n}Οl@ۂ'MLcN1W^hg|(!h5gg{ʾ._CE9$+"eQV"P`Xu74.A_yGk9`g-۳P&Zk,-&@mHǠ{wFhG<ϗ ]S/72-5ͻm?0Gwi24A[v~qQ;d6IJ+<}76pGk/de^P\9Ke_53maY/-„t%\3qP1p:k̐܁ R =3 _ٷ>ڑs?ả(ЙP7Ԣv Xa{MZ:%ԉ#r(23Sasݲe+_&G4'XRH=-B} 6w ":I\u3z{M)Xs?ޫ5?𜟯E~E7Wt)#U{ 5tgLk xFGv=(FַHaa$~ DP:lEWy7B8F}x'>-W?i~N7 4Idx?7EW^Ǵ`ڿi?/Q(2>|O(B_%>p`+>ӾJz r.$Qm=ʮ@i/dV0u"gd}V" vp{}Jf,.[x'}iQxVV*iiQ<F=\K|!nXpݺ/Mr^W矂,XK*t‡ɩ3*'?A;yoAo_cEEDO` O6%T&Wu&{1RX86ͻnJ~NN2i5n#![;3ڡcv^ɵnk|14Cۻ`PTéK)H\`Q?^kŋ 7F_Zl+S%<  eA ,vSh[ ԑ~;3,F_يG;~x/A NtE(/*Lt!nb)~@{.武|3AT`;g/66ڙvp1|'S#;Y|d]{~:<+,뀆(ax@OMe/zڹgjGdž-/dhA{Nht90YS]6@WVŘt?&lI8kf`j1P.Jmv੝Vb;ww'z8_XrK¹ [8"O I?^p+S@0 8˥ҹ}O>ZsB Z?-E)ڷ[A+{^ d5~$\9߹(?WU'9\}, ᝘ U0*EL@GXq&؁Ɲc. K\Jpd✵p7AmxV {3߂0 f>|>r}+Vb٪^5O4]lI,Z5a?cRjqTR^?;AFVr-`]C}֬YVjݱO";,=Bw٥#.'2L?dߴ_b\2;at&fL)9eY?И>*wVk{ڦFȹK# W]6貋Ў /^it1OLc?ʎ ?IKiFa{Z!/n娩j0ǚ|ahǎ>syDd`'<1JshLBH4[*q׊d' lz}gkF{Qo. ;_\p&9l@4]I`N5oj1^´iU*34N;z f`X3 ҈i5K v%LBl~L%.d3g ͭLGقy:up$0Z`ׂ蟚igf13QיHL}[s˷k|5~a%\⎈sJU۱#?iz{L@fgJlبdg _?̷/q2B30R ַ2DJ3ߕf| ٦Q?cG[BB&t '= tƷ'qoN3ABOS%y2sM8hJtD,#9$j\}")0$Q-:<>av%G󬾄5R)K?HO+1o7hGDQ9f0װ"L`|<1ȷ5=}.`$N.tq#~+2Lah~%'U%<=nozRL?k~Cȇvo0}+fL^%>8f!ӎ:HbWuF}] HΙB& r4PgSŕ͏sXiq^~l%i_e}⪈-L`YՎ쇫->WG~k¥BΏb|#pl!^Eܷ&f|W~N0zOd&0{h& {mOX:!  [:xd2B`}\ _§Qp Kq%R+ְX:SN\_x@|_;_r@N[ml B#8̳`w l<%\$V2k WÒnͩ IM3]@!>>\2uÏ~槄pl׀LfZ p&\9"Lj=? bp_v%8f\ l!B^Lsiݹ͇ }GfI2s]V |v$,fT*b CN`OZ DA0䊞0O@7h: K s9uD?B%CWå7LEyR!#?ˆ?Å\P Ixp_@ 4 2.rr%`zd |IB/gf@,t"QWo vdYy ?GFoWقXb p9.#B'@ѽic, 'ILJp|]RV?Rp6pdBrt5^n`vHf#1\AR_ ;<&~+ai2šZu/ 횦iJ,ťaf=n?{uͯB> Z;`^iL@. v&0J,3yGO7;V{>ĥP뇫/4M%2߇“%ngT|..O<Ǵ.;48R g_3ՋqKE?&Uodacl5):0GOO1(N̓/Iex@_pUGHEH&vw@;wqX'ZVX8aũ%aa|{z%:D4#@j_T؀,L7wQL 3m:'Pi0i~>N3ܧWXVs~N%VoVਏuu8̀<ڌ W",&_.Τ&c 83!/Ka!3jV{p*1"fu Ġ" D*6,]_%DjAI#luk,p!{P!wHzJ!̋l}~'>Wi6`2=T1O@ D<I' K:Xd-,◌ O' @]⧿GMa:V@_H~ nt&6=.Ub''LN ӏe\v>ncNRØi3fhէԒ'lɴߩ\z<850t ; AUbGBJ<ɬ:ªK>*qK(0 1&.}%pqU_Tw}di~o Vk5yw{8"L',|YV[ q ^&Yb>Ξ !I:y;Z8:5~әETBJ>IS+.e[,ͻCBCW!S(|[o0w5vlp:`*'0=J@p?£;h_HX*M2?.FyWzsCVo@_X[G5`GR@m5Q" X xIuBNsjs_ hczOs// xuu]pk<bBcў@hTor&@E>I{za xҹ\bSB }ѕ+ iEf|GY{*10=Ӑ0^/XZqCv%~}C^-U"Νg~j;8$0f!6{Ub!4 0'HOLe? / O&;0c 1px(xw |(ש/-]B$0T\JzGewbOZ;8vu)L@$"'=[p D ч$d(x6 _?jz߇c n95sHO|<'# =a=.5׀,-*1gJL&p3 xu>[||B ygPTwŞݶπ,ͦ#L ;ϐMu3B&ɂ7|-RVUD+j6T3bi#?4ϟ%6^bd50nŞ2(l;St;LĜacQȰli`) $ryeK۷w ̀, mܓvWnNH>ѓ)4AM|s<oruJ5K\tww 0N^#@46,aәS?,٦|tU}:HՅe "8@ x7 p[lbq޻yKܨLπQKh.żր}P,?2bn436 \dWn!c\i|; ٍs{qˎl46 kUR Rm|[&"H}&jbՓ+V"32K+Kf' C}D`7kc7(rF?;{;jd.tҳ0]J50`KW `޵Kz3\.S kZpadvd3nnJ`VݴoϞնjZ02A;5 ŵÒ}_¾IENDB`ic09҉PNG  IHDRx$iCCPICC Profile8UoT>oR? XGůUS[IJ*$:7鶪O{7@Hkk?<kktq݋m6nƶد-mR;`zv x#=\% oYRڱ#&?>ҹЪn_;j;$}*}+(}'}/LtY"$].9⦅%{_a݊]hk5'SN{<_ t jM{-4%TńtY۟R6#v\喊x:'HO3^&0::m,L%3:qVE t]~Iv6Wٯ) |ʸ2]G4(6w‹$"AEv m[D;Vh[}چN|3HS:KtxU'D;77;_"e?Yqxl+@IDATxMeWu_D8QY N U覜.f 1@YIԳ- 6 aRK9#@  )t8>cZ{s{aG8{ow{gJ|pqvvؑ*+]C? {Ftl偛ꁚ7g]~-+*})Ƹ{6^ u<<>93)ɽA`h#T:jpp=syOv{bOmAn)Wo&`sӕCy_ ,{w_ܹGww}аӕ~;,Ϋ[;{%{%K#l{woxǏk-_쁚;e[y y`|/H>|[g73|U 69"OQPWg\8m0Oʲ'?8;Ƴ w xmo 3>`^ AHO2g_['tyA ]SS2l)=em_)73MS'C+9R%ןf'Pg#%Tlo=?{|? (EJx`v%{dzCMf`|-6J| tt`;wvNnh<=P>( '}{nO/ ;u\\&ď0޾'H~H6.zC8vÉ}Yyy

sٟ/@7r r<2t̴[z#Pӟ xڣN!O<=PzRV~?s.׌W53qA8nC6p;DHWҪ l-$(*lwO/; zL<:gi#z mBl.f~:vJ6r^@yyxm-#?=M;P#:R3dZ3.kh#ܛ|솇:C >?߽{ p}}wK* @%'?wP$ IᗀK\rm m֜a89e+vQ:6?{ϟ190LV<)n%8@f\?p*Os\8 xn_h6E&噀&y0RT(yE_޷yBJ}'OL纜kwR&7t<"#mˑm v"w7\SyyeO"rls1u#a4s_b]T40:^>X-Ӕ葊L@{E틁O֦~AFq-)ly{@3}Ohi0-ʢQ[83sRI93JV ?-uH66228S(IYܔqB9Sy6y0lY>2Za ʙ2xq)0$:v>$[`]`2,}tͳm܋gQ}TFT—g>)HyErɿő~lyDH* OP\ :d v`;:3,sX5FX *7>agLΑefbd @>G@y`@Q:to?"?>+Q[EUPpV_sx3D:ؙFTh쁞H$lroBvF:D?7g陀[?X·U* 쑪zAm=XE2<Ru#W2\NѫeV,F.ʕħR :;O *42&`C#y\ x_׬M(VnXm UPW#p*7$e٦ti6sJ\ 0ml{) (._I%|CU#d=D IC#̹$xrbsO嘃Gn`(sѾ SzmQia[``{'1W^[@{㟵IAK\3OכP>/Ayfx!1K]@hWT]/s;em"-Dn0ݻ+$Q6[xj"D{euH !N"Љ"]MBTFifq =)A4ۺ% %+Etr#H?әbԑ^r e{S_[Ibyz=[<}[= :s`!:H%G YAG j9CZVpB qƍ^x9ץC{ : FmT.kEF;ABe/~t=& ˪ry{=\苼JZ[{0l'>R1A0ұl3,C|\K2pN5Ce5GiCџ% y7J N9͹'e~0mFԑ UpӸi]1b7̧֮jOy`Zy@z CW(P@!D#oWݢaؓɾm#L/Ph3|=PW}V^[_<0J8:`9 CTsdɼpFDz$;њ(&Gy46ėN0%>2$hЧrNoA|ھ+J}خ#K׹ e{y=/.y ~{- Ia*+f s\~Ώ6vf .At%Hg2uӬ52v['瞡=nd)G/گ^m3cU+׹_EWr7R@e\.S}k,\V9Ӈ>ǜ3F.9 "K9pm;Xs!e|_x8A7(%l kUB<&L@Np%@)|򘿮m(y1oG$\'*4=L0h:,\BLz.K϶,Cj`a8ل< eݣ^hluFiO;`mvx~;@>t==PWgկ\ +`VDZh7֑ EA( zYmrrY3j b͘,-(QD)IRTsk|.UW2/dY!̅]Rtmu -mo٨L%rsGO%i}NZ6^<Zz`/kiYVx[|ha-u10/c&:]M65% W)c'=JjoЄȵ K̼+`#Fk%R:,07ぺf^Zu] {W(/.;M39 mq %w広(rT>vd;pWH.(r>ZY.wȮІ-k8X͚+:ңhm 9FQ:6'pi~Zu7⿼{g20H*)8'XuRM#rq"Q:esxvq!{-m\/>xʡa,C墝X14"u :Q.4cyEPֈ.ntwD=P2<]i&@Wx -XӤ=p':D$@n.$(hN=Z0 Ʋe!lK֊v{s$JAʡ>`ynL#}āRT^80FO2" ;]7ぺf^Z7<3S?[_}޶ E,nJaGr4$F8@VaK|Yh0GoA83y.x#|f kt^F9[7.Q~4K$Klݏ rܚ,fɷ{}wT|T )ʷܮ9I!ȁ% CA688NѯiLm) k<ۮ2.ڬ+l hhȓ#+*e,- O9;3sK9]!҃z4hN[J3_uU{@}3௤SGuGofA`U?\MvJ@xW;ܺu hUYAr/,dwX<@ɦ-)!G<5B&^ڄ`[ z|dF&d+N b (V>ۦPW;}3fW<}x6߇KG^"V̟׋~W/K;e:KZїLhG5UȘcpTu([h뙒2r$Ue)M ǢLmX^61cXNvO_Y^kmՖmxʅvb`(̗틁!a9P 亏ԡU>{8p#26=lQjsvE[K;Yh,3ŧ4#0 ۶ycc5gxHtg^vB~p sv{x?O_ֶ+/^Ǣ*MttKƩfH4h"/J9ٓ::eMe}V )E=KGrr)3=ed}1 ^ΐpm/,?ex o.͌гvՕi̜Uܾ*_/lՆngLkx8ic9rLFF?"G9[26m7wnKOO?N<@p\#7A R/&y$gtϴ_ hQ 7 Y ˬ/kDEI5|r>BG>^)6. z.DKٴ75f !Gy.͚CZ{L{blOn_#Z_xG+/|s*[ݫB!u{x]o#?}IyA|qZe(h~.4YvRm\Q+a7 mަ/8@!V|p}fCrdOglӣfQ+dR2X8Vϸ-$CxاW^>zѾ6mH6mJqkaL?dz#MI/qʛ}g+‘o|al M6cPbZ?#8K=ےt6ݶil˾,g.AVy|ۻMmeYwG~ϋyQtr)XWRY$otgK<ՓwL6 f_03<.YRKd  yDRqOL#Ze!6!1-B !5ayA^H.E,nwnK-hyj TT:ւWxڟ+0 Ƣ)ء89X+<^? RdS*[j7|,H[[.g?A~I!O}|h|sHmz67'iy1z>﫧y_/[y!kBheQ{b6_좃ΚNrB3B_) m8Lc;/dAu<˲E?JSߎZoZ-a'/Jv}IjkC|z9MY+vfٙGefGg|G)Gw35ơ"O8mm%`UЫpSmɖƷvK}RW@m[O5~??#E uI:9g :rT,Ѫ?j۟%:bm>6#;rqݒ-lD,gZz3,ESmf-+'%f gIzCY,+_X;΋L,%!7^yO{:NS\B_=VM>V8Su S,QeyyMsX3o.s T:c}sHpsFsh/4ïUSuqÞ ʕ`2uُXF`2<4ϛ Y".dƷQ򕣆iJcy`@Q}垿XD3m/v|{5e-\g:T$AKG\ڂjm~PoPZ+经/~75:SIg%J}u eˮu2Q6&r:dc彜(݋: 8aۤ!졌]%>ڜe9V$ptd] dϼ_hVi#TA3.h'u冭LMz繯-z#ܙ&`.٠Y, P!DQA-"I:٦ ZS@-GDM3=Pzt4or!p{<*W@a!kx?gk]Z ~6ҚWyWZu}Ӟ h=?%L[hz.p[COlw1 ei1Jz3=f]-'f< * |kelY!~ qnlC=n{p6?7+T`pu H)[ Ld`30q:X3~rоŋ'61|jJ ?'jpo5$PιtK0:t:mB!zH3\1c;r._W"yn>^;ra[(r<-(E+0* Bg<:Y lK'KЬ7z_KD"坘R5^Rj6 ]4Hʢ#W NoI ^ӈV)ۗmcMDMWg h/X[icȑd+:m5y no+qo\=-.,ȇh[;(QRfwGc Ly^hWܞCe|zt]gv|ߵgFHߧ^0/^~`߃@??/ZXXd5bk=o,rGisy h8S[7up]5tq??䲽z_{j³{oW|Ӷ!w§YV Xד`X!JѿQ6&hT k:23fq.s  bK=a3t2<Ðf!?пA/[F> <]m4|^:b4/xƂIu )| !^̳hLڐl HڳZDfAR<:Ʀww~aOs0[d>eB, 9/Yf ]57EB#ΣJZbcyH0-2/kg-Xo <O}lcIGvI=a{^Ԅlտm3E 9ܲ*ߒsX/~>vϔyP~M/e=!P۸`Jx^{W>IFCbغOm(ՑmjA:#AVn}k^h l#pfgUe Oo4_|<~g|0~o~KY(XW߳ Eugܼ FYAgLeF8?DMH$ zaG3vr _Z_^oww?ꀼ贾ݿ{wH}.>sr 3-: )c̄L%lKEfve~D6e4󃯚SҮ_<_̒va1=/d. c)/Th/9gI:s[ƃ绿7Q?G9V幞y8SyNeCt[9A+x.Ce6CsY%W<@}GBv; em.yxz ?/>Byh1@2 țCzgXR,Nnllav&]*x u={v?>T8G~ -.'s~'%SO%cեuT:,mI$E52v?V#+m ,ow@IDAT5o7}[yۧKj>g*??'XNbqՅ :X䑝rg+GOe,.G7J3[o#WOH[^ƍKG` 0C&ip?) =4QvOܦ!=?%<>RfrW7mm!Vg ?k}1E*/Jc) 7BcHP G.X̱E.u@4l%^RőETPt=SIY~k%Iɘ_SSۿ|>8բW0q+eeX)GZp-*S4JPG[|{w礿hzx_}Wo<> ~3w[,Ml}z_ hH,@yQ\A'%:4kh$9أl55q~E޻e>1u%(DGOSM8NW-4H}1õYD }u~\ /$Z0b 24)#GC1N.zY t[!aW>~ޣ^^VvԙsJP%}sLJ2 ̟А 71<':"*ͼJR)n(_\z& |zJ[n n ,O좀kCٲxఀ22ͼPƒpE5\c2"پ[mAmK B]:0&"Мy|i' O'ϴcTX]'y! y ݢt˥_ ߯ܥs2%` \ǂf݄zКjΗϗZ<,/jz̭n#Z2pر[dA,{clƯP}ܾ&޺mQ whyO+M֘ jB'}eEP޵<)c5Q[҄iCZF]^\@n'{)  ys0Y6-1= @NX3v.w"| 8,oͽ~$߅W?>woc/XjpNY!ak!!+ƺr d/El xs/'SzW^66w׿L^еj{gvFX0\ dˢ 9>޲)G.$VPg^mLĴp?3rV_^tp>X4ѧ - =, ^~Ɩэ,Pٺ̱m6,Y+׳V/T=I,1BB/4]qYtzNp fCeVz6{Cu[h ̰;ΰz v%%9oT(F_Zn:3$A/;\35oS9G`֣~E^AHXuXs ?<98#oPV8`.`~4#[nwi|dn} 0|'˷cn$$"T*z Ej9BhiQe4 X<%[ #3m}ڔ1E2-~\?QyWGj]nu=$S6Isk?粤Wey 6@'vruEȱ_Boإu=`MW@mg6,JQOckI},³`+e!sc:]ȑ.4^KѢijA/ ۔a!-H c*:e#Pza<S_ tu/72&.g<>ob-)<9rcז~vC9Z ̯_y0ym|x=sZ HoQfO -wVLpҸ9XZ=#-3Z0/~Ƅ~t#GBָx'h!d}ŦQo9Ix2>;}h>@)!qq@<ty|l=;L\xC;[C>r;ݢW 1Wo6pJzV{5x=suuhփzڟMX$Wa5E?./)+d ˳Y-ExLM%,A{])鳪%-:[74lF; \s>>ܸ-Adܴ5It~ g`XYzX"~aM.^W t)i㦤]otW\CmQwq/5=/<鵘xvV'x8 *:$<0f.Ih96pl Xhd>M@wꀏ䩿kM0Hs$RaGk92l1cH9L jКڴndn7uL"٢ɲ]~~WpqO8>M8-Z}Iž"fp9 p«\QSi{1I؅~PΔ#C%Tsg}@-^ -6x9Ϟ\޳GNhHHprja»OM?E s2cXra<'Gd;W7Ƿ|mUу^ E¶ <\~geؓ.@LCY܋ʣRI^ d{qR Z$Pj:t)7MP b6g]XcY rizbP& |FIŃ_PDZ~;A,ZE;Ң\Hv0~43^ۀ̟oG9Y!l.Q^J2w jm ,58>ҮZgšLz4L EG,<B%hQu\K |CK.sy uUϔޟ*2n W|8SrJpgZBibjܸY6)ϺT%G}?=>22l+-َ-pEnQJ?}t @W,k#N7 M'2' {yB);U{E Ѓ+]?mN8NI=@{z/!Y2~kRgX3\8Cr2:$y]DXXȜڮ4\[r菺mr /g{7v۞zeOG͛cr_APp7ӓ0϶<$gGGMrz6\F(Bz+PR|ECth ag^|%KL@K8^ф-H>91'opMZ1}`Ģ&?G_Yw$VH{˶ 2Y, lpX9b"K/]ݒ7]7K5ЯfA/}) \.$#z8rư,qd%#Ɲ_m@Gyji#dR|7H:_W2 nv+u+Ϟ^^ t)e?[ 'vc68nMf$oOedM>щGLexS QɋX>, gy1ztE|`S՝;;XgFqOG3BXD@1-Mh3,05,YV9^0VgiMHħ%q#m`xMI@mNr[4͸O3Hԋ.sSRtu2lov`mG4ּXw B9A.Uy닻/OpȗN} 7C% nD+|Ns#"C=N9>SbvR``b53>sn5Zd![9X?`2cߨjF ̧A&"R\$62!]i8˱zt-X0Im0c,3wv)dmEtmK:BO.9Oa*˒$^Իṟ6?{&oJsEy4'D2R ̼@GUqgtÓqYw Im%# ڬ#eK߭?{.Yc @d:_oxOq6˙sM虱c=n׭G2'ݮ3ɦs[%Р\ԳcrS^\RT.?}6~x* |bܹiߚ~>&vC3k"-ɴ.by;~a֨@<>LG3Leegl&`9i '~qiFLLi2\ֈ˶%<NҐͶQX=OԕYgW&ytd3[ՓAoW?Os‰> <\ϴ`3?S>' .grr-ti *BF~XȌV5WiWԧh.3k Hmބ,tz_?[fk/'3\O 4c&p L92;qD3./Qŋ$3$ %tnu] L$-fna |Y֢g#ѽ['?~yˌU{@BAHK"C*r%_яɴh;\ #|!˺-Y&x€ ]. f5/r>]kQL_`H>kM,0d9TA^$(s:rч4Ӛ>Cse;D.\V][6cAU73r+4ksNg9?S4JI[%ʮeg׹VòlAT^5rB;R/&:#e7ó4Ѯ]޸$oBsCCξ[]7.kΔ> ) #^=ndn4 J!MҨNTE3.(LO=ttXSȇW%! Ǯr2ߏjy3ۗcq)%O43Wo$ɋސDcCLsa86)/-l.QoWx,r pg7> I]zM>:ȽGDOwEϽgKc0ӚKGݲIRs2a:"gJ\2DԱ4])Qd8r1'm 9Ʌ<ٞ媦d< c{|o|o~큠 }ۿ7} $(3gS<|=l!o,,EԘ.IhCbzhNyQ2ްig8F\4lgV!l_~uzZNX`cP{,v,wCm0`٦LQXX Y#ci-'X)"۩zN)kr,O-el!g]h~Tz3 `Sy_$L z3 u˅9f5T|'y=Nr/#d5)X fyK¶}XGF:39P_-F{gyV~WL xq0:dl :B4Ё,[<y3G.CmVu63w>;,3TTqC8` <-qb>~J}YWy$3u k4e{O3O$OL-3? & rOLmR8:$KE)#9vl!Y[ti ,M ,d^pZ),jQv`or 0=Y#c#x]}G j")CA1ԇ%/x-1.\1,.n[g{^qc7f|cz?-Vx%c} ).u[>:l!YHaT>*[}&~@G]$~;`K/{Yg߬&A\LI& "L?_G&~I*XTyQ.,CǐZs 5nc,E __|*v@C4n ,C0l>6fm {v%ch 8cӼH7yŕӴ7WYgP%K Zxfg˷$0l hPJ~ mhseoot+ ^}^WS-bȏd<"OyL0K`Y3 Ю ܴcҕ\řܶq)?scW voыIwͶ ,00k1[ :/?o`x4(ɔIFN4#/HRڹ \ %KB"|9s/-xߕv goo_\i h3_Q1-OH-A/.>i~ 4 Ȯ4LL)\ ?x \/K7k^\3}.:Š(c]DhvW9$oƫat*)ξgf/vw\z< };^(}9uql[N3Z`2Rll8*m`XLr(޾1 MY"4βDe*rSkEt_v姯m (Bt^j (ޮ;O̟ A$b !c$d1/5 ofeU&uJ[urT͚\y` 0nK7tp>ŒقjQd#/`VWcGH?8(s_kIRb4yXfkɰ<.Ձmt`P,acHiQzoև=/%^2f;@o,QhYsx6{WXv[1Y TWb 6j֣(LqeYԡ xά*cs=8BJŎ 6V ]ҟ8fn$#0h ;nrg2*WI3a}/jkNFFJGQ7,!ᣏU&:2g G1 Y5Qj,!_S\6ۚq=\_ϭCjCa>Tۃ-x2`)dha#yG1G/[,*d)1 -yu0<[t7,bPTipiyyKL-4!,Ӝ2\z`ĩ&:ue ɚ<2c{ rN«]0 Yhw;5NW>mv@/']Kf`jܦ?-{50WQ'L!s  &la $ތ/rM!:`Ո>Yzcm? h$xIGͮ-i}=؀v[o}ao~<-IL »GZ-Q҃?}TrMGa8zuB5^ Kg{'6`aUCv|UؠZɂjr DY^>[nt.4KƷOxI_}5^-=ZD2c@{Pk`߱ bzȈ&R}\2 ƪꔱO#L| ~drhq\psgy)}!ۃ4z zvﯞ ʵ- _#7:'8 8n+gKLc ʅ{xx˂$u,Iz6{ Fx8k릵4\ h2E^] ۲>]#?_{{-ۓUbLL:n8&G8yf~H`v(/p1 h.dsʡ:Xph בlϹJNrcGX0`_|۔}jd“c߽w~_£KlԪcP>d~xByLQ6UA[gcIy&.gSuLQ낭#yO@}6ghqoβ@m>9lu*_{о~ՏI V(`:A\*d1Aɡ˹'8/TpڪXH2,Q}N𑃇2«6Bn $yEe[.L೥f#d3_Oq]=ߟ(=~yfnyor`׻0{sR'!ǜ:9AGg}K'-1n)KOuCć `4#XA#1nSSIxȆRvGFmLm \ʒ.$Fn:m[Ph~>_\!LT+y6WrSzϿLZѩљ?()`q0N2Q S{LS÷Snh{ d:pjw Z$ZYy~QFQcj:NBrmŖC_4 w?i@̓Pvn(P9&28*&>=!\SP\g-=ŋUAUC'JLLw=c\(8Լ>,w al_iiҟq=g/m~6`y|>bSGZ$6q\\FVw8_e eù`JjJZG'2,/ke<_igOY([RɍF_loØǂ.+2-x.1/DpiAD0!bŔ`A93洭H178B`#gnt#Sl[j2h޶UJA͉~MլoBHq;쏋]-\I:<ǀ/t;퀱ojF}\wC+N~tL1ǔLw5ײđ LW3RƩ.yY&v7\n ^ZƒQ2DK{"$նf[&},H7=:@m8/QH=|2ǺKׇ;Ρ->smY%:y̷|gHqܐoZ;{=qfS_\杔}}r"">9Ǔc оy}{_sjUyR8z}/wϯ| YmIy|_͋%8'zƻwޛ6NB|:D,+svmXx1x^P߱0aˉ^:ڣѩ)Ԧ=f7>ڞ|jk q!-_t-{Azgߔ8f{2LU#DSGI?ٙc!+&6ի}r1J\l:cDtq$\O-8~l_7<]Xc/4wƷg_8>6oĈ6scgCX]pD'NthP9Q8&Nzu$2Oc1ihfQhwWpߞtu^g_84iJVÿ|Ǐ{e$4ߛ~@{KK[~u~w{g7_2̱Qϑ=OV\ŀb3 ùsmy$BCJ/9#&qC=Â.c Ԫ+ݡx_?gyh)qi䌝/(}gv{h:wǽ q::ug3uT45z+xߣzmPty^9t_s00Z`{o9`w>ȭ܏UUo~~mhݵ)W:.~*_WC0v -2͘o^zXyI}>2rј~au|ǨGtC2Wo:7mſ0,Sq|^ޞ?;?x qi8Gʾڔ]/ovuB*qxa"1o>yc{tsI/P$'d |xOwo>ZﭱQV$ ޸HOJ cxٸk0w^*>vis6FymBs\Ux5vWێ[" 9Zdߨv2u]#N18[1V|y[،oGW>>6^]7֗U=_)}}X"*)$k ړU<[8YWȽZ7{ˈ%&=ʽnLW~W{w]^ꂮǏ n_ !\?uulhl&6ʓlߠr :{$X'yUG|s3?Ƙ9h'pQ=>:aWwxjLpA1D_S=Qh>,軞8c kJQXwlJfcKuף㍊mƛ^%OS~"e*Hg>߳V# z@;Ҭ; _ 48ǝg$'봽nK~6}Aʎўkzٸf6[9=ʡҼʞXJݿ'sRAoJ{=FǨDZHަ9*+?]}c`!:jq_ k}i=WU=u}n|=Wf,r^SKKO\#Rs,SUq9Ȼφ~|5IZ͜}϶ܾg߿¸Yz/>yXlp ubTN'9r/s'9v/s_l/Ilqq95^.i2GmwzMպ,}Op~ >kZ;üz49\8}_*:cbSqױ̨Σ~|pYe\}f9. Ã7t7ǀN?#k+I~<~?>}7:6TߐFs9֓b?HN`5ߚտ:o%x%`=6GyVߎ/n;ԥ cr6c^{l&>J\%O0@xÂ潡Xu6~M{Wx+~cy7x]ssFsMW{_Uyg 9rz{5u&?N쀶xٟw --M7fmV GXD>5Hֿ{N;8Tđ'9+^iQS׹|nSmHtj;LXwEޠΏxݧ#t!&o=z+pzx~S9sU5lwc>|ފ(񩵯 >rvΩ^#iX7mIs-d6#1(K˫X+: |<7mG0ߞAgNW7uC/(":㝏)>ya.*=/nZ Ǐɋw?{2wU\J}#u{~"\bGf+4r߿?]/U7_UOzYVݶw`]qQrkq?9^ž Q j̓4Fps_Y,J]nry:ri6سܮ;׻7ș0sgi(u*h\s9|&^)q3hs[hȿG)%ĥȂrAx6ԯ^ct>>Ï~ {c-EG"M@~{@ :뷎5]bNr|3Je{ P }1:VnO5].9OxuxO@'})0!?_}Oˍztݎ:}Ϊ䂲jk998_9Aq_92ʱWY'\wjr'N8z+> wɡNJ/Me^ǩO{o8oy^cnW Wj2:y|wXZd/l<+WvPY+MC|Ί<*@L"sm w1bR>xq;bݯ+Wt_} G@IDAT`/sz9쏗c/=ub1V\?qĬrx٤uscF}W_q .&3qUb .uGq^6y/TϹ CʩznkmX+U,o~_| %W%˜o|ܞP0: M@@i/|}* 0zV{{^~mSXc\Jbŧv6tz3u8A~F~0ٰ=^nwo¨Kml?%+Bc]7"6 Z83Ͼх^seSL$qneWLfÜg:kt.O[ygPDX3g/Z96ԔC_,f_gߗwaf\EJu\a#Oo#c{ut@Ȇuէ^,;V\w${Qr1?E.+7lKg%kxg}3䑹E8^F_.۾wkIs>>̿o7XLz؞r?۷Nll4%~ яu86փ>3kYy|+>Tj .ZsAV#ݪ@Nf,mXzhp;_F16M70\|q?^n>Cs&;z3+B[+js"Wt{G? EKV~l%кEGOsz}?wl:1z2Vow}C>vf2U5{bo7>۟w_I-ʮ-:F:_66D)+T;O0MNʠVSp팩 1=yDx[~uQ=K!YdI3˜?H+2Ǟz%Q@_q?jW5#=sc"H3d+kJ),ONsU.3Ksn_K=1~^.{h?trq㵧`-,hWnO &{i'I{^pƨ͒s`:nMqܱQ#;Ə S,KS~Dt={60^"Fkltב^ ϸ{uKqS~[ 3vcfDpq5>r.XX}!YHZf˱G xeDM髄_ѽ6 +};7;l@noOx)̱~Jܐ]mm Ҝ7 (udzj'TaR3!: dcl*[0s}}rMEoVx8mXk6W q|onH9m̑z?=,fQ:{ّS^a-cM_oLsWvV[Vo/V%9}F^r%F׉^#`qa3K|GG^ 'ax_7>`AX;c&Tا/L-ݣ#<1H0^gpX%6Uyv\?SA[XhDq4Պo1#}*+Zcb8"k&c O:O"#zSÖx$v|Dw'N Xb[*e2q\=K{sٻ#R}wu9Ȳ:">/߶`C'} xOW~A>ʯre&W_s7O;ce}7:u7U-x.2yԉY\}s/#CfmٌScx3W6A}sCWu5G|:G]w,F|qB+Uzy[7G#?|hN?y.myŷtŃxfaNFl7}іX'+ *o\zl1H?u^e+xʫ⭯X*Octp0C}iU;c+TY^ϡl}DOy3>۷7|2|C(U5wd8I;,6Z}Q'lEmh[dP #ڴb_~]m8է W>f^eea(A_Y嚑K3cNy[Q}e{x8:Nx$!'< ه-w̋l}J[y1Ym<5>:#2c&nuW(c͞?Vq=L[.*=|a˜c'(~}}z)̖˞ 'U7wtuɃs?έ+ ㉳S aԜ` _[ NkF·{ALa6I;UL椯ŭ<jq{)&zmJXۊǶpu^37>{k{>׃lkςZ#xЋd8oN3 )v.p[c-ͽBߚe'8Ívܱs/#cNO_՞ 1rAE|L Oce,Z;19m5r8yjH9¿Ж-LBڗ 51Į>f=QV`n{3"u>M2'1`,Ol'y8Gnu:گ.՗涿|oeFHʬ!KM+”c_l4말=^?ΛN[1|b :z̤~b7,8W]/z9u4xcUTNb]l`>h2Ɔo͹#(2'uɣwU?nի7jޥI)~'x` ܜy%`hI5 n:n2n$>{lqR{c|XHGz &qmO2+_VQ֬d(?4UzɗJF[Gh#Xړ3vzj/l)e6Ox5O ubx%ߣ,.>말y?)Y]ewT jE?bW+SpruCobgmsn?_>؃]nx3 Ť%YTW9 geϾُn\8G/q0~j=Jox1mKRrV35PRd\Gqx%Gzqf~04#:Ys6%%=^f|+9[d=ǎd,>}"'٩ӎ<%fՌ9M@;WHx}︘!?, TΥ1}A_g-l9ۥ/A+ü{uZcmO_:2}dS5KI!u6>S݌:wlr"aX[>KO;dhZzlu[@Y< ~=c7 >>>~fpX^U,k+Xsf X*Kpݳp(٣UU-xz 07~/sMLB_gIe+< 0:_gϼ#{0?Era.x6}m1uʃOZ"dLhӯ)8À͍.\E2Y0L{ kf ǽ1ݿU2Ir5cu?c$SzV&hr쳑;(O~-GE͹x=jo2NMh3Aji؇7W#=ӯ>A#w]NZDiX(Xmu+ﰻ] cZ᫷s`cȭ-J#Vt23g6{-컦rU$AT.s8+#c;Vg,G#>{sg:Q7~Y/HSa*v|Z۫9Z3koUyrK7G +̆5d'DZz_pXRdWdy«}y65%e1Hl+jͬ5kY}C6^lx,s_N|@囀G`;r=؇?-HdsKf\,-SI-Wi V+{eP1{iHȸ+򷇬yhh,ΨWc"WqPW14guB>ipm~oKx/ Yy15kn)~枙=wƟor8z% L,F/zFf{Ҟ` FG}g+p|٫C>Θb|:^\2rgp~Ĩcp+"M+eѿGs|sQLpشF~}ѻ?rO6tUVt>ObO]|ZFXs$E9^VzwFc\9KyY#&`sNΓqoĬu/ΪK5aI/9Y=W->[暼Qή1Ng_J&_{dnrR Ʒm/owi / شJ}5b3)o_'#5geҫ)sqw'ǪK&'9'6ssUg2b]sǪsˉ_׃5HV̵+]3 Hcfao6z'^jF٪+Qq]ˍ|v K1cLg}s}bv:xps8@o;'B[ЮvFM%mxlwMxmr[V;.{ fmvh,gl%v"vqiI {<+7=m/gW>1='1/; Wӆ^7Bw#8Vv_cvl6F߱p267{ /I#)Kz'YJ|;/=t^)Қb}dϝ~f|M.As׭}2m_dE]C8S|IJ|pd$= {ŞsOP"QMHκs3GVf]Vh-1^uJ{zEkE+[0#׳An;Gǹ(7[Yx .-,NG BodGq"#;Wl |:b7])[xǾ9CkЀu>t='1Hpߵ5^c%DyU+d]~}qU b@Kf i%bd4j6|&uJƽﵹ?'`@/'_m8(qs4׬)kD$߰f/JtW8ѥm/غ>\܉>߳2+]jci)fzQhv*l,&`<}^ xUoq,ʃ>󧐶ѻXJXNXYz{]5>;E'_ͿbC)z1gTs9u暨wKȎGDML+A?_R)5->y/xԎ$ \Q4s‘xO]wn׏W6|lpIj˘7ևl{acmRSMyW{e =h`#?yJ#:R_f]ɺs$&?x?=O:F^:|_ ؘA}XqlwSZy(̺( <&8:~1|/p(}3E>'vYqilřS\z^"+/휜26?ec1fĭe>^H<EG.3[K/rbf8_gpMĊ9y GLortNm&~xgI' _rU {ץ E͞;>VFzt\DFw'xe#9|͹ ۜ>׎#bQ_Au1מkI>ؾgb ʏؾ_aE7x6e`_}z^ڔ=O[%s}8am~Pq_)'F-[\-w.4}F=f0>8JĊr2qJ.~z9Ce6q7=rNW{em3+'>5>-*uyou@>6θ@m'R}_e;JlsE;A7,8c|:~-r [M8UO79e~|V8o[YndmKoCi(~ڎ.[FN?b~,z](ϸ3oNl0sOduNAҬ<:7F|su]D=uՈw,zY Ss>NW 7D&6Y9-mG3n[++2:xu@Q 5rJRk\ַcSkR끶|z!A1753Ljkh}~se4s§ٟ6Fnt>'_<9Ǘѽ&ix_gQPһU!EBi{ܱp%+=s+7䐜g SwaG: 7~" O]O%ܴ$y͉qɚ[I;{;UWSOͬla6@\G8ד^C#92=s>8vzOIo^֣f:B`Yt\Ω*0YXz|>gkU}OŝhD-56.Eq![_앻ڼ'+)udcF~)b2g% O + $N% Mt4G7CA-]r~j%SrXc50pyH2)ڇczK.+#ޠc W8>Qq8ӎjuUz9:X4tr2=T]_`1%W['`$ak5ϳ~E:;?4jl)}ϡ0LCոHuaA_8Jġ%s> <r9kLV B/ &5Nb&^wX{`3gd稊T]AGr>gS9U)xiȃ59bS9%?L&58񻪱38W$8 J=vLlxBk:bwTШ5a:ټt'ا_$:/Sp (UoՓc &^b,4=l50׏.zLnCmi_yɈ~Ē_9:Y"itгs$Sy|u.Eޯ''8|kLc<˓ȏc%ogD_RGoH5[g v+[?*qw6\ʾ=:e@(VsEG0+Cx'7sϾ1wx#}yYF=ޏZ^L1'1w<󷰖X#frWb\9$J cNMYxNx<艅8+gĮB.;u^F'. :k?[Fk"bBYk}^G]9;I4in܋5O!_sWD2cgV4U"<ʞaA~{sxBqbWGA5O~p_q^yo\Zo;|K/l67->9*5\ ؒ"4dWȬgօɵnJVĵ-1pɻ"+,8oL͓g٬GEZ8D]7>xCgpg??w @`l?۰gs1NA_97 o 6tNk[to{ +:k@7m~<'.w×7VTGܨJF6E;PO٧ϾĈxq 2֨9>}*gΉy`霞'>4}?X1H qTmbK^XKj6xIs}p:\.Xsf2αcکsL^}m}n99]uE2xiy*8^yy97o}W n/>qP{z~w>7>w^Qē}ᙻ@Hm'xJ^ ud6f9RIJr=J#~y>lqpwJϵ}Xu]9j~Xo̔;sgo/_,Xfg'R+}%٨7WeW:t>?'?LvfҾZ3v&{.Lθ5^jw opTY>6sܥ ]Χ2j08繦诳J:d9,el'h$|eN_4Az8Z9j? ؉8_wq-Ͻ7>Uk8G0Yَr+ۊc7.\Gf\#B|k.,j*mVz X7m>puֆ>ᶾ>77 BRԲqaFv1u!;j1 a䟹bwړ{xo簿ZuD_sS9{q;~>u=ǟdqc]v;hh^<| $@răd 3 -X3W{:">ءwvz3<^%xk/'m:8 ;qO<;~U?΃Jˮ~m^ t߻]k8:$}D_}vgv٧{Z+7n~kJztx[ۦ?_;(נ)VX=2ދ)g+&Ձ7:[?I}o,eX'߽y<<~ sf WWn7#csKŚpNR&?xs|p 7e<k52?Zǭs:`je=j5vѯ]_7*cMϥy̞^̝sdv}Ǜ}1 p{%_V{ֻ߉BWen>Z.Wx9 .lt/|taKz:+J%Ƴq99AS8qu|syo2n~T{xOj= Bw/I^/NV{Avq .a"qeFLx'05 Yz\.KojLů9tDxu1w^YlsZx_||'6)ǖ\uѿ/lǓ'[I Qu-EL-3gΩI;V[>,hz|f24.קFxG>o~o=#Vk[5ξd5w29 Rj ]_U٦|JGN_8"p:ўy>o~ébjJfm]]g-Y5^G%ʼnq\I\p f`?2#>>$u=p@Y| /s'NsjN eRNBq"aJ8؂8꾕]a03M=<33{s>zz@&N؂]i/$p8% }\NTܒO f%k6cy*8n][t"iG֟*Kaʧqr<^F"՞"=uo$0\lЭԄiF+8u8wsyϝ綛%B% nƾy=}Rʳ} N jfn=0P%n[Yx(\|x}m CP?9oM˾ `N$|// 8 lUF QqqWK !_G:S,FXӚeFT?>72nLo DU_h+'Ge(9'6Y1+R&bCcn^<;H/4\0Oj+-zױgxcfƳ| xMJgպf&>?~瞱Oݾ@h͓{bPUT&`qmׇ5:Fv<gV.]+2a5 `198Bv| CS+2FS+~ub \W^|/^ zgQ[[$MU5zF(>}`gnpv;Fz5v63ESZ3G;NNt43]pXAjB"HwM2棾p_V1)ͷ|9Q4R4#laFlme~3~uA䑙3^ul¨IDdq2vmAJ?>Lz>|"$cnƧ+>{|V:fm+^YkV)V}jS?=^t#Lambcܱ۾6o7$8ؓ^#;Whۚ |e اc4ɤ.խ ًԱj e.6{9f]海I+H}'N~Odb9셕*+b0 L2XuUڔ8y֚Y񒷙'yb#b,=hO٪S%y\QgA uYpÐM;7GB2\'1Q_#KiZVȪde6鰷`r?nw>kGWىзXh8e\dV1EV K%^jO|e7~pIt\wMVN qTAG{ Q'JÛzӇ۟^K:ANR=Xc:1Zzԋ+)S4Ș;X+hzQƝçs0x1\g@`!wX<qp%M1OY3CܞW?=5|pĻI.Ob܊3cN|'8y<>~;yO|Y{xg>\\#=u*?slm92X7\Kܬ6%h?KϬ+oVR{fמ;ssߛsSTGoUN8،Fl.>|p> 04OZ%IF9n4@o$G/ay=}֕ШuSD sVqu;{k/ˏ4O98:R?8>,hmݪy&@͇mƟyQMQuuj{=[o _;OB/cfi9;Vzɿfݛ8ۥhWvnjC:fe¬a99v.][ߌ®_ϥ]]\}ӱR^õV`>]V8:-V~p|Ԇo' 'r6Op̢bǽzSꕺt{L@>6oZ22uu:i[>AάE Rb8s\p7}ʺ{nULjW &j9O):VLfȹ~܏o~7; w~w\\όr:v=/_nnwJw-kw]~<\{]+Wf(& KUKڀ{9üڳ^KKvp}eG+KK9sK~N1ydV'فU\|8{|ݝO/$(WAmaXO^-ѵt77>oWp-Wo #df=zm>t8tDU~o]f4?/ Y3H"{D//&sƝ;Q%d/ɡ~]IЖ9W/GO_/c 4xWqxdm1[OOοT?_'9%#>?v7R fLn' mO}=j <}4gpl񇃾l픵ņ:_۹Id4ƒ,aOq;}WYYSra}h siLIw}pAXD:Ժ"Fys{c7<J{N/>[U΋PdY}ey]#;XdX~ۇ>?fwM wLBx7ye2ɳ~zp#/~lKO齉q?I6Z '7/9|_n㟧O{j+33΅e5_r΅6~9.G_O0''eK~=ώs Lų2}[%iG wFi:;>>zGt>Np=U%j{ 6ZgM\|s(A\qk|IupμĢiN4ql{:D:wߐZmqǚ]zro=L4&cJx0ŋdoοr8W[r4>!> zjÿ7׉EG]Uo%}Lk@IDAT6t*a=V_"Ż#Wah>Bi+fzsf#7:~S=5z}mǠ.豾G̐ˆ9GEU;Z0&jp4Oc1M{J@rO& Psw7J?>x 7;9E5X-uuN $-[wz"= &1W}!wm~beѩQr{ɧndJUo{Cϼ99Nj~ȬQ7?N_K/{m)L`ORhMJBc+#ZտOۇq_?ux/߇{Ȗˍ7p3oO{8rS?qLv,-TsޥI\~zoI^e9LW?lG>Z}cǥ{_+#㹔QKx2J{D"|Ğ(*;2'MgF.2̪.P}vֳV¹ZYsd]1917'pO RֻFi<6Pzj[m\um\SPuY)*aYx}?j׷KO|ǑUQ*cyW]t^t0V8 ŏǭc&Pi ҢS}F:|Kgx؏şn)Ý> F#:|$8FNڠud:1)5ؠsM7\76t{~VsC1>N`|S ѭVcsg\+?O}"g#v}xcr$*HvsyU;j_w#Wpox*7Mc>>-GMѶ_x?yE6ewuJ$q}#s棆Fp8ʐyQǬʣ?݆F "{}^m.]D1Np{a*/+3_#c0u_غ=0k爜#џ[6_s8z=n?Gj> ?cgeZ+k.C+Dk/l君>6x6UYzm|,1^͵t]yպ/KXtywɃ ߲.`G7Ql.P^b6G֊k6W~ ' R%^>Ogo=_OnH\ k)^_nѷapU~0x8̩d6NAM038ol C<ӰiK蓑>pO zOzJ}:8Nlṅ'F={'dzKkHmܝ]kSzɪ[\sΨإ9uq_1'VP:ƎwG[a/s)\Tn"wǯ ɺ @?y?sb)IɅ895vJ`q>O}׃7>x?O|+oYKES_?pߛO?}&̘V=jXu׶ℿbuX%Ӄwv?OMNK뾽/ܰ]%caua(앧lքq+'{Gz? Fc7.w"x_'y gUrɝ,s4儮7ў\8JeM|/NfX&Jnz}G) #y/F۽o[y6%8Qz?5U w}œ/&nrtkVʒ@Mvps._?~?Շ?1gRy0s_7+osķ| !>gXVNrJ^^ac6BE1N5@Kl5˵>AF\Wp4 kD{l-ceNjh{986d壶Kךy(Sgq1Npg*×>3LGee1S.e{pi\k~M1pD4*֒dGnpi.$9AedL?97U899|hѸNr)D\<2 xZ }YO귶\'N^z~d财qrڱoAIyo=l9K 62&ɯÇ6>O֖ 6F;?]aVU^Yz=K~Α[g]ae"8P bFGq;:U&T=nVs=p G'S#ד8WmƦ>8_Xflr,iD<rIwr?3~[ҬJ z$γ3F>/}U[Z3c8qj\ړ4gCOOypDI !¼%ɤ?Wi&`Z7~oO~۾e{_~-6F}ƛ ?A?綯μ/h4Gb#őq \w1ƛCCY]K|2R'" ^Qϙ%S N#cqZjrˁ!3Wpu|_y&,Y ukSwYԓ>'qOEH؉wӫ½^J K @'O6횾J+OK;;m^aO.cFU<9ʔH\8Aͷ޲^[GsOߙ ! :[xއޛ4h"E!9~pN,2_Ͷ{N?𵛷ru`SoVpwK(1ݿ;/ڕMsO<ʧY#WC3z$z$")eᱲJ1rzLp* =| p_>3IZ[Dɢ^ T߸cjpa)%ee\Wڝ񧁷>̛}"ӔN=cxՋ뫟Jxy4=jGe簏}'<ݼ3DX\? Y˜je= fTua"j=G/l/sg:V èU̺:!5ؠKYlcSR^PT5̃qi29|~ZhgpkFO&C'G}˴AN0b1q`'Pi;hr_p?ۂsevlPp/XjG~Wt(^5:*4zބ>ȅ]`ΜCV^L՛/W$5/'7ud>ĞCsL V J^u==-TJ6eSy}>;8 žtK.uګ}SRzMt{|!귭@Mk=]#3΄nY`W`_1D﹤aeťW^VKXj~N9}7=, _0v`օbD`qҢ<S _'*)c O~$۴1~)wMg~M_쐸^͌#[Yj$[m&Z >LwTzbI0[Uߌc fM;g,tJ9/̔ъ]1䒼0y [ρsswt^̳Hѥ<:}x0#]cŮ:~vv ++۷G*kMӼغشÕ~F{CW4̸Ɖ>2蕱ӫ[YꈎKUg77}E(jT3!LJc3\qٿ'jT9a(mG_6W(mʏ*N'mr^C 2>;jV~EGhD3?箃c-QD)[2ƷsKc7q3[%25y"S_8;ow_*z{`ĵ {jw̬zLQCB]ǽcǨ2ѱ!GlҏxҺ7 7lo犷s힕= Y"%sP1aE8["(N,d}9WOLl쮒n L@s  qIz}d|5Fڗ7ZU r&>]S=} [9]-4[}EVlYkΑ@8`v3*O#mğug]nκηs*V @JtU` "MA$X1*xЀgqR25LI AQŒ3c:5u'>9g~Kݡwλz.k+'s3ۦ^/[=-P.$`2BmA{5p/ncW=,C\1flPu{Pd|Ƣؑ=VaK>/ǮrWYM@b-Ɓ>]ƻa$ÜÆ\ 2{ >r=j| ~yPLf}95l#35>Vλpe,WPs*@y#vCPkؾv`VAuwpzKόyIR8u ͸cԄ3oÇμr7Q"җ8j;sۇE{ֆ/rmEWv&+az/D`WK=K$KkRw,myPGJ1.\z%cUfGbnoW{#)M3_EN,cu[%բ, QxRAXz4…%C?[\U扠r0uUѧjL3x}I/ 8Kx:wыaIy,v-ݧ%q=nu .\{W"j¢I#~duEFz`9DHFϞAo+Gr_9wNݎ"9v3``!8: ' Hw[aEwIO_'ݦg g/$BZ q6U_>`M\-0^ב\^ԢSd'%_ųGXOnW6W{ݣGܼwsWTlz/ZD+X_iY巺oxX$:`FUir (xLiw'ύ+0ZΒZgS+F,[1klrQ!o מ91cڊKN`e؍Wa1 Ы8$3*Vfpe=n}}R[ d-Ŕf.^p%r?3oY?|!MҀͬr mDZ^bK^#9[\us*'0ySGTq؈iշR+b75Kz3W"ݛ̧MgĨmduFŒ5f;Ȗ5v=$( ^`SYK5Q_)yYjЋW<iwTMNY&rpݶq(7B5'VE;l=#in.H@ jG3 94oW+~$sO11&0dξ˂xz`|?_wq3rVv=Bs=+^sb!/lFq06>s;CSYg?m+KA o=#򊥇()?% 6Ʊע3Wn] 0yv,e [ɭy ;ь{JRk]7렾ckCOe.9ieYB=7^}TzcGYdom_&R?tZ+d]gCɎd#ILYEI@_9ˁ +aTK-:_vƱ_(KhޜwݡeV;q_^nؗ"Y^45B绍$ݑWw_?3>ǹx]Ӳc:o@u=^_n>Aqy Srf8:G6Xcf3n=̧oocUH.ErV6b-sT3R ]㐋O;ihoveT t#/]xhȰLG>(&n7ܓ gnHN~Nc,hɽ3+mUևQU]lN>[|<Wig@B}*9M2Kz[0s{0g1u?^0ec Ucܫչ-窡,n/9:NtaO,D[p1,68U^{DbXs},c.Yx#"C_Wa$'`Ԧ21:9zh#/}fn%ŢcE(5{Z '[-ǀNvPD>]2>{jT-n9::߱ύOzb꾎ެu>"]ˬZy?],mlsV|UxLX+AhO6֭7z_u(Vq09(,AU үycR/WY)Za"qu ǚĔDZ[%*O՟DqPXHt&WaI.#BPv]?q瘜FyqJ\If6ۈ [#" osدqNwGwȧF#'9Lk<1r:^zwL5']}:A7]znxb֓XO_JvMd qug1볡kJ}+uf3'z.|G}r埽O@ O ј+DǸ3cpf;g u#^}4n}r˂Wh9җFڄY9F#6.1&Uk-ތ9v?uz\2}QE># ȊyoAtIvl#Z&uzU߅8櫀㮢sM+sVRv0JsݘsZ8٬.Vzs?g^Z?o+^lZqޠzۥuz޴>z2r99}fTƾ݇6rc1ƥcu#vݫk^.%c6H3?-`O?걻:},@9;h$8BؿG]S4z/޸~%pWhߣʜwp$Ew)E5s ;Ie>i9s 3-Wyrrr5A6Vb+Wojӻ:] -_Aj~k:qƦ,5Ֆ&,'qw'ޕ/e6ԬCy%1y_uCq!{XF0~XS*QfawVe!zEϰ+|-O>78~[@2s>jOvue[}l VȴK>}u,O8zc㌏O%3(e"(Of\>gŎB(up< \<.^} ƳZ_%LR}2)~K;?;vlǻ.˹W,˽vm\ߺ^tnX2ŸF!K}vZ~tl5%K\O_>O\9vfzMc8@O=].Kd`}F9kh㌵g/Oex|cb i}j ~]ص&y06T/yA^t+|ȼֳ {8QK?^ GUhވ/~QzsC2NٴOE*wz]A?{֧vOWϣ_s᏶u|Unb7߿\ي9's/Oo}my˵!}u&>:A<ٛI>aá?TNb{N>q3{zʚegb9"gg_]Ƭ_ma_H=s|q&g0JXJ&o|^"/m;Y4z]6mXX{xC`Oyuc\ g`.BbG2K˙ß/,-x)io/E+1?#YTV#Z>xz $#=# VVc#Iȶy"QN1ݿXucU#9J-8Y2r91(bOz>aޒ;06#m Ug]x S;}`ͽisqS^ l$I{uBuq8Y۬Yg[?їq"+'ưȥJݹ:9NlŮ< 5xrw U=/|KMilvl[Z0Vdu(_d#Gơ1~m3ʣw[7c}\9mч` /o rV Җp#R}_XQ4XhdX.N&-b57S2:z`~E?{e;cv;T6HN~pqeOpgit9x?ߑx_ǃ7_8њX[.xM;]P_3DCcR8%APlHl"=`:E[߱|nwļ^۾py|r៿iHaXgG2QMLƅm?< :/wO[#ߴ &p;~yyBx;+LD_Md-6֟qt:j\y}p\ϼ:^>g\az*U}>rU}0Ҋ"+6F{,U#!'q72՞E-ڨ[YZA oP^~둿巜my/Vp_ϳ1Ԋ] kɘ:tk}1F'c57y˧AbHcSv5%kYG4[}V&}ꑞxuwܿQ ENGV$01v^ W~͟lj74+h"+\ɟ]_gR:Q_k`ܥ:~i}-")lVV;轾t%|N΁;skZ5 3ɝwۣ'7vbU =nЃ .5@(sӤz  R|=vy%'3/zޞ6FKltrj=_E ohu|gWGn}k/{t>bzEXw2fa/s\JRPvfN63Tw]s1ǐ8{BVy_̆z# <#u]w[ֈ:(7sW*u\N)K-/lW-= 3ކǝmKwQZLYh$:B:N]k5!YJB9ыM|Ǡk:Rrwc1EƘljV.?pa|n߂w6O~a5-8U0tk{e޸<y4?~j*TwoebG 4[u1ЇGؚHvr;?hnf4CXqd]6t5#8Ne.YdRz>pc ^ٖ y =9^@[k*{OzU!ճֺ۵mR?9"bV?}E {c*6FcXVfpq@|WyN0ُ}ۙq~>\?8hOk^dѽ3wgrHb:v+I~n$zW޵>י̟_Q!c1>F_%co.ܝCQ3o׼+q|7Tn`s,պt~CZoqQ._|-,ǹ>X ^93D:̕1QfT86P Z=s9_FbsmV9֧sxzܕ%cM-`'˖L=l_< B%f M8G~5!9v;iB zt~١"'Ύ0\ VOUw>U|a"}Zj52H3GYjS78+ 9Yۚˁ/Q=-m!BടJ[ԉcPZ9[AFٗ\"YK9sazLѳ 16E~MUX:b/}~nnN]Ș6\]3+1c[lK\5.2!y3[5~o]u^<7t87QPP DRz$DRM2xm}}nb6('sc4zz?#> Y(s1;֖^Ɠ'_6}|x/rf_JVάS8VW5b1ͭ9bfLڛ mX.s]c0՛g^9"e5im 2&~z1RQ&9ޞżVq8R' I@ržngÑ?qiy݃{hܹZ|?eԾ׹NHg}jXuv@fIo]>0gtjpʐGNY{Ǖ/,]r z5Y1m<_Ob>cpͧc _p}LEx9o痆LbU&GY$Uu~W/}3\<~=UϯB^7ٴ"N:C$̣?wf>1>z3Wd!d꣩#Vw|^̳m8K9nO#u>>{ۖzb|.|4f_NTzqf3p>~:bjcg^`isq4ptlyCI9Gzu<]m}: _E:^7ŒxcI߁4L_ȶ:qXG_ #Y'N}ǟEyG."A85|g ͈>c~+/:_U6~iY6|]^?Gg\š`UWÀl{G%Ijew4T@)\xN`f<Pm|ǀMyc^D/־cA/ݯ{(2g~^?vnX ~%ќ9pn/_}«/c5ou%=>ZY[- +┈q^X{|OvڻDnrчCڻ&nuM\_4\x y/oP۽1O # |.^S8zQ?wyt_{Q9Kq;ktd#%s[bX6fǏ ;oߺG0r⌝=b<wg#{#H5j z( ̊gzd@IDAT"t/2F^Cauw}b<\k|:֫cnŦ^DW3YzkG63 _tO__CԼ_}e#[ fyG\Cq{ }l6~N-7"q_"+ˮJH>業v3Oܻ;X j\l @'@}9TcrEA̳]~'l<%/Rh]G}:7?'^ضmч].h#&үV?s0q,~8ts 3Hd䯑̶c]bBgo^-JڃqF_~kj̻ >Ȍ1bTmgV,K$گ\>lxը\:R+/cgƱJ`QcpCKDzlZ}ݥo*z;H깰e;._?j`MZ'j횀}mǹ B_rkoGֻVe>E{y2.$}ouvD$po|۟6Ol8 xcy9r Bg3i"YT GDZ$^ᪿ? KBC,ħm=F5:d.<"HcG6s󰕟X9 G[EY:ƉPk\=VZ>!;^WW[4X1.x4GSBtb#?-qCNK*g^[EWt,c~-r/@}4ۥ/$~^mԩ7Aֳx,ˬlq29:Ex;G6;}:o›j>v s> |ԏG3㓾Sv^8m] ^ҙ`K;?;x|EWy r[IOz+ĿSE[>#sh#Sc#^"xAw*N|`ÖV){; l+LوW2}cDz|ZfSmˋm͙BxMg5uv"29⬁kX ~ v{䃋J=H;c[G(U۝}6BrSa!:6bu Aj&vޠ?^Qub{_dh=ARXm<=N_wDže݉?ɟ=֊ :=%'êXZUbgyq:N:MNfnWX,w"39^g:2+."mO?7p=L_s6x-/,ÞX84vJ\*,>t=lIv˰Ʀl2M>RǪ?+rSc4`㌅7[3|:?fϩ=v%ٔ|pܠFƧ!S:5_u3GIK4& x\aq{*G^px'^s'Fd6G^/X8 6=;NWl*8%5Nۼ5=ZǾ0Sv7-WgMg*]Z0Ԝq*,}e ͑{O~]wQBۋZ\{Q:6H8JPK>i'?=֟o3!6233ƅˉ 2Z.˝ ._o]ױ!+:eI\0f~93}P}7XF.9}2#`.#㴪QT^Ȋ0%9&BC;nk xʡ=ȈcxěcB1faeۢ߶Tj*Q7˙0޽77 q~n O̟I֋3_Yyh?bS?SmSw^کSܵkYVmɮDX3rn:c${kǨ7V$؄no|?o]dOx@~@(X$^%3(;+-`fAkׂwy~y5ycc S%ѮW:_wI׵$o䙀#<=8fN>W]mXKJx38f|%xa$d IEn{纕cn@P!#5UGMq|F/fW=y(^>$\|,;_lgٰϤpVm֜GwmCw_ZGHaf:Se6Wy:q;Goc/o cGէ2{[c9<#<=6<{K. ϝ(rPOaz&ˆf[u+} vx;hkgkca<{=~W6x"?BIJM{NxOpKKAiWU=i >QϬ᪵ed-1f>Ĝxø>J_w~H{hK&G6V{|5tE?>- =[ / n딵JG/辞>m*x.ni:c0@fff/ &޻xup9cyNriƙY:?o}vo?[uew~;SYRoK azqYGy(,z x߼i]HCH6h4m;c[.+\ge%CKD'jrrzZ1'V#z_FTF=>!ھj~^'xa܌gx'Q5K3?0b{oh9^;&}m>#b/!>2xdf!9lED`;7],gz$>5[۸`w#EK)BR͋T|e.?&P2pm-Y$ƥhw~\?p~u3ܙ]ONkLn_x]\`֭(󈓋\jpX;^M~<]F11o1ȷ29kH.ۗ7,w-oc=3RNnKE Z5F"͑j~!U;9/ZdŞx 8JEtR}R(L98__?4Gkģ[x˞N|$D˂^3~E{h}o(bn ̽jmX@iJQquyzۋ?;'lWO&xkё+ Q"Ci auQFAGp֜-~8A_؎jED>xt)Ic^ 嘬'~.IogV/iuOT8XӇkhoKO'65ӗ372"|Ȍg:},Y~t?ǺV?hH?|۸3`.NL{ѧ xKDX=LOZL6Zuy|8\jܶ۝9ިkFָ+9Umf^dYFTk K@+M_=ܵ3Cz@"adκOj܍(O~+u… -c0 z+ g<:ǯbJݑJU|}\b1o9oyLW;^Ĉc^Ov|*vS B؋xTY4q}wyV5}V}KƋÛMl2xT_Ap?\wAu?5"W5,ϻ処QkE̿Td!9& xVӸmH+?zfX],7[0v͉w^̱C=¹G'۲\[+GIRoEn<c@{Jq/ O<ه?q_};u!zbߝZ=pngCWo׏%<ü*g=4QSO1ݮ .3օ6OT=fʖ'0#y۶.j >BXwdY*WGdߢ_~8ӧm9?8Qh"ڸ$ٔA'HO5FeSsk+cW~DZ>wYt,GoI>FnF>cz-OE'ycw^sf͚6H/'))k+L=1<frocW,gy;sȰ=Y=WtW/W/ڍ919G_bĞw%oi+,1XX,Ȋ-u" f/WbֻO Z҃~x~;7ܛ-nG6ؤc6>Y0diۥDZPr٣<}~rv }Y?s;uۥ׮^طqnqAXI#>jZ;a.xc>jXual];EI}qbI͍yk/VvnoG'kBy~߁e|e7k׳szªx(?6vϘJkur폨'ℏ&xGrǝf{׸Bx3 d>m @35>o}61i9!r; 1w)bca -gIQ 1=[޷~o.tNi5ԟ{ual׌ ~L@6SXd'aԱ?k}5CF oHqFO H+Ep19ªSp`m{/N{Fm{TZQM5vy{暾nkrwE[#W)x_s}te=wuFm.Ñ+ hcoܵw췣׾WqNljX"2Q]w~W-ǣtXKZFv#3qdzcVC4A#m}e-XB̷*Qn'w:p-8o~!q Od9vm7V~\AwYZmy ^{%?o#6zq O9u݉Q ק|c˜YКH>l}_݉5OԽQΰ=3>׽Fǎ%obtCmqs{Z$g۞~;웙8rdƌ:!V{1zf6sǶNȠǡmrvYM5P |G3򌢋F39vrJXA~Ge+۶X?ԇGp ü)g|WuU Wx\Y"ײNj&XoObќ}tբ{~Ԙ%V=b_?twcoPܿo?_{4q%+\"[*Z^_{}ɤ5 {E],`#>mc :N96Lq\G2[ݼ0ʀL99'6wzլqXX'.5YpU;s$ζv}/bʍFߘ:ayo~Y9"H,U7%Ї ]!(Z%ُÀnP}*]3spNek}QYFl?7oX %KVxg'跤}k\Qd]1 .b\Ok0~ ¸i?0ګ<|cj9*}rCq*Z{k/hk{.a?Kg f92a-Nmہ$K?]]]'9T;q]٣bz_ɿi>>Uwq|){RZyI2Tb}1K_:.E6!YGfaY4QhS|cD~{͟X(VYueO_G9ߨߡl9TaJ=gz?pvix^{`|^clJ׸]Kױbn1uQl}m[oa;&qtxkqݟre̍罕/k$z5^bƗ:}챟4~Ƽ p^O ?.0}6E1xYl.ي|eԌ.7"kz}g6~So5Ȭ19κys'^x`nkƧn:ΣsQgRT1fQJqޱzd?~vBX޼q8L)*#Zwb\'I1+Vڱ9>+7ʌͨXA3g֧?sx'gE\6x逾Y|ҩM aSL=V+2 &F6e<`eRoL1#kXhlW1.h-bԅD-:;Y IQAa9GJ7ӛ2ݕD,Rf )e^5F|ϻ-sa3={_P Ƚ4Et!sܗE%ϢGaLÖG|_1Xؑ/yty/~CX;cͷb]QwH`wo~ 'q8A-qvcks~i#6Krq]rko5:8cN/,ڊ(`3d,ԡlF>Xto[6}w3+th_My,(|˥$da|+/7yL>i-q#,wvO - [ż/k"C[߱<_OYgw׈o??/꧗+>TlyfIzv,(;}Focɿ"Jժ񁬛r#;V FK3+{%wYX)gHr<:;z5'G0:姸j 'Vq?%&meaG} Y*<*\B\-8tb+wlW0g9т[1bCl>;>N JgU1L|krEz^ڮUچ-30O%gk֫$Qb52x~˅#>>NOs0VƗ?u%ߺ2޶<\_ޟ{,_#mmx,y/$$'U 7 oHvcRt֟=u0oצr>B^y)BTT{_>g-zt̥W*γR:?z_uW1~TGߛy)9Yrsˠ vF>ymA}]# {kx_ug:wۊOιuvGXOF>lEu;w#sk#g Ƌ {^}im5p;k ALs`hK?Drȥm>̱wbys'^/$:6ޓb,y7FƴΫm4WX5moG!}mujt\F9ʼn@wO; ==37ktRuv,'X+u|tی̗(:w"^7vu^}Vi?e,]-a>s[y.K}([_po}]3gM{gM6W\Ƿ,W1 c[_ddnF c>zӇ~qb)&I_͜yɂ"λr >5j 9 YYv8I$gOX_JҰ/c#+g˦<Ul|y _?gX5+mF-y;,cm+8e~w c"e]lUJss> 7z|=nۙvhfk#7(q,9zMס<'e>o'gnYy@B}[xxo W)U?M7V>iVj>V/X*^bsQl͞zڟxfY|xzvTbg43q'`qWw;V\.},x:K 6ٖXs|lܚӸ1K&ǩA*q`nMm{sY CױGDXdxXm™8Y")m *~yRct)s}u'Xlgq,K~|oow Tox6gk[os1Rх<˺  Ұ9m"Z1bc9"jdbb{\F_F|+n},q'xHk="nM!ߊ): u-W|qݕ}z@h!X䲏Ԧ2ʅp,Hdsn^)9o{ݩ=Z$UȪZ߱O`㿎 MÖlfUc͎8^yIt!Rms4bV^٪tLox@+QͳZΧ,:n>bx6+/׋ rwWheٌT_̓qnΰjۓ+unn7 |Ο9!}y`Ѭl]G?ZOa_.0}\bnڣƄ>{|`hƐٱȉGݻZGÑ sNYuUMLwkAzyLeXs꜃Qo><}Hj~Lg Mp&hxRoѩ/{x26c͌YwO6>Q3:ǚv|@>${γ$(Q•#疷X*n~pGʳ@#<*Ύ6d#6nF4h?2OK~8'qL۩O$t89SK<ݾ^ʶےaQ%&VV#Bp"USrC[}dvV쀇?z;̤Sʌ6{/䉋э7m){}F"YN#swMe'}}i-3_¦Ž +C8H#dL,8GfF. ҉MË̊Q;WOo+M%9Bd$gdž]}z|6'# 7e5W?›< 苻"|umٿrL<GV5ID ?.8X0GNly "ok'y\4 Wd!үOeŶnYڋG1ª<}9n1"eGFUl`$7 `;7qɾ?=5êi/V&Lǡ-SEoٕ$|9{KnIť?cL\VNXXtznw g<35J!UB]ЕSq}ǫ2'eg|u}@5k)&Y1+os~"hy*iL1vqo{t<0`Ne56OG&V21ţ⇯"W˿?ƞYEԎ>b.,i.kBYjX77JbF?m(nVs,A2W@&gKP_{7~WӋ'c-ǺAk٬D ՙX(Ԭbc[,*Ix@-qi[r}ǿ )]KN4{W;1NgԝF~ `skM4q:[*lA+}-KnrH `Qc$h[LָP_є}"9>ˑXm=V/k+/7} Nl}su_'^ʫ9о-'cm+'5QNzq^d\qklUGqJ_%V?&fuDn#+蝇K/+Q=M<QaL&n#hm+;aI\ŝS`V~ۓ{tD^eB9첎1lɻU%<6sYoKfǏ J%gK,h|D 7"\$L.6v]oDSm@t[gf>l#8'"§Q{t,c?+V~9nloc(m$Yӧjjr{^-vOi?:Mσ$"kTzfjnʭ7sDZ/ik_c7o;!}h!.|1㪕u{ODclX5-bO=2+lUԕM$W_^]-n|,wMgz#Q5Ӿ]x#5>rO9 *c<\dc7%s7:s򿱧7O389VPdSR*.Q[q7JcX6v{|tc eLSgi%wӋ[0Nd>Bu+mƯ|TrȖ{M#.;޻[}v=/(H!XBD *J% cC aPȌUAe c!,c;L\XT'TRIefQ{;woϹgzz]k}ǚs,Wwi"~.WtU~'rgТmY̸LH㴺Y?%mL_j1-|Z9mnx%d2^pmPp察U|rL ]՟ד}𐐾L$J Y..8N>_u#sMlÖmќp `U\k?ˉn 厪2)Dsl#yKȊ2!%-8,_ {u,J dko^, ^|s-N>|e?5mJb`,ϋ%:z討;Ȉ 9@'4CJ-s*KxeZS =Nhw=yxn˾HnwOusn[1(sl83qakN RD8@8i0Af`A%R.C$O \tU޷/[򢗵ÉEQY.PRY$AG2D~ 8`I5-GZvIe|taE<}fzb~-un{@rOꏥq, Iiۘkj<^`+p<՗mB1ilWXk4[lQIkuik!1aڬHYLId붏 ҳ 㻭f/ _R8Veoފe-[ւE'{姄_sҪysF]T Je6[w}׷LG>Ϸ-f{Yv h?!stWJVKd H٦#N`"C]y՟>87~J<]Tr <χt4^~Z \LEz`8 urʱr063N[hHSټ66/'0Lֽr=h؁9G!Ħmpʇz>H}&@IDAT#[Jt~֗6]k^1 VY0Jz~e@bhto"B#wPcc'K\^6sU?Y'{æ閂\Ky"D/iu}dKk z},Ӗ[Z67v+ryLen! h|t<0ϸu(-}/4mߖ:m-a2mS'Ǘ8.mT!eOUG/ؕI'&Wj'(Eg}zܩ$b~~D %s d5֦\6~6Wr=0WغqM|lI:slQcZwXx/rn+lH.U׻+{*e+v^}6jW;ӟ'.wo B%NJ(:nԢ& e9_IB ]k'91VsA~Ъ!˷h/vHXn9!Ғ!qm̦߾M2mc[6 lqyI11DzQX-ڢDX±uwrv;O\Z=VkG/Ľ3F3lo&\6Sy*>3\]KZJ%XZN߿IMh>3N̑3C LߖR |:ϣ-ElMoOved{ܾrŤnyN,'Q8nRf@$]H }ۄM$ ds]W~wښ?e@7"i&dW._-B<}MFn*Xu^R>\϶)爟-V1ˇĴm*IqXv=iowgSOM/ZU[R{-|$('Y,R=ucgY{22˅lABPzm5~aC], N y&3<4| dbŒk{_}⻿c?g H|s?F;_4xP6! I'{4ױv%T~Y|0r`o-m̵a1RBuzz%?5G`Xb+U9e ,@(oh3f+v5yIq*\S¿]^sHzP~PklrA^K~·OO]XySm#^@LBm]xkoP-l!(nDtkOH9c6[0;QXne[kq{>Gs8-sیK)pTw-QYWmފ 4 i5'ۧ?w۩N?9tm|W[R.23-m*g%]R(_X k`!>@X_oGX;Pu+mڣv+w~ڟ"8*bge$"O.^t' Օr=> p8P[֧hM'tki3/s{~ImYh1k*۱)/\>Are_]_AWӕ6g BtASN9 m)i%6t&uk?6]_Y2Nߜv^voCÎl0'{zŏuvG,/>mhQB \4\C2~롙jL̄ݭzR'u^ƪnwU_bP{ݳCdC@.:rA [$M2!ifD.iYRsђ 4I>96/Þavtٱt%? eR[Ox}#7x;@1}oNq龃f*1tGedDI*BCFKϦ\k9k:%_1]?>J+ ;;7BVmtI|}әO#Owwx:鯘vNʋÌғmiגy%YJe^_z/17x^n+Gy_^*3}4߼ dSaoSG]=*.KMd*:KP3hToy=dDϴVs3fpޤ%7uɈvHIz_~Տ7[yNZk=|-grʃӂXߋ]e\GzcL{+y%'.OvBn0:]{g}thM?Khot7tʣodܭXC۹8UgTjשu?l,Tz֦x>KuNK1\"f_2#c^2fܿzydsYx{ IzPY[fe#gؔ{D^8=xJ7v+ߑ@jS}[;ܣpQH}ޯG+iM\ni>oS.y/ےq3]:g:e$q42VU|S6Z|{]ޖ|x.%Π5I@Xo7J!7Mq=M|%P {vzb}tөOFҳOGK>f_ۺ!y/ym7_s^W6~>?W)sǥ/kreT^:}t5v.{a, jfw83M8Cŵdcyۆ^С[$D/N|J9Rq<x0YU[t`gzs!2bTBp<^kZ/kK`v_y}I./?CkmnKIv*m>5w3 KƯLg'nP}tۏcjT&BIMH)'~q塒j,VJ'yHqxMxG]Bq0c;mYPߥCR\tKWl  C:z蠋r%eh6mY7 (G*}V# m"!O~wN,kIOQSQuN\8@3o/"xqs<)ǠxKgA.NίWw@WnL.˦t%W˃X6q}IV_{c?!|~wy:xNtڹ+_9yÑ.(z>BI(1SWrP[X|d$ii#Tn=㫬LJi\:h</+~njq+&yts-߮ȑ#ƘMlu_/)_ɘ1/MsH% "x͕򊳔dʓ8hɛPLLz g;'ɦqr#.~tyÊvԂ6' {{96Kz`Kxr I_R"\@| muppDzXi\I%GjxWmsms*ӗ0=~MŅfQ.gͶbIŴW&'T#ݔ+-/Q24'\앍+ѩ>GCl9WΝ]x00rjV`eY%l: d]?O|Vҕ?te.=mO Oȃ[yasWLw| nkۿ'U6=ьm>8#8JDnDZ=4[UOtB^~rXY)}c#?5W+t0Z_4BGKt-Zz#j+c xvķmɯ~^XwS^^{̖5Wz l@S>`z?T5CeE %J,D9Qoy5]_*/A}} 櫬¸R?Lޖ?]e8boQC޸o$[hRBnE#-G(W8GyS<iz23G&hP~x# 2\HnoFR- \cu)g>F+ih~YR%893%s}y<5f굓_O˂y{o1љ1Ux o?I%2<墁<:KFGQ9b^0}{c:L]Ow;w_ '\Gц K@,9Qa._L18*uDSBTGPo%=&RɅ|$yaSxZ3C~!S='rʲ`2&pɘ,zЕX%lwTG.=-cu~ʩx?r=,Z}I:Qtq"1K\ue3}k1Z#jBk-%eEJ=_4+G^OuDz kk aO$o>No<y2?vIL?{%kmd[0<׌O&>v(g~B>Wu;-_8NQo3##M$6l\}l_~؇+Bj8bV;X ,ʤ`DJH3De#%M: $T=cQ^Y?6T{="aC7nwt|BJzqQ8` 1|r,6]kQy,|Μ}߸!":h13#O}P^Kͽe}aMx1,ROn]-2X3- ɖ)hH2^hlK_U?ΓH?t QW3GE '7td҉{Y&s\oz5~(`@=8n}Bf,pFQ@'93i.rԝ+)*tzuկ10>'szbw8Ģr4r]e|fȃ.䙇Y_ug-#JiCv#đ.ƶ640-Vc;_Ϸë_+/ dtXIWw JL)3EXUux* u4J;Y=?'Ķ.}Jcx~ Q=M1CV/wÎwW|1R[ Yij!rfCw8m՘K,U2 rE/̇&sBZưG"$H 2lrThTnmd+֓~dIPA"/$,ny_sd̓>ro}<]- rN@y0''LL&ԑ. YLd_6K~Ib2*["Z2JeE?l?aDz(ҕfcƑ|_)88. Weo?tqo3GC4Y?WZ+%G#-ZZ7#99a"rq_7c}.!Jl}oVO5 -f+:⋦!<0};e:CY噏Jj:V𔋯'<޿ۿq_#q5󝀲ޥ7zi䉥 >SRPec9:M#Y+B)WѢV[z~|C[C>oOnD7u wnl9g@P,jK ,h@W/d=ݦkh4^`K\h2c6hKDeb26mz߷5qoX !-t\hRk'Y,YM<1 ySwmZ:%aځm {_vm51l_~ rт5myT_Mrz.v#@l ް+N1@UT"cJ(x\%$ 3 xԱ<=!`JLeQFQxJсF]\VgwM\*wV+"h\ϡzq7 ›Ng4I'}&hK2inOyKN ?2[cO\Ǫ}|a?G#)xvJC{x|]B*~$<}:}h^1D'eYcC%ɫnQl;p)E(*4妛T7(Nlcz%qVn2k$WrQ2N^/7MU냁od+O]^B`|S*t^ٲ5y!'ʲhc|{zN/W|,n#k*N[E^@FY]:v,zђ)nVqGTjS*@~E^}ے-gǻ}c}GRgJ$@ ]T;ˉf\[%g|D un٘6;;ϟ_\ )\eMz,HyR:!-AX(. . Bm{4aFi};YIJJ RLDS߀K Zn+5p_Hg B xwONϬ湁^r %rQVNY@ n&~.Jn6gh{Ra[>եH7M Mv$?vfw51crz4˓tSAzZmo4/4>2ű E,Fn^g~el/'_ Є/CF%%9ʒtuz٤<#;m|"gX1g#}M:e=vcc|;yeӬtJ3ZšmЬi;yG r|uUޔϷ?6~1 <`[eF񞀇_d32x_TɓFbRd/LST%DX7 :}w{M+ //qr;WQSig\^]hw":J9Fw(,6Fsq5~GAO]*[#vBߚI(4rqh-r`_'.Z/qCK*>Z&MtᏏB hh2i_vv4.{8Q:䢵Z0=? qco̫[!Z1f: |@\<=gU?=/]{olOnT<XBۖdU~}]skҫ]}4>%e(, %drqi*׿:f#3a.,3\ȇqG3noDP: (OE?x'^sw' &zo o+oI5OO}іg?狪/ ȕ~zڟ%G]3 `vќ{eA\{gά> 8ĈQ_z;ӫN{~b_YiÓ]8ۖZv~O;7$w0if1ĽX~E0;I;o1ubk{R{31hE ˰8~k| ZP_\m)e=NJsbuV4L+ lgQ.G^}aXz/>6z*/۰4G=jyAj1DYZ/ֿ,HLSӧN}7WrpmsTf!ےYp %H' ^y cPܧY}1b%GϷMDm#uY*KamK~1MG>~j|}!}ڋ'2r~dz?0_S?YWdDe_mXWRy&]0\Z9njJ3AqcZW7]$ )#e" |HN h aa5[jcMRŨejFsl!=v y< 2`Irco81E@OJyZ,x9=ϜďEIKn|çt:?RAOOO~r-?No+{XP!sڟ6~N L]z|mSă;[˯MO⥱=#l;.ؤcDN9k#kKXg)#[~o;qjgy0V}>V~"ʣ96բ"=L{/L0 XlYHLק3Bhm+K~@VfI6R:ڊl!=%d|\ƃjExXʱXo1q!rWi1,'Gx1/ydž,16yia"q<췕m7=E1P MYJl!%5:yV3[{|ڛy}O?mbKB.|d:1 6Dh`(WRs^?IR ]SV%mX2DMys}g~\X_1մ` $8P#G7Q("6hGƀ/У$S /nuzoWqKxm>Nmׅ: cvo٭Z, B"_P]X"̙UjZ_P4+&HV[˶l Ke!'dSO]y~Tۧ|'X7yc{k,[G5bWRt:RΣ[zhK6s,VG D/)[״I#궡zbS~կ5n}T,ԭ_{aSm䄮x(q[2'-q_OJݩW'ORw% g@0?+6]/^7d=(SK>袘J6Kinkϯ-1>ϯDkiמd̛6'ܤ_dyaKZ_5. iAĢq/njj~_!#JP1')PrLv/yХc@GUf;BZ-}uROƯoG+ґ]WDw }75$8Il#G.>etrw>#$/نoDhQI|BOJpgcG[qp{m<WWHE)o@xrK8,&"z;rX#Z ҂'þ7~\/Wme '2C_rbJ!z=7@˝Nz|+ĥ7`ei@DWpQpC]rG\GN-[1/|[,|l.r%;`˖(_54[56"ukǦu3vOm xqӝ.E4]ErxQo[H8]z#N^<β :gEBnP/#h; GWV)߁_;;=MՁWĘt(LSTw#Kkr/HY;М%Ms[N5c.9䦇lcYzw %ŕq˟:8uiI=c׬} {,# P,^EY'Z欗/|G ٤-dn.);bIz6B`DR4ag{('$@sE$;+|3n|/¡cR/o*Gq݃ ahhy /\gvYD酶G;$`@O:!#N 3o|V7nʘT$ Usi5+h,) -ےc,H5Ϛ7y@O4^F/s69J lX1ӥO^_T1ʞ[% #Po/ aiBBYhY.ſ뻾e7gr-8䱊)BsMʄm *oib,<g [{3VJ'*!v9?b舯2cҜ^-)Pl@GΒl-\m/.ZEC7EU"wk[BI]lʂy+) `qB.f,Ͳu))WO/wڇ~,ne *ԶrxYk˒@&um%g|UyNbN 3qYc/TzHcJ4EeG#Utu` M8D+(𿕮dUوe HR̵]r[E3yk'=%,9^sơOn|ܺ}۴{KY k8EE $/-G4/)!o!4rcNO߫ S+baKѦQ-zYxWSBWrY˯}nyK`ݪ͒WczPGt6zj1h)XC<{uiDmSBrI`F]^_2f, .EO5GoOT߈ @,zA"b. 9F0RwwŇ?0h]jb%@6ۧl|Ħqr\-ŢmF=caq ZN=}\d`cQ{T֕_yrzՃU_V^99m9_:$:=MkO +8,J.ǢdxGY|ZQ,|X؉Mi[Zc h/:$>C#Ǿr_;[TwTrԚ9o䏘䫝q?'gno|rC>Xc\8(rlz3O3.rK[ . D+1v_~?_3_,';׍:t|UWF$uIZx0r/˸z~QWyed,분wĢmlw]׮Mp}$鲦?w| hӴW>JsW LCz/1 NYȩ)-C/au|D^dYn݌bɅ96Q62쯾7_$]Et%}Ty39/ݢk{ޘx[1y9: Ѓ+<ASnDCXMls9 A̦n}- ,`/y+ >2/K6e:;LOf,x]Mů`ͷub nhcUI(oo7d'YŊ|BPК3Wɶh8k)&큑i}YJ}l[7>?CGd'Ջ?Ճ\H1]7\,t^XKKXsnTzuNK{Fd9-Oبe E66w}IY5pxJlQ_50zWvy҃Kox>E|7%g\ecچ1!HGCiNy' MK l=oP}.w[=%)x]1\NԥՆbڶ𶋕1Jj֬h[>b1+g%cgyE^Cė(YrβбxSg]93̛x[60oJvjӗ_^US>:Ѣ";6 QZ ,мH ll؇a/ȓcC_{SN !k;dשFkO}\Y}+oBY$k\;C ~bx9QXUf{N_~C[~BCMH:N\:K |Տ-Ek##j J,,\Э-yKe|X≆Y9<ʕ@QrlHvpbO^{gʮwW+W_[eeDJF>r֍~/n;|"+H:DZM7n|&;)}ɏ#8NrF@;zL8와< W:, Jgl ŵ::+随^~MrdW%%%IL3Vm過^g[9c"Dُ̃N.^.gYčԎM~ez. wh(Y֔+nƕ1(4"=<1D {QVK6/ZSY!UGݨ#Y' `JN\Zj5,Z(M'$1ۅniaXѳM~֠ Ge#K.TV8e$l)f 2td69N2BOPWc%nЭ_7s,E`,Ee# %L$`= `ab",/},¢Dʋ]i:%N˱/F9%r#ncU4薊cϷoұcۏMic]%Z}ڂn*?);Fax(C_ukȴ5a|GF֢.?Zom?GG}D`c8 wʂS@{Y,2&'гS=v_G62,9D.N` g*6Ry(i_Dr'RSG.4] qSNK[=n9.!^:gt IlM1:f{2s_"7(l`Sd}cqv=禇Ϝ:^XAIߴ `Z'S ǃܼ\2,lF!m%ب-cƐDb‰7te4H8?E0lKޭ_r Ѝ$mnYن"l-L,ID$g]xⓠneIl OBD,?'}+ݑC'$GiDqsxBe)H'TKii  >ueeE j[}4)<2!I 偳n 2!lA[ԕcu#Y{ ^ػo6av#&7*V-˻G{=˴8 ,t3]eeiУdN&qIٟ=mWDkqZ5dWЂ?m};Ol,)JXKN>i26Jlͪff9gOV'j}ɏܨ=%^DAw`g']K>)9m?/lImLHfY<'b&hՐ 9ˈoOCNI{ zۿ1HYqG1w`D& mj,,B*[,؁vYteÉ8%혴Dt/BI]N:/Z"ctG~+s$ϋ'[Tz#'gYsBN^!u璌 Zص~]|.#P9N럭 *[>PV;2:}5$H[^X ~z_sJ'#\u=9j!C :=waz,,Q O-8`@Elf\|̒Zo:G7a> i,oi:9>ofI)幦8ٖ墬R曲#˴ekA[is/K~t寫~>WKQgqFnmL3JmKJ\8wYr,*Yʛ|r%:|K⣏~1~ǹh /Үu.0'!Ҕ*4UFa:vLA\jYpLAYY?u]/XȐg,ctl3KfU?]9 GG3#ccX]+ .\lZ$ɢjf)6-/,,-R[?Qp- >T"SQ$i锗|X7m{ Ⱥmgh|__˷-;ၿ-x=}"PNo<4v YJUelh%eHI>E 4,Uz9_ɦtR!"+|lehe-bi}YuRF>e;^]PI8AwUW0i!y͛?NCxFnX 3= 8'R<<bX"\/MmLMes}:!CZuGX]k ?Y*Ckw6nKk>D?,TPs='kI.Gu H/T**ɝ7LYYp^]^lAm99fQQ+c5(7> E xWy&@o dͪ`DgAM]eZe|Szk[\7ciotyc`]nkM.hE)dLŽEjJ;ʳ/F ]V+y<5˺'r5A4|Ѱۮuו-0naoD`cS噀='66#dr. /ol(!^L|{z_ϲ,Z JbZ%={9uϒ}oWG+gym+,x}\\F~}7$wnnDx0' 3ZNs{< 0 QΩmc!AdZdz9$کza ׼`n@k$A@Gm9|Q/9DGyFk9}-&M=6WvieGmDx a{c-򞀝򞀋&@lyQfrl l2}>tʥ})fhQbA?zv8՛sBRgo&х/gS>m98 ,ڔ}܆l[%ڨ2ɖ{ߣ毷qOF~E`idd.wNrAG@'}EueAy1Ҝ)] FP]ϽQd,e yIRHDT7qRu.>QlFl~`rCkT~fK7;c>>#g[|DH#7uL)B{!ksd2[ַTw mi؊mC^;r*uudrrqr}f)Cln_1N%1OF~3F`<p3o =y_'/xQeYAu9]bQ_I>ew_@̡1C֓6C6lOo-qUFTJV#~2iͿ, ×^/Ѓg+koa^v/cÐ#Z@TWBqâe\o`cW7?ʕ 6[*:XOl>Y%zPq"F{]=>|)ڑYʭMC 궿_-k[Dp7s4ZG86X}EpZ 3,yS[J}4,X-ѫ/ڥ@h7^} jT^g;m^+}B`J88lGl;>Ͳ\ǭ"1;7û&B> x,ǒ-qTB:dDnK2'Gȗ79g]{K 1<ǔz[N_7ro⊗qa[q!\N=%Yr|Ͽa>WDh!K&'@D-1<%y>zrU$N(_%%GzC[3EYO\[.e):*T{/!azzش? .fo]|F9t /qnC%G~_yD{#7{37{ #0~8 r/^ܗeij7075dzGt,/=೹Ʀ}n#ytO⫬V!@Snl)8ȓ/s[5)Y_TD-I'Ii9;÷\u)PVWwWzl,/oOYN|o ސ( +UgȺ{zPdZMZ+rڔ12]$c-cJF}gh_%2bBiзiOqKe~xטq;X^ĉszY 3b/ d棺a2efj/{'2pzmĆdݨ/)d߈)G\Zȷ8֋JvU`De:EOJ90}|y|?id2ta=Av7iO 6~g"d=m7Z:jIMqn?5~_o{KdU8&9iX6h~ۿ8lY>{x1:Ϥ,U"[V@DчlZ!&!tmc+tFNVHojClR ǽur߰womkm#Xy1F1r1zg|_Ŀ}#LU;pj9['b̈́!AGٗgWtOs{=˭m_5J2q7p' dI(!ˣۉ%Sq"P{sQm un|]'.^%4)h Db۲$֊6?ӕ|\?3!x÷K˶1VD=zdѳc7,w3`MN\GW-YQOC_/kCE4VB8zQ'-rgOccdVLBv-RBC$o'ݭE(>ɳOA9[qQv80,m#>(_}J[HwU*pmz_m˾E;`L&"$E7.3%e-ff$ܟ3keO̾seE)˧Z;GǏNX{$U?Y;^髷a 0O*Nj@8϶Fv !_}9z;K{bN,&S]fJ9! ćXDF$@Xgb9oF\ʑc-Kܶ_mkf\R|Ƙum]__ڡA@ܤOƺC@?j%t?_Ji)H8H)6& )R_Ajn_f-tDq]u&j b)"ֱ?lG/`Ͱ5`Xۥ|kycגǍqFW$xw@$xzXD$r(]v vo=Dw~߳/yl{\1)}eDǔ'98>}HM'٢ʅ#P+_V ?-vKJ:F2xrNb# :Mxplm> ;ezh!):-Xn{ 1ŏc ;C>F}ݞ|uBܬϻFW =!Ϩtz$I U6X{R5=f?Ds>%%b+|[B3ٓ\uFރMd2}юl}[em?mH]V"P+7qoAAʽ' \V1E52)bc ibD>YW2xE&^lozUm5}  ~ѡ7ۋGv%Znq?]>\ۿXD~{68Uf#͹x e~Nv )l.[vg{B<ߒ\~](A*oY/km~+msKOYwK{Ͽ%?ƣsB; F3YB芬˳q/2DDYQQs,yqy6󸥹mmQG+)c[/|?mZaugԮZ!ps=7_ȂF]?' HKdf\$Ch5sYc&G.&[^b"mYg4W1\:ǰ$@~N+ϓsM`ܦ+ znSPImKhφ ?dy臧()6 ўK2f9eljP5-~`XB|hO(mwo@h$PMe>>Ic_o`]ܚMKx.܎Ͼx-u?XB J&KB8|LAqxOH]doҺ#Z-HN,崹_jU2a=>X'6$h\e iyl{nۂM_UV8@8M蓀(4Q7qd<#7- ¥Մi>-~sFۭH#`h Q1dr[c/aKՙc!pp:VPfRۻJHK!$I* Ć ĉoʳ.s;e59B ?Vf _꧷~W7R [VC!P{S|Sgmw|"8&4Y,;CLz#v8 mtiHG +?/?Z1p<[e^'mgfJ$-5U(&j`$mꌳL+ PeDgRDmXx&tkSyN-ߔW>>%C'Ǡ}-/Yϱ-%ѳE?r!P*Bpk(Q)?'gO;!ĶEArSIr%tjٷt'vXcs;2mϳ>Ѣx̌5co@XZ FV1?'tfIOesݵhr~CJ)ه"cgzmMնu^أkD\kZ>J@!W1+B`@@{v+ltOd܆ܤnE;1z֥,Lَ֋oX/ {z!w1|ٖ׆?YuձxjmP+B !0+g=Z2i#mtQdcY&ҠF YKE(Ɂl5ӞG k3G}0qL4[z!}¿u}ՏÇJB L *Hz޽; HP6&8(ǟrlC䪿91D>Ks%W}b3*IGRC}Q+^'Yz(sok_v@!0!Пdwo,\]*S pI] *hOtԪ4Q1 w_.mrNrTbbGV/_d͓Q[VW5g?U. 7CV .^VDZWڞoO$@zʤcjK.g VI 'rLۋG.ZO5&_ɿCa\y!P5ୡ+B0 huܿr' +$ -*eM"…An}eh]v&∔ۑ9}t3qhr}_oX)mm B!P__Y"p^{pqZnt;%QjӦ&5/,զ'M:mzȏO$ WU. w@3(Q!p c?oU{B?&Ψd C&Jjus앏mM?; 1c}+}lJ_0\+QR!P7ὅ(Dž@!PKi.@gҶxG|ܮ9TN(Rut4uԙTU @Gpu!H.vE+& Ԗ+gvXDƒBhEu>x(cpy(L㙴]]~xI!L.1qat}M'Z| ~p(f$%V9;_^# l9mypnösI5OzGA|+h!h[߯SƑzN79J"X"T]e*Yn?M\9*c\iGVk zuM';i#T 𡐮8+`@oԻڞ=')h]L2xڂ!q! &$Ʊ^RTOV:Y B!P_}E.nlgwo=1 I&_/hviSVZ}L^rkL@p~`Ty!1cb@B_L@hB&mBs!Ɵ54n֭Nn-_+kҚjPT\ j='P{os|4mݹIC&mYfkKxؖAhm;]K:G@Mk=[1saa  IDAT,8khIENDB`icnV Bffgit-cola-3.6/contrib/git-cola-completion.bash000066400000000000000000000050121356743264500212430ustar00rootroot00000000000000# This is a git-cola extension for Git's git-completion.bash script # # This script must be sourced *after* Git's git-completion.bash script. # See git.git's contrib/completion/git-completion.bash for details. # # Completion is provided for "git cola ..." and "git dag ..." via the # _git_cola() and _git_dag() functions. __git_cola_common_options="--prompt --repo --version" __git_cola_subcommands_list= __git_cola_common_opts () { __gitcomp "$__git_cola_common_options $1" } _git_cola () { __git_has_doubledash && return if test -z "$__git_cola_subcommands_list" then __git_cola_subcommands_list=$( git cola --help-commands | grep '^ [a-z]' | grep -v cola | cut -d' ' -f5) fi local subcommand=$(__git_find_on_cmdline "$__git_cola_subcommands_list") case "$prev" in --repo) return ;; esac if test -z "$subcommand" then __gitcomp " $__git_cola_subcommands_list $__git_cola_common_options --amend --help-commands --status-filter " return fi case "$subcommand" in am) return ;; dag) _git_dag "$@" return ;; archive|diff|merge) __git_complete_revlist __git_cola_common_opts ;; grep) # do nothing ;; pull) __git_cola_common_opts --rebase ;; rebase) case "$prev" in --exec) return ;; --whitespace) __gitcomp "nowarn warn fix error error-all" return ;; --strategy) __gitcomp "resolve recursive octopus ours subtree" return ;; --strategy-option) __gitcomp "ours theirs patience diff-algorithm=patience diff-algorithm=minimal diff-algorithm=histogram diff-algorithm=myers ignore-all-space ignore-space-at-eol ignore-space-change renormalize no-renormalize rename-threshold= subtree= " return ;; esac __git_complete_revlist __git_cola_common_opts " --abort --autostash --autosquash --committer-date-is-author-date --continue --ignore-date --ignore-whitespace --edit-todo --exec --force-rebase --fork-point --merge --no-autosquash --no-ff --no-stat --onto --preserve-merges --quiet --rerere-autoupdate --root --skip --stat --stop --strategy --strategy-option --verbose --verify --whitespace " ;; tag) case "$cword" in 3) # do nothing ;; *) __git_complete_revlist ;; esac ;; *) __git_cola_common_opts ;; esac } _git_dag () { __git_has_doubledash && return if test "$prev" = "--max-count" then return fi __git_cola_common_opts --max-count __git_complete_revlist } git-cola-3.6/contrib/install-python2.6.sh000077500000000000000000000001261356743264500203110ustar00rootroot00000000000000#!/bin/sh ./contrib/travis-build --sudo --verbose contrib/install-python2.6.yaml "$@" git-cola-3.6/contrib/install-python2.6.yaml000066400000000000000000000040101356743264500206320ustar00rootroot00000000000000language: python python: - "2.6" env: - CC="gcc-4.8 -fPIC" CXX="g++-4.8 -fPIC" PATH="$PWD/local/python2.6/bin":"$PATH" before_install: - sudo apt-get install -y libreadline-gplv2-dev - sudo apt-get install -y libsqlite3-dev zlib1g-dev libssl-dev - sudo apt-get install -y libgdbm-dev tk-dev libncursesw5-dev # setup setuptools, etc. for virtualenv # This is intended to be used on a Debian sid system where python2.6 # is a minimal install without setuptools or virtualenv. install: - mkdir -p local/sandbox - cd local/sandbox # python 2.6 - wget "https://www.python.org/ftp/python/2.6.9/Python-2.6.9.tgz" - tar xzf Python-2.6.9.tgz - cd Python-2.6.9 # Debian sid disabled SSLv3 - sed -i -e "s,SSL_CTX_new(SSLv3_method()),NULL," Modules/_ssl.c - ./configure --prefix="$(readlink -f ../../python2.6)" --enable-unicode=ucs4 - echo "_ssl _ssl.c -DUSE_SSL -DOPENSSL_NO_SSL2 -DOPENSSL_NO_EGD -I/usr/include/openssl -lssl -lcrypto" >Modules/Setup.local - echo "crypt cryptmodule.c -lcrypt" >>Modules/Setup.local - echo "_md5 md5module.c md5.c" >>Modules/Setup.local - echo "_sha shamodule.c" >>Modules/Setup.local - echo "_sha256 sha256module.c" >>Modules/Setup.local - echo "_sha512 sha512module.c" >>Modules/Setup.local - echo "readline readline.c -lreadline -ltermcap" >>Modules/Setup.local - echo "zlib zlibmodule.c -lz" >>Modules/Setup.local - make -j4 - make install - cd .. # setuptools - wget "https://pypi.python.org/packages/source/s/setuptools/setuptools-19.3.zip" - unzip -o setuptools-19.3.zip - cd setuptools-19.3 - python setup.py install - cd .. # pip, virtualenv - easy_install 'pip<10.0' - pip install virtualenv # for travis-build - cd ../.. - ./local/python2.6/bin/virtualenv --no-pip --no-setuptools --no-wheel env26 - cd local/sandbox/setuptools-19.3 - ../../../env26/bin/python setup.py install - cd ../../.. - ./env26/bin/easy_install 'pip<10.0' - ./env26/bin/pip install argparse - ./env26/bin/pip install pyyaml - ./env26/bin/pip install pytest git-cola-3.6/contrib/svg.tidy000066400000000000000000000011341356743264500162310ustar00rootroot00000000000000// Config file for [HTML Tidy](html-tidy.org) to properly format SVG markup // The main goal is to split elements attributes to separate lines, useful in comparing in diffs // Documentation: http://api.html-tidy.org/tidy/tidylib_api_next/tidy_config.html // Credit goes to [blalasaadri](https://stackoverflow.com/users/2382246/blalasaadri), who asks the question and find the solution themself. // https://stackoverflow.com/questions/25447006/adding-line-breaks-between-attributes input-xml: yes output-xml: yes add-xml-decl: yes indent: auto indent-attributes: yes indent-spaces: 4 hide-comments: yes git-cola-3.6/contrib/travis-build000077500000000000000000000432061356743264500171000ustar00rootroot00000000000000#!/usr/bin/env python # flake8: noqa from __future__ import absolute_import, division, unicode_literals from __future__ import print_function import argparse import json import os import re import shlex import signal import sys import unittest import yaml sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from cola import core from cola import git from cola import gitcmds from cola import gitcfg def parse_args(): parser = argparse.ArgumentParser() parser.add_argument('filename', metavar='', help='yaml travis config') parser.add_argument('--build-versions', '-V', action='append', help='build the specified versions') parser.add_argument('--dry-run', '-k', default=False, action='store_true', help='dry-run, do nothing') parser.add_argument('--sudo', default=False, action='store_true', help='allow commands to use sudo') parser.add_argument('--skip-missing', default=False, action='store_true', help='skip missing interpreters') parser.add_argument('--no-prompt', '-y', default=False, action='store_true', help='do not prompt before each command') parser.add_argument('--default', default='y', metavar='', help='default command for empty input (default: y)') parser.add_argument('--remote', default='origin', help='remote name whose URL will used for slugs') parser.add_argument('--before-install', '-b', default=False, action='store_true', help='run the before_install step') parser.add_argument('--before-script', '-B', default=False, action='store_true', help='run the before_script step') parser.add_argument('--slug', '-s', metavar='', help='specify the URL slug') parser.add_argument('--start', metavar='', type=int, default=0, help='specify the starting command index') parser.add_argument('--test', default=False, action='store_true', help='run built-in unit tests') parser.add_argument('--verbose', '-v', default=False, action='store_true', help='increase verbosity') return parser.parse_args() def load_yaml(filename): with core.xopen(filename, 'r') as f: return yaml.load(f) def find_interpreter(language, version): return core.find_executable(language + version) def get_platform(platform): if platform.lower().startswith('linux'): platform = 'linux' else: platform = 'osx' return platform def print_error(msg): core.print_stderr('error: %s' % msg) def error(msg): print_error(msg) sys.exit(1) def parse_slug(url): url = url.rstrip('/') if url.endswith('.git'): url = url[:-len('.git')] github_prefixes = ( 'https://github.com/', 'git://github.com/', 'git@github.com:', ) for prefix in github_prefixes: if url.startswith(prefix): return url[len(prefix):] patterns = ( # ssh+git://user:password@host/slug r'^ssh\+git://[^@]+:[^@]+@[^@/]+/([^:]+)$', # ssh+git://user@host/slug r'^ssh\+git://[^@]+@[^@]+?/([^:]+)$', # user@host:slug (no ports, etc r'^[^@]+@[^@]+:([^:]+)$', ) for pattern in patterns: rgx = re.compile(pattern) match = rgx.match(url) if match: return match.group(1) return '' def guess_slug(context, remote): key = 'remote.%s.url' % remote url = context.cfg.get(key) default_slug = 'git-cola/git-cola' if url: slug = parse_slug(url) or default_slug else: slug = default_slug return slug def get_slug(context, args): if args.slug: slug = args.slug else: slug = guess_slug(context, args.remote) return slug class ApplicationContext(object): def __init__(self, args): self.args = args self.git = None self.cfg = None def new_context(args): """Create top-level ApplicationContext objects""" context = ApplicationContext(args) context.git = git.create() context.cfg = gitcfg.create(context) return context def setup_environment(args, language, version): env = os.environ.copy() repo = git.Git() if not repo.is_valid(): error('%s is not a Git repository' % core.getcwd()) context = new_context(args) version_var = 'TRAVIS_%s_VERSION' % language.upper() env.setdefault(version_var, version) env.setdefault('CI', 'true') env.setdefault('TRAVIS', 'true') env.setdefault('CONTINUOUS_INTEGRATION', 'true') env.setdefault('DEBIAN_FRONTEND', 'noninteractive') env.setdefault('HAS_DAVID_A_SEAL_OF_APPROVAL', 'true') env.setdefault('USER', 'travis') env.setdefault('HOME', '/home/travis') env.setdefault('LANG', 'en_US.UTF-8') env.setdefault('LC_ALL', 'en_US.UTF-8') env.setdefault('RAILS_ENV', 'test') env.setdefault('RACK_ENV', 'test') env.setdefault('MERB_ENV', 'test') env.setdefault('TRAVIS_BRANCH', gitcmds.current_branch(context)) env.setdefault('TRAVIS_BUILD_DIR', core.getcwd()) env.setdefault('TRAVIS_BUILD_ID', '1') env.setdefault('TRAVIS_BUILD_NUMBER', '1') env.setdefault('TRAVIS_COMMIT', 'HEAD') env.setdefault('TRAVIS_COMMIT_RANGE', 'HEAD^..HEAD') env.setdefault('TRAVIS_JOB_ID', '1') env.setdefault('TRAVIS_JOB_NUMBER', '1.1') env.setdefault('TRAVIS_PULL_REQUEST', 'false') env.setdefault('TRAVIS_SECURE_ENV_VARS', 'false') env.setdefault('TRAVIS_REPO_SLUG', get_slug(context, args)) env.setdefault('TRAVIS_OS_NAME', get_platform(sys.platform)) env.setdefault('TRAVIS_TAG', '') return env def jsonify(obj): return json.dumps(obj, sort_keys=True, indent=2) def print_environment(environ): print('# Environment') print(jsonify(environ)) def expandvars(path, environ=None): """ Like os.path.expandvars, but operates on a provided dictionary `os.environ` is used when `environ` is None. >>> expandvars('$foo', environ={'foo': 'bar'}) == 'bar' True >>> environ = {'foo': 'a', 'bar': 'b'} >>> expandvars('$foo:$bar:${foo}${bar}', environ=environ) == 'a:b:ab' True """ if '$' not in path: return path if environ is None: environ = os.environ.copy() # pylint: disable=protected-access try: expandvars_re = expandvars._re_cache except AttributeError: expandvars_re = expandvars._re_cache = re.compile(r'\$(\w+|\{[^}]*\})') i = 0 while True: m = expandvars_re.search(path, i) if not m: break i, j = m.span(0) name = m.group(1) if name.startswith('{') and name.endswith('}'): name = name[1:-1] if name in environ: tail = path[j:] path = path[:i] + environ[name] i = len(path) path += tail else: i = j return path def default_shell(): shell_env = os.getenv('SHELL') if shell_env: shell = shell_env else: shell = '/bin/sh' for sh in ('bash', 'zsh', 'ksh', 'sh'): executable = core.find_executable(sh) if executable: shell = executable break return shell class RunCommands(object): def __init__(self, state, cmds=None): self.state = state self.cmds = cmds self.idx = state.start self.running = False self.errors = [] if cmds: self.idx = min(self.idx, len(cmds)-1) def loop(self, cmds=None): if cmds: self.cmds = cmds self.errors = [] self.running = True while self.running: self.show_prompt() self.eval_input(self.read_input()) def quit(self): self.running = False def show_initial_prompt(self, title=None): state = self.state prompt = '# %s %s' % (state.language.title(), state.version) if title: prompt += ' - ' + title prompt += ' #' dashes = '#' * len(prompt) print(dashes) print(prompt) print(dashes) self.print_help() def print_help(self): print(""" *** Commands *** # ... repeat # times, ex: "5s" skips 5 y, r ... yes/run current command (default) b, k, p ... back/prev f, j, n, s ... forward/next/no/skip g, goto # ... goto command at index rw, begin ... start over from the beginning ff, end ... fast-forward to end ls, list ... list commands shell ... enter a subshell (also "bash", "zsh") cd

... change directories env ... print config-provided environment variables environ ... print current environment variables pwd ... print current working directory h, help ... show help q, quit ... quit """) def prep_command(self, cmd): sudo = self.state.sudo if not sudo and cmd.startswith('sudo '): cmd = cmd[len('sudo '):] return cmd def current_command(self): cmd = self.cmds[self.idx] return self.prep_command(cmd) def expandvars(self, string): return expandvars(string, environ=self.state.environ) def show_prompt(self): state = self.state prompt = state.prompt cmd = self.current_command() expanded = self.expandvars(cmd) print('$ %s' % expanded) if prompt: sys.stdout.write('? ') def read_input(self): if self.state.prompt: answer = sys.stdin.readline().strip() else: answer = 'y' return answer def chdir(self, directory): os.chdir(directory) self.state.environ['PWD'] = os.getcwd() def goto(self, idx): top = len(self.cmds) - 1 self.idx = max(0, min(idx, top)) def goto_next(self): if self.is_last(): self.quit() return self.goto(self.idx + 1) def goto_prev(self): self.goto(self.idx - 1) def rewind(self): self.goto(0) def fast_forward(self): self.goto(len(self.cmds) - 1) def is_last(self): return self.idx == len(self.cmds) - 1 def list_commands(self): for idx, cmd in enumerate(self.cmds): cmd = self.prep_command(cmd) if idx == self.idx: decoration = '$' else: decoration = ' ' print('%03d - %s %s' % (idx, decoration, self.expandvars(cmd))) def show_status(self): cmd = self.current_command() print('%03d - $ %s' % (self.idx, self.expandvars(cmd))) def run_current_command(self): state = self.state dry_run = state.dry_run cmd = self.current_command() argv = shlex.split(cmd) if not argv: error('empty command at index %s' % self.idx - 1) if len(argv) == 2 and argv[0] == 'cd': directory = self.expandvars(argv[1]) self.chdir(directory) return if dry_run: return self.run_command(cmd) def run_command(self, cmd): environ = self.state.environ status, _, _ = core.run_command(cmd, env=environ, shell=True, stdin=None, stdout=None, stderr=None) expanded = self.expandvars(cmd) print('The command "%s" exited with %d.' % (expanded, status)) if status != 0: self.errors.append(expanded) def run_shell(self, shell): self.run_command(shell) def eval_input(self, answer): # Accept the action by default if not answer: answer = self.state.default words = shlex.split(answer) first = words[0] # Multi-command, e.g. "5s" skips 5 commands rgx = re.compile(r'^(\d+)(.*)$') if answer in ('f', 'j', 'n', 'N', 'next', 'no', 's', 'skip'): self.goto_next() elif answer in ('b', 'k', 'p', 'back', 'prev'): self.goto_prev() elif answer in ('r', 'y', 'Y', 'yes', 'run'): self.run_current_command() self.goto_next() elif answer in ('rw', 'rewind'): self.rewind() elif answer in ('ff', 'last', 'end'): self.fast_forward() elif answer in ('ls', 'list'): self.list_commands() elif answer in ('shell',): self.run_shell(default_shell()) elif answer in ('bash', 'sh', 'zsh', 'ash', 'dash', 'ksh', 'csh'): self.run_shell(answer) elif answer in ('st', 'status'): self.show_status() elif answer in ('pwd',): print(os.getcwd()) elif answer in ('env',): print_environment(self.state.env) elif answer in ('environ',): print_environment(self.state.environ) elif first in ('g', 'go', 'goto'): self.goto(int(words[1])) elif first in ('cd', 'chdir'): self.chdir(self.expandvars(words[1])) elif answer in ('h', 'help', '?'): self.print_help() elif answer in ('q', 'quit'): self.quit() elif rgx.match(answer): match = rgx.match(answer) count = match.group(1) action = match.group(2) for _ in range(int(count)): self.eval_input(action) else: print_error('%s: unknown command' % answer) self.print_help() class State(object): def __init__(self, **kwargs): for k, v in kwargs.items(): setattr(self, k, v) def expand_config_environment(envs, environ): # Operate on a copy so that we can add to it as we expand the variables. # This allows subsequent variables to reference previous variables. expanded = [] environ = environ.copy() for env in envs: env_values = {} # Entries look like "VAR1=x VAR2=x$VAR1" so we split using # the shell lexer to get the individual VAR=value entries env_entries = shlex.split(env) for entry in env_entries: key, value = entry.split('=', 1) expanded_value = expandvars(value, environ=environ) # Add to the returned environment env_values[key] = expanded_value # Also add to the outer environ to allow subsequent lookups # to use a previously defined value environ[key] = expanded_value expanded.append(env_values) # Ensure that we have at least a single environment if not expanded: expanded.append({}) return expanded def build_version(args, data, language, version): errors = [] environ = setup_environment(args, language, version) # Get the possibly config-specified execution environments envs = expand_config_environment(data.get('env', []), environ) for env in envs: environ = environ.copy() environ.update(env) state = State(default=args.default, dry_run=args.dry_run, env=env, environ=environ, language=language, prompt=not args.no_prompt, start=args.start, sudo=args.sudo, verbose=args.verbose, version=version) # pylint: disable=no-member if state.verbose: print_environment(environ) cmds = [] if args.before_install: cmds.extend(data.get('before_install', [])) cmds.extend(data.get('install', [])) if args.before_script: cmds.extend(data.get('before_script', [])) cmds.extend(data.get('script', [])) run_commands = RunCommands(state, cmds=cmds) run_commands.show_initial_prompt() run_commands.loop() errors.extend(run_commands.errors) return errors def build(args, data): language = data['language'] if args.build_versions: versions = args.build_versions else: versions = data[language] if args.skip_missing: versions = [v for v in versions if find_interpreter(language, v)] status = 0 for version in versions: errors = build_version(args, data, language, version) if errors: status = 1 return status class TravisBuildTestCase(unittest.TestCase): def test_parse_slug(self): urls = ( 'https://github.com/example/slug', 'https://github.com/example/slug.git', 'git://github.com/example/slug', 'git://github.com/example/slug.git', 'git@github.com:example/slug', 'git@github.com:example/slug.git', 'git@example.com:example/slug', 'git@example.com:example/slug.git', 'ssh+git://git@example.com/example/slug.git', 'ssh+git://user:password@example.com/example/slug.git', 'ssh+git://user:password@example.com:66/example/slug.git', ) expect = 'example/slug' for url in urls: actual = parse_slug(url) self.assertEqual(expect, actual) def test(): suite = unittest.TestLoader().loadTestsFromTestCase(TravisBuildTestCase) runner = unittest.TextTestRunner(verbosity=2) result = runner.run(suite) if result.errors or result.failures: status = 1 else: status = 0 return status def main(): signal.signal(signal.SIGINT, signal.SIG_DFL) args = parse_args() if args.test: return test() data = load_yaml(args.filename) return build(args, data) if __name__ == '__main__': sys.exit(main()) git-cola-3.6/contrib/win32/000077500000000000000000000000001356743264500155025ustar00rootroot00000000000000git-cola-3.6/contrib/win32/README.md000066400000000000000000000010351356743264500167600ustar00rootroot00000000000000Windows Tips ============ * git-cola is tested on Git for Windows. * Other git environments should work fine as long as `git` can be found in the $PATH. * The provided `cola` shell script can be used to launch *git-cola* if you do not want to keep `python.exe` in your $PATH. * If your python is installed in a location other than `/c/Python*/` then you can tell the `cola` script about it by setting the `cola.pythonlocation` git configuration variable. e.g.: $ git config --global cola.pythonlocation "/c/Python27/python.exe" git-cola-3.6/contrib/win32/cola000077500000000000000000000023251356743264500163500ustar00rootroot00000000000000#!/bin/sh # Windows doesn't have the 'dirname' command, so fake it dirname() { dir=$(echo "$@" | perl -pe 's,(.*)/[^/]+,\1,') test "$dir" = "$1" && dir=. echo "$dir" } mydir="$(dirname "$0")" parentdir="$(dirname "$mydir")" # Windows uses 'git-cola.pyw' instead of 'git-cola' COLA="$parentdir"/bin/git-cola if test -f "$COLA".pyw; then COLA="$COLA".pyw fi # The path to python can be specified by setting the # PYTHON environment variable. if test -z "$PYTHON" then PYTHON="$(which python.exe 2>/dev/null)" fi # The path to python can be specified in the # `cola.pythonlocation` git configuration variable. if test -z "$PYTHON" then PYTHON="$(git config cola.pythonlocation)" fi if test -n "$PYTHON" then exec "$PYTHON" "$COLA" "$@" fi # Find a suitable Python and use it to run cola. # If your python is installed in another location then # add that path to the top of the list below or # set the `cola.pythonlocation` git configuration variable. for python in \ "/c/Python39" \ "/c/Python38" \ "/c/Python37" \ "/c/Python36" \ "/c/Python35" \ "/c/Python34" \ "/c/Python27" \ "/c/Python26" \ "/c/Python25" do if test -d "$python" then PATH="$python":"$PATH" exec "$python/python.exe" "$COLA" "$@" fi done exit 1 git-cola-3.6/contrib/win32/dag000077500000000000000000000011211356743264500161560ustar00rootroot00000000000000#!/bin/sh # Windows doesn't have the 'dirname' command, so fake it dirname() { dir=$(echo "$@" | perl -pe 's,(.*)/[^/]+,\1,') test "$dir" = "$1" && dir=. echo "$dir" } mydir="$(dirname "$0")" parentdir="$(dirname "$mydir")" # Windows uses 'git-cola.pyw' instead of 'git-cola' COLA="$parentdir"/bin/git-dag if test -f "$COLA".pyw; then COLA="$COLA".pyw fi # Find a suitable Python and use it to run cola for python in "/c/Python27" "/c/Python26" "/c/Python25"; do if test -d "$python"; then PATH="$PATH":"$python" export PATH exec "$python/python.exe" "$COLA" "$@" fi done exit 1 git-cola-3.6/contrib/win32/git.bmp000066400000000000000000003171501356743264500167740ustar00rootroot00000000000000BMh6(2%.%.ٲfffffffffffffffooo⼼ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffşoooffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffϕfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffyyyyyyffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffoooffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffoooffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffyyyfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffooofffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffyyyfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffoooffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffooofffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffooofffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffoooٲfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffϩyyyfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffyyyfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffooo⩩ooofffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffooofffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffyyyooofffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffooofffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffyyyfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffoooffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffoooffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffyyyffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffoooffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffyyyfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffyyyfffffffffffffffffffffffffffffffffffffffffffffffffffffffffooofffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffyyyfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffoooffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffoooffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffyyyffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffyyyffffffffffffffffffffffffffffffffffffffffffffffffffffffoooffffffffffffffffffffffffffffffffffffffffffffffffffffffoooffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffooofffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffyyyfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffoooffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffyyyfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffoooffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffooofffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffoooffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffٌfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffyyyffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffόffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffoooyyyffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffyyyffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffyyyfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffooofffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffyyyffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffooofffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffoooffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff삂ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff₂fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffooofffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffooofffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffłfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff켼ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffŲfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8ai-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8ai-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8ai-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8ai-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8ai-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8ai-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8ai-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8ai-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8ai-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8ai-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8ai-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8ai-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8ai-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8ai-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8ai-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8ai-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8ai-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8ai-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8ai-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8ai-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8-8aiL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@xoߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟL@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@L@ߟgit-cola-3.6/contrib/win32/git.ico000066400000000000000000000537261356743264500167760ustar00rootroot0000000000000000f h00 %  B hnS(0` L@J>K?OCI<dYdYK?dZODE?b]K>IEIDKDKDK5K5M4M4M5-8,3).(+'''')))()**.+1,5(3HS-8-9-:-:)4IS)4JS.9.:/:1</:(5#0-))'6C,7*6*5*6*6*6)5(4(4"/+(%$"0=rpXmlVnmXbcf^_kY\pY[phh`ffafffeedffemmmhhhccceeedddxxxjjjgggtttiiinnnlllkkkzzzaaa```HHHzzzmmmfffeeeeeecccfffmmm\\\mmmhhhgggeeeeeedddeeeeeefffdddnnnhhheeefffccchhh^^^mmmyyynnnddddddfffdddccciiigggffffffffffffffffffeeefffffffffeeegggcccfffpppgggqqqzzzqqqhhheeeeeegggeeegggtttiiimmmhhhffffffffffffeeefffgggddddddddddddeeehhheeehhhppp}}}tttX\SZSYSYWbXfeZYSSSSSWSW]WXYe]XXSYSSSYSSSZSSSSYSSYSSSSSSYYSSSYYSSXSSYYZSSSSSSSYSSZXYSSXYSYSSYSdXSXSWYYSYYSYZZc]]SSYS]XSYSS_]WYX__YYYSaWSYSYSSSYbZSSYSYSYSVWSYSSYSSY`WYWa_SSYSSSY]SYSSSWZSY]SYYXSYYZYYWYSXWZZSZX_SSSSSY]XSYY]Y]^_SSSYZZZZYW[SWSWW\SSSSYSSYSSYSSYZZSSSSSSSYYSSYSYYVWXSSSSSSYSSYSSYSSSQRSMTUSSSSSSSSSSSSJKLMNOOOPPPPOOOP:;;<=>?@ABCDEFFFGGGGFFHI./010234566677776689,-&'(())))))('*+ !"#$%    ??~||> ?  ( @L@K?K?SFI=[O\PYKRDPCNALAM@NBPCMA^QK>KCLBJAM5M4M3N51=-8*/%! !))+1*5>I1=+3*/)+(')**+*,*,*-*1+1,5?I.;*6+7+81=0</<.;-:-9*5?H)7&1$1$2*7)6'4&3&3%1$07BvuFtrJsoKsoLspLrnLlkbhh]mmWmlXkjZji[jiZji\ggfccedddddeeeeffggggfffghhccchhhiiijjjlllbbbmmmaaa```_YYX[X[*)-1+2>?7?28.0*&R1O7L9M5M4M3N5N3P1'*#($;2 N3L;JDKCKCLBJAJAM:P)b1,`H\@V7T9Q;N=L@L@L@K>L@L@M<O9R7P2`A"_PYKSFRDPCNAL@L@L@K?LAL@M@NBPCMA^Q6'>/b]b___bba_]]bbbb__ba___b]__b]bbbd_bd_bbekl__bjb__b__bb_bab__b_b_b__a_bh_i__b___fgbfb]ee__bfe_b__]dbbeee_bb__b[\]^_`ab__bb_cSTUVWXXXXXYZXMNOPPPPQRPABCDEFGHIJIIIIKL56789:;<===>>?@'()*+,-./0123%4 !"!"#$%&   801???????( @L@K?L=L?K>K@J=SFN8LBJ@LAI;TAM5W W" !! "+&!," (hg_hhagg_omUomTnmTolUpnTnngggeddcppoggfhhfdddgggeeedeefffiiihhhAJ5M4M3M5N=18-/*% !!))1+5*I>=13+/*+)'(*)+*,*,*-*1*1+5,I?;.6*7+8+=1<0KCLBJAM5M4M3N51=-8*/%! !))+1*5>I1=+3*/)+(')**+*,*,*-*1+1,5?I.;*6+7+81=0</<.;-:-9*5?H)7&1$1$2*7)6'4&3&3%1$07BvuFtrJsoKsoLspLrnLlkbhh]mmWmlXkjZ22422224222546421401232*+,+-./%&%'()"#$ !   O(0` %)DesP.IEEE???^^^fffdddfffeeefffeeeeeeQQQ###U$!+++yXXXHHH```dddeeefffffffffffffffhhhfffhhh^^^///d)<<>>ghhheeefffcccHHHC ```dddfffdddcccNNNOSSS_ffffffeeefffl\^^^eeegggcccfff yzzzaaaFeeeeeegggeeegggggg,,,;PPPcfffffffffeee\\\dddddddddeee@@@MvvvfffhhhfffhhhhhhjjjFOOOgffffffeeeeee^^^fffeeeffffffeeeAAAv8 rrr,,,;fffeeeddddddeeefffGOOOhffffffeeefffeeeeeeffffffeeefff[[[UUUShhhhhhcccfffffffffIMMMhffffffdddddddddddddddeeeeeeeeeffffff444]jjaThh`ffafffbcf7VVUpffefffffffffffffffffffffffffffffffff999ImlTkjTnmX::0K\\TNbcf^_kY\pY\pY\pY[pY[pY[pY[pY\pY\pY\pBDS $001234445F))#UNNNNNNNNN&'$Y8% %m],7*6*6*5*6*6*6)5(4(4"/+(%%%$$$$%%"&1z&-8-8-8-8.9.:/:1IEIDKDKDKD.s)cN=L@L@K?J>K>*k#aL@L@L@J>L@(f!o1PihffffhL@L@L@J>K?%]reffffg_@C87./w'/w(/w(/w(/w(.t'/w(L@L@L@K?K?D;'b!,q%/w(/w(/w(/w(/v',|(,]*n#L@L@L@L@L@L@L@L@L@L@L@L@L@L@K?K?L@L@L@L@L@L@IF;C8C8D9D9D9C8D9L@L@L@K?K?E:0z)>4D9D9D9D9C9B6QHkL@L@L@J>J>$\bL@L@L@J>L@)h"bPCL@L@L@J>L@+l$dRDL@L@L@L@L@,p%_SFL@L@L@L@L@3+@K?J>G!$1%1%1%1%1%1%1%3$/;E 4B)7&1$1$2*7)6'4&3&3%1&3&3&3&3$07B 7D.;*6+7+81=0I[ 8F5B1=/5__YLYJXI[X[*)-1+2>?7?28.0*&R1O7L9M5M4M3N5N3P1'*#($;2 N3L;JDKCKCLBJAJAM:P)b1,`H\@V7T9Q;N=L@L@L@K>L@L@M<O9R7P2`A"_PYKSFRDPCNAL@L@L@K?LAL@M@NBPCMA^Q6'>/[LSFL@L@L@L@L@L@L@L@K?K?L@L@L@I=\P3&7([LSFL@L@L@L@L@L@L@L@K?K?L@L@L@I=[O0#7([LSFL@L@L@L@L@L@L@K?L@L@{K?L@L@I=[Oe2%7(_PYKSFRDPCNAL@L@L@K?L@L@L@PCREQDbU7);,bS_P[LWISFPCL@L@L@L@K?L@PCTFWJYKj[>.@0QDNBL@L@L@L@L@L@NBSFPCL@L@L@L@L@L@PC801???????(  @tttoooggggggfffeeeeeeggg*ffffff```iiipppffffffeeeeeeeeeeeefffffffffwwwyyyoooeeeeeeeeeeeeLhhhKiiifffhhheeeooowwwmmmfffeeecccddcggg___gggfffeeeooozz{oopdddgggdddfffFeeedeeeeeeeeooo||vssmnnggge`_^DddciggeppowggfhhfgdddoopeusZON/omUomTolTFomUnmTolUpnTomTwvbjkzOPVdepfgfgfbhg_dhhaRgg_bii`Ahg^ppn3@&1!," ( !5>.2" !!  "+& "'9T7ZXW YW WnVX<] I)>HN\O-N1M6M5M5M3N1QG718}]DU>N8L=LBJ@LBLAI;TA9L1\JTDL=L?L@K>K@K@J=SF9(K:[LSFL@L@L@K?L@L@L@SG7*J=[LSFL@L@L@L@L@L@J>SG8+J=Ogit-cola-3.6/contrib/win32/gpl-2.0.rtf000066400000000000000000000400701356743264500172770ustar00rootroot00000000000000{\rtf1\ansi\ansicpg1250\deff0\deflang1033\deflangfe1060{\fonttbl{\f0\fswiss\fprq2\fcharset238 Verdana;}{\f1\fmodern\fprq1\fcharset238 Lucida Console;}} {\*\generator Msftedit 5.41.15.1507;}\viewkind4\uc1\pard\nowidctlpar\sb100\sa100\qc\lang1060\kerning36\b\f0\fs28 GNU General Public License\par \kerning0\b0\fs16 Version 2, June 1991\par \pard\nowidctlpar\f1\fs14\par Copyright (C) 1989, 1991 Free Software Foundation, Inc.\par 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA\par \par Everyone is permitted to copy and distribute verbatim copies\par of this license document, but changing it is not allowed.\par \par \pard\keepn\nowidctlpar\sb100\sa100\qc\b\f0\fs20 Preamble\fs24\par \pard\nowidctlpar\fi142\sb100\sa100\b0\fs16 The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. \par When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. \par To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. \par For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. \par We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. \par Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. \par Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. \par The precise terms and conditions for copying, distribution and modification follow. \par \pard\keepn\nowidctlpar\sb100\sa100\qc\b\fs20 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\par \pard\nowidctlpar\fi142\sb100\sa100\fs16 0.\b0 This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". \par \pard\nowidctlpar\sb100\sa100 Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. \par \pard\nowidctlpar\fi142\sb100\sa100\b 1.\b0 You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. \par \pard\nowidctlpar\sb100\sa100 You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. \par \pard\nowidctlpar\fi142\sb100\sa100\b 2.\b0 You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: \par \pard\nowidctlpar\li284\sb100\sa100\b a)\b0 You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. \par \b b)\b0 You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. \par \b c)\b0 If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) \par \pard\nowidctlpar\sb100\sa100 These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. \par Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. \par In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. \par \pard\nowidctlpar\fi142\sb100\sa100\b 3.\b0 You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: \v \v0\par \pard\nowidctlpar\li284\sb100\sa100\b a)\b0 Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, \par \b b)\b0 Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, \par \b c)\b0 Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) \par \pard\nowidctlpar\sb100\sa100 The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. \par If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. \par \pard\nowidctlpar\fi142\sb100\sa100\b 4.\b0 You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. \par \b 5.\b0 You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. \par \b 6.\b0 Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. \par \b 7.\b0 If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. \par \pard\nowidctlpar\sb100\sa100 If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. \par It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. \par This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. \par \pard\nowidctlpar\fi142\sb100\sa100\b 8.\b0 If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. \par \b 9.\b0 The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. \par \pard\nowidctlpar\sb100\sa100 Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. \par \pard\nowidctlpar\fi142\sb100\sa100\b 10.\b0 If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. \par \pard\nowidctlpar\sb100\sa100\qc\fs20 NO WARRANTY\par \pard\nowidctlpar\fi142\sb100\sa100\b\fs16 11.\b0 BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. \par \b 12.\b0 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. \par \pard\keepn\nowidctlpar\sb100\sa100\qc\b END OF TERMS AND CONDITIONS\fs20\par } git-cola-3.6/contrib/win32/pynsist-preamble.py000066400000000000000000000004551356743264500213560ustar00rootroot00000000000000# TODO pynsist commands call it "installdir", entry points call it "scriptdir" import os try: installdir = scriptdir except NameError: pass pythondir = os.path.join(installdir, 'Python') path = os.environ.get('PATH', '') os.environ['PATH'] = os.pathsep.join([pythondir, pkgdir, path]) # noqa git-cola-3.6/contrib/win32/run-pynsist.sh000077500000000000000000000002471356743264500203570ustar00rootroot00000000000000#!/bin/sh rm -rf build/nsis && make all && make doc && make htmldir="$PWD/share/doc/git-cola/html" install-doc && pynsist pynsist.cfg && rm -r share/doc/git-cola/html git-cola-3.6/docs000077700000000000000000000000001356743264500172372share/doc/git-colaustar00rootroot00000000000000git-cola-3.6/extras/000077500000000000000000000000001356743264500144065ustar00rootroot00000000000000git-cola-3.6/extras/README.md000066400000000000000000000006361356743264500156720ustar00rootroot00000000000000extras ====== The extras directory contains third-party code that is used by Git Cola. Git Cola uses [sphinx-to-github](https://github.com/michaeljones/sphinx-to-github) for massaging the output of the [Sphinx](https://github.com/sphinx-doc/sphinx)-generated documentation. The license and author information for the [QtPy](https://github.com/spyder-ide/qtpy) library is included in the [qtpy/](qtpy) directory. git-cola-3.6/extras/__init__.py000066400000000000000000000012541356743264500165210ustar00rootroot00000000000000# pylint: disable=import-error,no-name-in-module from __future__ import absolute_import, division, unicode_literals from distutils.command.build import build from distutils.command.install import install from extras.build_helpers import build_helpers from extras.build_mo import build_mo from extras.build_pot import build_pot from extras.install_helpers import install_helpers cmdclass = { 'build_mo': build_mo, 'build_pot': build_pot, 'build_helpers': build_helpers, 'install_helpers': install_helpers, } build.sub_commands.insert(0, ('build_mo', None)) build.sub_commands.append(('build_helpers', None)) install.sub_commands.append(('install_helpers', None)) git-cola-3.6/extras/build_helpers.py000066400000000000000000000014041356743264500176000ustar00rootroot00000000000000"""build_helpers command for setup.py""" # pylint: disable=attribute-defined-outside-init # pylint: disable=import-error,no-name-in-module from __future__ import absolute_import, division, unicode_literals from distutils.command.build_scripts import build_scripts import os import sys class build_helpers(build_scripts): description = "fixup #! lines for private share/git-cola/bin scripts" # Private share/git-cola/bin scripts that are visible to cola only. helpers = [] def finalize_options(self): """Set variables to copy/edit files to build/helpers-x.y""" build_scripts.finalize_options(self) self.build_dir = os.path.join( 'build', 'helpers-%s.%s' % sys.version_info[:2]) self.scripts = self.helpers git-cola-3.6/extras/build_mo.py000066400000000000000000000076661356743264500165710ustar00rootroot00000000000000"""build_mo command for setup.py""" # pylint: disable=attribute-defined-outside-init # pylint: disable=no-name-in-module,import-error from __future__ import absolute_import, division, unicode_literals import os import re from distutils.core import Command from distutils.dep_util import newer from distutils.spawn import find_executable from distutils import log from . import build_util class build_mo(Command): """Subcommand of build command: build_mo""" description = 'compile po files to mo files' # List of options: # - long name, # - short name (None if no short name), # - help string. user_options = [ ('build-dir=', 'd', 'Directory to build locale files'), ('output-base=', 'o', 'mo-files base name'), ('source-dir=', None, 'Directory with sources po files'), ('force', 'f', 'Force creation of mo files'), ('lang=', None, 'Comma-separated list of languages to process'), ] user_options = build_util.stringify_options(user_options) boolean_options = build_util.stringify_list(['force']) def initialize_options(self): self.build_dir = None self.output_base = None self.source_dir = None self.force = None self.lang = None def finalize_options(self): self.set_undefined_options('build', ('force', 'force')) self.prj_name = self.distribution.get_name() if self.build_dir is None: self.build_dir = os.path.join('share', 'locale') if not self.output_base: self.output_base = self.prj_name or 'messages' if self.source_dir is None: self.source_dir = 'po' if self.lang is None: if self.prj_name: re_po = re.compile( r'^(?:%s-)?([a-zA-Z_]+)\.po$' % self.prj_name) else: re_po = re.compile(r'^([a-zA-Z_]+)\.po$') self.lang = [] for i in os.listdir(self.source_dir): mo = re_po.match(i) if mo: self.lang.append(mo.group(1)) else: self.lang = [i.strip() for i in self.lang.split(',') if i.strip()] def run(self): """Run msgfmt for each language""" if not self.lang: return if find_executable('msgfmt') is None: log.warn('GNU gettext msgfmt utility not found!') log.warn('Skip compiling po files.') return if 'en' in self.lang: if find_executable('msginit') is None: log.warn('GNU gettext msginit utility not found!') log.warn('Skip creating English PO file.') else: log.info('Creating English PO file...') pot = (self.prj_name or 'messages') + '.pot' if self.prj_name: en_po = '%s-en.po' % self.prj_name else: en_po = 'en.po' self.spawn([ 'msginit', '--no-translator', '--no-wrap', '--locale', 'en', '--input', os.path.join(self.source_dir, pot), '--output-file', os.path.join(self.source_dir, en_po), ]) basename = self.output_base if not basename.endswith('.mo'): basename += '.mo' po_prefix = '' if self.prj_name: po_prefix = self.prj_name + '-' for lang in self.lang: po = os.path.join(self.source_dir, lang + '.po') if not os.path.isfile(po): po = os.path.join(self.source_dir, po_prefix + lang + '.po') dir_ = os.path.join(self.build_dir, lang, 'LC_MESSAGES') self.mkpath(dir_) mo = os.path.join(dir_, basename) if self.force or newer(po, mo): log.info('Compile: %s -> %s' % (po, mo)) self.spawn(['msgfmt', '--output-file', mo, po]) git-cola-3.6/extras/build_pot.py000066400000000000000000000106221356743264500167420ustar00rootroot00000000000000"""build_pot command for setup.py""" # pylint: disable=attribute-defined-outside-init # pylint: disable=no-name-in-module,import-error from __future__ import absolute_import, division, unicode_literals import os import glob from distutils import log from distutils.core import Command from distutils.errors import DistutilsOptionError from . import build_util class build_pot(Command): """Distutils command build_pot""" description = 'extract strings from python sources for translation' # List of options: # - long name, # - short name (None if no short name), # - help string. user_options = [('build-dir=', 'd', 'Directory to put POT file'), ('output=', 'o', 'POT filename'), ('lang=', None, 'Comma-separated list of languages to update po-files'), ('no-lang', 'N', "Don't update po-files"), ('english', 'E', 'Regenerate English PO file')] user_options = build_util.stringify_options(user_options) boolean_options = build_util.stringify_list(['no-lang', 'english']) def initialize_options(self): self.build_dir = None self.output = None self.lang = None self.no_lang = False self.english = False def finalize_options(self): if self.build_dir is None: self.build_dir = 'po' if not self.output: self.output = (self.distribution.get_name() or 'messages') + '.pot' if self.lang is not None: self.lang = [i.strip() for i in self.lang.split(',') if i.strip()] if self.lang and self.no_lang: raise DistutilsOptionError( "You can't use options " "--lang=XXX and --no-lang in the same time.") def run(self): """Run xgettext for project sources""" # project name based on `name` argument in setup() call prj_name = self.distribution.get_name() # output file if self.build_dir != '.': fullname = os.path.join(self.build_dir, self.output) else: fullname = self.output log.info('Generate POT file: ' + fullname) if not os.path.isdir(self.build_dir): log.info('Make directory: ' + self.build_dir) os.makedirs(self.build_dir) cmd = [ 'xgettext', '--language=Python', '--keyword=N_', '--no-wrap', '--no-location', '--omit-header', '--sort-output', '--output-dir', self.build_dir, '--output', self.output, ] cmd.extend(glob.glob('bin/git-*')) cmd.extend(glob.glob('share/git-cola/bin/git-*')) cmd.extend(glob.glob('cola/*.py')) cmd.extend(glob.glob('cola/*/*.py')) self.spawn(cmd) _force_LF(fullname) # regenerate english PO if self.english: log.info('Regenerating English PO file...') if prj_name: en_po = prj_name + '-' + 'en.po' else: en_po = 'en.po' self.spawn([ 'msginit', '--no-translator', '--locale', 'en', '--input', os.path.join(self.build_dir, self.output), '--output-file', os.path.join(self.build_dir, en_po)]) # search and update all po-files if self.no_lang: return for po in glob.glob(os.path.join(self.build_dir, '*.po')): if self.lang is not None: po_lang = os.path.splitext(os.path.basename(po))[0] if prj_name and po_lang.startswith(prj_name+'-'): po_lang = po_lang[5:] if po_lang not in self.lang: continue new_po = po + '.new' self.spawn([ 'msgmerge', '--no-location', '--no-wrap', '--sort-output', '--output-file', new_po, po, fullname]) # force LF line-endings log.info('%s --> %s' % (new_po, po)) _force_LF(new_po, po) os.unlink(new_po) def _force_LF(src, dst=None): f = open(src, 'rU') try: content = f.read() finally: f.close() if dst is None: dst = src f = open(dst, 'wb') try: f.write(build_util.encode(content)) finally: f.close() git-cola-3.6/extras/build_util.py000066400000000000000000000005741356743264500171220ustar00rootroot00000000000000def encode(string): try: result = string.encode('utf-8') except (ValueError, UnicodeEncodeError): result = string return result def make_string(x): if x: x = str(x) return x def stringify_options(items): return [[make_string(x) for x in i] for i in items] def stringify_list(items): return [make_string(i) for i in items] git-cola-3.6/extras/generate-build-version.sh000077500000000000000000000004331356743264500213170ustar00rootroot00000000000000#!/bin/sh GIT=${GIT:-git} if "$GIT" version 2>&1 >/dev/null && test -e .git then BUILD_VERSION=$("$GIT" describe --first-parent) && echo '"""Generated build version"""' >cola/_build_version.py echo "BUILD_VERSION = '$BUILD_VERSION'" >>cola/_build_version.py fi exit 0 git-cola-3.6/extras/install_helpers.py000066400000000000000000000023711356743264500201530ustar00rootroot00000000000000"""install_helpers command for setup.py""" # pylint: disable=attribute-defined-outside-init # pylint: disable=import-error,no-name-in-module from __future__ import absolute_import, division, unicode_literals from distutils.command.install_scripts import install_scripts import os import sys class install_helpers(install_scripts): description = "install helper scripts" boolean_options = ['force', 'skip-build'] def initialize_options(self): install_scripts.initialize_options(self) self.skip_build_helpers = None self.install_scripts_dir = None def finalize_options(self): self.set_undefined_options( 'install', ('install_scripts', 'install_scripts_dir'), ('force', 'force'), ('skip_build', 'skip_build_helpers'), ) self.build_dir = os.path.join( 'build', 'helpers-%s.%s' % sys.version_info[:2]) self.install_prefix = os.path.dirname(self.install_scripts_dir) self.install_dir = os.path.join( self.install_prefix, 'share', 'git-cola', 'bin') self.skip_build = True def run(self): if not self.skip_build_helpers: self.run_command('build_helpers') install_scripts.run(self) git-cola-3.6/extras/qtpy/000077500000000000000000000000001356743264500154035ustar00rootroot00000000000000git-cola-3.6/extras/qtpy/AUTHORS.md000066400000000000000000000005711356743264500170550ustar00rootroot00000000000000Maintainer ========== Gonzalo Peña-Castellanos ([@goanpeca](http://github.com/goanpeca)) Main Authors ============ * Colin Duquesnoy ([@ColinDuquesnoy](http://github.com/ColinDuquesnoy)) * [The Spyder Development Team](https://github.com/spyder-ide/spyder/graphs/contributors) Contributors ============ * Thomas Robitaille ([@astrofrog](http://www.github.com/astrofrog))git-cola-3.6/extras/qtpy/CHANGELOG.md000066400000000000000000000451601356743264500172220ustar00rootroot00000000000000# History of changes ## Version 1.9.0 (2019-07-23) ### New features * Add the FORCE_QT_API environment variable to keep using the Qt bindings selected with the QT_API variable and avoid switching to the currently imported bindings. This allows to have applications that import PySide and PyQt bindings at the same time (which is possible if both bindings are compiled for the same Qt version). ### Issues Closed * [Issue 195](https://github.com/spyder-ide/qtpy/issues/195) - Errors in the Qt3D modules with PySide2 5.12.4+ and Python 2 ([PR 196](https://github.com/spyder-ide/qtpy/pull/196)) * [Issue 192](https://github.com/spyder-ide/qtpy/issues/192) - Binding Selection Logic ([PR 194](https://github.com/spyder-ide/qtpy/pull/194)) In this release 2 issues were closed. ### Pull Requests Merged * [PR 196](https://github.com/spyder-ide/qtpy/pull/196) - PR: Don't load Qt3D modules for buggy versions of PySide2 ([195](https://github.com/spyder-ide/qtpy/issues/195)) * [PR 194](https://github.com/spyder-ide/qtpy/pull/194) - PR: Add FORCE_QT_API environment variable ([192](https://github.com/spyder-ide/qtpy/issues/192)) In this release 2 pull requests were closed. ---- ## Version 1.8.0 (2019-06-12) ### New features * Add support for several Qt 3D modules. ### Issues Closed * [Issue 172](https://github.com/spyder-ide/qtpy/issues/172) - Support for Qt3D ([PR 191](https://github.com/spyder-ide/qtpy/pull/191)) In this release 1 issue was closed. ### Pull Requests Merged * [PR 191](https://github.com/spyder-ide/qtpy/pull/191) - PR: Add Qt 3D bindings ([172](https://github.com/spyder-ide/qtpy/issues/172)) In this release 1 pull request was closed. ---- ## Version 1.7.1 (2019-05-05) ### Pull Requests Merged * [PR 189](https://github.com/spyder-ide/qtpy/pull/189) - PR: Skip testing PyQt4 and PySide in Python 3.5 * [PR 188](https://github.com/spyder-ide/qtpy/pull/188) - PR: Trivial maintenance tweaks * [PR 187](https://github.com/spyder-ide/qtpy/pull/187) - PR: Avoid deprecated "from collections import MutableMapping" In this release 3 pull requests were closed. ---- ## Version 1.7.0 (2019-03-16) ### New features * Add support for QtCharts. ### Pull Requests Merged * [PR 186](https://github.com/spyder-ide/qtpy/pull/186) - PR: Generate PyPI long description from README.md * [PR 183](https://github.com/spyder-ide/qtpy/pull/183) - PR: Add QtCharts module support * [PR 182](https://github.com/spyder-ide/qtpy/pull/182) - PR: Prevent warnings for equivalent APIs * [PR 176](https://github.com/spyder-ide/qtpy/pull/176) - PR: Don't warn about bindings change if user did not specify a binding In this release 4 pull requests were closed. ---- ## Version 1.6 (2019-01-12) ### New features * Add support for QtQuickWidgets. ### Issues Closed * [Issue 178](https://github.com/spyder-ide/qtpy/issues/178) - Error when import QtCore.__version__ in PySide2 ([PR 180](https://github.com/spyder-ide/qtpy/pull/180)) In this release 1 issue was closed. ### Pull Requests Merged * [PR 181](https://github.com/spyder-ide/qtpy/pull/181) - PR: Restore QWebEngineSettings for PySide2 * [PR 180](https://github.com/spyder-ide/qtpy/pull/180) - PR: Add QtCore.__version__ for PySide2 ([178](https://github.com/spyder-ide/qtpy/issues/178)) * [PR 179](https://github.com/spyder-ide/qtpy/pull/179) - PR: Add QtQuickWidgets In this release 3 pull requests were closed. ---- ## Version 1.5.2 (2018-10-20) ### Pull Requests Merged * [PR 175](https://github.com/spyder-ide/qtpy/pull/175) - PR: Fix tests * [PR 174](https://github.com/spyder-ide/qtpy/pull/174) - PR: Add support for PySide2.QtOpenGL In this release 2 pull requests were closed. ---- ## Version 1.5.1 (2018-09-18) ### Issues Closed * [Issue 170](https://github.com/spyder-ide/qtpy/issues/170) - Can't catch PythonQtError ([PR 173](https://github.com/spyder-ide/qtpy/pull/173)) In this release 1 issue was closed. ### Pull Requests Merged * [PR 173](https://github.com/spyder-ide/qtpy/pull/173) - PR: Make PythonQtError inherit from RuntimeError to be easily catchable ([170](https://github.com/spyder-ide/qtpy/issues/170)) In this release 1 pull request was closed. ---- ## Version 1.5 (2018-08-25) ### New features * Add support for QtLocation, QtMultimediaWidgets, QtQml, QtQuick, QtWebChannel, QtWebSockets and QtXmlPatterns. * Raise an error when trying to use the wrong combination of macOS and Qt versions. ### Issues Closed * [Issue 155](https://github.com/spyder-ide/qtpy/issues/155) - Add warnings for Qt 5.9 in macOS 10.9 and Qt 5.11 and macOS 10.11 ([PR 168](https://github.com/spyder-ide/qtpy/pull/168)) * [Issue 153](https://github.com/spyder-ide/qtpy/issues/153) - Shim PyQt5 ToPyDateTime for compatibility with PySide2 ([PR 169](https://github.com/spyder-ide/qtpy/pull/169)) * [Issue 123](https://github.com/spyder-ide/qtpy/issues/123) - Wrap QWebChannel module ([PR 157](https://github.com/spyder-ide/qtpy/pull/157)) In this release 3 issues were closed. ### Pull Requests Merged * [PR 169](https://github.com/spyder-ide/qtpy/pull/169) - PR: Shim PyQt5 QDateTime.toPyDateTime to QDateTime.toPython for compatibility with PySide2 ([153](https://github.com/spyder-ide/qtpy/issues/153)) * [PR 168](https://github.com/spyder-ide/qtpy/pull/168) - PR: Raise error when trying to use the wrong combination of macOS and Qt versions ([155](https://github.com/spyder-ide/qtpy/issues/155)) * [PR 167](https://github.com/spyder-ide/qtpy/pull/167) - PR: Migrate to CircleCI 2.0 * [PR 163](https://github.com/spyder-ide/qtpy/pull/163) - PR: Add QtLocation * [PR 162](https://github.com/spyder-ide/qtpy/pull/162) - PR: Update readme to remove funding appeal, harmonize with other readmes and minor fixes * [PR 161](https://github.com/spyder-ide/qtpy/pull/161) - PR: Fix pyside2 wheels install * [PR 157](https://github.com/spyder-ide/qtpy/pull/157) - PR: Add more Qt modules ([123](https://github.com/spyder-ide/qtpy/issues/123)) In this release 7 pull requests were closed. ---- ## Version 1.4.2 (2018-05-06) ### Issues Closed * [Issue 150](https://github.com/spyder-ide/qtpy/issues/150) - PySide2-5.11 alpha2 compatibility ([PR 151](https://github.com/spyder-ide/qtpy/pull/151)) * [Issue 144](https://github.com/spyder-ide/qtpy/issues/144) - ValueError: API 'QString' has already been set to version 1 at line 141 in __init__.py file. ([PR 152](https://github.com/spyder-ide/qtpy/pull/152)) In this release 2 issues were closed. ### Pull Requests Merged * [PR 152](https://github.com/spyder-ide/qtpy/pull/152) - PR: Catch ValueError when trying to set sip API ([144](https://github.com/spyder-ide/qtpy/issues/144)) * [PR 151](https://github.com/spyder-ide/qtpy/pull/151) - PR: Add a preventive change for PySide-5.11a2 ([150](https://github.com/spyder-ide/qtpy/issues/150)) * [PR 149](https://github.com/spyder-ide/qtpy/pull/149) - PR: Use Qt official wheels to run tests for PySide2 * [PR 148](https://github.com/spyder-ide/qtpy/pull/148) - PR: Remove internal conda recipe In this release 4 pull requests were closed. ---- ## Version 1.4.1 (2018-04-28) ### New features * Show a warning when QT_API is changed automatically by qtpy. ### Issues Closed * [Issue 145](https://github.com/spyder-ide/qtpy/issues/145) - Raise a warning if QT_API value is changed automatically ([PR 146](https://github.com/spyder-ide/qtpy/pull/146)) * [Issue 142](https://github.com/spyder-ide/qtpy/issues/142) - On OSX qtpy applications are forcing discrete graphics ([PR 143](https://github.com/spyder-ide/qtpy/pull/143)) In this release 2 issues were closed. ### Pull Requests Merged * [PR 147](https://github.com/spyder-ide/qtpy/pull/147) - PR: Add better compatibility with PySide2 * [PR 146](https://github.com/spyder-ide/qtpy/pull/146) - PR: Add a warning if API is changed automatically ([145](https://github.com/spyder-ide/qtpy/issues/145)) * [PR 143](https://github.com/spyder-ide/qtpy/pull/143) - PR: Avoid using PyQt5.Qt, which imports unneeded stuff and forces discrete GPU on OSX ([142](https://github.com/spyder-ide/qtpy/issues/142)) In this release 3 pull requests were closed. ---- ## Version 1.4 (2018-03-11) ### New features * Add support for QtHelp and QtSql * Use already imported bindings ### Issues Closed * [Issue 138](https://github.com/spyder-ide/qtpy/issues/138) - If one binding has already been imported, then qtpy should just use it ([PR 139](https://github.com/spyder-ide/qtpy/pull/139)) * [Issue 135](https://github.com/spyder-ide/qtpy/issues/135) - Add Wrapper for QtSql [feature request] ([PR 136](https://github.com/spyder-ide/qtpy/pull/136)) * [Issue 131](https://github.com/spyder-ide/qtpy/issues/131) - Methods missing from QStandardPaths when QT_API=pyqt4 * [Issue 127](https://github.com/spyder-ide/qtpy/issues/127) - Add Wrapper for QtHelp [feature request] ([PR 128](https://github.com/spyder-ide/qtpy/pull/128)) In this release 4 issues were closed. ### Pull Requests Merged * [PR 140](https://github.com/spyder-ide/qtpy/pull/140) - PR: Pin PyQt5 to 5.9.2 in CircleCI because 5.10 is generating segfaults * [PR 139](https://github.com/spyder-ide/qtpy/pull/139) - PR: If a Qt binding is already imported, then use it. ([138](https://github.com/spyder-ide/qtpy/issues/138)) * [PR 136](https://github.com/spyder-ide/qtpy/pull/136) - PR: Add QtSql wrapper (incl. test) ([135](https://github.com/spyder-ide/qtpy/issues/135)) * [PR 132](https://github.com/spyder-ide/qtpy/pull/132) - PR: Changes to QDesktop split * [PR 128](https://github.com/spyder-ide/qtpy/pull/128) - PR: Add QtHelp Wrapper ([127](https://github.com/spyder-ide/qtpy/issues/127)) In this release 5 pull requests were closed. ---- ## Version 1.3.1 (2017-08-21) ### Bugs fixed **Issues** * [Issue 129](https://github.com/spyder-ide/qtpy/issues/129) - Spurious cache files in PyPI tarball * [Issue 119](https://github.com/spyder-ide/qtpy/issues/119) - Importing qtpy should not raise exceptions In this release 2 issues were closed **Pull requests** * [PR 130](https://github.com/spyder-ide/qtpy/pull/130) - PR: No cache files included in the release tarball * [PR 126](https://github.com/spyder-ide/qtpy/pull/126) - PR: Remove Quantified Code badge because the service doesn't exist anymore * [PR 121](https://github.com/spyder-ide/qtpy/pull/121) - PR: Warn if QHeaderView deprecated methods are used In this release 3 pull requests were merged ---- ## Version 1.3 (2017-08-12) ### New features * Add support for PySide2 and PyQt 4.6 ### Bugs fixed **Issues** * [Issue 124](https://github.com/spyder-ide/qtpy/issues/124) - Typo in readme title * [Issue 111](https://github.com/spyder-ide/qtpy/issues/111) - Update Readme for 1.3 release * [Issue 110](https://github.com/spyder-ide/qtpy/issues/110) - Add tests for untested modules * [Issue 101](https://github.com/spyder-ide/qtpy/issues/101) - Missing: QtOpenGL Module * [Issue 89](https://github.com/spyder-ide/qtpy/issues/89) - QDesktopServices split into QDesktopServices and QStandardPaths * [Issue 57](https://github.com/spyder-ide/qtpy/issues/57) - qInstallMessageHandler <-> qInstallMsgHandler * [Issue 15](https://github.com/spyder-ide/qtpy/issues/15) - Feature Request: PySide2 support In this release 7 issues were closed **Pull requests** * [PR 125](https://github.com/spyder-ide/qtpy/pull/125) - PR: Fix typo in Readme. * [PR 117](https://github.com/spyder-ide/qtpy/pull/117) - PR: Add compatibility for the rename of qInstallMsgHandler to qInstallMessageHandler * [PR 115](https://github.com/spyder-ide/qtpy/pull/115) - PR: Update Readme to reflect that we actually use the PySide2 layout * [PR 114](https://github.com/spyder-ide/qtpy/pull/114) - PR: Update Readme to mention that we now support PySide2. * [PR 113](https://github.com/spyder-ide/qtpy/pull/113) - PR: Add tests for Qtdesigner, QtNetwork, QtPrintSupport, QtSvg and QtTest. * [PR 112](https://github.com/spyder-ide/qtpy/pull/112) - PR: Follow QStandardPaths location in Qt5 for PyQt4/PySide * [PR 109](https://github.com/spyder-ide/qtpy/pull/109) - PR: Add a coveragerc file * [PR 106](https://github.com/spyder-ide/qtpy/pull/106) - PR: Add support for PyQt 4.6 * [PR 102](https://github.com/spyder-ide/qtpy/pull/102) - PR: Add a new QtOpenGL module * [PR 84](https://github.com/spyder-ide/qtpy/pull/84) - PR: Add PySide2 support In this release 10 pull requests were merged ---- ## Version 1.2.1 (2017/01/21) ### Bugs fixed **Pull requests** * [PR 98](https://github.com/spyder-ide/qtpy/pull/98) - PR: Don't use Travis to test macOS because it slows down the entire spyder-ide organization * [PR 97](https://github.com/spyder-ide/qtpy/pull/97) - PR: Update Appveyor badge in Readme because of moving to an org account * [PR 94](https://github.com/spyder-ide/qtpy/pull/94) - PR: Include test suite in sdist In this release 3 pull requests were merged ---- ## Version 1.2 (2017/01/08) ### New features * Add support for QtMultimedia * Use relative imports so its vendored more easily ### Bugs fixed **Issues** * [Issue 83](https://github.com/spyder-ide/qtpy/issues/83) - Include core doc files in PyPi releases * [Issue 78](https://github.com/spyder-ide/qtpy/issues/78) - Request for a new bugfix release * [Issue 75](https://github.com/spyder-ide/qtpy/issues/75) - Missing copyright headers * [Issue 67](https://github.com/spyder-ide/qtpy/issues/67) - uic.loadUiType is missing * [Issue 64](https://github.com/spyder-ide/qtpy/issues/64) - QHeaderView.setSectionResizeMode * [Issue 49](https://github.com/spyder-ide/qtpy/issues/49) - QtMultimedia support In this release 6 issues were closed **Pull requests** * [PR 93](https://github.com/spyder-ide/qtpy/pull/93) - Restore uic full namespace for PyQt5 and PyQt4 * [PR 92](https://github.com/spyder-ide/qtpy/pull/92) - Add missing copyright header in _patch/qheaderview.py * [PR 91](https://github.com/spyder-ide/qtpy/pull/91) - Use star imports in QtSvg again instead of direct ones (reverts PR #55) * [PR 88](https://github.com/spyder-ide/qtpy/pull/88) - PR: Add manifest * [PR 74](https://github.com/spyder-ide/qtpy/pull/74) - Move QStringListModel to QtCore * [PR 71](https://github.com/spyder-ide/qtpy/pull/71) - PR: Use relative imports so its vendored more easily * [PR 65](https://github.com/spyder-ide/qtpy/pull/65) - Introduce renamed methods of QHeaderView in PyQt4 and PySide * [PR 59](https://github.com/spyder-ide/qtpy/pull/59) - Don't install qtpy as a conda package in CircleCI * [PR 58](https://github.com/spyder-ide/qtpy/pull/58) - Remove reference to how qtpy is pronounced in README * [PR 55](https://github.com/spyder-ide/qtpy/pull/55) - PR: Add explicit imports to QtSvg module * [PR 50](https://github.com/spyder-ide/qtpy/pull/50) - Add support for QtMultimedia In this release 11 pull requests were merged ---- ## Version 1.1.2 (2016-08-08) ### Bugfixes **Pull requests** * [PR 54](https://github.com/spyder-ide/qtpy/pull/54) - PR: Fix/ci * [PR 53](https://github.com/spyder-ide/qtpy/pull/53) - PR: Move tests to module so they can be run when installed * [PR 52](https://github.com/spyder-ide/qtpy/pull/52) - PR: Update readme * [PR 51](https://github.com/spyder-ide/qtpy/pull/51) - PR: Add circle ci * [PR 47](https://github.com/spyder-ide/qtpy/pull/47) - Remove PyQt variant symbols from QtCore * [PR 46](https://github.com/spyder-ide/qtpy/pull/46) - del QtWidgets.QStyleOptionViewItemV4 * [PR 45](https://github.com/spyder-ide/qtpy/pull/45) - Allow QT_API values that are not completely in lower case In this release 7 pull requests were merged ---- ## Version 1.1.1 (2016-07-01) ### Bugfixes **Pull requests** * [PR 44](https://github.com/spyder-ide/qtpy/pull/44) - Make qtpy to set the QT_API environment variable In this release 1 pull requests were merged --- ## Version 1.1 (2016-06-30) ### New features * Make importing `qtpy` thread-safe * Add a uic module to make loadUI work for PySide * Add QtTest support for PySide ### Bugfixes **Issues** * [Issue 42](https://github.com/spyder-ide/qtpy/issues/42) - Wrong old PyQt4 version check * [Issue 21](https://github.com/spyder-ide/qtpy/issues/21) - Patch QComboBox with PySide? * [Issue 16](https://github.com/spyder-ide/qtpy/issues/16) - Add loadUI functionality In this release 3 issues were closed **Pull requests** * [PR 43](https://github.com/spyder-ide/qtpy/pull/43) - Don't check PyQt version with qtpy's version for old PyQt versions * [PR 41](https://github.com/spyder-ide/qtpy/pull/41) - `qtpy.__version__` should be QtPy version, not Qt version * [PR 40](https://github.com/spyder-ide/qtpy/pull/40) - Mention qt-helpers in README.md, and add myself to AUTHORS.md * [PR 39](https://github.com/spyder-ide/qtpy/pull/39) - Fix remaining segmentation fault that occurs with the patched QComboBox in PySide * [PR 38](https://github.com/spyder-ide/qtpy/pull/38) - QtTest for PySide * [PR 37](https://github.com/spyder-ide/qtpy/pull/37) - Automatically load custom widget classes when using PySide * [PR 33](https://github.com/spyder-ide/qtpy/pull/33) - Ignore case for QT_API env variable in qtpy submodules * [PR 32](https://github.com/spyder-ide/qtpy/pull/32) - Remove QItemSelectionModel from QtWidgets for PyQt4 and PySide * [PR 31](https://github.com/spyder-ide/qtpy/pull/31) - Add compatibility for QItemSelectionModel * [PR 29](https://github.com/spyder-ide/qtpy/pull/29) - Use ci-helpers (from Astropy) for CI and enable AppVeyor * [PR 28](https://github.com/spyder-ide/qtpy/pull/28) - Make tests.py into proper unit test, and add Qt version info to pytest header * [PR 27](https://github.com/spyder-ide/qtpy/pull/27) - Make sure loadUi is available * [PR 25](https://github.com/spyder-ide/qtpy/pull/25) - Add patched version of QComboBox In this release 13 pull requests were merged --- ## Version 1.0.2 (2016-06-02) ### New features * Add a WEBENGINE constant to QtWebEngineWidgets, which is True if Qt 5 comes with the WebEngine module and False otherwise. ### Bugfixes **Pull requests** * [PR 24](https://github.com/spyder-ide/qtpy/pull/24) - Add constant to QtWebEngineWidgets to see if we are using WebEngine or WebKit * [PR 23](https://github.com/spyder-ide/qtpy/pull/23) - Fix "Prefer `format()` over string interpolation operator" issue In this release 2 pull requests were merged --- ## Version 1.0.1 (2016-04-10) ### Bugfixes **Issues** * [Issue 18](https://github.com/spyder-ide/qtpy/issues/18) - QIntValidator left in QtWidgets, should be in QtGui In this release 1 issues were closed **Pull requests** * [PR 19](https://github.com/spyder-ide/qtpy/pull/19) - Import QIntValidator in QtGui and remove it from QtWidgets In this release 1 pull requests were merged ---- ## Version 1.0 (2016-03-22) * Add QtWebEngineWidgets module for Qt 5.6. This module replaces the previous QtWebKit one. * Import the right objects in QtGui, QtWidgets and QtCore * Add a QtPrintSupport module --- ## Version 0.1.3 (2015-12-30) * Add tests and continuous integration ## Version 0.1.2 (2015-03-01) * First release git-cola-3.6/extras/qtpy/LICENSE.txt000066400000000000000000000021301356743264500172220ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) The Spyder Development Team Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. git-cola-3.6/extras/sphinxtogithub/000077500000000000000000000000001356743264500174655ustar00rootroot00000000000000git-cola-3.6/extras/sphinxtogithub/__init__.py000066400000000000000000000013601356743264500215760ustar00rootroot00000000000000"""Script for preparing the html output of the Sphinx documentation system for github pages. """ # flake8: noqa from __future__ import absolute_import, division, unicode_literals VERSION = (1, 1, 0, 'dev') __version__ = ".".join(map(str, VERSION[:-1])) __release__ = ".".join(map(str, VERSION)) __author__ = "Michael Jones" __contact__ = "http://github.com/michaeljones" __homepage__ = "http://github.com/michaeljones/sphinx-to-github" __docformat__ = "restructuredtext" from .sphinxtogithub import ( setup, sphinx_extension, LayoutFactory, Layout, DirectoryHandler, VerboseRename, ForceRename, Remover, FileHandler, Replacer, DirHelper, FileSystemHelper, OperationsFactory, HandlerFactory ) git-cola-3.6/extras/sphinxtogithub/sphinxtogithub.py000066400000000000000000000241421356743264500231210ustar00rootroot00000000000000#! /usr/bin/env python from __future__ import absolute_import from optparse import OptionParser import os import sys import shutil import codecs def stdout(msg): sys.stdout.write(msg + '\n') class DirHelper(object): def __init__(self, is_dir, list_dir, walk, rmtree): self.is_dir = is_dir self.list_dir = list_dir self.walk = walk self.rmtree = rmtree class FileSystemHelper(object): def __init__(self, open_, path_join, move, exists): self.open_ = open_ self.path_join = path_join self.move = move self.exists = exists class Replacer(object): "Encapsulates a simple text replace" def __init__(self, from_, to): self.from_ = from_ self.to = to def process(self, text): return text.replace(self.from_, self.to) class FileHandler(object): "Applies a series of replacements the contents of a file inplace" def __init__(self, name, replacers, opener): self.name = name self.replacers = replacers self.opener = opener def process(self): text = self.opener(self.name, "r").read() for replacer in self.replacers: text = replacer.process(text) self.opener(self.name, "w").write(text) class Remover(object): def __init__(self, exists, remove): self.exists = exists self.remove = remove def __call__(self, name): if self.exists(name): self.remove(name) class ForceRename(object): def __init__(self, renamer, remove): self.renamer = renamer self.remove = remove def __call__(self, from_, to): self.remove(to) self.renamer(from_, to) class VerboseRename(object): def __init__(self, renamer, stream): self.renamer = renamer self.stream = stream def __call__(self, from_, to): self.stream.write( "Renaming directory '%s' -> '%s'\n" % (os.path.basename(from_), os.path.basename(to)) ) self.renamer(from_, to) class DirectoryHandler(object): "Encapsulates renaming a directory by removing its first character" def __init__(self, name, root, renamer): self.name = name self.new_name = name[1:] self.root = root + os.sep self.renamer = renamer def path(self): return os.path.join(self.root, self.name) def relative_path(self, directory, filename): path = directory.replace(self.root, "", 1) return os.path.join(path, filename) def new_relative_path(self, directory, filename): path = self.relative_path(directory, filename) return path.replace(self.name, self.new_name, 1) def process(self): from_ = os.path.join(self.root, self.name) to = os.path.join(self.root, self.new_name) self.renamer(from_, to) class HandlerFactory(object): def create_file_handler(self, name, replacers, opener): return FileHandler(name, replacers, opener) def create_dir_handler(self, name, root, renamer): return DirectoryHandler(name, root, renamer) class OperationsFactory(object): def create_force_rename(self, renamer, remover): return ForceRename(renamer, remover) def create_verbose_rename(self, renamer, stream): return VerboseRename(renamer, stream) def create_replacer(self, from_, to): return Replacer(from_, to) def create_remover(self, exists, remove): return Remover(exists, remove) class Layout(object): """ Applies a set of operations which result in the layout of a directory changing """ def __init__(self, directory_handlers, file_handlers): self.directory_handlers = directory_handlers self.file_handlers = file_handlers def process(self): for handler in self.file_handlers: handler.process() for handler in self.directory_handlers: handler.process() class NullLayout(object): """ Layout class that does nothing when asked to process """ def process(self): pass class LayoutFactory(object): "Creates a layout object" def __init__(self, operations_factory, handler_factory, file_helper, dir_helper, verbose, stream, force): self.operations_factory = operations_factory self.handler_factory = handler_factory self.file_helper = file_helper self.dir_helper = dir_helper self.verbose = verbose self.output_stream = stream self.force = force def create_layout(self, path): contents = self.dir_helper.list_dir(path) renamer = self.file_helper.move if self.force: remove = self.operations_factory.create_remover( self.file_helper.exists, self.dir_helper.rmtree) renamer = self.operations_factory.create_force_rename( renamer, remove) if self.verbose: renamer = self.operations_factory.create_verbose_rename( renamer, self.output_stream) # Build list of directories to process directories = [d for d in contents if self.is_underscore_dir(path, d)] underscore_directories = [ self.handler_factory.create_dir_handler(d, path, renamer) for d in directories ] if not underscore_directories: if self.verbose: self.output_stream.write( "No top level directories starting with an underscore " "were found in '%s'\n" % path ) return NullLayout() # Build list of files that are in those directories replacers = [] for handler in underscore_directories: for directory, _, files in self.dir_helper.walk(handler.path()): for f in files: replacers.append( self.operations_factory.create_replacer( handler.relative_path(directory, f), handler.new_relative_path(directory, f) ) ) # Build list of handlers to process all files filelist = [] for root, _, files in self.dir_helper.walk(path): for f in files: if f.endswith(".html"): filelist.append( self.handler_factory.create_file_handler( self.file_helper.path_join(root, f), replacers, self.file_helper.open_) ) if f.endswith(".js"): filelist.append( self.handler_factory.create_file_handler( self.file_helper.path_join(root, f), [self.operations_factory .create_replacer("'_sources/'", "'sources/'")], self.file_helper.open_ ) ) return Layout(underscore_directories, filelist) def is_underscore_dir(self, path, directory): return ( self.dir_helper.is_dir(self.file_helper.path_join(path, directory)) and directory.startswith("_")) def sphinx_extension(app, exception): "Wrapped up as a Sphinx Extension" if app.builder.name not in ("html", "dirhtml"): return if not app.config.sphinx_to_github: if app.config.sphinx_to_github_verbose: stdout("Sphinx-to-github: Disabled, doing nothing.") return if exception: if app.config.sphinx_to_github_verbose: msg = ("Sphinx-to-github: " "Exception raised in main build, doing nothing.") stdout(msg) return dir_helper = DirHelper( os.path.isdir, os.listdir, os.walk, shutil.rmtree ) file_helper = FileSystemHelper( lambda f, mode: codecs.open(f, mode, app.config.sphinx_to_github_encoding), os.path.join, shutil.move, os.path.exists ) operations_factory = OperationsFactory() handler_factory = HandlerFactory() layout_factory = LayoutFactory( operations_factory, handler_factory, file_helper, dir_helper, app.config.sphinx_to_github_verbose, sys.stdout, force=True ) layout = layout_factory.create_layout(app.outdir) layout.process() def setup(app): "Setup function for Sphinx Extension" app.add_config_value("sphinx_to_github", True, '') app.add_config_value("sphinx_to_github_verbose", True, '') app.add_config_value("sphinx_to_github_encoding", 'utf-8', '') app.connect("build-finished", sphinx_extension) def main(args): usage = "usage: %prog [options] " parser = OptionParser(usage=usage) parser.add_option( "-v", "--verbose", action="store_true", dest="verbose", default=False, help="Provides verbose output") parser.add_option( "-e", "--encoding", action="store", dest="encoding", default="utf-8", help="Encoding for reading and writing files") opts, args = parser.parse_args(args) try: path = args[0] except IndexError: sys.stderr.write( "Error - Expecting path to html directory:" "sphinx-to-github \n" ) return dir_helper = DirHelper( os.path.isdir, os.listdir, os.walk, shutil.rmtree ) file_helper = FileSystemHelper( lambda f, mode: codecs.open(f, mode, opts.encoding), os.path.join, shutil.move, os.path.exists ) operations_factory = OperationsFactory() handler_factory = HandlerFactory() layout_factory = LayoutFactory( operations_factory, handler_factory, file_helper, dir_helper, opts.verbose, sys.stdout, force=False ) layout = layout_factory.create_layout(path) layout.process() if __name__ == "__main__": main(sys.argv[1:]) git-cola-3.6/po/000077500000000000000000000000001356743264500135165ustar00rootroot00000000000000git-cola-3.6/po/.gitignore000066400000000000000000000000111356743264500154760ustar00rootroot00000000000000*.msg *~ git-cola-3.6/po/README000066400000000000000000000001451356743264500143760ustar00rootroot00000000000000These are from the git-gui sources. Please see git-gui's po/README file for more details. TODO: todo git-cola-3.6/po/cs.po000066400000000000000000001543141356743264500144730ustar00rootroot00000000000000# Translation of git-cola to Czech. # Copyright (C) 2017 Pavel Rehak # This file is distributed under the same license as the git-cola package. # Pavel Rehak , 2017. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-16 17:32+0200\n" "PO-Revision-Date: 2018-07-01 07:25+0200\n" "Last-Translator: Pavel Rehak \n" "Language-Team: \n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.0.4\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" msgid "" "\n" "

\n" " Drag and drop or use the Add button to add\n" " patches to the list\n" "

\n" " " msgstr "" "\n" "

\n" " Záplaty přidáte na seznam buď přetažením nebo kliknutím na\n" " Přidat\n" "

\n" " " #, python-format msgid "" "\n" "
\n" " Git Cola has been translated into different languages thanks\n" " to the help of the individuals listed below.\n" "\n" "
\n" "

\n" " Translation is approximate. If you find a mistake,\n" " please let us know by opening an issue on Github:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " We invite you to participate in translation by adding or updating\n" " a translation and opening a pull request.\n" "

\n" "\n" "
\n" "\n" " " msgstr "" "\n" "
\n" " Git Cola je překládána do různých jazyků díky\n" " pomoci níže uvedených jednotlivců.\n" "\n" "
\n" "

\n" " Může se stát, že něco v překladu nebude správně. Pokud najdete chybu,\n" " oznamte nám to prosím založením hlášení o chybě na portálu Github:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " Zveme vás, abyste se na překladu podíleli tím, že ho doplníte nebo aktualizujete\n" " překlad, a otevřete pull request.\n" "

\n" "\n" "
\n" "\n" " " #, python-format msgid "" "\n" "
\n" " Git Cola version %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " msgstr "" "\n" "
\n" " Git Cola verze %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " #, python-format msgid "" "\n" "
\n" " Please use %(bug_link)s to report issues.\n" "
\n" " " msgstr "" "\n" "
\n" " K hlášení problémů použijte %(bug_link)s.\n" "
\n" " " #, python-format msgid "" "\n" " Format String Variables\n" " -----------------------\n" " %(path)s = relative file path\n" " %(abspath)s = absolute file path\n" " %(dirname)s = relative directory path\n" " %(absdirname)s = absolute directory path\n" " %(filename)s = file basename\n" " %(basename)s = file basename without extension\n" " %(ext)s = file extension\n" msgstr "" "\n" " Proměnné formátovacího řetězce\n" " -----------------------\n" " %(path)s = relativní popis umístění souboru\n" " %(abspath)s = absolutní popis umístění souboru\n" " %(dirname)s = relativní popis umístění složky\n" " %(absdirname)s = absolutní popis umístění složky\n" " %(filename)s = název souboru\n" " %(basename)s = název souboru bez přípony\n" " %(ext)s = přípona souboru\n" msgid "" "\n" "Commands\n" "--------\n" "pick = use commit\n" "reword = use commit, but edit the commit message\n" "edit = use commit, but stop for amending\n" "squash = use commit, but meld into previous commit\n" "fixup = like \"squash\", but discard this commit's log message\n" "exec = run command (the rest of the line) using shell\n" "\n" "These lines can be re-ordered; they are executed from top to bottom.\n" "\n" "If you disable a line here THAT COMMIT WILL BE LOST.\n" "\n" "However, if you disable everything, the rebase will be aborted.\n" "\n" "Keyboard Shortcuts\n" "------------------\n" "? = show help\n" "j = move down\n" "k = move up\n" "J = shift row down\n" "K = shift row up\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "spacebar = toggle enabled\n" "\n" "ctrl+enter = accept changes and rebase\n" "ctrl+q = cancel and abort the rebase\n" "ctrl+d = launch difftool\n" msgstr "" msgid "" "\n" "Keyboard Shortcuts\n" "------------------\n" "J, Down = Move Down\n" "K, Up = Move Up\n" "Enter = Edit Selected Files\n" "Spacebar = Open File Using Default Application\n" "Ctrl + L = Focus Text Entry Field\n" "? = Show Help\n" "\n" "The up and down arrows change focus between the text entry field\n" "and the results.\n" msgstr "" msgid " - DAG" msgstr " – DAG" msgid " commits ago" msgstr " zápisů před" #, python-format msgid "\"%(branch)s\" has been deleted from \"%(remote)s\"." msgstr "„%(branch)s“ byla smazána z „%(remote)s“." #, python-format msgid "\"%(command)s\" returned exit status \"%(status)d\"" msgstr "„%(command)s“ vrátil návratový kód „%(status)d“" #, python-format msgid "\"%(command)s\" returned exit status %(status)d" msgstr "„%(command)s“ vrátil návratový kód %(status)d" #, python-format msgid "\"%s\" already exists" msgstr "„%s“ už existuje" #, python-format msgid "\"%s\" already exists, cola will create a new directory" msgstr "„%s“ už existuje, cola vytvoří novou složku" #, python-format msgid "\"%s\" requires a selected file." msgstr "„%s“ vyžaduje označený soubor." msgid "#" msgstr "č." #, python-format msgid "%(project)s: %(branch)s - Browse" msgstr "%(project)s: %(branch)s – procházet" #, python-format msgid "%(project)s: %(ref)s - DAG" msgstr "%(project)s: %(ref)s – DAG" #, python-format msgid "%d days ago" msgstr "Před %d dny" #, python-format msgid "%d hours ago" msgstr "Před %d hodinami" #, python-format msgid "%d minutes ago" msgstr "Před %d minutami" #, python-format msgid "%d patch(es) applied." msgstr "%d záplaty aplikovány." #, python-format msgid "%d skipped" msgstr "%d přeskočeno" #, python-format msgid "" "%s appears to contain merge conflicts.\n" "\n" "You should probably skip this file.\n" "Stage it anyways?" msgstr "" "Zdá se, že %s obsahuje konflikty začlenění.\n" "\n" "Tento soubor byste nejspíš měli přeskočit.\n" "Odložit ho i tak?" #, python-format msgid "%s is not a Git repository." msgstr "%s není Git repozitář." #, python-format msgid "%s will be removed from your bookmarks." msgstr "%s bude odstraněn ze záložek." #, python-format msgid "%s will be removed from your recent repositories." msgstr "%s bude odstraněn z nedávných repozitářů." #, python-format msgid "%s: No such file or directory." msgstr "%s: Žádný takový soubor nebo složka." msgid "&Edit" msgstr "&Upravit" msgid "&File" msgstr "&Soubor" msgid "(Amending)" msgstr "(Pozměnit)" msgid "*** Branch Point ***" msgstr "" msgid "*** Sandbox ***" msgstr "*** pískoviště ***" msgid "100%" msgstr "100%" msgid "200%" msgstr "200%" msgid "25%" msgstr "25%" msgid "400%" msgstr "400%" msgid "50%" msgstr "50%" msgid "800%" msgstr "800%" msgid " ..." msgstr "…" msgid "" "A commit template has not been configured.\n" "Use \"git config\" to define \"commit.template\"\n" "so that it points to a commit template." msgstr "" #, python-format msgid "A hook must be provided at \"%s\"" msgstr "" #, python-format msgid "A stash named \"%s\" already exists" msgstr "Odklad s názvem \"%s\" již existuje" msgid "Abort" msgstr "Zrušit" msgid "Abort Action" msgstr "Zrušit akci" msgid "Abort Merge" msgstr "Zrušit sloučení" msgid "Abort Merge..." msgstr "Zrušit sloučení (merge)…" msgid "Abort the action?" msgstr "Zrušit akci?" msgid "" "Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" "Recovering uncommitted changes is not possible." msgstr "" "Zrušení současného sloučení způsobí, že *VŠECHNY* nezapsané změny budou ztraceny.\n" "Obnovení nezapsaných změn není možné." msgid "Aborting the current merge?" msgstr "Zrušit stávající sloučení?" msgid "About" msgstr "O aplikaci" msgid "About git-cola" msgstr "O aplikaci git-cola" msgid "Accept" msgstr "Přijmout" msgid "" "Accept changes and rebase\n" "Shortcut: Ctrl+Enter" msgstr "" "Přijmout změny a přeskládat\n" "Klávesová zkratka: Ctrl+Enter" msgid "Action Name" msgstr "Název akce" msgid "Actions" msgstr "Akce" msgid "Actions..." msgstr "Akce…" msgid "Add" msgstr "Přidat" msgid "Add Favorite" msgstr "Přidat oblíbený" msgid "Add Remote" msgstr "Přidat vzdálený" msgid "Add Separator" msgstr "Přidat oddělovač" msgid "Add Toolbar" msgstr "Přidat nástrojovou lištu" msgid "" "Add and remove remote repositories using the \n" "Add(+) and Delete(-) buttons on the left-hand side.\n" "\n" "Remotes can be renamed by selecting one from the list\n" "and pressing \"enter\", or by double-clicking." msgstr "" "Přidat a odstranit vzdálené repozitáře pomocí tlačítek \n" "Přidat(+) a Odstranit(-) na levé straně.\n" "\n" "Vzdálené mohou být přejmenovány tak, že se jeden vybere\n" "ze seznamu a stiskne se \"enter\", nebo dvojklikem." msgid "Add new remote git repository" msgstr "Přidat nový vzdálený git repozitář" msgid "Add patches (+)" msgstr "Přidat záplaty (+)" msgid "Add remote" msgstr "Přidat vzdálený" msgid "Add to .gitignore" msgstr "Přidat do .gitignore" msgid "Add to Git Annex" msgstr "Přidat do Git Annex" msgid "Add to Git LFS" msgstr "Přidat do Git LFS" msgid "Additions" msgstr "Přidáno" msgid "Advanced" msgstr "Pokročilé" msgid "Age" msgstr "Stáří" msgid "All Repositories" msgstr "Všechny repozitáře" #, python-format msgid "" "All submodules will be updated using\n" "\"%s\"" msgstr "" msgid "Allow non-fast-forward updates. Using \"force\" can cause the remote repository to lose commits; use it with care" msgstr "Povolit aktualizace Ne rychle vpřed. Použití „vynutit“ může způsobit, že vzdálený repositář ztratí zápisy; používejte obezřetně" msgid "Always create a merge commit when enabled, even when the merge is a fast-forward update" msgstr "Vždy vytvořit zápis sloučení, je-li povoleno, a to i v případě, že sloučení je aktualizace Rychle vpřed" msgid "Amend" msgstr "Pozměnit" msgid "Amend Commit" msgstr "Pozměnit zápis" msgid "Amend Last Commit" msgstr "Pozměnit poslední zápis" msgid "Amend the published commit?" msgstr "Pozměnit uveřejněný zápis?" msgid "Amending" msgstr "Pozměnit" msgid "" "An action is still running.\n" "Terminating it could result in data loss." msgstr "" "Akce stále probíhá.\n" "Její ukončení by mohlo vést ke ztrátě dat." msgid "" "An unsigned, lightweight tag will be created instead.\n" "Create an unsigned tag?" msgstr "" "Místo toho bude vytvořena nepodepsaná prostá značka.\n" "Vytvořit nepodepsanou značku?" msgid "Appearance" msgstr "" msgid "Apply" msgstr "Aplikovat" msgid "Apply Patches" msgstr "Aplikovat záplaty" msgid "Apply Patches..." msgstr "Aplikovat záplaty…" msgid "Apply and drop the selected stash (git stash pop)" msgstr "Aplikovat a zahodit vybraný odklad (git stash pop)" msgid "Apply the selected stash" msgstr "Aplikovat vybraný odklad" msgid "Arguments" msgstr "Argumenty" msgid "Attach" msgstr "Připnout" msgid "Author" msgstr "Autor" msgid "Authors" msgstr "Autoři" msgid "Auto" msgstr "" msgid "Auto-Wrap Lines" msgstr "Automaticky zalamovat řádky" msgid "Basic Regexp" msgstr "Základní regul. výraz" msgid "Blame Viewer" msgstr "" msgid "Blame selected paths" msgstr "" msgid "Blame..." msgstr "Blame…" msgid "Bold on dark headers instead of italic" msgstr "Hlavičky tučným písmem na tmavém pozadí místo kurzívy" msgid "Branch" msgstr "Větev" #, python-format msgid "" "Branch \"%(branch)s\" does not exist in \"%(remote)s\".\n" "A new remote branch will be published." msgstr "" "Větev \"%(branch)s\" neexistuje v \"%(remote)s\".\n" "Bude uveřejněna nová vzdálená větev." #, python-format msgid "Branch \"%s\" already exists." msgstr "Větev „%s“ už existuje." msgid "Branch Diff Viewer" msgstr "Diff prohlížeč větví" msgid "Branch Exists" msgstr "Větev existuje" msgid "Branch Name" msgstr "Název větve" #, python-format msgid "Branch: %s" msgstr "Větev: %s" msgid "Branches" msgstr "Větve" msgid "Branches..." msgstr "Větve…" msgid "Brazilian translation" msgstr "Brazilský překlad" msgid "Browse" msgstr "Procházet" msgid "Browse Commits..." msgstr "Procházet zápisy…" msgid "Browse Current Branch..." msgstr "Procházet stávající větev…" msgid "Browse Other Branch..." msgstr "Procházet jinou větev…" msgid "Browse..." msgstr "Procházet…" msgid "Browser" msgstr "Prohlížeč" #, python-format msgid "Browsing %s" msgstr "Prochází se %s" msgid "Bypass Commit Hooks" msgstr "Přemostit háčky nahrání" msgid "Cancel" msgstr "Storno" msgid "" "Cancel rebase\n" "Shortcut: Ctrl+Q" msgstr "" "Zrušit přeskládání\n" "Zkratka: Ctrl+Q" msgid "Cannot Amend" msgstr "Není možné amend" #, python-format msgid "Cannot exec \"%s\": please configure a blame viewer" msgstr "Nedaří se spustit „%s" #, python-format msgid "Cannot exec \"%s\": please configure a history browser" msgstr "Nelze spustit \"%s\": prosím nakonfigurujte prohlížeč historie" #, python-format msgid "Cannot exec \"%s\": please configure your editor" msgstr "Nelze spustit \"%s\": prosím nakonfigurujte editor" msgid "Changed Upstream" msgstr "Změněno v upstreamu" msgid "Check Spelling" msgstr "Kontrolovat pravopis" msgid "Check spelling" msgstr "Kontrolovat pravopis" msgid "Checkout" msgstr "Přepnout" msgid "Checkout After Creation" msgstr "Přepnout po vytvoření" msgid "Checkout Branch" msgstr "Přepnout větev" msgid "Checkout Detached HEAD" msgstr "Přepnout odpojené hlavní" msgid "Checkout as new branch" msgstr "Přepnout jako novou větev" msgid "Checkout..." msgstr "Přepnout…" msgid "Cherry Pick" msgstr "Sloučit selektivně" msgid "Cherry-Pick Commit" msgstr "Sloučit konkrétní nahrání" msgid "Cherry-Pick..." msgstr "Selektivně sloučit…" msgid "Choose Paths" msgstr "Zvolit umístění" msgid "Choose the \"git grep\" regular expression mode" msgstr "Zvolte režim regulárního výrazu „git grep“" msgid "Clear Default Repository" msgstr "Zrušit výchozí repozitář" msgid "Clear commit message" msgstr "Vyčistit zprává nahrání" msgid "Clear commit message?" msgstr "Vyčistit zprávu nahrání?" msgid "Clear..." msgstr "Vyčístit…" msgid "Clone" msgstr "Klonovat" msgid "Clone Repository" msgstr "Klonovat repozitář" msgid "Clone..." msgstr "Klonovat…" #, python-format msgid "Cloning repository at %s" msgstr "Klonuje se repozitář na %s" msgid "Close" msgstr "Zavřít" msgid "Close..." msgstr "Zavřít…" msgid "Collapse all" msgstr "Sbalit vše" msgid "Command" msgstr "Příkaz" msgid "Commit" msgstr "Zapsat" msgid "Commit failed" msgstr "Zapsání se nezdařilo" msgid "Commit staged changes" msgstr "Zapsat připravené změny" msgid "" "Commit staged changes\n" "Shortcut: Ctrl+Enter" msgstr "" "Zapsat (commit) připravené změny\n" "Klávesová zkratka: Ctrl+Enter" msgid "Commit summary" msgstr "Souhrn zápisu" msgid "Commit the merge if there are no conflicts. Uncheck to leave the merge uncommitted" msgstr "Zapsat sloučení, pokud nejsou žádné konflikty. Je-li odškrtnuto, sloučení zůstane nezapsáno" msgid "Commit@@verb" msgstr "Zapsat" msgid "Compare" msgstr "Porovnat" msgid "Compare All" msgstr "Porovnat vše" msgid "Configure the remote branch as the the new upstream" msgstr "Nastavit vzdálenou větev jako nový upstream" msgid "Configure toolbar" msgstr "Upravit nástrojovou lištu" msgid "Console" msgstr "Konzole" msgid "Continue" msgstr "Pokračovat" msgid "Copy" msgstr "Kopírovat" msgid "Copy Basename to Clipboard" msgstr "Kopírovat název souboru do schránky" msgid "Copy Leading Path to Clipboard" msgstr "Zkopírovat popis umístění do schránky" msgid "Copy Path to Clipboard" msgstr "Zkopírovat popis umístění do schránky" msgid "Copy Relative Path to Clipboard" msgstr "Zkopírovat relativní popis umístění do schránky" msgid "Copy SHA-1" msgstr "Kopírovat SHA-1" msgid "Copy..." msgstr "Kopírovat…" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "Nedaří se zpracovat Git URL: „%s“" msgid "Create Branch" msgstr "Vytvořit větev" msgid "Create Patch" msgstr "Vytvořit záplatu" msgid "Create Remote Branch" msgstr "Vytvořit vzdálenou větev" msgid "Create Signed Commit" msgstr "Vytvořit podepsaný zápis" msgid "Create Tag" msgstr "Vytvořit štítek" msgid "Create Tag..." msgstr "Vytvořit štítek…" msgid "Create Unsigned Tag" msgstr "Vytvořit nepodepsanou značku" msgid "Create a merge commit even when the merge resolves as a fast-forward" msgstr "Vytvořit zápis sloučení i v případě, že je sloučení vyřešeno jako Rychle vpřed" msgid "Create a new remote branch?" msgstr "Vytvořit novou vzdálenou větev?" msgid "Create..." msgstr "Vytvořit…" #, python-format msgid "Created a new tag named \"%s\"" msgstr "Vytvořena nová značka názvaná „%s“" msgid "Current Repository" msgstr "Stávající repozitář" msgid "Custom Copy Actions" msgstr "Vlastní akce kopírování" msgid "Customize..." msgstr "Přizpůsobit…" msgid "Cut" msgstr "Vyjmout" msgid "Czech translation" msgstr "Český překlad" msgid "DAG..." msgstr "DAG…" msgid "Dark Theme" msgstr "" msgid "Date, Time" msgstr "Datum, čas" msgid "Default" msgstr "" msgid "Delete" msgstr "Odstranit" #, python-format msgid "Delete %d file(s)?" msgstr "Smazat %d soubory?" msgid "Delete Bookmark" msgstr "Odstranit záložku" msgid "Delete Bookmark?" msgstr "Odstranit záložku?" msgid "Delete Branch" msgstr "Smazat větev" msgid "Delete Files" msgstr "Smazat soubory" msgid "Delete Files..." msgstr "Smazat soubory…" msgid "Delete Files?" msgstr "Smazat soubory?" msgid "Delete Remote" msgstr "Odstranit vzdálený" msgid "Delete Remote Branch" msgstr "Smazat vzdálenou větev" msgid "Delete Remote Branch..." msgstr "Smazat vzdálenou větev…" msgid "Delete remote" msgstr "Odstranit vzdálený" #, python-format msgid "Delete remote \"%s\"" msgstr "Odstranit vzdálený „%s“" msgid "Delete remote?" msgstr "Odstranit vzdálený?" msgid "Delete selected branch?" msgstr "Smazat vybranou větev?" msgid "Delete toolbar" msgstr "Odstranit nástrojovou lištu" msgid "Delete..." msgstr "Smazat…" #, python-format msgid "Deleting \"%s\" failed" msgstr "Odstraňování „%s“ se nezdařilo" msgid "Deletions" msgstr "Odstraněno" msgid "Detach" msgstr "Odpojit" msgid "Detect Conflict Markers" msgstr "Zjistit značky konfliktů" msgid "Detect conflict markers in unmerged files" msgstr "Zjistit značky konfliktů v nesloučených souborech" msgid "Developer" msgstr "Vývojář" msgid "Diff" msgstr "Diff" msgid "Diff Against Predecessor..." msgstr "Rozdíl oproti předchůdci…" msgid "Diff Options" msgstr "Volby Diff" msgid "Diff Tool" msgstr "Nástroj Diff" msgid "Diff selected -> this" msgstr "Diff vybraný -> tento" msgid "Diff this -> selected" msgstr "Diff tento -> vybraný" msgid "Diffstat" msgstr "" msgid "Difftool" msgstr "" msgid "Directory Exists" msgstr "Složka existuje" msgid "Display Untracked Files" msgstr "Zobrazit nesledované soubory" msgid "Documentation" msgstr "Dokumentace" msgid "Drop" msgstr "Zahodit" msgid "Drop Stash" msgstr "Zahodit odklad" msgid "Drop Stash?" msgstr "Zahodit odklad?" #, python-format msgid "Drop the \"%s\" stash?" msgstr "Zahodit odklad „%s“?" msgid "Drop the selected stash" msgstr "Zahodit vybraný odklad" msgid "Edit" msgstr "Upravit" msgid "Edit Rebase" msgstr "Upravit přeskládání" msgid "Edit Remotes" msgstr "Upravit vzdálené" msgid "Edit Remotes..." msgstr "Upravit vzdálené…" msgid "Edit remotes by selecting them from the list" msgstr "Upravit vzdálené jejich výběrem ze seznamu" msgid "Edit selected paths" msgstr "Upravit označená umístění" msgid "Edit..." msgstr "Upravit…" msgid "Editor" msgstr "Editor" msgid "Email Address" msgstr "E-mailová adresa" msgid "Email contributor" msgstr "Napsat přispěvateli e-mail" msgid "Enabled" msgstr "Povoleno" msgid "Enter New Branch Name" msgstr "Zadat nový název větve" msgid "Enter a name for the new bare repo" msgstr "Zadejte název pro nový holý repozitář" msgid "Enter a name for the stash" msgstr "Zadat název odkladu" msgid "Error" msgstr "Chyba" msgid "Error Cloning" msgstr "Chyba při klonování" msgid "Error Creating Branch" msgstr "Chyba při vytváření větve" msgid "Error Creating Repository" msgstr "Chyba při vytváření repozitáře" msgid "Error Deleting Remote Branch" msgstr "Chyba při odstraňování vzdálené větve" msgid "Error Editing File" msgstr "Chyba při úpravě souboru" msgid "Error Launching Blame Viewer" msgstr "Chyba při spouštění blame prohlížeče" msgid "Error Launching History Browser" msgstr "Chyba při spouštění prohlížeče historie" #, python-format msgid "Error creating remote \"%s\"" msgstr "Chyba při vytváření vzdálené \"%s\"" msgid "Error creating stash" msgstr "Chyba při vytváření stash" #, python-format msgid "Error deleting remote \"%s\"" msgstr "Chyba při odstraňování vzdálené \"%s\"" #, python-format msgid "Error renaming \"%(name)s\" to \"%(new_name)s\"" msgstr "Chyba při přejmenovávání „%(name)s“ na „%(new_name)s“" msgid "Error running prepare-commitmsg hook" msgstr "Chyba spouštění háčku prepare-commitmsg" #, python-format msgid "Error updating submodule %s" msgstr "" msgid "Error updating submodules" msgstr "" msgid "Error: Cannot find commit template" msgstr "Chyba: nedaří se nalézt šablonu nahrání" msgid "Error: Stash exists" msgstr "Chyba: Odklad existuje" msgid "Error: Unconfigured commit template" msgstr "Chyba: Nenastavená šablona nahrání" #, python-format msgid "Error: could not clone \"%s\"" msgstr "Chyba: „%s“ nemohl být klonován" #, python-format msgid "Error: could not create tag \"%s\"" msgstr "Chyba: značka „%s“ nemohla být vytvořena" #, python-format msgid "Executing action %s" msgstr "Spouští se akce %s" msgid "Expand all" msgstr "Rozbalit vše" msgid "Export Patches" msgstr "Exportovat záplaty" msgid "Export Patches..." msgstr "Exportovat záplaty…" msgid "Expression..." msgstr "Výraz…" msgid "Extended Regexp" msgstr "" msgid "Extended description..." msgstr "Podrobný popis…" msgid "Fast Forward Only" msgstr "Pouze rychle vpřed" msgid "Fast-forward only" msgstr "Pouze rychle vpřed" msgid "Favorite repositories" msgstr "Oblíbené repozitáře" msgid "Favorites" msgstr "Oblíbené" msgid "Fetch" msgstr "Vyzvednout" msgid "Fetch Tracking Branch" msgstr "Vyzvednout sledovanou větev" msgid "Fetch..." msgstr "Vyzvednout (fetch)…" msgid "File Browser..." msgstr "Prohlížeč souborů…" msgid "File Differences" msgstr "Rozdíly souboru" msgid "File Saved" msgstr "Soubor uložen" #, python-format msgid "File saved to \"%s\"" msgstr "Soubor uložen jako „%s“" msgid "File system change monitoring: disabled because \"cola.inotify\" is false.\n" msgstr "Monitorování změn na souborovém systému: vypnuto protože „cola.inotify“ je nastaveno na false.\n" msgid "File system change monitoring: disabled because libc does not support the inotify system calls.\n" msgstr "Monitorování změn na souborovém systému: vypnuto protože libc nepodporuje systémová volání inotify.\n" msgid "File system change monitoring: disabled because pywin32 is not installed.\n" msgstr "Monitorování změn na souborovém systému: vypnuto protože není nainstalováno pywin32.\n" msgid "" "File system change monitoring: disabled because the limit on the total number of inotify watches was reached. You may be able to increase the limit on the number of watches by running:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" msgstr "" msgid "File system change monitoring: enabled.\n" msgstr "Monitorování změn na souborovém systému: zapnuto.\n" msgid "Filename" msgstr "Název souboru" msgid "Files" msgstr "Soubory" msgid "Filter branches..." msgstr "Filtrovat větve…" msgid "Filter paths..." msgstr "Filtrovat umístění…" msgid "Find Files" msgstr "Hledat soubory" msgid "Fixed String" msgstr "Pevný řetězec" msgid "Fixed-Width Font" msgstr "Písmo s pevnou šířkou" msgid "Fixup" msgstr "Opravit" msgid "Fixup Previous Commit" msgstr "Opravit předchozí zápis" msgid "Flat dark blue" msgstr "" msgid "Flat dark green" msgstr "" msgid "Flat dark grey" msgstr "" msgid "Flat dark red" msgstr "" msgid "Flat light blue" msgstr "" msgid "Flat light green" msgstr "" msgid "Flat light grey" msgstr "" msgid "Flat light red" msgstr "" msgid "Font Size" msgstr "Velikost písma" msgid "Force" msgstr "Vynutit" msgid "Force Fetch" msgstr "Vynutit vyzvednutí" msgid "Force Fetch?" msgstr "Vynutit vyzvednutí?" msgid "Force Push" msgstr "Vynutit odeslání" msgid "Force Push?" msgstr "Vynutit odeslání?" #, python-format msgid "Force fetching from %s?" msgstr "Vynutit vyzvednutí z %s?" #, python-format msgid "Force push to %s?" msgstr "Vynutit odeslání do %s?" msgid "Format String" msgstr "Formátovací řetězec" msgid "French translation" msgstr "Francouzský překlad" msgid "GPG-sign the merge commit" msgstr "GPG podepsaný zápis sloučení" msgid "GUI theme" msgstr "" #, python-format msgid "Gathering info for \"%s\"..." msgstr "Shromažďování informací pro „%s“…" msgid "German translation" msgstr "Německý překlad" msgid "Get Commit Message Template" msgstr "Získat šablonu zprávy zápisu" msgid "Go Down" msgstr "Jít níže" msgid "Go Up" msgstr "Jít výše" msgid "Grab File..." msgstr "Získat soubor…" msgid "Graph" msgstr "Graf" msgid "Grep" msgstr "Grep" msgid "Have you rebased/pulled lately?" msgstr "Nepřeskládali/nestáhli jste v poslední době?" msgid "Help" msgstr "Nápověda" msgid "Help - Custom Copy Actions" msgstr "Nápověda – uživatelské akce kopírování" msgid "Help - Find Files" msgstr "Nápověda – najít soubory" msgid "Help - git-xbase" msgstr "Nápověda – git-xbase" msgid "Hide Details.." msgstr "Skrýt podrobnosti…" msgid "High DPI" msgstr "" msgid "History Browser" msgstr "Prohlížeč historie" msgid "Hungarian translation" msgstr "Maďarský překlad" msgid "Icon theme" msgstr "" msgid "Ignore all whitespace" msgstr "Ignorovat všechny mezery" msgid "Ignore changes in amount of whitespace" msgstr "Ignorovat změny v počtu mezer" msgid "Ignore changes in whitespace at EOL" msgstr "Ignorovat změny v mezerách na konci řádků" msgid "Ignore custom pattern" msgstr "Ignorovat dle šablony" msgid "Ignore exact filename" msgstr "Ignorovat přesný název souboru" msgid "Ignore filename or pattern" msgstr "Ignorovat název souboru nebo šablonu" msgid "Include tags " msgstr "Zahrnout značky " msgid "Indent Status paths" msgstr "" msgid "Indonesian translation" msgstr "Indonéský překlad" msgid "Initialize Git Annex" msgstr "Inicializovat Git Annex" msgid "Initialize Git LFS" msgstr "Inicializovat Git LFS" msgid "Inititalize submodules" msgstr "Inicializovat dílčí moduly" msgid "Insert spaces instead of tabs" msgstr "Vkládat mezery místo tabelátorů" msgid "Interactive Rebase" msgstr "Interaktivní přeskládání" msgid "Invalid Revision" msgstr "Neplatná revize" msgid "Keep *.orig Merge Backups" msgstr "Ponechat *.orig zálohy začlenění" msgid "Keep Index" msgstr "Zachovat index" msgid "Keyboard Shortcuts" msgstr "Klávesové zkratky" msgid "Launch Diff Tool" msgstr "Spustit nástroj Diff" msgid "Launch Directory Diff Tool" msgstr "Spustit nástroj pro porovnání rozdílů mezi složkami" msgid "Launch Editor" msgstr "Spustit editor" msgid "Launch Terminal" msgstr "Spustit terminál" msgid "" "Launch external diff tool\n" "Shortcut: Ctrl+D" msgstr "" "Spustit externí diff nástroj\n" "Zkratka: Ctrl+D" msgid "Launch git-cola" msgstr "Spustit git-cola" msgid "Launch git-difftool against previous versions" msgstr "Spustit git-difftool proti předchozím verzím" msgid "Launch git-difftool on the current path" msgstr "Spustit git-difftool na stávajícím umístění" msgid "Light Theme" msgstr "" msgid "Load Commit Message" msgstr "Nahrát zprávu zápisu" msgid "Load Commit Message..." msgstr "Načíst zprávu zápisu…" msgid "Load Previous Commit Message" msgstr "Načíst zprávu předchozího zápisu" msgid "Loading..." msgstr "Načítání…" msgid "Local" msgstr "Místní" msgid "Local Branch" msgstr "Místní větev" msgid "Local branch" msgstr "Místní větev" msgid "Lock Layout" msgstr "Zamknout rozvržení" msgid "Log" msgstr "Záznam událostí" msgid "Maintainer (since 2007) and developer" msgstr "Správce (od roku 2007) a vývojář" msgid "Merge" msgstr "Sloučit" #, python-format msgid "Merge \"%(revision)s\" into \"%(branch)s\"" msgstr "Začlenit „%(revision)s“ do „%(branch)s“" msgid "Merge Tool" msgstr "Nástroj sloučení" msgid "Merge Verbosity" msgstr "Výřečnost při sloučení" msgid "Merge failed. Conflict resolution is required." msgstr "Sloučení se nezdařilo. Je třeba rozhodnout o konfliktech." #, python-format msgid "Merge into \"%s\"" msgstr "Začlenit do „%s“" msgid "Merge into current branch" msgstr "Začlenit do současné větve" msgid "Merge..." msgstr "Sloučit (merge)…" msgid "Merging" msgstr "Slučování" msgid "Message" msgstr "Zpráva" msgid "Missing Commit Message" msgstr "Chybí zpráva příspěvku" msgid "Missing Data" msgstr "Chybí data" msgid "Missing Name" msgstr "Chybí název" msgid "Missing Revision" msgstr "Chybějící revize" msgid "Missing Tag Message" msgstr "Zpráva značky chybí" msgid "Modified" msgstr "Změněno" msgid "More..." msgstr "Více…" msgid "Move Down" msgstr "Posunout dolů" msgid "Move Up" msgstr "Posunout nahoru" msgid "Move files to trash" msgstr "Přesunout soubory do koše" msgid "Name" msgstr "Název" msgid "Name for the new remote" msgstr "Název nového vzdáleného" msgid "New Bare Repository..." msgstr "Nový holý repozitář…" msgid "New Repository..." msgstr "Nový repozitář…" msgid "New..." msgstr "Nový…" msgid "Next File" msgstr "Následující soubor" msgid "No" msgstr "Ne" msgid "No Revision Specified" msgstr "Nezadána žádná revize" msgid "" "No changes to commit.\n" "\n" "You must stage at least 1 file before you can commit." msgstr "" "Žádné změny, které by bylo možné zapsat.\n" "\n" "Je potřeba připravit k zapsání alespoň jeden soubor předtím, než ho bude možné zapsat." msgid "No commits exist in this branch." msgstr "V této větvi nejsou žádné zápisy." msgid "No fast forward" msgstr "Ne rychle vpřed" msgid "No fast-forward" msgstr "Ne rychle vpřed" msgid "No repository selected." msgstr "Nevybrán žádný repozitář." msgid "Non-fast-forward fetch overwrites local history!" msgstr "Vyzvednutí Ne rychle vpřed přepíše místní historii!" msgid "" "Non-fast-forward push overwrites published history!\n" "(Did you pull first?)" msgstr "" "Odeslání Ne rychle vpřed přepíše uveřejněnou historii!\n" "(Dali jste nejdříve stáhnout?)" msgid "Nothing to commit" msgstr "Není co odeslat" msgid "Nothing to do" msgstr "Není co udělat" msgid "Number of Diff Context Lines" msgstr "Počet kontextový řádků Diff" msgid "Open" msgstr "Otevřít" msgid "Open Git Repository..." msgstr "Otevřít Git repozitář…" msgid "Open Parent" msgstr "" msgid "Open Parent Directory" msgstr "Otevřít nadřazenou složku" msgid "Open Recent" msgstr "Otevřít nedávné" msgid "Open Using Default Application" msgstr "Otevřít ve výchozí aplikaci" msgid "Open in New Window" msgstr "Otevřít v novém okně" msgid "Open in New Window..." msgstr "Otevřít v novém okně…" msgid "Open..." msgstr "Otevřít…" msgid "Other branches" msgstr "Další větve" msgid "Overwrite" msgstr "Přepsat" #, python-format msgid "Overwrite \"%s\"?" msgstr "Přepsat „%s“?" msgid "Overwrite File?" msgstr "Přepsat soubor?" msgid "" "Parse arguments using a shell.\n" "Queries with spaces will require \"double quotes\"." msgstr "" "Zpracovat argumenty pomocí shellu.\n" "Dotazy s mezerami vyžadují \"dvojité uvozovky\"." msgid "Partially Staged" msgstr "Částečně staged" msgid "Paste" msgstr "Vložit" msgid "Patch(es) Applied" msgstr "Záplaty aplikovány" msgid "Path" msgstr "Cesta" msgid "Path or URL to clone (Env. $VARS okay)" msgstr "Cesta nebo URL, která se má klonovat (Env. $VARS okay)" msgid "Pick" msgstr "Vybrat" msgid "Pixel XOR" msgstr "Pixel XOR" msgid "Please provide both a branch name and revision expression." msgstr "Zadejte jak název větve, tak výraz revize." msgid "Please select a file" msgstr "Vyberte soubor" msgid "Please specify a name for the new tag." msgstr "Zadejte název nové značky." msgid "Please specify a revision to tag." msgstr "Zadejte štítek revize." msgid "" "Please supply a commit message.\n" "\n" "A good commit message has the following format:\n" "\n" "- First line: Describe in one sentence what you did.\n" "- Second line: Blank\n" "- Remaining lines: Describe why this change is good.\n" msgstr "" msgid "Point the current branch head to a new commit?" msgstr "Umístit současnou hlavu větve na nový zápis?" msgid "Polish translation" msgstr "Polský překlad" msgid "Pop" msgstr "Pop" msgid "Preferences" msgstr "Předvolby" msgid "Prefix" msgstr "Předpona" msgid "Prepare Commit Message" msgstr "Připravit zprávu zápisu" msgid "Prevent \"Stage\" from staging all files when nothing is selected" msgstr "Zabránit „Stage“ ze staging všech souborů když není nic vybráno" msgid "Previous File" msgstr "Předchozí soubor" msgid "Prompt on creation" msgstr "Dotázat se při vytvoření" msgid "Prompt when pushing creates new remote branches" msgstr "Dotázat se když nahrání vytváří nové vzdálené větve" msgid "Prune " msgstr "Prune" msgid "Pull" msgstr "Stáhnout si" msgid "Pull..." msgstr "Stáhnout si (pull)…" msgid "Push" msgstr "Odeslat" msgid "Push..." msgstr "Odeslat (push)…" msgid "Quit" msgstr "Ukončit" msgid "Rebase" msgstr "Přeskládat" #, python-format msgid "Rebase onto %s" msgstr "Přeskládat do %s" msgid "Rebase stopped" msgstr "Přeskládání zastaveno" msgid "Rebase the current branch instead of merging" msgstr "Místo sloučení přeskládat současnou větev" msgid "Rebasing" msgstr "Přeskládání" msgid "Recent" msgstr "Nedávné" msgid "Recent repositories" msgstr "Nedávné repozitáře" msgid "Recent repository count" msgstr "Počet nedávných repozitářů" msgid "Recently Modified Files" msgstr "Nedávno změněné soubory" msgid "Recently Modified Files..." msgstr "Nedávno změněné soubory…" msgid "Recovering a dropped stash is not possible." msgstr "Obnova zahozeného odkladu není možná." msgid "Recovering lost commits may not be easy." msgstr "Obnova ztracených příspěvků nemusí být snadná." msgid "Redo" msgstr "Znovu" msgid "Reduce commit history to minimum" msgstr "Omezit historii zápisů na minimum" msgid "Refresh" msgstr "Načíst znovu" msgid "Refuse to merge unless the current HEAD is already up-to-date or the merge can be resolved as a fast-forward" msgstr "Odmítnout sloučení, jestliže současná HLAVA není již aktualizovaná, nebo sloučení, které nemůže být vyřešeno jako Rychle vpřed" msgid "Remote" msgstr "Vzdálená" msgid "Remote Branch" msgstr "Vzdálená větev" msgid "Remote Branch Deleted" msgstr "Vzdálená větev smazána" msgid "Remote git repositories - double-click to rename" msgstr "Vzdálené git repozitáře – přejmenujete dvojklikem" msgid "Remove" msgstr "Odstranit" #, python-format msgid "Remove %s from the recent list?" msgstr "Odstranit %s ze seznamu nedávných?" msgid "Remove Element" msgstr "Odebrat prvek" msgid "Remove remote-tracking branches that no longer exist on the remote" msgstr "Odstranit odkazy na vzdálené větve, které již neexistují ve vzdáleném" msgid "Remove selected (Delete)" msgstr "Odstranit vybrané (Smazat)" msgid "Rename" msgstr "Přejmenovat" #, python-format msgid "Rename \"%s\"" msgstr "Přejmenovat „%s“" msgid "Rename Branch" msgstr "Přejmenovat větev" msgid "Rename Branch..." msgstr "Přejmenovat větev…" msgid "Rename Existing Branch" msgstr "Přejmenovat stávající větev" msgid "Rename Remote" msgstr "Přejmenovat vzdálenou" msgid "Rename Repository" msgstr "Přejmenovat repozitář" msgid "Rename branch" msgstr "Přejmenovat větev" #, python-format msgid "Rename remote \"%(current)s\" to \"%(new)s\"?" msgstr "Přejmenovat vzdálenou „%(current)s“ na „%(new)s“?" msgid "Rename selected paths" msgstr "Přejmenovat vybraná umístění" #, python-format msgid "Repository: %s" msgstr "Repozitář: %s" msgid "Reset" msgstr "Resetovat" #, python-format msgid "Reset \"%(branch)s\" to \"%(revision)s\"?" msgstr "Resetovat \"%(branch)s\" do \"%(revision)s\"?" msgid "Reset Branch" msgstr "Resetovat větev" msgid "Reset Branch Head" msgstr "Resetovat hlavu větve" msgid "Reset Branch?" msgstr "Resetovat větev?" msgid "Reset Hard" msgstr "Tvrdý reset" msgid "Reset Merge" msgstr "Resetovat sloučení" msgid "Reset Soft" msgstr "Měkký reset" msgid "Reset Worktree" msgstr "Resetovat pracovní strom" msgid "Reset hard?" msgstr "Tvrdý reset?" msgid "Reset merge?" msgstr "Resetovat sloučení?" msgid "Reset soft?" msgstr "Měkký reset?" msgid "Reset worktree?" msgstr "Resetovat pracovní strom?" #, python-format msgid "Resetting \"%(branch)s\" to \"%(revision)s\" will lose commits." msgstr "Resetováním „%(branch)s“ do „%(revision)s“ se ztratí zápisy." msgid "Restart the application after changing appearance settings." msgstr "" msgid "Revert" msgstr "Vrátit" msgid "Revert Diff Hunk" msgstr "Vrátit komplex rozdílů" msgid "Revert Diff Hunk..." msgstr "Vrátit komplex rozdílů…" msgid "Revert Diff Hunk?" msgstr "Vrátit komplex rozdílů?" msgid "Revert Selected Lines" msgstr "Vrátit vybrané řádky" msgid "Revert Selected Lines..." msgstr "Vrátit vybrané řádky…" msgid "Revert Selected Lines?" msgstr "Vrátit vybrané řádky?" msgid "Revert Uncommitted Changes" msgstr "Vrátit nezapsané změny" msgid "Revert Uncommitted Changes?" msgstr "Vrátit nezapsané změny?" msgid "Revert Uncommitted Edits..." msgstr "Vrátit nezapsané úpravy…" msgid "Revert Unstaged Changes" msgstr "Vrátit nepřipravené změny" msgid "Revert Unstaged Changes?" msgstr "Vrátit nepřipravené změny?" msgid "Revert Unstaged Edits..." msgstr "Vrátit nepřipravené úpravy…" msgid "Revert the uncommitted changes?" msgstr "Vrátit nezapsané změny?" msgid "Revert the unstaged changes?" msgstr "Vrátit nepřipravené změny?" msgid "Revert uncommitted changes to selected paths" msgstr "Vrátit nenahrané změny v označených umístěních" msgid "Revert unstaged changes to selected paths" msgstr "Vrátit unstaged změny v značených umístěních" msgid "Review" msgstr "Revidovat" msgid "Review..." msgstr "Revidovat…" msgid "Revision" msgstr "Revize" msgid "Revision Expression:" msgstr "Číslo revize:" msgid "Revision to Merge" msgstr "Revize ke sloučení" msgid "Reword" msgstr "" msgid "Rewrite Published Commit?" msgstr "Přepsat uveřejněný zápis?" msgid "Run" msgstr "Spustit" #, python-format msgid "Run \"%s\"?" msgstr "Spustit „%s“?" #, python-format msgid "Run %s?" msgstr "Spustit %s?" #, python-format msgid "Run the \"%s\" command?" msgstr "Spustit příkaz „%s“?" #, python-format msgid "Running command: %s" msgstr "Spuštěný příkaz: %s" msgid "Russian translation" msgstr "Ruský překlad" msgid "SHA-1" msgstr "SHA-1" msgid "Safe Mode" msgstr "Bezpečný režim" msgid "Save" msgstr "Uložit" msgid "Save Archive" msgstr "Uložit Archiv" msgid "Save As Tarball/Zip..." msgstr "Uložit jako Tarball/Zip…" msgid "Save GUI Settings" msgstr "Uložit nastavení graf. rozhraní" msgid "Save Stash" msgstr "Uložit odklad" msgid "Save modified state to new stash" msgstr "Uložit modifikovaný stav jako nový odklad" #, python-format msgid "Saved \"%(filename)s\" from \"%(ref)s\" to \"%(destination)s\"" msgstr "Uloženo „%(filename)s“ z „%(ref)s“ do „%(destination)s“" msgid "Search" msgstr "Hledat" msgid "Search Authors" msgstr "Hledat autory" msgid "Search Commit Messages" msgstr "Hledat zprávy zápisů" msgid "Search Committers" msgstr "Hledat tvůrce zápisů" msgid "Search Date Range" msgstr "Hledat datový rozsah" msgid "Search Diffs" msgstr "Hledat rozdíly" msgid "Search by Expression" msgstr "Hledat dle výrazu" msgid "Search by Path" msgstr "Hledat dle cesty" msgid "Search for a fixed string" msgstr "Hledat pevný řetězec" msgid "Search using a POSIX basic regular expression" msgstr "Hledat s použitím základních POSIX regulárních výrazů" msgid "Search using a POSIX extended regular expression" msgstr "Hledat s použitím rozšířených POSIX regulárních výrazů" msgid "Search..." msgstr "Hledat…" msgid "Select" msgstr "Vybrat" msgid "Select All" msgstr "Vybrat vše" msgid "Select Branch to Review" msgstr "Vybrat větev k revizi" msgid "Select Child" msgstr "Vybrat podřízený" msgid "Select Commit" msgstr "Vybrat zápis" msgid "Select Directory..." msgstr "Vybrat složku…" msgid "Select New Upstream" msgstr "Vybrat nový upstream" msgid "Select Newest Child" msgstr "Vybrat nejnovější podřízený" msgid "Select Oldest Parent" msgstr "Vybrat nejstarší nadřazený" msgid "Select Parent" msgstr "Vybrat nadřazený" msgid "Select Previous Version" msgstr "Vybrat předchozí verzi" msgid "Select Repository..." msgstr "Vybrat repozitář…" msgid "Select a parent directory for the new clone" msgstr "Vybrat nadřazenou složku pro nový klon" msgid "Select manually..." msgstr "Vybrat ručně…" msgid "Select output dir" msgstr "Vybrat výstupní složku" msgid "Select output directory" msgstr "Vybrat výstupní složku" msgid "Select patch file(s)..." msgstr "Vybrat soubory se záplatami (patch)…" msgid "Select repository" msgstr "Vybrat repozitář" msgid "Set Default Repository" msgstr "Nastavit výchozí repozitář" msgid "Set Upstream Branch" msgstr "Nastavit upstream větev" msgid "" "Set the sort order for branches and tags.\n" "Toggle between date-based and version-name-based sorting." msgstr "" msgid "Set upstream" msgstr "Nastavit upstream" msgid "Settings" msgstr "Nastavení" msgid "Shell arguments" msgstr "Shell argumenty" msgid "Shift Down" msgstr "Posunout dolů" msgid "Shift Up" msgstr "Posunout nahoru" msgid "Shortcuts" msgstr "Klávesové zkratky" msgid "Show Details..." msgstr "Zobrazit podrobnosti…" msgid "Show Diffstat After Merge" msgstr "Zobrazit Diffstat po sloučení" msgid "Show Full Paths in the Window Title" msgstr "V nadpisu okna zobrazovat úplné popisy umístění" msgid "Show Help" msgstr "Zobrazit nápovědu" msgid "Show History" msgstr "Zobrazit historii" msgid "Show file counts in Status titles" msgstr "" msgid "" "Show help\n" "Shortcut: ?" msgstr "" "Zobrazit nápovědu\n" "Zkratka: ?" msgid "Show icon? (if available)" msgstr "Zobrazit ikonu? (je-li dostupná)" msgid "Show line numbers" msgstr "Zobrazit čísla řádků" msgid "Show whole surrounding functions of changes" msgstr "Zobrazit celé obklopující funkce změn" msgid "Showing changes since" msgstr "Zobrazit změny před" msgid "Side by side" msgstr "Vedle sebe" msgid "Sign Off" msgstr "Podepsat" msgid "Sign Tag" msgstr "Podepsat značku" msgid "Sign off on this commit" msgstr "Podepsat na tomto nahrání" msgid "Simplified Chinese translation" msgstr "Překlad do zjednodušené čínštiny" msgid "Skip" msgstr "Přeskočit" msgid "Skip Current Patch" msgstr "Přeskočit současnou záplatu" msgid "Sort bookmarks alphabetically" msgstr "Záložky řadit abecedně" msgid "Spanish translation" msgstr "Španělský překlad" msgid "Specifies the SHA-1 to tag" msgstr "Určuje SHA-1 štítku" msgid "Specifies the tag message" msgstr "Určuje zprávu značky" msgid "Specifies the tag name" msgstr "Určuje název značky" msgid "Spelling Suggestions" msgstr "Doporučení pravopisu" msgid "Squash" msgstr "" msgid "Squash the merged commits into a single commit" msgstr "Squash sloučené nahrání do jediného nahrání" msgid "Stage" msgstr "Připravit k zapsání" msgid "Stage / Unstage" msgstr "Připravit k zapsání / zrušit přípravu" msgid "Stage All Untracked" msgstr "Připravit všechny nesledované" msgid "Stage Changed Files To Commit" msgstr "Připravit změněné soubory k zapsání" msgid "Stage Diff Hunk" msgstr "Připravit k zapsání komplex rozdílů" msgid "Stage Modified" msgstr "Změněné připravit k zapsání" msgid "Stage Selected" msgstr "Vybrané připravit k zapsání" msgid "Stage Selected Lines" msgstr "Připravit k zapsání vybrané řádky" msgid "Stage Unmerged" msgstr "Nesloučené připravit k zapsání" msgid "Stage Untracked" msgstr "Nesledované připravit k zapsání" msgid "Stage and Commit" msgstr "Připravit k zapsání a zapsat" msgid "Stage and commit?" msgstr "Připravit k zapsání a zapsat?" msgid "Stage conflicts" msgstr "Konflikty přípravy k zapsání" msgid "Stage conflicts?" msgstr "Konflikty přípravy k zapsání?" msgid "Stage/unstage selected paths for commit" msgstr "Připravit / zrušit přípravu označených umístění pro nahrání" msgid "Staged" msgstr "Připraveno k zapsání" #, python-format msgid "Staging: %s" msgstr "Připravuje s k zápisu: %s" msgid "Start Interactive Rebase..." msgstr "Zahájit interaktivní přeskládání (rebase)…" msgid "Starting Revision" msgstr "Počáteční revize" msgid "Stash" msgstr "Odložit" msgid "Stash Index" msgstr "Odložit index" msgid "Stash staged changes only" msgstr "Odložit pouze připravené změny" msgid "Stash unstaged changes only, keeping staged changes" msgstr "Odložit pouze nepřipravené změny, zachovat připravené změny" msgid "Stash..." msgstr "Odložit (stash)…" msgid "Status" msgstr "Stav" msgid "Stop tracking paths" msgstr "Zastavit sledující umístění" msgid "Submodules" msgstr "" msgid "Summarize Merge Commits" msgstr "Shrnout nahrání sloučení" msgid "Summary" msgstr "Shrnutí" msgid "Tab Width" msgstr "Šířka tabelátoru" msgid "Tag" msgstr "Značka" msgid "Tag Created" msgstr "Značka vytvořena" msgid "Tag message..." msgstr "Zpráva značky…" msgid "Tag-signing was requested but the tag message is empty." msgstr "Byl požadován podpis značky, ale zpráva značky je prázdná." msgid "Tags" msgstr "Značky" msgid "Text Width" msgstr "Šířka textu" msgid "The branch will be no longer available." msgstr "Větev nebude již k dispozici." #, python-format msgid "The branch will be reset using \"git reset --hard %s\"" msgstr "Větev bude resetována za použití \"git reset --hard %s\"" #, python-format msgid "The branch will be reset using \"git reset --merge %s\"" msgstr "Větev bude resetována za použití \"git reset --merge %s\"" #, python-format msgid "The branch will be reset using \"git reset --mixed %s\"" msgstr "Větev bude resetována za použití \"git reset --mixed %s\"" #, python-format msgid "The branch will be reset using \"git reset --soft %s\"" msgstr "Větev bude resetována za použití \"git reset --soft %s\"" msgid "The commit message will be cleared." msgstr "Zpráva o nahrání bude vyčištěna." #, python-format msgid "The file \"%s\" exists and will be overwritten." msgstr "Soubor \"%s\" existuje a bude přepsán." msgid "The following files will be deleted:" msgstr "Následující soubory budou smazány:" msgid "The revision expression cannot be empty." msgstr "Výraz revize nemůže zůstat nevyplněný." #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be reset using \"git reset --keep %s\"" msgstr "Větev bude resetována za použití \"git reset --keep %s\"" msgid "This cannot be undone. Clear commit message?" msgstr "Tuto akci nelze vzít zpět. Vyčistit zprávu k nahrání?" msgid "" "This commit has already been published.\n" "This operation will rewrite published history.\n" "You probably don't want to do this." msgstr "" "Tento zápis už byl zveřejněn.\n" "Tato činnost přepíše uveřejněnou historii.\n" "Pravděpodobně to nechcete udělat." msgid "" "This operation drops uncommitted changes.\n" "These changes cannot be recovered." msgstr "" "Tato akce zahodí nezapsané změny.\n" "Tyto změny nemohou být obnoveny." msgid "" "This operation removes uncommitted edits from selected files.\n" "These changes cannot be recovered." msgstr "" "Tato akce zahodí nezapsané změny.\n" "Tyto změny nemohou být obnoveny." msgid "" "This operation removes unstaged edits from selected files.\n" "These changes cannot be recovered." msgstr "" "Tato akce zahodí nepřipravené změny.\n" "Tyto změny nemohou být obnoveny." msgid "" "This repository is currently being rebased.\n" "Resolve conflicts, commit changes, and run:\n" " Rebase > Continue" msgstr "" msgid "" "This repository is in the middle of a merge.\n" "Resolve conflicts and commit changes." msgstr "" msgid "Toggle Enabled" msgstr "" msgid "Toggle the branches filter" msgstr "Zobrazit/skrýt filtr větví" msgid "Toggle the paths filter" msgstr "Zobrazit/skrýt filtr cest" msgid "Tracking Branch" msgstr "Sledovaná větev" msgid "Tracking branch" msgstr "Sledovaná větev" msgid "Traditional Chinese (Taiwan) translation" msgstr "Překlad do tradiční čínštiny (taiwanštiny)" msgid "Translators" msgstr "Překladatelé" msgid "Turkish translation" msgstr "Turecký překlad" msgid "URL" msgstr "URL" #, python-format msgid "URL: %s" msgstr "URL: %s" msgid "Ukranian translation" msgstr "Ukrajinský překlad" msgid "Unable to rebase" msgstr "Nelze přeskládat" #, python-format msgid "Unable to set URL for \"%(name)s\" to \"%(url)s\"" msgstr "Nedaří se nastavit URL pro „%(name)s“ na „%(url)s“" msgid "Undo" msgstr "Zpět" msgid "Unmerged" msgstr "Nesloučeno" msgid "Unstage" msgstr "Zrušit přípravu" msgid "Unstage All" msgstr "Zrušit veškerou přípravu" msgid "Unstage Diff Hunk" msgstr "Zrušit přípravu komplexu rozdílů" msgid "Unstage From Commit" msgstr "Zrušit přípravu k zapsání" msgid "Unstage Selected" msgstr "Zrušit přípravu vybraných" msgid "Unstage Selected Lines" msgstr "Zrušit přípravu vybraných řádků" #, python-format msgid "Unstaging: %s" msgstr "Ruší se příprava: %s" msgid "Untrack Selected" msgstr "Přestat sledovat vybrané" msgid "Untracked" msgstr "Nesledováno" #, python-format msgid "Untracking: %s" msgstr "Přestává se sledovat: %s" msgid "Update All Submodules..." msgstr "" msgid "Update Existing Branch:" msgstr "Aktualizovat stávající větev:" msgid "Update Submodule" msgstr "" msgid "Update Submodule..." msgstr "" msgid "Update Submodules" msgstr "" msgid "Update all submodules?" msgstr "" msgid "Update submodules..." msgstr "" msgid "Update this submodule" msgstr "" msgid "Update this submodule?" msgstr "" msgid "Updating" msgstr "Aktualizuje se" msgid "User Name" msgstr "Uživatelské jméno" msgid "Version" msgstr "Verze" msgid "View" msgstr "Zobrazit" msgid "View History..." msgstr "Prohlížet historii…" msgid "View history for selected paths" msgstr "Zobrazit historii vybraných umístění" msgid "Visualize" msgstr "Vizualizovat" msgid "Visualize All Branches..." msgstr "Vizualizovat všechny větve…" msgid "Visualize Current Branch..." msgstr "Vizualizovat stávající větev…" msgid "Whether to sign the tag (git tag -s)" msgstr "" msgid "Would you like to stage and commit all modified files?" msgstr "Chcete připravit k zapsání a zapsat všechny změněné soubory?" msgid "XOR" msgstr "" msgid "Yes" msgstr "Ano" msgid "" "You are in the middle of a merge.\n" "Cannot amend while merging." msgstr "" "Jste vprostřed slučování.\n" "Nelze amend při slučováné." msgid "You cannot rebase with uncommitted changes." msgstr "Nelze přeskládat s nezapsanými změnami." msgid "You must specify a revision to merge." msgstr "Pro sloučení je třeba určit revizi." msgid "You must specify a revision to view." msgstr "Je třeba určit kterou revizi zobrazit." msgid "Zoom In" msgstr "Přiblížit" msgid "Zoom Out" msgstr "Oddálit" msgid "Zoom to Fit" msgstr "Přizpůsobit velikosti okna" msgid "command-line arguments" msgstr "argumenty příkazového řádku" msgid "error: unable to execute git" msgstr "chyba: nedaří se spustit git" #, python-format msgid "exit code %s" msgstr "návratový kód %s" #, python-format msgid "fatal: \"%s\" is not a directory. Please specify a correct --repo ." msgstr "" #, python-format msgid "git cola version %s" msgstr "git cola verze %s" msgid "git-cola" msgstr "git-cola" msgid "git-cola diff" msgstr "git-cola diff" msgid "grep result..." msgstr "výsledek z grep…" msgid "hotkeys.html" msgstr "hotkeys.html" msgid "unknown" msgstr "neznámé" msgid "vX.Y.Z" msgstr "vX.Y.Z" msgid "x 1" msgstr "" msgid "x 1.5" msgstr "" msgid "x 2" msgstr "" msgid "yyyy-MM-dd" msgstr "rrrr-mm-dd" #~ msgid "PATCH %(current)d/%(count)d" #~ msgstr "PATCH %(current)d/%(count)d" #~ msgid "Rename remote?" #~ msgstr "Přejmenovat vzdálenou?" #~ msgid "Select File" #~ msgstr "Vybrat soubor" #~ msgid "Summary:" #~ msgstr "Shrnutí:" git-cola-3.6/po/de.po000066400000000000000000002644011356743264500144550ustar00rootroot00000000000000# Translation of git-cola to Deutsch. # Copyright (C) 2007, 2013 Shawn Pearce, et al. # This file is distributed under the same license as the git-cola package. # # Christian Stimming , 2007 # Sven Claussner , 2013 # msgid "" msgstr "" "Project-Id-Version: git-cola VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-04-14 07:38+0200\n" "PO-Revision-Date: 2019-03-07 07:18+0100\n" "Last-Translator: Kai Krakow \n" "Language-Team: German\n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.0.6\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Poedit-SourceCharset: UTF-8\n" "X-Poedit-KeywordsList: N_\n" "X-Poedit-Basepath: ../cola\n" "X-Poedit-SearchPath-0: .\n" msgid "" "\n" "

\n" " Drag and drop or use the Add button to add\n" " patches to the list\n" "

\n" " " msgstr "" "\n" "

\n" " Ziehen und ablegen oder nutzen Sie den Hinzufügen-Knopf,\n" " um Patches zur Liste hinzuzufügen\n" "

\n" " " #, python-format msgid "" "\n" "
\n" " Git Cola has been translated into different languages thanks\n" " to the help of the individuals listed below.\n" "\n" "
\n" "

\n" " Translation is approximate. If you find a mistake,\n" " please let us know by opening an issue on Github:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " We invite you to participate in translation by adding or updating\n" " a translation and opening a pull request.\n" "

\n" "\n" "
\n" "\n" " " msgstr "" "\n" "
\n" " Git Cola wurde Dank der Hilfe unten aufgeführter Leute in\n" " verschiedene Sprachen übersetzt.\n" "\n" "
\n" "

\n" " Übersetzungen sind nur eine Annäherung. Falls Sie einen\n" " Fehler finden, lassen Sie es uns wissen, indem Sie auf\n" " Github einen Fehlerbericht eröffnen:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " Wir laden Sie ein, an einer Übersetzung teilzuhaben, indem\n" " Sie Übersetzungen aktualisieren oder hinzufügen und einen\n" " Pull-Request öffnen.\n" "

\n" "\n" "
\n" "\n" " " #, python-format msgid "" "\n" "
\n" " Git Cola version %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " msgstr "" "\n" "
\n" " Git Cola Version %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " #, python-format msgid "" "\n" "
\n" " Please use %(bug_link)s to report issues.\n" "
\n" " " msgstr "" "\n" "
\n" " Bitte verwenden Sie %(bug_link)s, um Fehler zu melden.\n" "
\n" " " #, python-format msgid "" "\n" " Format String Variables\n" " -----------------------\n" " %(path)s = relative file path\n" " %(abspath)s = absolute file path\n" " %(dirname)s = relative directory path\n" " %(absdirname)s = absolute directory path\n" " %(filename)s = file basename\n" " %(basename)s = file basename without extension\n" " %(ext)s = file extension\n" msgstr "" "\n" " Format-String-Variablen\n" " -----------------------\n" " %(path)s = relativer Dateipfad\n" " %(abspath)s = absoluter Dateipfad\n" " %(dirname)s = relativer Verzeichnispfad\n" " %(absdirname)s = absoluter Verzeichnispfad\n" " %(filename)s = Dateiname\n" " %(basename)s = Dateiname ohne Erweiterung\n" " %(ext)s = Erweiterung\n" msgid "" "\n" "Commands\n" "--------\n" "pick = use commit\n" "reword = use commit, but edit the commit message\n" "edit = use commit, but stop for amending\n" "squash = use commit, but meld into previous commit\n" "fixup = like \"squash\", but discard this commit's log message\n" "exec = run command (the rest of the line) using shell\n" "\n" "These lines can be re-ordered; they are executed from top to bottom.\n" "\n" "If you disable a line here THAT COMMIT WILL BE LOST.\n" "\n" "However, if you disable everything, the rebase will be aborted.\n" "\n" "Keyboard Shortcuts\n" "------------------\n" "? = show help\n" "j = move down\n" "k = move up\n" "J = shift row down\n" "K = shift row up\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "spacebar = toggle enabled\n" "\n" "ctrl+enter = accept changes and rebase\n" "ctrl+q = cancel and abort the rebase\n" "ctrl+d = launch difftool\n" msgstr "" "\n" "Befehle\n" "-------\n" "pick = Commit verwenden\n" "reword = Commit verwenden, aber Commit-Beschreibung bearbeiten\n" "edit = Commit verwenden, aber zum Nachbessern anhalten\n" "squash = Commit verwenden, aber mit vorhergehendem Commit verschmelzen\n" "fixup = wie \"squash\", aber diese Commit-Beschreibung verwerfen\n" "exec = Befehl ausführen (Rest der Zeile) unter Verwendung der Befehlszeile\n" "\n" "Diese Zeilen können neu angeordnet werden; die Ausführung läuft von oben nach unten.\n" "\n" "Wenn Sie eine Zeile deaktivieren, GEHT DER COMMIT VERLOREN.\n" "\n" "Wenn Sie jedoch alles deaktivieren, wird der Rebase abgebrochen.\n" "\n" "Tastaturkürzel\n" "--------------\n" "? = Hilfe anzeigen\n" "j = nach unten gehen\n" "k = nach oben gehen\n" "J = Zeile hoch schieben\n" "K = Zeile runter schieben\n" "\n" "1, p = pick (auswählen/verwenden)\n" "2, r = reword (umformulieren)\n" "3, e = edit (bearbeiten)\n" "4, f = fixup (nachbessern)\n" "5, s = squash (verschmelzen)\n" "spacebar = Aktivierung umschalten\n" "\n" "Strg+Eingabe = Akzeptieren und Rebase starten\n" "Strg+q = Verwerfen und Rebase abbrechen\n" "Strg+d = Diff-Betrachter starten\n" msgid "" "\n" "Keyboard Shortcuts\n" "------------------\n" "J, Down = Move Down\n" "K, Up = Move Up\n" "Enter = Edit Selected Files\n" "Spacebar = Open File Using Default Application\n" "Ctrl + L = Focus Text Entry Field\n" "? = Show Help\n" "\n" "The up and down arrows change focus between the text entry field\n" "and the results.\n" msgstr "" "\n" "Tastaturkürzel\n" "--------------\n" "J, Runter = Nach unten\n" "K, Hoch = Nach oben\n" "Eingabe = Ausgewählte Dateien bearbeiten\n" "Leertaste = Datei mit Standardanwendung öffnen\n" "Strg + L = Texteingabefeld fokussieren\n" "? = Hilfe anzeigen\n" "\n" "Die Pfeile hoch und runter ändern den Fokus zwischen dem\n" "Texteingabefeld und den Ergebnissen.\n" msgid " - DAG" msgstr " - Verlauf" msgid " commits ago" msgstr " Versionen davor" #, python-format msgid "\"%(branch)s\" has been deleted from \"%(remote)s\"." msgstr "\"%(branch)s\" wurde von \"%(remote)s\" gelöscht." #, python-format msgid "\"%(command)s\" returned exit status \"%(status)d\"" msgstr "\"%(command)s\" wurde beendet mit Status \"%(status)d\"" #, python-format msgid "\"%(command)s\" returned exit status %(status)d" msgstr "\"%(command)s\" wurde mit Code %(status)d beendet" #, python-format msgid "\"%s\" already exists" msgstr "\"%s\" existiert bereits" #, python-format msgid "\"%s\" already exists, cola will create a new directory" msgstr "\"%s\" existiert bereits, cola wird ein neues Verzeichnis anlegen" #, python-format msgid "\"%s\" requires a selected file." msgstr "\"%s\" erwartet, dass eine Datei ausgewählt wird." msgid "#" msgstr "#" #, python-format msgid "%(project)s: %(branch)s - Browse" msgstr "%(project)s: %(branch)s - Durchsuchen" #, python-format msgid "%(project)s: %(ref)s - DAG" msgstr "%(project)s: %(ref)s - DAG" #, python-format msgid "%d days ago" msgstr "vor %d Tagen" #, python-format msgid "%d hours ago" msgstr "vor %d Stunden" #, python-format msgid "%d minutes ago" msgstr "vor %d Minuten" #, python-format msgid "%d patch(es) applied." msgstr "%d Patch(es) angewendet." #, python-format msgid "%d skipped" msgstr "%d übersprungen" #, python-format msgid "" "%s appears to contain merge conflicts.\n" "\n" "You should probably skip this file.\n" "Stage it anyways?" msgstr "" "%s scheint Merge-Konflikte zu enthalten.\n" "\n" "Sie sollten diese Datei ggf. überspringen.\n" "Trotzdem vormerken?" #, python-format msgid "%s is not a Git repository." msgstr "%s ist kein Git-Repository." #, python-format msgid "%s will be removed from your bookmarks." msgstr "%s wird von den Favoriten entfernt." #, python-format msgid "%s will be removed from your recent repositories." msgstr "%s wird von den kürzlich verwendeten Repositories entfernt." #, python-format msgid "%s: No such file or directory." msgstr "%s: Datei oder Verzeichnis nicht gefunden." msgid "&Edit" msgstr "Bearbeiten" msgid "&File" msgstr "&Datei" msgid "(Amending)" msgstr "(Nachbesserung)" msgid "*** Branch Point ***" msgstr "*** Branch-Punkt ***" msgid "*** Sandbox ***" msgstr "*** Arbeitsbereich ***" msgid "100%" msgstr "100%" msgid "200%" msgstr "200%" msgid "25%" msgstr "25%" msgid "400%" msgstr "400%" msgid "50%" msgstr "50%" msgid "800%" msgstr "800%" msgid " ..." msgstr " ..." msgid "" "A commit template has not been configured.\n" "Use \"git config\" to define \"commit.template\"\n" "so that it points to a commit template." msgstr "" "Eine Commit-Vorlage wurde noch nicht konfiguriert.\n" "Verwenden Sie \"git config\" um \"commit.template\" so zu definieren,\n" "dass es auf eine Commit-Vorlage zeigt." #, python-format msgid "A hook must be provided at \"%s\"" msgstr "Ein Hook muss bereitgestellt sein für \"%s\"" #, python-format msgid "A stash named \"%s\" already exists" msgstr "Eine Ablage mit dem Namen \"%s\" existiert bereits" msgid "Abort" msgstr "Abbrechen" msgid "Abort Action" msgstr "Befehl abbrechen" msgid "Abort Merge" msgstr "Zusammenführung abbrechen" msgid "Abort Merge..." msgstr "Zusammenführung abbrechen..." msgid "Abort the action?" msgstr "Möchten Sie den Befehl abbrechen?" msgid "" "Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" "Recovering uncommitted changes is not possible." msgstr "" "Abbrechen der gegenwärtigen Zusammenführung bedeutet den Verlust *ALLER* nicht vorgemerkten Änderungen.\n" "Eine Wiederherstellung nicht vorgemerkter Änderungen ist nicht möglich." msgid "Aborting the current merge?" msgstr "Möchten Sie die Zusammenführung abbrechen?" msgid "About" msgstr "Über git-cola" msgid "About git-cola" msgstr "Über git-cola" msgid "Accept" msgstr "Akzeptieren" msgid "" "Accept changes and rebase\n" "Shortcut: Ctrl+Enter" msgstr "" "Änderungen akzeptieren und Rebase starten\n" "Tastenkürzel: Strg+Enter" msgid "Action Name" msgstr "Befehlsname" msgid "Actions" msgstr "Befehle" msgid "Actions..." msgstr "Befehle..." msgid "Add" msgstr "Hinzufügen" msgid "Add Favorite" msgstr "Favorit hinzufügen" msgid "Add Remote" msgstr "Hinzufügen" msgid "Add Separator" msgstr "Trenner hinzufügen" msgid "Add Toolbar" msgstr "Werkzeugleiste hinzufügen" msgid "" "Add and remove remote repositories using the \n" "Add(+) and Delete(-) buttons on the left-hand side.\n" "\n" "Remotes can be renamed by selecting one from the list\n" "and pressing \"enter\", or by double-clicking." msgstr "" "Verwenden Sie die Knöpfe Hinzufügen(+) und Löschen(-) auf der linken\n" "Seite, um externe Repositories zur Liste hinzuzufügen oder zu löschen.\n" "\n" "Externe Referenzen können umbenannt werden, indem Sie sie auswählen\n" "und \"Eingabe\" drücken, oder darauf doppelt klicken." msgid "Add new remote git repository" msgstr "Externes Git-Repository hinzufügen" msgid "Add patches (+)" msgstr "Patches hinzufügen (+)" msgid "Add remote" msgstr "Externe Referenz hinzufügen" msgid "Add to .gitignore" msgstr "Zu .gitignore hinzufügen" msgid "Add to Git Annex" msgstr "Zu Git Annex hinzufügen" msgid "Add to Git LFS" msgstr "Zu Git LFS hinzufügen" msgid "Additions" msgstr "Hinzufügungen" msgid "Advanced" msgstr "Erweitert" msgid "Age" msgstr "Alter" msgid "All Repositories" msgstr "Alle Repositories" #, python-format msgid "" "All submodules will be updated using\n" "\"%s\"" msgstr "" msgid "Allow non-fast-forward updates. Using \"force\" can cause the remote repository to lose commits; use it with care" msgstr "Aktualisierungen ohne schnelles Vorspulen erlauben. Die Nutzung von \"force\" kann dazu führen, dass im externen Repository Commits verloren gehen; seien Sie vorsichtig" msgid "Always create a merge commit when enabled, even when the merge is a fast-forward update" msgstr "Immer einen Merge-Commit erzeugen, selbst wenn schnelles Vorspulen möglich ist" msgid "Amend" msgstr "Ergänzen" msgid "Amend Commit" msgstr "Letzten Commit nachbessern" msgid "Amend Last Commit" msgstr "Letzten Commit nachbessern" msgid "Amend the published commit?" msgstr "Möchten Sie die veröffentlichten Commit nachbessern?" msgid "Amending" msgstr "Am Nachbessern" msgid "" "An action is still running.\n" "Terminating it could result in data loss." msgstr "" "Zurzeit wird noch ein Befehl ausgeführt.\n" "Wenn Sie ihn abbrechen, könnten Daten verloren gehen." msgid "" "An unsigned, lightweight tag will be created instead.\n" "Create an unsigned tag?" msgstr "" "Stattdessen wird ein einfacher, unsignierter Tag erstellt.\n" "Unsignierten Tag erstellen?" msgid "Appearance" msgstr "" msgid "Apply" msgstr "Anwenden" msgid "Apply Patches" msgstr "Patches anwenden" msgid "Apply Patches..." msgstr "Patches anwenden..." msgid "Apply and drop the selected stash (git stash pop)" msgstr "Die ausgewählte Ablage in den Arbeitsbereich zurück übernehmen" msgid "Apply the selected stash" msgstr "Die ausgewählte Ablage in den Arbeitsbereich zurück übernehmen" msgid "Arguments" msgstr "Argumente" msgid "Attach" msgstr "Anhängen" msgid "Author" msgstr "Autor" msgid "Authors" msgstr "Autoren" msgid "Auto" msgstr "" msgid "Auto-Wrap Lines" msgstr "Zeilen automatisch umbrechen" msgid "Basic Regexp" msgstr "Einfacher regulärer Ausdruck" msgid "Blame Viewer" msgstr "Verantwortlichkeitsbetrachter" msgid "Blame selected paths" msgstr "" msgid "Blame..." msgstr "Verantwortlichkeit..." msgid "Bold on dark headers instead of italic" msgstr "Fettschrift mit dunklem Hintergrund verwenden anstelle von schräg geschriebenen Überschriften" msgid "Branch" msgstr "Branch" #, python-format msgid "" "Branch \"%(branch)s\" does not exist in \"%(remote)s\".\n" "A new remote branch will be published." msgstr "" "Der Branch \"%(branch)s\" existiert nicht in \"%(remote)s\".\n" "Ein neuer externer Branch wird veröffentlicht." #, python-format msgid "Branch \"%s\" already exists." msgstr "Der Branch \"%s\" existiert bereits." msgid "Branch Diff Viewer" msgstr "Branch-Diff-Betrachter" msgid "Branch Exists" msgstr "Branch existiert" msgid "Branch Name" msgstr "Branch-Name" #, python-format msgid "Branch: %s" msgstr "Branch: %s" msgid "Branches" msgstr "Branches" msgid "Branches..." msgstr "Branches..." msgid "Brazilian translation" msgstr "Brasilianische Übersetzung" msgid "Browse" msgstr "Ansehen" msgid "Browse Commits..." msgstr "Commits durchsuchen..." msgid "Browse Current Branch..." msgstr "Gegenwärtigen Branch durchsuchen..." msgid "Browse Other Branch..." msgstr "Anderen Branch durchsuchen..." msgid "Browse..." msgstr "..." msgid "Browser" msgstr "Verzeichnisstruktur" #, python-format msgid "Browsing %s" msgstr "Durchsuche %s" msgid "Bypass Commit Hooks" msgstr "Commit-Hooks übergehen" msgid "Cancel" msgstr "Abbrechen" msgid "" "Cancel rebase\n" "Shortcut: Ctrl+Q" msgstr "" "Rebase abbrechen\n" "Tastenkürzel: Strg+Q" msgid "Cannot Amend" msgstr "Fehler beim Ergänzen" #, python-format msgid "Cannot exec \"%s\": please configure a blame viewer" msgstr "Kann \"%s\" nicht ausführen: Bitte Verantwortlichkeiten-Betrachter konfigurieren" #, python-format msgid "Cannot exec \"%s\": please configure a history browser" msgstr "Kann \"%s\" nicht ausführen: Bitte Verlaufsbetrachter konfigurieren" #, python-format msgid "Cannot exec \"%s\": please configure your editor" msgstr "\"%s\" nach nicht ausgeführt werden: Bitte einen Editor konfigurieren" msgid "Changed Upstream" msgstr "In Upstream geändert" msgid "Check Spelling" msgstr "Rechtschreibung prüfen" msgid "Check spelling" msgstr "Rechtschreibung prüfen" msgid "Checkout" msgstr "Umstellen" msgid "Checkout After Creation" msgstr "Umschalten nach Erstellung" msgid "Checkout Branch" msgstr "Zu Branch wechseln" msgid "Checkout Detached HEAD" msgstr "Wechseln zu losgelöstem HEAD" msgid "Checkout as new branch" msgstr "Als neuen Branch erstellen und wechseln" msgid "Checkout..." msgstr "Wechseln..." msgid "Cherry Pick" msgstr "Einzelne Commits übernehmen" msgid "Cherry-Pick Commit" msgstr "Diesen Commit übernehmen" msgid "Cherry-Pick..." msgstr "Einzelnen Commit übernehmen..." msgid "Choose Paths" msgstr "Pfad wählen" msgid "Choose the \"git grep\" regular expression mode" msgstr "Modus für reguläre Ausdrücke für \"git grep\" wählen" msgid "Clear Default Repository" msgstr "Standard-Repository vergessen" msgid "Clear commit message" msgstr "Commit-Beschreibung leeren" msgid "Clear commit message?" msgstr "Commit-Beschreibung leeren?" msgid "Clear..." msgstr "Leeren..." msgid "Clone" msgstr "Klonen" msgid "Clone Repository" msgstr "Repository klonen" msgid "Clone..." msgstr "Klonen..." #, python-format msgid "Cloning repository at %s" msgstr "Klone Repository aus %s" msgid "Close" msgstr "Schließen" msgid "Close..." msgstr "Schließen..." msgid "Collapse all" msgstr "Alle zuklappen" msgid "Command" msgstr "Kommando" msgid "Commit" msgstr "Commit" msgid "Commit failed" msgstr "Commit fehlgeschlagen" msgid "Commit staged changes" msgstr "Vorgemerkte Änderungen aufnehmen" msgid "" "Commit staged changes\n" "Shortcut: Ctrl+Enter" msgstr "" "Vorgemerkte Änderungen aufnehmen\n" "Kürzel: Strg+Enter" msgid "Commit summary" msgstr "Commit-Zusammenfassung" msgid "Commit the merge if there are no conflicts. Uncheck to leave the merge uncommitted" msgstr "Merge eintragen, wenn es keine Konflikte gibt. Haken entfernen, um den Merge offen zu lassen" msgid "Commit@@verb" msgstr "Commit aufnehmen" msgid "Compare" msgstr "Vergleichen" msgid "Compare All" msgstr "Alle vergleichen" msgid "Configure the remote branch as the the new upstream" msgstr "Externen Branch als neuen Upstream konfigurieren" msgid "Configure toolbar" msgstr "Werkzeugleiste konfigurieren" msgid "Console" msgstr "Meldungen" msgid "Continue" msgstr "Fortsetzen" msgid "Copy" msgstr "Kopieren" msgid "Copy Basename to Clipboard" msgstr "Dateiname in Zwischenablage kopieren" msgid "Copy Leading Path to Clipboard" msgstr "Führenden Pfad in Zwischenablage kopieren" msgid "Copy Path to Clipboard" msgstr "Kopiere Pfad in Zwischenablage" msgid "Copy Relative Path to Clipboard" msgstr "Relativen Pfad in Zwischenablage kopieren" msgid "Copy SHA-1" msgstr "SHA-1 kopieren" msgid "Copy..." msgstr "Kopieren..." #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "URL konnte nicht ausgewertet werden: \"%s\"" msgid "Create Branch" msgstr "Branch erstellen" msgid "Create Patch" msgstr "Patch erstellen" msgid "Create Remote Branch" msgstr "Externen Branch erstellen" msgid "Create Signed Commit" msgstr "Unterzeichneten Commit erstellen" msgid "Create Tag" msgstr "Tag erstellen" msgid "Create Tag..." msgstr "Tag erstellen..." msgid "Create Unsigned Tag" msgstr "Unsignierten Tag erstellen" msgid "Create a merge commit even when the merge resolves as a fast-forward" msgstr "Merge-Commit erstellen, selbst wenn der Merge mit schnellem Vorspulen auflösbar ist" msgid "Create a new remote branch?" msgstr "Neuen externen Branch erstellen?" msgid "Create..." msgstr "Neu..." #, python-format msgid "Created a new tag named \"%s\"" msgstr "Tag erstellt als \"%s\"" msgid "Current Repository" msgstr "Gegenwärtiges Repository" msgid "Custom Copy Actions" msgstr "Benutzerdefinierte Kopier-Befehle" msgid "Customize..." msgstr "Anpassen..." msgid "Cut" msgstr "Ausschneiden" msgid "Czech translation" msgstr "Tschechische Übersetzung" msgid "DAG..." msgstr "DAG..." msgid "Dark Theme" msgstr "" msgid "Date, Time" msgstr "Datum und Zeit" msgid "Default" msgstr "" msgid "Delete" msgstr "Löschen" #, python-format msgid "Delete %d file(s)?" msgstr "Wollen Sie %d Datei(en) löschen?" msgid "Delete Bookmark" msgstr "Favoriten löschen" msgid "Delete Bookmark?" msgstr "Favorit löschen?" msgid "Delete Branch" msgstr "Branch löschen" msgid "Delete Files" msgstr "Lösche Dateien" msgid "Delete Files..." msgstr "Lösche Datei(en)..." msgid "Delete Files?" msgstr "Datei(en) löschen?" msgid "Delete Remote" msgstr "Externe Referenz löschen" msgid "Delete Remote Branch" msgstr "Externen Branch löschen" msgid "Delete Remote Branch..." msgstr "Externen Branch löschen..." msgid "Delete remote" msgstr "Externe Referenz löschen" #, python-format msgid "Delete remote \"%s\"" msgstr "Externe Referenz \"%s\" löschen" msgid "Delete remote?" msgstr "Externe Referenz löschen?" msgid "Delete selected branch?" msgstr "Gewählten Branch löschen?" msgid "Delete toolbar" msgstr "Werkzeugleiste löschen" msgid "Delete..." msgstr "Löschen..." #, python-format msgid "Deleting \"%s\" failed" msgstr "Löschen von \"%s\" fehlgeschlagen" msgid "Deletions" msgstr "Löschungen" msgid "Detach" msgstr "Loslösen" msgid "Detect Conflict Markers" msgstr "Konflikt-Markierungen erkennen" msgid "Detect conflict markers in unmerged files" msgstr "Konflikt-Markierungen in nicht zusammengeführten Dateien erkennen" msgid "Developer" msgstr "Entwickler" msgid "Diff" msgstr "Vergleich" msgid "Diff Against Predecessor..." msgstr "Mit einem Vorgänger vergleichen..." msgid "Diff Options" msgstr "Vergleichsoptionen" msgid "Diff Tool" msgstr "Werkzeug zum Dateivergleich" msgid "Diff selected -> this" msgstr "Auswahl mit diesem vergleichen" msgid "Diff this -> selected" msgstr "Mit Auswahl vergleichen" msgid "Diffstat" msgstr "Vergleichsstatistik" msgid "Difftool" msgstr "Diff-Werkzeug" msgid "Directory Exists" msgstr "Verzeichnis existiert" msgid "Display Untracked Files" msgstr "Nicht verfolgte Dateien anzeigen" msgid "Documentation" msgstr "Online-Hilfe" msgid "Drop" msgstr "Löschen" msgid "Drop Stash" msgstr "Ablage löschen" msgid "Drop Stash?" msgstr "Möchten Sie die Ablage löschen?" #, python-format msgid "Drop the \"%s\" stash?" msgstr "Möchten Sie die Ablage \"%s\" löschen?" msgid "Drop the selected stash" msgstr "Die ausgewählte Ablage löschen" msgid "Edit" msgstr "Bearbeiten" msgid "Edit Rebase" msgstr "Rebase bearbeiten" msgid "Edit Remotes" msgstr "Externe Referenzen bearbeiten" msgid "Edit Remotes..." msgstr "Externe Referenzen bearbeiten..." msgid "Edit remotes by selecting them from the list" msgstr "Bearbeiten Sie externe Referenzen, indem Sie sie in der Liste auswählen" msgid "Edit selected paths" msgstr "Ausgewählten Pfad bearbeiten" msgid "Edit..." msgstr "Bearbeiten..." msgid "Editor" msgstr "Editor" msgid "Email Address" msgstr "E-Mail-Adresse" msgid "Email contributor" msgstr "E-Mail an Beitragenden" msgid "Enabled" msgstr "Aktiviert" msgid "Enter New Branch Name" msgstr "Namen für neuen Branch vergeben" msgid "Enter a name for the new bare repo" msgstr "Namen für neues kahles Repository" msgid "Enter a name for the stash" msgstr "Geben Sie einen Namen für die Ablage an" msgid "Error" msgstr "Fehler" msgid "Error Cloning" msgstr "Fehler beim Klonen" msgid "Error Creating Branch" msgstr "Fehler beim Erstellen des Branches" msgid "Error Creating Repository" msgstr "Fehler beim Anlegen des Repositories" msgid "Error Deleting Remote Branch" msgstr "Fehler beim Löschen des externen Branches" msgid "Error Editing File" msgstr "Fehler beim Bearbeiten der Datei" msgid "Error Launching Blame Viewer" msgstr "Fehler beim Starten der Verantwortlichkeitansicht" msgid "Error Launching History Browser" msgstr "Fehler beim Starten der Verlaufsansicht" #, python-format msgid "Error creating remote \"%s\"" msgstr "Fehler beim erstellen der externen Referenz \"%s\"" msgid "Error creating stash" msgstr "Fehler beim Erstellen der Ablage" #, python-format msgid "Error deleting remote \"%s\"" msgstr "Fehler beim Löschen der externen Referenz \"%s\"" #, python-format msgid "Error renaming \"%(name)s\" to \"%(new_name)s\"" msgstr "Fehler beim Umbenennen von \"%(name)s\" in \"%(new_name)s\"" msgid "Error running prepare-commitmsg hook" msgstr "Fehler beim Aufrufen der Vor-Eintragen-Kontrolle" #, python-format msgid "Error updating submodule %s" msgstr "" msgid "Error updating submodules" msgstr "" msgid "Error: Cannot find commit template" msgstr "Fehler: Commit-Vorlage nicht gefunden" msgid "Error: Stash exists" msgstr "Fehler: Diese Ablage existiert bereits" msgid "Error: Unconfigured commit template" msgstr "Fehler: Commit-Textvorlage nicht konfiguriert" #, python-format msgid "Error: could not clone \"%s\"" msgstr "Fehler: Konnte \"%s\" nicht klonen" #, python-format msgid "Error: could not create tag \"%s\"" msgstr "Fehler: Konnte Tag \"%s\" nicht erstellen" #, python-format msgid "Executing action %s" msgstr "Ausführen von Aktion %s" msgid "Expand all" msgstr "Alles ausklappen" msgid "Export Patches" msgstr "Patches exportieren" msgid "Export Patches..." msgstr "Patches exportieren..." msgid "Expression..." msgstr "Mit Suchausdruck..." msgid "Extended Regexp" msgstr "Erweiterte reguläre Ausdrücke" msgid "Extended description..." msgstr "Ausführliche Beschreibung..." msgid "Fast Forward Only" msgstr "Bei lokalen Änderungen abbrechen" msgid "Fast-forward only" msgstr "Nur schnelles Vorspulen" msgid "Favorite repositories" msgstr "Repository-Favoriten" msgid "Favorites" msgstr "Favoriten" msgid "Fetch" msgstr "Holen" msgid "Fetch Tracking Branch" msgstr "Verfolgten Branch holen" msgid "Fetch..." msgstr "Holen..." msgid "File Browser..." msgstr "Dateien durchsuchen..." msgid "File Differences" msgstr "Dateiunterschiede" msgid "File Saved" msgstr "Datei gespeichert" #, python-format msgid "File saved to \"%s\"" msgstr "Datei gespeichert als \"%s\"" msgid "File system change monitoring: disabled because \"cola.inotify\" is false.\n" msgstr "Benachrichtigung über Änderungen im Dateisystem: deaktiviert, da \"cola.inotify\" auf falsche gesetzt ist.\n" msgid "File system change monitoring: disabled because libc does not support the inotify system calls.\n" msgstr "Überwachung von Dateisystemänderungen: deaktiviert, da libc die entsprechenden Systemaufrufe nicht unterstützt.\n" msgid "File system change monitoring: disabled because pywin32 is not installed.\n" msgstr "Überwachung von Dateisystemänderungen: deaktiviert, da pywin32 nicht installiert ist.\n" msgid "" "File system change monitoring: disabled because the limit on the total number of inotify watches was reached. You may be able to increase the limit on the number of watches by running:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" msgstr "" "Überwachung von Dateisystemänderungen: deaktiviert, da die Obergrenze an Überwachungen erreicht wurde. Sie können versuchen, die Obergrenze dafür anzuheben, indem Sie folgendes ausführen:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" "\n" msgid "File system change monitoring: enabled.\n" msgstr "Benachrichtigungen über Änderungen im Dateisystem: aktiviert.\n" msgid "Filename" msgstr "Dateiname" msgid "Files" msgstr "Dateien" msgid "Filter branches..." msgstr "Branches filtern..." msgid "Filter paths..." msgstr "Pfade filtern..." msgid "Find Files" msgstr "Dateien suchen" msgid "Fixed String" msgstr "Feste Zeichenkette" msgid "Fixed-Width Font" msgstr "Schriftart" msgid "Fixup" msgstr "Nachbessern (fixup)" msgid "Fixup Previous Commit" msgstr "Vorherigen Commit nachbessern (fixup)" msgid "Flat dark blue" msgstr "" msgid "Flat dark green" msgstr "" msgid "Flat dark grey" msgstr "" msgid "Flat dark red" msgstr "" msgid "Flat light blue" msgstr "" msgid "Flat light green" msgstr "" msgid "Flat light grey" msgstr "" msgid "Flat light red" msgstr "" msgid "Font Size" msgstr "Schriftgröße" msgid "Force" msgstr "Erzwingen" msgid "Force Fetch" msgstr "Abruf erzwingen" msgid "Force Fetch?" msgstr "Möchten Sie den Abruf erzwingen?" msgid "Force Push" msgstr "Veröffentlichung erzwingen" msgid "Force Push?" msgstr "Möchten Sie die Veröffentlichung erzwingen?" #, python-format msgid "Force fetching from %s?" msgstr "Möchten Sie den Abruf von \"%s\" erzwingen?" #, python-format msgid "Force push to %s?" msgstr "Möchten Sie die Veröffentlichung in \"%s\" erzwingen?" msgid "Format String" msgstr "Format-String" msgid "French translation" msgstr "Französische Übersetzung" msgid "GPG-sign the merge commit" msgstr "GPG-signierter Merge-Commit" msgid "GUI theme" msgstr "" #, python-format msgid "Gathering info for \"%s\"..." msgstr "Frage Informationen zu »%s« ab..." msgid "German translation" msgstr "Deutsche Übersetzung" msgid "Get Commit Message Template" msgstr "Commit-Beschreibung aus Vorlage einfügen" msgid "Go Down" msgstr "Nach unten" msgid "Go Up" msgstr "Nach oben" msgid "Grab File..." msgstr "Datei extrahieren..." msgid "Graph" msgstr "Diagramm" msgid "Grep" msgstr "Grep" msgid "Have you rebased/pulled lately?" msgstr "Haben Sie kürzlich einen Rebase oder Pull durchgeführt?" msgid "Help" msgstr "Hilfe" msgid "Help - Custom Copy Actions" msgstr "Hilfe - Benutzerdefinierte Kopier-Befehle" msgid "Help - Find Files" msgstr "Hilfe - Dateien suchen" msgid "Help - git-xbase" msgstr "Hilfe - git-xbase" msgid "Hide Details.." msgstr "" msgid "High DPI" msgstr "" msgid "History Browser" msgstr "Werkzeug für die Verlaufsansicht" msgid "Hungarian translation" msgstr "Ungarische Übersetzung" msgid "Icon theme" msgstr "" msgid "Ignore all whitespace" msgstr "Alle Leerzeichen ignorieren" msgid "Ignore changes in amount of whitespace" msgstr "Anzahl von Leerzeichen ignorieren" msgid "Ignore changes in whitespace at EOL" msgstr "Leerzeichen am Zeilenende ignorieren" msgid "Ignore custom pattern" msgstr "Benutzerdefiniertes Muster ignorieren" msgid "Ignore exact filename" msgstr "Exakten Dateinamen ignorieren" msgid "Ignore filename or pattern" msgstr "Dateiname oder Muster ignorieren" msgid "Include tags " msgstr "Übernehmen der Tags " msgid "Indent Status paths" msgstr "" msgid "Indonesian translation" msgstr "Indonesische Übersetzung" msgid "Initialize Git Annex" msgstr "Git Annex intialisieren" msgid "Initialize Git LFS" msgstr "Git LFS initialisieren" msgid "Inititalize submodules" msgstr "Submodule initialisieren" msgid "Insert spaces instead of tabs" msgstr "Leerzeichen statt Tabs einfügen" msgid "Interactive Rebase" msgstr "Interaktiver Rebase" msgid "Invalid Revision" msgstr "Unzulässige Revision" msgid "Keep *.orig Merge Backups" msgstr "Sicherheitskopie beim Zusammenführen anlegen (Datei.orig)" msgid "Keep Index" msgstr "Vormerkliste unverändert lassen" msgid "Keyboard Shortcuts" msgstr "Tastenkürzel" msgid "Launch Diff Tool" msgstr "Mit direktem Vorgänger vergleichen" msgid "Launch Directory Diff Tool" msgstr "Werkzeug für Verzeichnis-Diff ausführen" msgid "Launch Editor" msgstr "Mit Editor bearbeiten" msgid "Launch Terminal" msgstr "Konsole starten" msgid "" "Launch external diff tool\n" "Shortcut: Ctrl+D" msgstr "" "Externen Diff-Betrachter starten\n" "Kürzel: Strg+D" msgid "Launch git-cola" msgstr "Starte git-cola" msgid "Launch git-difftool against previous versions" msgstr "Git-difftool gegen Vorversionen ausführen" msgid "Launch git-difftool on the current path" msgstr "Gegenwärtigen Pfad im Vergleichswerkzeug öffnen" msgid "Light Theme" msgstr "" msgid "Load Commit Message" msgstr "Commit-Beschreibung laden" msgid "Load Commit Message..." msgstr "Commit-Beschreibung laden..." msgid "Load Previous Commit Message" msgstr "Vorherige Commit-Beschreibung laden" msgid "Loading..." msgstr "Lade..." msgid "Local" msgstr "Lokal" msgid "Local Branch" msgstr "Lokaler Branch" msgid "Local branch" msgstr "Lokalem Branch" msgid "Lock Layout" msgstr "Layout sperren" msgid "Log" msgstr "Log" msgid "Maintainer (since 2007) and developer" msgstr "Pflege (seit 2007) und Entwicklung" msgid "Merge" msgstr "Zusammenführen" #, python-format msgid "Merge \"%(revision)s\" into \"%(branch)s\"" msgstr "\"%(revision)s\" in \"%(branch)s\" zusammenführen" msgid "Merge Tool" msgstr "Werkzeug zum Zusammenführen" msgid "Merge Verbosity" msgstr "Ausführlichkeit der Meldungen beim Zusammenführen" msgid "Merge failed. Conflict resolution is required." msgstr "Zusammenführen fehlgeschlagen. Konfliktauflösung ist notwendig." #, python-format msgid "Merge into \"%s\"" msgstr "Zusammenführen in »%s«" msgid "Merge into current branch" msgstr "In gegenwärtigen Branch zusammenführen" msgid "Merge..." msgstr "Zusammenführen..." msgid "Merging" msgstr "Am Zusammenführen" msgid "Message" msgstr "Beschreibung" msgid "Missing Commit Message" msgstr "Die Commit-Beschreibung fehlt" msgid "Missing Data" msgstr "Fehlende Daten" msgid "Missing Name" msgstr "Fehlender Name" msgid "Missing Revision" msgstr "Revision fehlt" msgid "Missing Tag Message" msgstr "Tag-Beschreibung fehlt" msgid "Modified" msgstr "Geändert" msgid "More..." msgstr "Mehr..." msgid "Move Down" msgstr "Nach unten bewegen" msgid "Move Up" msgstr "Nach oben bewegen" msgid "Move files to trash" msgstr "Dateien in den Papierkorb schieben" msgid "Name" msgstr "Name" msgid "Name for the new remote" msgstr "Name der neuen externen Referenz" msgid "New Bare Repository..." msgstr "Neues kahles Repository..." msgid "New Repository..." msgstr "Neues Repository..." msgid "New..." msgstr "Neu..." msgid "Next File" msgstr "Nächste Datei" msgid "No" msgstr "Nein" msgid "No Revision Specified" msgstr "Keine Revision angegeben" msgid "" "No changes to commit.\n" "\n" "You must stage at least 1 file before you can commit." msgstr "" "Nichts für einen Commit vorhanden.\n" "\n" "Merken Sie mindestens eine Datei für einen Commit vor." msgid "No commits exist in this branch." msgstr "In diesem Branch gibt es keine Commits." msgid "No fast forward" msgstr "Kein schnelles Vorspulen" msgid "No fast-forward" msgstr "Kein schnelles Vorspulen" msgid "No repository selected." msgstr "Kein Repository ausgewählt." msgid "Non-fast-forward fetch overwrites local history!" msgstr "Holen ohne schnelles Vorspulen überschreibt den lokalen Verlauf!" msgid "" "Non-fast-forward push overwrites published history!\n" "(Did you pull first?)" msgstr "Versenden ohne schnelles Vorspulen überschreibt den veröffentlichten Verlauf! (Haben Sie zuvor Änderungen geholt und zusammengeführt?)" msgid "Nothing to commit" msgstr "Nichts für einen Commit vorhanden" msgid "Nothing to do" msgstr "Nichts zu tun" msgid "Number of Diff Context Lines" msgstr "Anzahl der Kontextzeilen beim Vergleich" msgid "Open" msgstr "Öffnen" msgid "Open Git Repository..." msgstr "Git-Repository öffnen..." msgid "Open Parent" msgstr "" msgid "Open Parent Directory" msgstr "Übergeordnetes Verzeichnis öffnen" msgid "Open Recent" msgstr "Zuletzt verwendet" msgid "Open Using Default Application" msgstr "Mit der Standardanwendung öffnen" msgid "Open in New Window" msgstr "In neuem Fenster öffnen" msgid "Open in New Window..." msgstr "In neuem Fenster öffnen..." msgid "Open..." msgstr "Öffnen..." msgid "Other branches" msgstr "Andere Branches" msgid "Overwrite" msgstr "Überschreiben" #, python-format msgid "Overwrite \"%s\"?" msgstr "Möchten Sie die Datei\"%s\" überschreiben?" msgid "Overwrite File?" msgstr "Möchten Sie die Datei überschreiben?" msgid "" "Parse arguments using a shell.\n" "Queries with spaces will require \"double quotes\"." msgstr "" "Führt die Suche in einer Kommandozeile aus.\n" "Setzen Sie Texte mit Leerzeichen in \"Gänsefüßchen\"." msgid "Partially Staged" msgstr "Teilweise vorgemerkt" msgid "Paste" msgstr "Einfügen" msgid "Patch(es) Applied" msgstr "Patch(es) angewendet" msgid "Path" msgstr "Pfad" msgid "Path or URL to clone (Env. $VARS okay)" msgstr "Quell-Pfad oder -URL" msgid "Pick" msgstr "Übernehmen" msgid "Pixel XOR" msgstr "Pixel-XOR" msgid "Please provide both a branch name and revision expression." msgstr "Bitte geben Sie beides, einen Branch-Namen und Revisionsausdruck, an." msgid "Please select a file" msgstr "Bitte wählen Sie eine Datei" msgid "Please specify a name for the new tag." msgstr "Bitte geben Sie einen Namen für den neuen Tag an." msgid "Please specify a revision to tag." msgstr "Bitte geben Sie eine Revision für den Tag an." msgid "" "Please supply a commit message.\n" "\n" "A good commit message has the following format:\n" "\n" "- First line: Describe in one sentence what you did.\n" "- Second line: Blank\n" "- Remaining lines: Describe why this change is good.\n" msgstr "" "Bitte geben Sie eine Commit-Beschreibung ein.\n" "\n" "Eine gute Commit-Beschreibung enthält folgende Abschnitte:\n" "\n" "- Erste Zeile: Zusammenfassung in einem Satz, was gemacht wurde\n" "- Zweite Zeile: Leerzeile\n" "- Rest: Ausführliche Beschreibung, warum diese Änderung hilfreich ist\n" msgid "Point the current branch head to a new commit?" msgstr "Soll der Branch-Head auf einen neuen Commit zeigen?" msgid "Polish translation" msgstr "Polnische Übersetzung" msgid "Pop" msgstr "" msgid "Preferences" msgstr "Einstellungen" msgid "Prefix" msgstr "Verzeichnis" msgid "Prepare Commit Message" msgstr "Commit-Beschreibung vorbereiten" msgid "Prevent \"Stage\" from staging all files when nothing is selected" msgstr "Bei \"Vormerken\" verhindern, dass alle Dateien vorgemerkt werden, wenn nichts ausgewählt wurde" msgid "Previous File" msgstr "Vorige Datei" msgid "Prompt on creation" msgstr "Beim Erstellen nachfragen" msgid "Prompt when pushing creates new remote branches" msgstr "Bestätigen, falls das Versenden neue Remote-Branches erzeugt" msgid "Prune " msgstr "Aufräumen von " msgid "Pull" msgstr "Holen und zusammenführen" msgid "Pull..." msgstr "Holen und zusammenführen..." msgid "Push" msgstr "Veröffentlichen" msgid "Push..." msgstr "Veröffentlichen..." msgid "Quit" msgstr "Beenden" msgid "Rebase" msgstr "Rebase" #, python-format msgid "Rebase onto %s" msgstr "Rebase auf %s" msgid "Rebase stopped" msgstr "Rebase angehalten" msgid "Rebase the current branch instead of merging" msgstr "Rebase statt Merge für gegenwärtigen Branch durchführen" msgid "Rebasing" msgstr "Rebase im Gange" msgid "Recent" msgstr "Kürzlich" msgid "Recent repositories" msgstr "Kürzlich verwendete Repositories" msgid "Recent repository count" msgstr "Anzahl zuletzt verwendeter Repositories" msgid "Recently Modified Files" msgstr "Kürzlich geänderte Dateien suchen" msgid "Recently Modified Files..." msgstr "Kürzlich geänderte Dateien suchen..." msgid "Recovering a dropped stash is not possible." msgstr "Eine gelöschte Ablage kann nicht wiederhergestellt werden." msgid "Recovering lost commits may not be easy." msgstr "Ein Wiederherstellen verlorener Commits könnte schwierig sein." msgid "Redo" msgstr "Wiederholen" msgid "Reduce commit history to minimum" msgstr "Commit-Verlauf auf ein Minimum reduzieren" msgid "Refresh" msgstr "Ansicht aktualisieren" msgid "Refuse to merge unless the current HEAD is already up-to-date or the merge can be resolved as a fast-forward" msgstr "Merge verweigern, außer der gegenwärtige HEAD ist aktuell oder der Merge kann mit schnellem Vorspulen ausgelöst werden" msgid "Remote" msgstr "Externe Referenz" msgid "Remote Branch" msgstr "Externer Branch" msgid "Remote Branch Deleted" msgstr "Externer Branch gelöscht" msgid "Remote git repositories - double-click to rename" msgstr "Externes Git-Repository - Doppelklick zum Umbenennen" msgid "Remove" msgstr "Entfernen" #, python-format msgid "Remove %s from the recent list?" msgstr "%s aus dem Verlauf entfernen?" msgid "Remove Element" msgstr "Element entfernen" msgid "Remove remote-tracking branches that no longer exist on the remote" msgstr "" msgid "Remove selected (Delete)" msgstr "Auswahl entfernen (löschen)" msgid "Rename" msgstr "Umbenennen" #, python-format msgid "Rename \"%s\"" msgstr "\"%s\" umbenennen" msgid "Rename Branch" msgstr "Branch umbenennen" msgid "Rename Branch..." msgstr "Branch umbenennen..." msgid "Rename Existing Branch" msgstr "Existierenden Branch umbenennen" msgid "Rename Remote" msgstr "Externe Referenz umbenennen" msgid "Rename Repository" msgstr "Repository umbenennen" msgid "Rename branch" msgstr "Branch umbenennen" #, python-format msgid "Rename remote \"%(current)s\" to \"%(new)s\"?" msgstr "Externe Referenz \"%(current)s\" umbenennen zu \"%(new)s\"?" msgid "Rename selected paths" msgstr "Ausgewählten Pfad umbenennen" #, python-format msgid "Repository: %s" msgstr "Repository: %s" msgid "Reset" msgstr "Zurücksetzen" #, python-format msgid "Reset \"%(branch)s\" to \"%(revision)s\"?" msgstr "Möchten Sie \"%(branch)s\" auf \"%(revision)s\" zurücksetzen?" msgid "Reset Branch" msgstr "Branch zurücksetzen" msgid "Reset Branch Head" msgstr "Branch-Head zurücksetzen" msgid "Reset Branch?" msgstr "Branch zurücksetzen?" msgid "Reset Hard" msgstr "" msgid "Reset Merge" msgstr "" msgid "Reset Soft" msgstr "" msgid "Reset Worktree" msgstr "Arbeitsbaum zurücksetzen" msgid "Reset hard?" msgstr "" msgid "Reset merge?" msgstr "" msgid "Reset soft?" msgstr "" msgid "Reset worktree?" msgstr "Arbeitsbaum zurücksetzen?" #, python-format msgid "Resetting \"%(branch)s\" to \"%(revision)s\" will lose commits." msgstr "Das Zurücksetzen von \"%(branch)s\" nach \"%(revision)s\" verwirft Commits." msgid "Restart the application after changing appearance settings." msgstr "" msgid "Revert" msgstr "" msgid "Revert Diff Hunk" msgstr "Abschnitt verwerfen" msgid "Revert Diff Hunk..." msgstr "Abschnitt verwerfen..." msgid "Revert Diff Hunk?" msgstr "Möchten Sie den Abschnitt verwerfen?" msgid "Revert Selected Lines" msgstr "Änderungen an den ausgewählten Zeilen verwerfen" msgid "Revert Selected Lines..." msgstr "Ausgewählte Zeilen wiederherstellen..." msgid "Revert Selected Lines?" msgstr "Möchten Sie die Änderungen an den ausgewählten Zeilen verwerfen?" msgid "Revert Uncommitted Changes" msgstr "Nicht vorgemerkte Änderungen verwerfen" msgid "Revert Uncommitted Changes?" msgstr "Möchten Sie die Änderungen verwerfen?" msgid "Revert Uncommitted Edits..." msgstr "Nicht vorgemerkte Änderungen verwerfen..." msgid "Revert Unstaged Changes" msgstr "Nehme nicht vorgemerkte Änderungen zurück" msgid "Revert Unstaged Changes?" msgstr "Wollen sie die nicht vorgemerkten Änderungen zurücknehmen?" msgid "Revert Unstaged Edits..." msgstr "Nicht vorgemerkte Änderungen zurücknehmen..." msgid "Revert the uncommitted changes?" msgstr "Möchten Sie die nicht vorgemerkten Änderungen verwerfen?" msgid "Revert the unstaged changes?" msgstr "Möchten Sie die nicht vorgemerkten Änderungen zurücknehmen?" msgid "Revert uncommitted changes to selected paths" msgstr "Änderungen an ausgewählten Pfaden verwerfen" msgid "Revert unstaged changes to selected paths" msgstr "Änderungen an ausgewählten Pfaden verwerfen" msgid "Review" msgstr "Vergleichen" msgid "Review..." msgstr "Review..." msgid "Revision" msgstr "Version" msgid "Revision Expression:" msgstr "Revisionsausdruck:" msgid "Revision to Merge" msgstr "Zusammenzuführende Revision" msgid "Reword" msgstr "Umformulieren" msgid "Rewrite Published Commit?" msgstr "Veröffentlichten Commit umschreiben?" msgid "Run" msgstr "Ausführen" #, python-format msgid "Run \"%s\"?" msgstr "Möchten Sie \"%s\" ausführen?" #, python-format msgid "Run %s?" msgstr "Möchten Sie \"%s\" ausführen?" #, python-format msgid "Run the \"%s\" command?" msgstr "Möchten Sie den Befehl \"%s\" ausführen?" #, python-format msgid "Running command: %s" msgstr "Führe Befehl \"%s\" aus" msgid "Russian translation" msgstr "Russische Übersetzung" msgid "SHA-1" msgstr "SHA-1" msgid "Safe Mode" msgstr "Abgesicherter Modus" msgid "Save" msgstr "Speichern" msgid "Save Archive" msgstr "Als TAR- oder ZIP-Archiv exportieren" msgid "Save As Tarball/Zip..." msgstr "Als TAR- oder ZIP-Archiv exportieren..." msgid "Save GUI Settings" msgstr "Einstellungen der Programmoberfläche sichern" msgid "Save Stash" msgstr "Ablage speichern" msgid "Save modified state to new stash" msgstr "Änderungen in einer neuen Ablage speichern" #, python-format msgid "Saved \"%(filename)s\" from \"%(ref)s\" to \"%(destination)s\"" msgstr "\"%(filename)s\" von \"%(ref)s\" in \"%(destination)s\" gespeichert" msgid "Search" msgstr "Suchen" msgid "Search Authors" msgstr "Autor" msgid "Search Commit Messages" msgstr "Commit-Beschreibungen durchsuchen" msgid "Search Committers" msgstr "Eintragender" msgid "Search Date Range" msgstr "Datum von-bis" msgid "Search Diffs" msgstr "Dateiunterschiede durchsuchen" msgid "Search by Expression" msgstr "Regulärer Ausdruck" msgid "Search by Path" msgstr "Datei" msgid "Search for a fixed string" msgstr "Nach einer festen Zeichenkette suchen" msgid "Search using a POSIX basic regular expression" msgstr "Suche mit einer einfachen POSIX Regular Expression durchführen" msgid "Search using a POSIX extended regular expression" msgstr "Suche mit einer erweiterten POSIX Regular Expression durchführen" msgid "Search..." msgstr "Suchen..." msgid "Select" msgstr "Auswählen" msgid "Select All" msgstr "Alle auswählen" msgid "Select Branch to Review" msgstr "Branch für Review auswählen" msgid "Select Child" msgstr "Nachfolger auswählen" msgid "Select Commit" msgstr "Wählen Sie einen Commit aus" msgid "Select Directory..." msgstr "Verzeichnis wählen..." msgid "Select New Upstream" msgstr "Neuen Upstream auswählen" msgid "Select Newest Child" msgstr "Jüngsten Nachfolger auswählen" msgid "Select Oldest Parent" msgstr "Ältesten Vorgänger auswählen" msgid "Select Parent" msgstr "Vorgänger Auswählen" msgid "Select Previous Version" msgstr "Vorherige Version auswählen" msgid "Select Repository..." msgstr "Repository wählen..." msgid "Select a parent directory for the new clone" msgstr "Wählen Sie das übergeordnete Verzeichnis für den Klon" msgid "Select manually..." msgstr "Selbst auswählen..." msgid "Select output dir" msgstr "Ausgabe-Verzeichnis wählen" msgid "Select output directory" msgstr "Ausgabe-Verzeichnis wählen" msgid "Select patch file(s)..." msgstr "Patch-Datei(en) wählen..." msgid "Select repository" msgstr "Repository wählen" msgid "Set Default Repository" msgstr "Standard-Repository auswählen" msgid "Set Upstream Branch" msgstr "Upstream-Branch setzen" msgid "" "Set the sort order for branches and tags.\n" "Toggle between date-based and version-name-based sorting." msgstr "" msgid "Set upstream" msgstr "Neuen Upstream setzen" msgid "Settings" msgstr "Allgemein" msgid "Shell arguments" msgstr "Als Kommandozeilenargumente" msgid "Shift Down" msgstr "Nach unten schieben" msgid "Shift Up" msgstr "Nach oben schieben" msgid "Shortcuts" msgstr "Tastenkürzel" msgid "Show Details..." msgstr "" msgid "Show Diffstat After Merge" msgstr "Vergleichsstatistik nach Zusammenführen anzeigen" msgid "Show Full Paths in the Window Title" msgstr "Vollständige Pfade in Fenstertiteln zeigen" msgid "Show Help" msgstr "Hilfe anzeigen" msgid "Show History" msgstr "Verlauf anzeigen" msgid "Show file counts in Status titles" msgstr "" msgid "" "Show help\n" "Shortcut: ?" msgstr "" "Hilfe anzeigen\n" "Kurzwahl: ?" msgid "Show icon? (if available)" msgstr "Symbol anzeigen? (falls verfügbar)" msgid "Show line numbers" msgstr "Zeilennummern anzeigen" msgid "Show whole surrounding functions of changes" msgstr "Gesamte übergeordnete Funktion anzeigen" msgid "Showing changes since" msgstr "Änderungen seit" msgid "Side by side" msgstr "Nebeneinander" msgid "Sign Off" msgstr "Abzeichnen" msgid "Sign Tag" msgstr "Tag unterzeichnen" msgid "Sign off on this commit" msgstr "Diesen Commit abzeichnen" msgid "Simplified Chinese translation" msgstr "Vereinfachte Chinesische Übersetzung" msgid "Skip" msgstr "Überspringen" msgid "Skip Current Patch" msgstr "Gegenwärtigen Patch überspringen" msgid "Sort bookmarks alphabetically" msgstr "Lesezeichen alphabetisch sortieren" msgid "Spanish translation" msgstr "Spanische Übersetzung" msgid "Specifies the SHA-1 to tag" msgstr "Legt den zu taggenden SHA-1 fest" msgid "Specifies the tag message" msgstr "Legt die Tag-Beschreibung fest" msgid "Specifies the tag name" msgstr "Legt den Namen des Tags fest" msgid "Spelling Suggestions" msgstr "Rechtschreibvorschläge" msgid "Squash" msgstr "Verschmelzen" msgid "Squash the merged commits into a single commit" msgstr "Zusammengeführte Commits in einzelnen Commit vereinen" msgid "Stage" msgstr "Änderung vormerken" msgid "Stage / Unstage" msgstr "Vormerken/Nicht vormerken" msgid "Stage All Untracked" msgstr "Alle neuen Dateien vormerken" msgid "Stage Changed Files To Commit" msgstr "Geänderte Dateien vormerken" msgid "Stage Diff Hunk" msgstr "Änderungen am Abschnitt vormerken" msgid "Stage Modified" msgstr "Vermerke Änderung" msgid "Stage Selected" msgstr "Auswahl vormerken" msgid "Stage Selected Lines" msgstr "Änderungen an ausgewählten Zeilen vormerken" msgid "Stage Unmerged" msgstr "Nicht zusammengeführte Dateien vormerken" msgid "Stage Untracked" msgstr "Neue Dateien vormerken" msgid "Stage and Commit" msgstr "Vormerken und eintragen" msgid "Stage and commit?" msgstr "Vormerken und eintragen?" msgid "Stage conflicts" msgstr "Konflikte beim Vormerken" msgid "Stage conflicts?" msgstr "Konflikte vormerken?" msgid "Stage/unstage selected paths for commit" msgstr "Vormerken für Commit umschalten für ausgewählte Pfade" msgid "Staged" msgstr "Vorgemerkt" #, python-format msgid "Staging: %s" msgstr "Vermerken: %s" msgid "Start Interactive Rebase..." msgstr "Interaktiven Rebase starten..." msgid "Starting Revision" msgstr "Start-Revision" msgid "Stash" msgstr "Git-Zwischenablage" msgid "Stash Index" msgstr "Inhalt der Zwischenablage" msgid "Stash staged changes only" msgstr "Nur vorgemerkte Änderungen in die Zwischenablage" msgid "Stash unstaged changes only, keeping staged changes" msgstr "Nur nicht vorgemerkte Änderungen in die Zwischenablage, vorgemerkte Änderungen behalten" msgid "Stash..." msgstr "Git-Zwischenablage..." msgid "Status" msgstr "Zustand" msgid "Stop tracking paths" msgstr "Versionskontrolle für den ausgewählten Pfad beenden" msgid "Submodules" msgstr "" msgid "Summarize Merge Commits" msgstr "Zusammenfassung beim Zusammenführen anzeigen" msgid "Summary" msgstr "Zusammenfassung" msgid "Tab Width" msgstr "Tabulatorweite" msgid "Tag" msgstr "Tag" msgid "Tag Created" msgstr "Tag erstellt" msgid "Tag message..." msgstr "Tag-Beschreibung..." msgid "Tag-signing was requested but the tag message is empty." msgstr "Eine Tag-Signatur wurde angefordert, aber die Tag-Beschreibung fehlt." msgid "Tags" msgstr "Tags" msgid "Text Width" msgstr "Textbreite" msgid "The branch will be no longer available." msgstr "Der Branch wird nicht mehr verfügbar sein." #, python-format msgid "The branch will be reset using \"git reset --hard %s\"" msgstr "Der Branch wird zurückgesetzt mit \"git reset --hard %s\"" #, python-format msgid "The branch will be reset using \"git reset --merge %s\"" msgstr "Der Branch wird zurückgesetzt mit \"git reset --merge %s\"" #, python-format msgid "The branch will be reset using \"git reset --mixed %s\"" msgstr "Der Branch wird zurückgesetzt mit \"git reset --mixed %s\"" #, python-format msgid "The branch will be reset using \"git reset --soft %s\"" msgstr "Der Branch wird zurückgesetzt mit \"git reset --soft %s\"" msgid "The commit message will be cleared." msgstr "Die Commit-Beschreibung wird geleert." #, python-format msgid "The file \"%s\" exists and will be overwritten." msgstr "Die Datei \"%s\" existiert bereits und wird überschrieben." msgid "The following files will be deleted:" msgstr "Die folgenden Zeilen werden gleich gelöscht:" msgid "The revision expression cannot be empty." msgstr "Der Ausdruck darf nicht leer sein." #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be reset using \"git reset --keep %s\"" msgstr "Der Arbeitsbaum wird zurückgesetzt mit \"git reset --keep %s\"" msgid "This cannot be undone. Clear commit message?" msgstr "Dies kann nicht rückgängig gemacht werden. Commit-Beschreibung leeren?" msgid "" "This commit has already been published.\n" "This operation will rewrite published history.\n" "You probably don't want to do this." msgstr "" "Dieser Commit wurde bereits veröffentlicht.\n" "Dieser Vorgang wird den veröffentlichten Verlauf umschreiben.\n" "Dies wollen Sie womöglich nicht tun." msgid "" "This operation drops uncommitted changes.\n" "These changes cannot be recovered." msgstr "" "Dieser Vorgang verwirft nicht vorgemerkte Änderungen.\n" "Diese Änderung kann nicht rückgängig gemacht werden." msgid "" "This operation removes uncommitted edits from selected files.\n" "These changes cannot be recovered." msgstr "" "Dieser Befehl verwirft nicht vorgemerkte Änderungen an den ausgewählten Dateien.\n" "Dieser Schritt kann nicht rückgängig gemacht werden." msgid "" "This operation removes unstaged edits from selected files.\n" "These changes cannot be recovered." msgstr "" "Damit verwerfen Sie nicht vorgemerkte Änderungen.\n" "Diese können nicht mehr wiederhergestellt werden." msgid "" "This repository is currently being rebased.\n" "Resolve conflicts, commit changes, and run:\n" " Rebase > Continue" msgstr "" "In diesem Repository ist gerade ein Rebase im Gange.\n" "Lösen Sie die Konflikte aus und committen Sie die Änderungen, dann nutzen Sie:\n" " Rebase > Fortsetzen" msgid "" "This repository is in the middle of a merge.\n" "Resolve conflicts and commit changes." msgstr "" "Dieses Repository befindet sich mitten in einem Merge.\n" "Beheben Sie zunächst die Konflikte und führen einen Commit durch." msgid "Toggle Enabled" msgstr "Aktivierung umschalten" msgid "Toggle the branches filter" msgstr "Branch-Filter umschalten" msgid "Toggle the paths filter" msgstr "Pfadfilter umschalten" msgid "Tracking Branch" msgstr "Nachverfolgter Branch" msgid "Tracking branch" msgstr "Nachverfolgtem Branch" msgid "Traditional Chinese (Taiwan) translation" msgstr "Traditionell-Chinesische (Taiwan) Übersetzung" msgid "Translators" msgstr "Übersetzer" msgid "Turkish translation" msgstr "Türkische Übersetzung" msgid "URL" msgstr "URL" #, python-format msgid "URL: %s" msgstr "URL: %s" msgid "Ukranian translation" msgstr "Ukrainische Übersetzung" msgid "Unable to rebase" msgstr "Rebase nicht durchführbar" #, python-format msgid "Unable to set URL for \"%(name)s\" to \"%(url)s\"" msgstr "Kann URL für \"%(name)s\" nicht auf \"%(url)s\" setzen" msgid "Undo" msgstr "Rückgängig" msgid "Unmerged" msgstr "Nicht zusammengeführt" msgid "Unstage" msgstr "Änderung nicht vormerken" msgid "Unstage All" msgstr "Alle Vormerkungen aufheben" msgid "Unstage Diff Hunk" msgstr "Änderungen am Abschnitt nicht vormerken" msgid "Unstage From Commit" msgstr "Vormerkung dieser Datei aufheben" msgid "Unstage Selected" msgstr "Vormerkung für Auswahl aufheben" msgid "Unstage Selected Lines" msgstr "Änderungen an ausgewählten Zeilen nicht mehr vormerken" #, python-format msgid "Unstaging: %s" msgstr "Entferne Datei »%s« aus Vormerkliste" msgid "Untrack Selected" msgstr "Auswahl von Versionskontrolle ausnehmen" msgid "Untracked" msgstr "Nicht unter Versionskontrolle" #, python-format msgid "Untracking: %s" msgstr "Nicht mehr verfolgen: %s" msgid "Update All Submodules..." msgstr "" msgid "Update Existing Branch:" msgstr "Existierenden Branch aktualisieren:" msgid "Update Submodule" msgstr "" msgid "Update Submodule..." msgstr "" msgid "Update Submodules" msgstr "" msgid "Update all submodules?" msgstr "" msgid "Update submodules..." msgstr "" msgid "Update this submodule" msgstr "" msgid "Update this submodule?" msgstr "" msgid "Updating" msgstr "Aktualisierung" msgid "User Name" msgstr "Benutzername" msgid "Version" msgstr "Version" msgid "View" msgstr "Ansicht" msgid "View History..." msgstr "Verlauf anzeigen..." msgid "View history for selected paths" msgstr "Verlauf für ausgewählte Pfade anzeigen" msgid "Visualize" msgstr "In Verlaufsansicht anzeigen" msgid "Visualize All Branches..." msgstr "Alle Branches visualisieren..." msgid "Visualize Current Branch..." msgstr "Gegenwärtigen Branch visualisieren..." msgid "Whether to sign the tag (git tag -s)" msgstr "Den Tag unterzeichnen (siehe git tag -s)" msgid "Would you like to stage and commit all modified files?" msgstr "Möchten Sie alle veränderten Dateien vormerken und aufnehmen?" msgid "XOR" msgstr "XOR" msgid "Yes" msgstr "" msgid "" "You are in the middle of a merge.\n" "Cannot amend while merging." msgstr "Es werden gerade Änderungen eingepflegt.Sie können deshalb im Moment keine Ergänzungen vornehmen." msgid "You cannot rebase with uncommitted changes." msgstr "Rebase nicht möglich mit ausstehenden Änderungen." msgid "You must specify a revision to merge." msgstr "Sie müssen eine Revision für die Zusammenführung angeben." msgid "You must specify a revision to view." msgstr "Sie müssen eine Revision zum Betrachten angeben." msgid "Zoom In" msgstr "Vergrößern" msgid "Zoom Out" msgstr "Verkleinern" msgid "Zoom to Fit" msgstr "In Ansicht einpassen" msgid "command-line arguments" msgstr "Kommandozeilenargumente" msgid "error: unable to execute git" msgstr "" #, python-format msgid "exit code %s" msgstr "Ende-Code %s" #, python-format msgid "fatal: \"%s\" is not a directory. Please specify a correct --repo ." msgstr "fatal: \"%s\" ist kein Verzeichnis. Bitte gültiges Repository angeben mit --repo ." #, python-format msgid "git cola version %s" msgstr "git cola Version %s" msgid "git-cola" msgstr "git-cola" msgid "git-cola diff" msgstr "git-cola diff" msgid "grep result..." msgstr "Ergebnis von grep..." msgid "hotkeys.html" msgstr "hotkeys_de.html" msgid "unknown" msgstr "unbekannt" msgid "vX.Y.Z" msgstr "vX.Y.Z" msgid "x 1" msgstr "" msgid "x 1.5" msgstr "" msgid "x 2" msgstr "" msgid "yyyy-MM-dd" msgstr "dd.MM.yyyy" #~ msgid "" #~ "\n" #~ "\n" #~ "A good replacement for %s\n" #~ "is placing values for the user.name and\n" #~ "user.email settings into your personal\n" #~ "~/.gitconfig file.\n" #~ msgstr "" #~ "\n" #~ "\n" #~ "Um den Namen »%s« zu ändern, sollten Sie die \n" #~ "gewünschten Werte für die Einstellung user.name und \n" #~ "user.email in Ihre Datei ~/.gitconfig einfügen.\n" #~ msgid "" #~ "\n" #~ "This is due to a known issue with the\n" #~ "Tcl binary distributed by Cygwin." #~ msgstr "" #~ "\n" #~ "Dies ist ein bekanntes Problem der Tcl-Version, die\n" #~ "in Cygwin mitgeliefert wird." #~ msgid "\"%s\" returned exit status %d" #~ msgstr "\"%s\" wurde mit Code %d beendet" #~ msgid "\"git %s\" succeeded." #~ msgstr "\"git %s\" erfolgreich ausgeführt." #~ msgid "\"git commit\" returned exit code %s" #~ msgstr "\"git commit\" wurde mit dem Code %s beendet" #~ msgid "%s ... %*i of %*i %s (%3i%%)" #~ msgstr "%s ... %*i von %*i %s (%3i%%)" #~ msgid "%s Repository" #~ msgstr "Projektarchiv %s" #~ msgid "%s of %s" #~ msgstr "%s von %s" #~ msgid "'%s' is not an acceptable branch name." #~ msgstr "»%s« ist kein zulässiger Zweigname." #~ msgid "* Binary file (not showing content)." #~ msgstr "* Binärdatei (Inhalt wird nicht angezeigt)" #~ msgid "A branch is required for 'Merged Into'." #~ msgstr "Für »Zusammenführen mit« muss ein Zweig angegeben werden." #~ msgid "Abort completed. Ready." #~ msgstr "Abbruch durchgeführt. Bereit." #~ msgid "Abort failed." #~ msgstr "Abbruch fehlgeschlagen." #~ msgid "Aborted checkout of '%s' (file level merging is required)." #~ msgstr "Auf Zweig »%s« umstellen abgebrochen (Zusammenführen der Dateien ist notwendig)." #~ msgid "Already up-to-date." #~ msgstr "Ist bereits aktuell" #~ msgid "Always (Do not perform merge checks)" #~ msgstr "Immer (Keine Zusammenführungsprüfung)" #~ msgid "Always (Do not perform merge test.)" #~ msgstr "Immer (ohne Zusammenführungstest)" #~ msgid "Amended Commit Message:" #~ msgstr "Nachgebesserte Beschreibung:" #~ msgid "Amended Initial Commit Message:" #~ msgstr "Nachgebesserte erste Beschreibung:" #~ msgid "Amended Merge Commit Message:" #~ msgstr "Nachgebesserte Zusammenführungs-Beschreibung:" #~ msgid "Annotation complete." #~ msgstr "Annotierung vollständig." #~ msgid "Any unstaged changes will be permanently lost by the revert." #~ msgstr "Alle nicht bereitgestellten Änderungen werden beim Verwerfen verloren gehen." #~ msgid "Apply Diff Selection to Work Tree" #~ msgstr "Auswahl auf den Arbeitsbereich anwenden" #~ msgid "Apply/Reverse Hunk" #~ msgstr "Kontext anwenden/umkehren" #~ msgid "Arbitrary URL:" #~ msgstr "Archiv-URL:" #~ msgid "Bookmarks" #~ msgstr "Favoriten" #~ msgid "Bookmarks Saved" #~ msgstr "Favoriten gesichert" #~ msgid "Bookmarks..." #~ msgstr "Favoriten..." #~ msgid "" #~ "Branch '%s' already exists.\n" #~ "\n" #~ "It cannot fast-forward to %s.\n" #~ "A merge is required." #~ msgstr "" #~ "Zweig »%s« existiert bereits.\n" #~ "\n" #~ "Zweig kann nicht mit »%s« schnellzusammengeführt werden. Reguläres Zusammenführen ist notwendig." #~ msgid "Branch '%s' does not exist." #~ msgstr "Zweig »%s« existiert nicht." #~ msgid "Branch created" #~ msgstr "Zweig erzeugt" #~ msgid "Browse %s's Files" #~ msgstr "Zweig »%s« durchblättern" #~ msgid "Browse Branch Files" #~ msgstr "Dateien des Zweigs durchblättern" #~ msgid "Browse Revision..." #~ msgstr "Zweig oder Markierung wählen" #~ msgid "Calling commit-msg hook..." #~ msgstr "Aufrufen der Versionsbeschreibungs-Kontrolle..." #~ msgid "" #~ "Cannot abort while amending.\n" #~ "\n" #~ "You must finish amending this commit.\n" #~ msgstr "" #~ "Abbruch der Nachbesserung ist nicht möglich.\n" #~ "\n" #~ "Sie müssen die Nachbesserung der Version abschließen.\n" #~ msgid "" #~ "Cannot amend while merging.\n" #~ "\n" #~ "You are currently in the middle of a merge that has not been fully completed. You cannot amend the prior commit unless you first abort the current merge activity.\n" #~ msgstr "" #~ "Nachbesserung währen Zusammenführung nicht möglich.\n" #~ "\n" #~ "Sie haben das Zusammenführen von Versionen angefangen, aber noch nicht beendet. Sie können keine vorige Übertragung nachbessern, solange eine unfertige Zusammenführung existiert. Dazu müssen Sie die Zusammenführung beenden oder abbrechen.\n" #~ msgid "Cannot determine HEAD. See console output for details." #~ msgstr "Die Zweigspitze (HEAD) konnte nicht gefunden werden. Kontrollieren Sie die Ausgaben auf der Konsole für weitere Angaben." #~ msgid "Cannot fetch branches and objects. See console output for details." #~ msgstr "Zweige und Objekte konnten nicht angefordert werden. Kontrollieren Sie die Ausgaben auf der Konsole für weitere Angaben." #~ msgid "Cannot fetch tags. See console output for details." #~ msgstr "Markierungen konnten nicht angefordert werden. Kontrollieren Sie die Ausgaben auf der Konsole für weitere Angaben." #~ msgid "Cannot find git in PATH." #~ msgstr "Git kann im PATH nicht gefunden werden." #~ msgid "" #~ "Cannot merge while amending.\n" #~ "\n" #~ "You must finish amending this commit before starting any type of merge.\n" #~ msgstr "" #~ "Zusammenführen kann nicht gleichzeitig mit Nachbessern durchgeführt werden.\n" #~ "\n" #~ "Sie müssen zuerst die Nachbesserungs-Version abschließen, bevor Sie zusammenführen können.\n" #~ msgid "Cannot move to top of working directory:" #~ msgstr "Es konnte nicht in das oberste Verzeichnis der Arbeitskopie gewechselt werden:" #~ msgid "Cannot parse Git version string:" #~ msgstr "Git Versionsangabe kann nicht erkannt werden:" #~ msgid "Cannot resolve %s as a commit." #~ msgstr "»%s« wurde nicht als Version gefunden." #~ msgid "Cannot use funny .git directory:" #~ msgstr "Unerwartete Struktur des .git Verzeichnis:" #~ msgid "Cannot write shortcut:" #~ msgstr "Fehler beim Schreiben der Verknüpfung:" #~ msgid "Change Font" #~ msgstr "Schriftart ändern" #~ msgid "Checked out '%s'." #~ msgstr "Umgestellt auf »%s«." #~ msgid "Clone Type:" #~ msgstr "Art des Klonens:" #~ msgid "Clone failed." #~ msgstr "Klonen fehlgeschlagen." #~ msgid "Cloning from %s" #~ msgstr "Kopieren von »%s«" #~ msgid "Commit %s appears to be corrupt" #~ msgstr "Version »%s« scheint beschädigt zu sein" #~ msgid "Commit declined by commit-msg hook." #~ msgstr "Eintragen abgelehnt durch Versionsbeschreibungs-Kontrolle (»commit-message hook«)." #~ msgid "Commit declined by pre-commit hook." #~ msgstr "Eintragen abgelehnt durch Vor-Eintragen-Kontrolle (»pre-commit hook«)." #~ msgid "Commit failed: %s" #~ msgstr "Versionierung fehlgeschlagen: %s" #~ msgid "Commit@@noun" #~ msgstr "Version" #~ msgid "Compress Database" #~ msgstr "Datenbank komprimieren" #~ msgid "Compressing the object database" #~ msgstr "Objektdatenbank komprimieren" #~ msgid "Copied Or Moved Here By:" #~ msgstr "Kopiert oder verschoben durch:" #~ msgid "Copying objects" #~ msgstr "Objektdatenbank kopieren" #~ msgid "Counting objects" #~ msgstr "Objekte werden gezählt" #~ msgid "Create Desktop Icon" #~ msgstr "Desktop-Icon erstellen" #~ msgid "Created commit: %s" #~ msgstr "Änderung %s übertragen:" #~ msgid "Creating working directory" #~ msgstr "Arbeitskopie erstellen" #~ msgid "Current Branch:" #~ msgstr "Aktueller Zweig:" #~ msgid "Database Statistics" #~ msgstr "Datenbankstatistik" #~ msgid "Decrease Font Size" #~ msgstr "Schriftgröße verkleinern" #~ msgid "Delete Local Branch" #~ msgstr "Lokalen Zweig löschen" #~ msgid "Delete Only If" #~ msgstr "Nur löschen, wenn" #~ msgid "Delete Only If Merged Into" #~ msgstr "Nur löschen, wenn zusammengeführt nach" #~ msgid "Destination Repository" #~ msgstr "Ziel-Projektarchiv" #~ msgid "Detach From Local Branch" #~ msgstr "Verbindung zu lokalem Zweig lösen" #~ msgid "Diff/Console Font" #~ msgstr "Vergleich-Schriftart" #~ msgid "Directory %s already exists." #~ msgstr "Verzeichnis »%s« existiert bereits." #~ msgid "Disk space used by loose objects" #~ msgstr "Festplattenplatz von unverknüpften Objekten" #~ msgid "Disk space used by packed objects" #~ msgstr "Festplattenplatz von komprimierten Objekten" #~ msgid "Display" #~ msgstr "Anzeigen" #~ msgid "Do Nothing" #~ msgstr "Nichts tun" #~ msgid "Enter Git Repository" #~ msgstr "Git Projektarchiv:" #~ msgid "Error %s" #~ msgstr "Fehler: %s" #~ msgid "Error loading commit data for amend:" #~ msgstr "Fehler beim Laden der Versionsdaten für Nachbessern:" #~ msgid "Error: Command Failed" #~ msgstr "Fehler: Kommando fehlgeschlagen" #~ msgid "Errors: %s" #~ msgstr "Fehler: \"%s\"" #~ msgid "Exit code: %s" #~ msgstr "Ende-Code: %s" #~ msgid "Failed to completely save options:" #~ msgstr "Optionen konnten nicht gespeichert werden:" #~ msgid "Failed to configure origin" #~ msgstr "Der Ursprungsort konnte nicht eingerichtet werden" #~ msgid "Failed to create repository %s:" #~ msgstr "Projektarchiv »%s« konnte nicht erstellt werden:" #~ msgid "" #~ "Failed to delete branches:\n" #~ "%s" #~ msgstr "" #~ "Fehler beim Löschen der Zweige:\n" #~ "%s" #~ msgid "Failed to open repository %s:" #~ msgstr "Projektarchiv »%s« konnte nicht geöffnet werden." #~ msgid "Failed to rename '%s'." #~ msgstr "Fehler beim Umbenennen von »%s«." #~ msgid "" #~ "Failed to set current branch.\n" #~ "\n" #~ "This working directory is only partially switched. We successfully updated your files, but failed to update an internal Git file.\n" #~ "\n" #~ "This should not have occurred. %s will now close and give up." #~ msgstr "" #~ "Lokaler Zweig kann nicht gesetzt werden.\n" #~ "\n" #~ "Diese Arbeitskopie ist nur teilweise umgestellt. Die Dateien sind korrekt aktualisiert, aber einige interne Git-Dateien konnten nicht geändert werden.\n" #~ "\n" #~ "Dies ist ein interner Programmfehler von %s. Programm wird jetzt abgebrochen." #~ msgid "Failed to stage selected hunk." #~ msgstr "Fehler beim Bereitstellen des gewählten Kontexts." #~ msgid "Failed to unstage selected hunk." #~ msgstr "Fehler beim Herausnehmen des gewählten Kontexts aus der Bereitstellung." #~ msgid "Failed to update '%s'." #~ msgstr "Aktualisieren von »%s« fehlgeschlagen." #~ msgid "Fast Forward Only " #~ msgstr "Nur Fast Forward" #~ msgid "Fetch from" #~ msgstr "Anfordern von" #~ msgid "Fetching new changes from %s" #~ msgstr "Neue Änderungen von »%s« holen" #~ msgid "File level merge required." #~ msgstr "Zusammenführen der Dateien ist notwendig." #~ msgid "Font Example" #~ msgstr "Schriftbeispiel" #~ msgid "Font Family" #~ msgstr "Schriftfamilie" #~ msgid "Force overwrite existing branch (may discard changes)" #~ msgstr "Überschreiben von existierenden Zweigen erzwingen (könnte Änderungen löschen)" #~ msgid "From Repository" #~ msgstr "In Projektarchiv" #~ msgid "Full Copy (Slower, Redundant Backup)" #~ msgstr "Alles kopieren (langsamer, volle Redundanz)" #~ msgid "GPG-signed" #~ msgstr "mit GPG signiert" #~ msgid "Garbage files" #~ msgstr "Dateien im Mülleimer" #~ msgid "Git Gui" #~ msgstr "Git Gui" #~ msgid "Git Repository (subproject)" #~ msgstr "Git-Projektarchiv (Unterprojekt)" #~ msgid "Git directory not found:" #~ msgstr "Git-Verzeichnis nicht gefunden:" #~ msgid "" #~ "Git version cannot be determined.\n" #~ "\n" #~ "%s claims it is version '%s'.\n" #~ "\n" #~ "%s requires at least Git 1.5.0 or later.\n" #~ "\n" #~ "Assume '%s' is version 1.5.0?\n" #~ msgstr "" #~ "Die Version von Git kann nicht bestimmt werden.\n" #~ "\n" #~ "»%s« behauptet, es sei Version »%s«.\n" #~ "\n" #~ "%s benötigt mindestens Git 1.5.0 oder höher.\n" #~ "\n" #~ "Soll angenommen werden, »%s« sei Version 1.5.0?\n" #~ msgid "Hardlinks are unavailable. Falling back to copying." #~ msgstr "Hardlinks nicht verfügbar. Stattdessen wird kopiert." #~ msgid "In File:" #~ msgstr "In Datei:" #~ msgid "Increase Font Size" #~ msgstr "Schriftgröße vergrößern" #~ msgid "Index" #~ msgstr "Vormerkliste" #~ msgid "Index Error" #~ msgstr "Fehler in Bereitstellung" #~ msgid "Initial Commit Message:" #~ msgstr "Erste Versionsbeschreibung:" #~ msgid "Initial file checkout failed." #~ msgstr "Erstellen der Arbeitskopie fehlgeschlagen." #~ msgid "Invalid GIT_COMMITTER_IDENT:" #~ msgstr "Ungültiger Wert von GIT_COMMITTER_INDENT:" #~ msgid "Invalid date from Git: %s" #~ msgstr "Ungültiges Datum von Git: %s" #~ msgid "Invalid font specified in %s:" #~ msgstr "Ungültige Zeichensatz-Angabe in %s:" #~ msgid "Invalid spell checking configuration" #~ msgstr "Unbenutzbare Konfiguration der Rechtschreibprüfung" #~ msgid "KiB" #~ msgstr "KB" #~ msgid "" #~ "Last scanned state does not match repository state.\n" #~ "\n" #~ "Another Git program has modified this repository since the last scan. A rescan must be performed before a merge can be performed.\n" #~ "\n" #~ "The rescan will be automatically started now.\n" #~ msgstr "" #~ "Der letzte geladene Status stimmt nicht mehr mit dem Projektarchiv überein.\n" #~ "\n" #~ "Ein anderes Git-Programm hat das Projektarchiv seit dem letzten Laden geändert. Vor einem Zusammenführen muss neu geladen werden.\n" #~ "\n" #~ "Es wird gleich neu geladen.\n" #~ msgid "" #~ "Last scanned state does not match repository state.\n" #~ "\n" #~ "Another Git program has modified this repository since the last scan. A rescan must be performed before another commit can be created.\n" #~ "\n" #~ "The rescan will be automatically started now.\n" #~ msgstr "" #~ "Der letzte geladene Status stimmt nicht mehr mit dem Projektarchiv überein.\n" #~ "\n" #~ "Ein anderes Git-Programm hat das Projektarchiv seit dem letzten Laden geändert. Vor dem Eintragen einer neuen Version muss neu geladen werden.\n" #~ "\n" #~ "Es wird gleich neu geladen.\n" #~ msgid "" #~ "Last scanned state does not match repository state.\n" #~ "\n" #~ "Another Git program has modified this repository since the last scan. A rescan must be performed before the current branch can be changed.\n" #~ "\n" #~ "The rescan will be automatically started now.\n" #~ msgstr "" #~ "Der letzte geladene Status stimmt nicht mehr mit dem Projektarchiv überein.\n" #~ "\n" #~ "Ein anderes Git-Programm hat das Projektarchiv seit dem letzten Laden geändert. Vor dem Wechseln des lokalen Zweigs muss neu geladen werden.\n" #~ "\n" #~ "Es wird gleich neu geladen.\n" #~ msgid "Linking objects" #~ msgstr "Objekte verlinken" #~ msgid "Loading annotation..." #~ msgstr "Annotierung laden..." #~ msgid "Loading copy/move tracking annotations..." #~ msgstr "Annotierungen für Kopieren/Verschieben werden geladen..." #~ msgid "Loading original location annotations..." #~ msgstr "Annotierungen für ursprünglichen Ort werden geladen..." #~ msgid "Local Branches" #~ msgstr "Lokale Zweige" #~ msgid "Local Merge..." #~ msgstr "Lokales Zusammenführen..." #~ msgid "Location %s already exists." #~ msgstr "Projektarchiv »%s« existiert bereits." #~ msgid "Main Font" #~ msgstr "Programmschriftart" #~ msgid "Match Tracking Branch Name" #~ msgstr "Passend zu Übernahmezweig-Name" #~ msgid "Match Tracking Branches" #~ msgstr "Passend zu Übernahmezweig" #~ msgid "Merge completed successfully." #~ msgstr "Zusammenführen erfolgreich abgeschlossen." #~ msgid "Merge strategy '%s' not supported." #~ msgstr "Zusammenführungsmethode »%s« nicht unterstützt." #~ msgid "Merged Into:" #~ msgstr "Zusammengeführt mit:" #~ msgid "Merging %s and %s..." #~ msgstr "Zusammenführen von %s und %s..." #~ msgid "Modified, not staged" #~ msgstr "Verändert, nicht bereitgestellt" #~ msgid "New Branch Name Template" #~ msgstr "Namensvorschlag für neue Zweige" #~ msgid "New Commit" #~ msgstr "Neue Version" #~ msgid "New Name:" #~ msgstr "Neuer Name:" #~ msgid "" #~ "No changes to commit.\n" #~ "\n" #~ "No files were modified by this commit and it was not a merge commit.\n" #~ "\n" #~ "A rescan will be automatically started now.\n" #~ msgstr "" #~ "Keine Änderungen einzutragen.\n" #~ "\n" #~ "Es gibt keine geänderte Datei bei dieser Version und es wurde auch nichts zusammengeführt.\n" #~ "\n" #~ "Das Arbeitsverzeichnis wird daher jetzt neu geladen.\n" #~ msgid "No default branch obtained." #~ msgstr "Kein voreingestellter Zweig gefunden." #~ msgid "" #~ "No differences detected.\n" #~ "\n" #~ "%s has no changes.\n" #~ "\n" #~ "The modification date of this file was updated by another application, but the content within the file was not changed.\n" #~ "\n" #~ "A rescan will be automatically started to find other files which may have the same state." #~ msgstr "" #~ "Keine Änderungen feststellbar.\n" #~ "\n" #~ "»%s« enthält keine Änderungen. Zwar wurde das Änderungsdatum dieser Datei von einem anderen Programm modifiziert, aber der Inhalt der Datei ist unverändert.\n" #~ "\n" #~ "Das Arbeitsverzeichnis wird jetzt neu geladen, um diese Änderung bei allen Dateien zu prüfen." #~ msgid "No files selected for checkout from HEAD." #~ msgstr "Es sind keine Dateien zum Auschecken von HEAD ausgewählt." #~ msgid "No working directory" #~ msgstr "Kein Arbeitsverzeichnis" #~ msgid "Number of loose objects" #~ msgstr "Anzahl unverknüpfter Objekte" #~ msgid "Number of packed objects" #~ msgstr "Anzahl komprimierter Objekte" #~ msgid "Number of packs" #~ msgstr "Anzahl Komprimierungseinheiten" #~ msgid "On Debian-based systems try: sudo apt-get install python-pyinotify" #~ msgstr "Wenn Sie git-cola auf einem Debian-System gestartet haben, versuchen Sie es mit \"sudo apt-get install python-pyinotify\" " #~ msgid "One or more of the merge tests failed because you have not fetched the necessary commits. Try fetching from %s first." #~ msgstr "Ein oder mehrere Zusammenführungen sind fehlgeschlagen, da Sie nicht die notwendigen Versionen vorher angefordert haben. Sie sollten versuchen, zuerst von »%s« anzufordern." #~ msgid "Options" #~ msgstr "Optionen" #~ msgid "Original File:" #~ msgstr "Ursprüngliche Datei:" #~ msgid "Originally By:" #~ msgstr "Ursprünglich von:" #~ msgid "" #~ "Output:\n" #~ "%s" #~ msgstr "" #~ "Ausgabe:\n" #~ "%s" #~ msgid "Output: %s" #~ msgstr "Ausgabe: \"%s\"" #~ msgid "PATCH %(current)d/%(count)d" #~ msgstr "PATCH %(current)d/%(count)d" #~ msgid "Packed objects waiting for pruning" #~ msgstr "Komprimierte Objekte, die zum Aufräumen vorgesehen sind" #~ msgid "Path to git repository" #~ msgstr "Pfad zum Projektarchiv" #~ msgid "Please select one or more branches to delete." #~ msgstr "Bitte wählen Sie mindestens einen Zweig, der gelöscht werden soll." #~ msgid "Please supply a branch name." #~ msgstr "Bitte geben Sie einen Zweignamen an." #~ msgid "Portions staged for commit" #~ msgstr "Teilweise bereitgestellt zum Eintragen" #~ msgid "" #~ "Possible environment issues exist.\n" #~ "\n" #~ "The following environment variables are probably\n" #~ "going to be ignored by any Git subprocess run\n" #~ "by %s:\n" #~ "\n" #~ msgstr "" #~ "Möglicherweise gibt es Probleme mit manchen Umgebungsvariablen.\n" #~ "\n" #~ "Die folgenden Umgebungsvariablen können vermutlich nicht \n" #~ "von %s an Git weitergegeben werden:\n" #~ "\n" #~ msgid "Preferences..." #~ msgstr "Einstellungen..." #~ msgid "Process Diff Hunk" #~ msgstr "Abschnitt verarbeiten" #~ msgid "Process Selection" #~ msgstr "Auswahl verarbeiten" #~ msgid "Prune Tracking Branches During Fetch" #~ msgstr "Übernahmezweige aufräumen während Anforderung" #~ msgid "Pruning tracking branches deleted from %s" #~ msgstr "Übernahmezweige aufräumen und entfernen, die in »%s« gelöscht wurden" #~ msgid "Push Branches" #~ msgstr "Zweige versenden" #~ msgid "Push to" #~ msgstr "Versenden nach" #~ msgid "Pushing %s %s to %s" #~ msgstr "%s %s nach %s versenden" #~ msgid "Reading %s..." #~ msgstr "%s lesen..." #~ msgid "Ready to commit." #~ msgstr "Bereit zum Eintragen." #~ msgid "Ready." #~ msgstr "Bereit." #~ msgid "Rebase Branch" #~ msgstr "Anfang des Zweigs verschieben" #~ msgid "Rebase..." #~ msgstr "Anfang verschieben..." #~ msgid "" #~ "Recovering deleted branches is difficult.\n" #~ "\n" #~ "Delete the selected branches?" #~ msgstr "" #~ "Das Wiederherstellen von gelöschten Zweigen ist nur mit größerem Aufwand möglich.\n" #~ "\n" #~ "Sollen die ausgewählten Zweige gelöscht werden?" #~ msgid "" #~ "Recovering deleted branches is difficult. \n" #~ "\n" #~ " Delete the selected branches?" #~ msgstr "" #~ "Gelöschte Zweige können nur mit größerem Aufwand wiederhergestellt werden.\n" #~ "\n" #~ "Gewählte Zweige jetzt löschen?" #~ msgid "Refreshing file status..." #~ msgstr "Dateistatus aktualisieren..." #~ msgid "Remote Branches" #~ msgstr "" #~ msgid "Remote:" #~ msgstr "Anderes Archiv:" #~ msgid "Remove selected paths from the staging area" #~ msgstr "Änderungen am ausgewählten Pfad nicht mehr vormerken" #~ msgid "Rename remote?" #~ msgstr "Möchten Sie die externe Referenz umbenennen?" #~ msgid "Repository" #~ msgstr "Projektarchiv" #~ msgid "Requires merge resolution" #~ msgstr "Konfliktauflösung nötig" #~ msgid "Rescan" #~ msgstr "Ansicht aktualisieren" #~ msgid "" #~ "Reset changes?\n" #~ "\n" #~ "Resetting the changes will cause *ALL* uncommitted changes to be lost.\n" #~ "\n" #~ "Continue with resetting the current changes?" #~ msgstr "" #~ "Änderungen zurücksetzen?\n" #~ "\n" #~ "Wenn Sie zurücksetzen, gehen alle noch nicht eingetragenen Änderungen verloren.\n" #~ "\n" #~ "Änderungen jetzt zurücksetzen?" #~ msgid "Revert Uncommitted Changes..." #~ msgstr "Nicht versionierte Änderungen verwerfen" #~ msgid "Revert changes in these %i files?" #~ msgstr "Änderungen in den gewählten %i Dateien verwerfen?" #~ msgid "Select File" #~ msgstr "Wähle Datei aus" #~ msgid "Select file from \"%s\"" #~ msgstr "Datei von \"%s\" auswählen" #~ msgid "Shared (Fastest, Not Recommended, No Backup)" #~ msgstr "Verknüpft (schnell, nicht empfohlen, kein Backup)" #~ msgid "Shared only available for local repository." #~ msgstr "Verknüpft ist nur für lokale Projektarchive verfügbar." #~ msgid "Show Less Context" #~ msgstr "Weniger Zeilen anzeigen" #~ msgid "Show More Context" #~ msgstr "Mehr Zeilen anzeigen" #~ msgid "Source Branches" #~ msgstr "Lokale Zweige" #~ msgid "Spell Checker Failed" #~ msgstr "Rechtschreibprüfung fehlgeschlagen" #~ msgid "Spell checker silently failed on startup" #~ msgstr "Rechtschreibprüfungsprogramm mit Fehler abgebrochen" #~ msgid "Spell checking is unavailable" #~ msgstr "Rechtschreibprüfung nicht verfügbar" #~ msgid "Spelling Dictionary:" #~ msgstr "Wörterbuch Rechtschreibprüfung:" #~ msgid "Stage Hunk For Commit" #~ msgstr "Kontext zur Bereitstellung hinzufügen" #~ msgid "Staged Changes (Will Commit)" #~ msgstr "Bereitstellung (zum Eintragen)" #~ msgid "Staged for commit, missing" #~ msgstr "Bereitgestellt zum Eintragen, fehlend" #~ msgid "Staged for removal" #~ msgstr "Bereitgestellt zum Löschen" #~ msgid "Staged for removal, still present" #~ msgstr "Bereitgestellt zum Löschen, trotzdem vorhanden" #~ msgid "Staging Area" #~ msgstr "" #~ msgid "Staging area (index) is already locked." #~ msgstr "Bereitstellung (»index«) ist zur Bearbeitung gesperrt (»locked«)." #~ msgid "Standard (Fast, Semi-Redundant, Hardlinks)" #~ msgstr "Standard (schnell, teilweise redundant, Hardlinks)" #~ msgid "Standard only available for local repository." #~ msgstr "Standard ist nur für lokale Projektarchive verfügbar." #~ msgid "Starting gitk... please wait..." #~ msgstr "Gitk wird gestartet... bitte warten." #~ msgid "Staying on branch '%s'." #~ msgstr "Es wird auf Zweig »%s« verblieben." #~ msgid "Success" #~ msgstr "Erfolgreich" #~ msgid "Successfully saved bookmarks" #~ msgstr "Die Favoriten wurden erfolgreich gesichert." #~ msgid "Summary:" #~ msgstr "Zusammenfassung:" #~ msgid "The 'master' branch has not been initialized." #~ msgstr "Der »master«-Zweig wurde noch nicht initialisiert." #~ msgid "The following branches are not completely merged into %s:" #~ msgstr "Folgende Zweige sind noch nicht mit »%s« zusammengeführt:" #~ msgid "" #~ "The following branches are not completely merged into %s:\n" #~ "\n" #~ " - %s" #~ msgstr "" #~ "Folgende Zweige sind noch nicht mit »%s« zusammengeführt:\n" #~ "\n" #~ " - %s" #~ msgid "" #~ "There is nothing to amend.\n" #~ "\n" #~ "You are about to create the initial commit. There is no commit before this to amend.\n" #~ msgstr "" #~ "Keine Version zur Nachbesserung vorhanden.\n" #~ "\n" #~ "Sie sind dabei, die erste Version zu übertragen. Es gibt keine existierende Version, die Sie nachbessern könnten.\n" #~ msgid "This Detached Checkout" #~ msgstr "Abgetrennte Arbeitskopie-Version" #~ msgid "" #~ "This PyQt4 does not include QtWebKit.\n" #~ "The keyboard shortcuts feature is unavailable." #~ msgstr "" #~ "Das vorhandene PyQt4 enthält nicht die Komponente \"QtWebKit\".\n" #~ "Deshalb ist die Anzeige der Tastenkürzel nicht verfügbar." #~ msgid "" #~ "This is example text.\n" #~ "If you like this text, it can be your font." #~ msgstr "" #~ "Dies ist ein Beispieltext.\n" #~ "Wenn Ihnen dieser Text gefällt, sollten Sie diese Schriftart wählen." #~ msgid "" #~ "This repository currently has approximately %i loose objects.\n" #~ "\n" #~ "To maintain optimal performance it is strongly recommended that you compress the database when more than %i loose objects exist.\n" #~ "\n" #~ "Compress the database now?" #~ msgstr "" #~ "Dieses Projektarchiv enthält ungefähr %i nicht verknüpfte Objekte.\n" #~ "\n" #~ "Für eine optimale Performance wird empfohlen, die Datenbank des Projektarchivs zu komprimieren, sobald mehr als %i nicht verknüpfte Objekte vorliegen.\n" #~ "\n" #~ "Soll die Datenbank jetzt komprimiert werden?" #~ msgid "Tools" #~ msgstr "Ansicht" #~ msgid "Tracking branch %s is not a branch in the remote repository." #~ msgstr "Übernahmezweig »%s« ist kein Zweig im anderen Projektarchiv." #~ msgid "Transfer Options" #~ msgstr "Netzwerk-Einstellungen" #~ msgid "Unable to copy object: %s" #~ msgstr "Objekt kann nicht kopiert werden: %s" #~ msgid "Unable to copy objects/info/alternates: %s" #~ msgstr "Kopien von Objekten/Info/Alternates konnten nicht erstellt werden: %s" #~ msgid "Unable to display %s" #~ msgstr "Datei »%s« kann nicht angezeigt werden" #~ msgid "Unable to hardlink object: %s" #~ msgstr "Für Objekt konnte kein Hardlink erstellt werden: %s" #~ msgid "Unable to obtain your identity:" #~ msgstr "Benutzername konnte nicht bestimmt werden:" #~ msgid "" #~ "Unable to start gitk:\n" #~ "\n" #~ "%s does not exist" #~ msgstr "" #~ "Gitk kann nicht gestartet werden:\n" #~ "\n" #~ "%s existiert nicht" #~ msgid "Unable to unlock the index." #~ msgstr "Bereitstellung kann nicht wieder freigegeben werden." #~ msgid "Unexpected EOF from spell checker" #~ msgstr "Unerwartetes EOF vom Rechtschreibprüfungsprogramm" #~ msgid "" #~ "Unknown file state %s detected.\n" #~ "\n" #~ "File %s cannot be committed by this program.\n" #~ msgstr "" #~ "Unbekannter Dateizustand »%s«.\n" #~ "\n" #~ "Datei »%s« kann nicht eingetragen werden.\n" #~ msgid "Unlock Index" #~ msgstr "Bereitstellung freigeben" #~ msgid "" #~ "Unmerged files cannot be committed.\n" #~ "\n" #~ "File %s has merge conflicts. You must resolve them and stage the file before committing.\n" #~ msgstr "" #~ "Nicht zusammengeführte Dateien können nicht eingetragen werden.\n" #~ "\n" #~ "Die Datei »%s« hat noch nicht aufgelöste Zusammenführungs-Konflikte. Sie müssen diese Konflikte auflösen, bevor Sie eintragen können.\n" #~ msgid "Unrecognized spell checker" #~ msgstr "Unbekanntes Rechtschreibprüfungsprogramm" #~ msgid "Unstage Hunk From Commit" #~ msgstr "Kontext aus Bereitstellung herausnehmen" #~ msgid "Unsupported spell checker" #~ msgstr "Rechtschreibprüfungsprogramm nicht unterstützt" #~ msgid "Updating the Git index failed. A rescan will be automatically started to resynchronize git-gui." #~ msgstr "Das Aktualisieren der Git-Bereitstellung ist fehlgeschlagen. Eine allgemeine Git-Aktualisierung wird jetzt gestartet, um git-gui wieder mit git zu synchronisieren." #~ msgid "Updating working directory to '%s'..." #~ msgstr "Arbeitskopie umstellen auf »%s«..." #~ msgid "Updating..." #~ msgstr "Aktualisiere..." #~ msgid "Use thin pack (for slow network connections)" #~ msgstr "Kompaktes Datenformat benutzen (für langsame Netzverbindungen)" #~ msgid "Verify Database" #~ msgstr "Datenbank überprüfen" #~ msgid "Verifying the object database with fsck-objects" #~ msgstr "Die Objektdatenbank durch »fsck-objects« überprüfen lassen" #~ msgid "Visualize %s's History" #~ msgstr "Historie von »%s« darstellen" #~ msgid "Working... please wait..." #~ msgstr "Verarbeitung. Bitte warten..." #~ msgid "" #~ "You are in the middle of a change.\n" #~ "\n" #~ "File %s is modified.\n" #~ "\n" #~ "You should complete the current commit before starting a merge. Doing so will help you abort a failed merge, should the need arise.\n" #~ msgstr "" #~ "Es liegen Änderungen vor.\n" #~ "\n" #~ "Die Datei »%s« wurde geändert. Sie sollten zuerst die bereitgestellte Version abschließen, bevor Sie eine Zusammenführung beginnen. Mit dieser Reihenfolge können Sie mögliche Konflikte beim Zusammenführen wesentlich einfacher beheben oder abbrechen.\n" #~ msgid "" #~ "You are in the middle of a conflicted merge.\n" #~ "\n" #~ "File %s has merge conflicts.\n" #~ "\n" #~ "You must resolve them, stage the file, and commit to complete the current merge. Only then can you begin another merge.\n" #~ msgstr "" #~ "Zusammenführung mit Konflikten.\n" #~ "\n" #~ "Die Datei »%s« enthält Konflikte beim Zusammenführen. Sie müssen diese Konflikte per Hand auflösen. Anschließend müssen Sie die Datei wieder bereitstellen und eintragen, um die Zusammenführung abzuschließen. Erst danach kann eine neue Zusammenführung begonnen werden.\n" #~ msgid "" #~ "You are no longer on a local branch.\n" #~ "\n" #~ "If you wanted to be on a branch, create one now starting from 'This Detached Checkout'." #~ msgstr "" #~ "Die Arbeitskopie ist nicht auf einem lokalen Zweig.\n" #~ "\n" #~ "Wenn Sie auf einem Zweig arbeiten möchten, erstellen Sie bitte jetzt einen Zweig mit der Auswahl »Abgetrennte Arbeitskopie-Version«." #~ msgid "You must correct the above errors before committing." #~ msgstr "Sie müssen die obigen Fehler zuerst beheben, bevor Sie eintragen können." #~ msgid "[Up To Parent]" #~ msgstr "[Nach oben]" #~ msgid "buckets" #~ msgstr "Buckets" #~ msgid "commit-tree failed:" #~ msgstr "commit-tree fehlgeschlagen:" #~ msgid "fatal: Cannot resolve %s" #~ msgstr "Fehler: »%s« kann nicht als Zweig oder Version erkannt werden" #~ msgid "" #~ "file notification: disabled\n" #~ "Note: install pywin32 to enable.\n" #~ msgstr "" #~ "git-cola wird nicht über Änderungen im Dateisystem benachrichtigt.\n" #~ "Installieren Sie pywin32, um diese Funktion zu nutzen.\n" #~ msgid "files" #~ msgstr "Dateien" #~ msgid "files checked out" #~ msgstr "Dateien aktualisiert" #~ msgid "files reset" #~ msgstr "Dateien zurückgesetzt" #~ msgid "git clone returned exit code %s" #~ msgstr "git clone wurde mit dem Fehlercode %s beendet" #~ msgid "git tag returned exit code %s" #~ msgstr "git tag wurde mit dem Fehlercode %s beendet" #~ msgid "git-gui - a graphical user interface for Git." #~ msgstr "git-gui - eine grafische Oberfläche für Git." #~ msgid "git-gui: fatal error" #~ msgstr "git-gui: Programmfehler" #~ msgid "inotify enabled." #~ msgstr "inotify aktiviert" #~ msgid "" #~ "inotify: disabled\n" #~ "Note: install python-pyinotify to enable inotify.\n" #~ msgstr "" #~ "inotify: deaktiviert\n" #~ "Installieren Sie python-pyinotify, um diese Funktion zu nutzen.\n" #~ msgid "lines annotated" #~ msgstr "Zeilen annotiert" #~ msgid "objects" #~ msgstr "Objekte" #~ msgid "pt." #~ msgstr "pt." #~ msgid "push %s" #~ msgstr "»%s« versenden..." #~ msgid "remote prune %s" #~ msgstr "Aufräumen von »%s«" #~ msgid "update-ref failed:" #~ msgstr "update-ref fehlgeschlagen:" #~ msgid "warning" #~ msgstr "Warnung" #~ msgid "warning: Tcl does not support encoding '%s'." #~ msgstr "Warning: Tcl/Tk unterstützt die Zeichencodierung »%s« nicht." #~ msgid "write-tree failed:" #~ msgstr "write-tree fehlgeschlagen:" git-cola-3.6/po/es.po000066400000000000000000001617411356743264500144770ustar00rootroot00000000000000# Translation of git-cola to Spanish. # Copyright (C) 2014 Pilar Molina Lopez # Copyright (C) 2014 David Aguilar # This file is distributed under the same license as the git-cola package. # # # Pilar Molina Lopez , 2014. # victorhck , 2018. msgid "" msgstr "" "Project-Id-Version: git-cola VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-17 01:06-0700\n" "PO-Revision-Date: 2018-08-04 18:02+0100\n" "Last-Translator: victorhck \n" "Language-Team: Spanish <>\n" "Language: es_ES\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Lokalize 2.0\n" msgid "" "\n" "

\n" " Drag and drop or use the Add button to add\n" " patches to the list\n" "

\n" " " msgstr "" "\n" "

\n" " Arrastre y suelte o use el botón Añadir para añadir\n" " parches a la lista\n" "

\n" " " #, python-format msgid "" "\n" "
\n" " Git Cola has been translated into different languages thanks\n" " to the help of the individuals listed below.\n" "\n" "
\n" "

\n" " Translation is approximate. If you find a mistake,\n" " please let us know by opening an issue on Github:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " We invite you to participate in translation by adding or updating\n" " a translation and opening a pull request.\n" "

\n" "\n" "
\n" "\n" " " msgstr "" "\n" "
\n" " Git Cola ha sido traducida a diferentes idiomas gracias\n" " a la ayuda de diferentes personas que se enumeran a continuación.\n" "\n" "
\n" "

\n" " La traducción es aproximada. Si encuentra un error,\n" " por favor avísenos para abrir una incidencia en Github:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " Le invitamos a participar en la traducción añadiendo o actualizando\n" " una traducción y abriendo un \"pull request\".\n" "

\n" "\n" "
\n" "\n" " " #, python-format msgid "" "\n" "
\n" " Git Cola version %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " msgstr "" "\n" "
\n" " Git Cola versión %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " #, python-format msgid "" "\n" "
\n" " Please use %(bug_link)s to report issues.\n" "
\n" " " msgstr "" "\n" "
\n" " Por favor utilice %(bug_link)s para informar de un problema.\n" "
\n" " " #, python-format msgid "" "\n" " Format String Variables\n" " -----------------------\n" " %(path)s = relative file path\n" " %(abspath)s = absolute file path\n" " %(dirname)s = relative directory path\n" " %(absdirname)s = absolute directory path\n" " %(filename)s = file basename\n" " %(basename)s = file basename without extension\n" " %(ext)s = file extension\n" msgstr "" "\n" " Formato de Variables de String\n" " -----------------------\n" " %(path)s = ruta de archivo relativa\n" " %(abspath)s = ruta del archivo absoluta\n" " %(dirname)s = ruta de la carpeta relativa\n" " %(absdirname)s = ruta de la carpeta absoluta\n" " %(filename)s = nombre base del archivo\n" " %(basename)s = nombre base del archivo sin extensión\n" " %(ext)s = extensión del archivo\n" msgid "" "\n" "Commands\n" "--------\n" "pick = use commit\n" "reword = use commit, but edit the commit message\n" "edit = use commit, but stop for amending\n" "squash = use commit, but meld into previous commit\n" "fixup = like \"squash\", but discard this commit's log message\n" "exec = run command (the rest of the line) using shell\n" "\n" "These lines can be re-ordered; they are executed from top to bottom.\n" "\n" "If you disable a line here THAT COMMIT WILL BE LOST.\n" "\n" "However, if you disable everything, the rebase will be aborted.\n" "\n" "Keyboard Shortcuts\n" "------------------\n" "? = show help\n" "j = move down\n" "k = move up\n" "J = shift row down\n" "K = shift row up\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "spacebar = toggle enabled\n" "\n" "ctrl+enter = accept changes and rebase\n" "ctrl+q = cancel and abort the rebase\n" "ctrl+d = launch difftool\n" msgstr "" "\n" "Comandos\n" "--------\n" "pick = usar commit\n" "reword = usar commit, pero editando el mensaje del commit\n" "edit = usar commit, pero parar al modificar\n" "squash = usar el commit, pero unirlo a un commit previo\n" "fixup = como \"squash\", pero descartando el mensaje de registro del commit\n" "exec = ejecutar un comando (el resto de la línea) utilizando la línea de comandos\n" "\n" "Estas líneas pueden ser re-ordenadas; son ejecutadas de arriba abajo.\n" "\n" "Si inhabilita una línea aquí ESE COMMIT SE PERDERÁ.\n" "\n" "Sin embargo, si inhabilita todo, el \"rebase\" será cancelado.\n" "\n" "Atajos de teclado\n" "------------------\n" "? = mostrar ayuda\n" "j = mover hacia abajo\n" "k = mover hacia arriba\n" "J = desplazar una fila hacia abajo\n" "K = desplazar una fila hacia arriba\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "spacebar = cambiador habilitado\n" "\n" "ctrl+enter = aceptar cambios y realizar un rebase\n" "ctrl+q = cancelar y abortar el rebase\n" "ctrl+d = arrancar la herramienta difftool\n" msgid "" "\n" "Keyboard Shortcuts\n" "------------------\n" "J, Down = Move Down\n" "K, Up = Move Up\n" "Enter = Edit Selected Files\n" "Spacebar = Open File Using Default Application\n" "Ctrl + L = Focus Text Entry Field\n" "? = Show Help\n" "\n" "The up and down arrows change focus between the text entry field\n" "and the results.\n" msgstr "" "\n" "Atajos de teclado\n" "------------------\n" "J, Down = Desplazar hacia abajo\n" "K, Up = Desplazar hacia arriba\n" "Enter = Editar los archivos seleccionados\n" "Spacebar = Abrir un archivo utilizando la aplicación predeterminada\n" "Ctrl + L = Llevar el foco al campo para introducir texto\n" "? = Mostrar ayuda\n" "\n" "Las flechas hacia arriba y hacia abajo cambian el foco entre los campos para introducir texto\n" "y los resultados.\n" msgid " - DAG" msgstr " - DAG" msgid " commits ago" msgstr "commits atrás" #, python-format msgid "\"%(branch)s\" has been deleted from \"%(remote)s\"." msgstr "\"%(branch)s\" ha sido eliminado de \"%(remote)s\"." #, python-format msgid "\"%(command)s\" returned exit status \"%(status)d\"" msgstr "\"%(command)s\" devolvieron este estado de salida \"%(status)d\"" #, python-format msgid "\"%(command)s\" returned exit status %(status)d" msgstr "\"%(command)s\" devolvieron este estado de salida %(status)d" #, python-format msgid "\"%s\" already exists" msgstr "\"%s\" ya existe" #, python-format msgid "\"%s\" already exists, cola will create a new directory" msgstr "\"%s\" ya existe, cola creará una nueva carpeta" #, python-format msgid "\"%s\" requires a selected file." msgstr "\"%s\" requiere que seleccione un archivo." msgid "#" msgstr "#" #, python-format msgid "%(project)s: %(branch)s - Browse" msgstr "%(project)s: %(branch)s - Navegar" #, python-format msgid "%(project)s: %(ref)s - DAG" msgstr "%(project)s: %(ref)s - DAG" #, python-format msgid "%d days ago" msgstr "Hace %d días" #, python-format msgid "%d hours ago" msgstr "Hace %d horas" #, python-format msgid "%d minutes ago" msgstr "Hace %d minutos" #, python-format msgid "%d patch(es) applied." msgstr "%d parche(s) aplicado(s)." #, python-format msgid "%d skipped" msgstr "%d omitido" #, python-format msgid "" "%s appears to contain merge conflicts.\n" "\n" "You should probably skip this file.\n" "Stage it anyways?" msgstr "" "%s parece contener conflictor al hacer merge.\n" "\n" "Quizás debería omitir este archivo.\n" "¿Incluirlo en \"Stage\" de todas formas?" #, python-format msgid "%s is not a Git repository." msgstr "%s no es un repositorio Git." #, python-format msgid "%s will be removed from your bookmarks." msgstr "%s será eliminado de sus marcadores." #, python-format msgid "%s will be removed from your recent repositories." msgstr "%s será eliminado de tus repositorios recientes." #, python-format msgid "%s: No such file or directory." msgstr "%s: el archivo o carpeta no existe." msgid "&Edit" msgstr "&Editar" msgid "&File" msgstr "&Archivo" msgid "(Amending)" msgstr "(Corrigiendo)" msgid "*** Branch Point ***" msgstr "*** Punto de la rama ***" msgid "*** Sandbox ***" msgstr "*** Sandbox ***" msgid "100%" msgstr "100%" msgid "200%" msgstr "200%" msgid "25%" msgstr "25%" msgid "400%" msgstr "400%" msgid "50%" msgstr "50%" msgid "800%" msgstr "800%" msgid " ..." msgstr " ..." msgid "" "A commit template has not been configured.\n" "Use \"git config\" to define \"commit.template\"\n" "so that it points to a commit template." msgstr "" "No se ha configurado una plantilla de commit.\n" "Utilice \"git config\" y modifique \"commit.template\"\n" "para que apunte a una plantilla." #, python-format msgid "A hook must be provided at \"%s\"" msgstr "Un hook debe ser configurado en \"%s\"" #, python-format msgid "A stash named \"%s\" already exists" msgstr "Un \"stash\" llamado \"%s\" ya existe" msgid "Abort" msgstr "Cancelar" msgid "Abort Action" msgstr "Cancelar acción" msgid "Abort Merge" msgstr "Cancelar Merge" msgid "Abort Merge..." msgstr "Cancelar Merge..." msgid "Abort the action?" msgstr "¿Desea cancelar la acción?" msgid "" "Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" "Recovering uncommitted changes is not possible." msgstr "" "Cancelar el \"merge\" actual causará que *TODOS* los cambios que no se haya hecho un commit se perderán.\n" "No es posible recuperar los cambios en los que no se haya hecho un commit." msgid "Aborting the current merge?" msgstr "¿Cancelar el merge actual?" msgid "About" msgstr "Acerca de" msgid "About git-cola" msgstr "Acerca de git-cola" msgid "Accept" msgstr "Aceptar" msgid "" "Accept changes and rebase\n" "Shortcut: Ctrl+Enter" msgstr "" "Aceptar cambios y rebase\n" "Atajo de teclado: Ctrl+Enter" msgid "Action Name" msgstr "Nombre de acción" msgid "Actions" msgstr "Acciones" msgid "Actions..." msgstr "Acciones..." msgid "Add" msgstr "Añadir" msgid "Add Favorite" msgstr "Añadir favorito" msgid "Add Remote" msgstr "Añadir repositorio remoto" msgid "Add Separator" msgstr "Añadir separador" msgid "Add Toolbar" msgstr "Añadir barra de herramientas" msgid "" "Add and remove remote repositories using the \n" "Add(+) and Delete(-) buttons on the left-hand side.\n" "\n" "Remotes can be renamed by selecting one from the list\n" "and pressing \"enter\", or by double-clicking." msgstr "" "Añadir y eliminar repositorios remotos usando los \n" "botones Añadir(+) y Eliminar(-) a la izquierda.\n" "\n" "Puede cambiar el nombre de los repositorios remotos \n" "seleccionando uno en la lista \n" "y presionando \"enter\", o haciendo doble clic." msgid "Add new remote git repository" msgstr "Añadir nuevo repositorio de git remoto" msgid "Add patches (+)" msgstr "Añadir parches (+)" msgid "Add remote" msgstr "Añadir repositorio remoto" msgid "Add to .gitignore" msgstr "Añadir a .gitignore" msgid "Add to Git Annex" msgstr "Añadir a Git Annex" msgid "Add to Git LFS" msgstr "Añadir a Git LFS" msgid "Additions" msgstr "Adiciones" msgid "Advanced" msgstr "Avanzado" msgid "Age" msgstr "Edad" msgid "All Repositories" msgstr "Todos los repositorios" #, python-format msgid "" "All submodules will be updated using\n" "\"%s\"" msgstr "" msgid "Allow non-fast-forward updates. Using \"force\" can cause the remote repository to lose commits; use it with care" msgstr "Permitir actualizaciones \"non-fast-forward\". Utilizar \"force\" puede causar que el repositorio remoto pierda los commits, utilizar con cuidado" msgid "Always create a merge commit when enabled, even when the merge is a fast-forward update" msgstr "Siempre utilizar un \"merge commit\" cuando este habilitado, incluso cuando el \"merge\" es una actualización \"fast-forward\"" msgid "Amend" msgstr "Corregir" msgid "Amend Commit" msgstr "Corregir commit" msgid "Amend Last Commit" msgstr "Corregir el último commit" msgid "Amend the published commit?" msgstr "¿Corregir el commit publicado?" msgid "Amending" msgstr "Corrigiendo" msgid "" "An action is still running.\n" "Terminating it could result in data loss." msgstr "" "Una acción está siendo ejecutada.\n" "Cancelarla podría causar pérdida de información." msgid "" "An unsigned, lightweight tag will be created instead.\n" "Create an unsigned tag?" msgstr "" "Una etiqueta sin firmar, de poca entidad será creada.\n" "¿Crear una etiqueta sin firmar?" msgid "Appearance" msgstr "" msgid "Apply" msgstr "Aplicar" msgid "Apply Patches" msgstr "Aplicar parches" msgid "Apply Patches..." msgstr "Aplicar parches..." msgid "Apply and drop the selected stash (git stash pop)" msgstr "Aplicar y eliminar el stash seleccionado (git stash pop)" msgid "Apply the selected stash" msgstr "Aplicar el stash seleccionado" msgid "Arguments" msgstr "Argumentos" msgid "Attach" msgstr "Adjuntar" msgid "Author" msgstr "Autor" msgid "Authors" msgstr "Autores" msgid "Auto" msgstr "" msgid "Auto-Wrap Lines" msgstr "Salto de línea automático" msgid "Basic Regexp" msgstr "Regexp básico" msgid "Blame Viewer" msgstr "" msgid "Blame selected paths" msgstr "" msgid "Blame..." msgstr "" msgid "Bold on dark headers instead of italic" msgstr "Fuente en negrita con fondo negro en vez de cabeceras en cursiva" msgid "Branch" msgstr "Rama" #, python-format msgid "" "Branch \"%(branch)s\" does not exist in \"%(remote)s\".\n" "A new remote branch will be published." msgstr "" "La rama \"%(branch)s\" no existe en \"%(remote)s\".\n" "Se publicará una nueva rama remota." #, python-format msgid "Branch \"%s\" already exists." msgstr "La rama \"%s\" ya existe." msgid "Branch Diff Viewer" msgstr "Visor de diferencias en ramas." msgid "Branch Exists" msgstr "Rama existe" msgid "Branch Name" msgstr "Nombre de la rama" #, python-format msgid "Branch: %s" msgstr "Rama: %s" msgid "Branches" msgstr "Ramas" msgid "Branches..." msgstr "Ramas..." msgid "Brazilian translation" msgstr "Traducción al Brasileño" msgid "Browse" msgstr "Navegar" msgid "Browse Commits..." msgstr "Navegar por los commits..." msgid "Browse Current Branch..." msgstr "Navegar por la rama actual..." msgid "Browse Other Branch..." msgstr "Navegar por otra rama..." msgid "Browse..." msgstr "Navegar..." msgid "Browser" msgstr "Navegador" #, python-format msgid "Browsing %s" msgstr "Navegado por %s" msgid "Bypass Commit Hooks" msgstr "Evitar Commit Hooks" msgid "Cancel" msgstr "Cancelar" msgid "" "Cancel rebase\n" "Shortcut: Ctrl+Q" msgstr "" "Cancelar rebase\n" "Atajo de teclado: Ctrl+Q" msgid "Cannot Amend" msgstr "No se puede corregir" #, python-format msgid "Cannot exec \"%s\": please configure a blame viewer" msgstr "" #, python-format msgid "Cannot exec \"%s\": please configure a history browser" msgstr "No se pudo ejecutar \"%s\": por favor, configure un navegador de historial" #, python-format msgid "Cannot exec \"%s\": please configure your editor" msgstr "No se pudo ejecutar \"%s\": por favor, configure su editor" msgid "Changed Upstream" msgstr "Cambiado aguas arriba (upstream)" msgid "Check Spelling" msgstr "Comprobar ortografía" msgid "Check spelling" msgstr "Comprobar ortografía" msgid "Checkout" msgstr "Checkout" msgid "Checkout After Creation" msgstr "Checkout después de crear" msgid "Checkout Branch" msgstr "Checkout rama" msgid "Checkout Detached HEAD" msgstr "Checkout HEAD separado" msgid "Checkout as new branch" msgstr "Checkout como nueva rama" msgid "Checkout..." msgstr "Checkout..." msgid "Cherry Pick" msgstr "Cherry Pick" msgid "Cherry-Pick Commit" msgstr "Cherry-Pick Commit" msgid "Cherry-Pick..." msgstr "Cherry-Pick..." msgid "Choose Paths" msgstr "Escoger ruta" msgid "Choose the \"git grep\" regular expression mode" msgstr "Escoger el modo de expresión regular \"git grep\"" msgid "Clear Default Repository" msgstr "Limpiar el repositorio predeterminado" msgid "Clear commit message" msgstr "Limpiar el mensaje de commit" msgid "Clear commit message?" msgstr "¿Limpiar el mensaje de commit?" msgid "Clear..." msgstr "Limpiar..." msgid "Clone" msgstr "Clonar" msgid "Clone Repository" msgstr "Clonar repositorio" msgid "Clone..." msgstr "Clonar..." #, python-format msgid "Cloning repository at %s" msgstr "Clonando repositorio en %s" msgid "Close" msgstr "Cerrar" msgid "Close..." msgstr "Cerrar..." msgid "Collapse all" msgstr "Colapsar todo" msgid "Command" msgstr "Comando" msgid "Commit" msgstr "Commit" msgid "Commit failed" msgstr "Commit fallido" msgid "Commit staged changes" msgstr "Hacer un commit de los cambios en \"stage\"" msgid "" "Commit staged changes\n" "Shortcut: Ctrl+Enter" msgstr "" "Hacer un commit de los cambios en \"stage\"\n" "Atajo de teclado: Ctrl+Enter" msgid "Commit summary" msgstr "Sumario de commit" msgid "Commit the merge if there are no conflicts. Uncheck to leave the merge uncommitted" msgstr "Hacer un commit del merge sin no hay conflictos. Desmarcar para dejar el merge sin commit" msgid "Commit@@verb" msgstr "Commit@@verb" msgid "Compare" msgstr "Comparar" msgid "Compare All" msgstr "Comparar todo" msgid "Configure the remote branch as the the new upstream" msgstr "Configurar la rama remota como la nueva \"upstream\"" msgid "Configure toolbar" msgstr "Configurar barra de herramientas" msgid "Console" msgstr "Terminal" msgid "Continue" msgstr "Continuar" msgid "Copy" msgstr "Copiar" msgid "Copy Basename to Clipboard" msgstr "Copiar el nombre base al portapapeles" msgid "Copy Leading Path to Clipboard" msgstr "Copiar la ruta principal al portapapeles" msgid "Copy Path to Clipboard" msgstr "Copiar la ruta al portapapeles" msgid "Copy Relative Path to Clipboard" msgstr "Copiar la ruta relativa al portapapeles" msgid "Copy SHA-1" msgstr "Copiar SHA-1" msgid "Copy..." msgstr "Copiar..." #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "No fue posible procesar la Git URL: \"%s\"" msgid "Create Branch" msgstr "Crear rama" msgid "Create Patch" msgstr "Crear parche" msgid "Create Remote Branch" msgstr "Crear rama remota" msgid "Create Signed Commit" msgstr "Crear commit firmado" msgid "Create Tag" msgstr "Crear etiqueta" msgid "Create Tag..." msgstr "Crear etiqueta..." msgid "Create Unsigned Tag" msgstr "Crear etiqueta sin firmar" msgid "Create a merge commit even when the merge resolves as a fast-forward" msgstr "Crear un \"merge commit\" incluso cuando el \"merge\" se resuelva como un \"fast-forward\"" msgid "Create a new remote branch?" msgstr "¿Desea crear una nueva rama remota?" msgid "Create..." msgstr "Crear..." #, python-format msgid "Created a new tag named \"%s\"" msgstr "Se creó una nueva etiqueta con nombre \"%s\"" msgid "Current Repository" msgstr "Repositorio actual" msgid "Custom Copy Actions" msgstr "Acciones de copiado personalizadas" msgid "Customize..." msgstr "Personalizar..." msgid "Cut" msgstr "Cortar" msgid "Czech translation" msgstr "Traducción al Checo" msgid "DAG..." msgstr "DAG..." msgid "Dark Theme" msgstr "" msgid "Date, Time" msgstr "Fecha, hora" msgid "Default" msgstr "" msgid "Delete" msgstr "Eliminar" #, python-format msgid "Delete %d file(s)?" msgstr "¿Desea eliminar %d archivo(s)?" msgid "Delete Bookmark" msgstr "Eliminar marcadores" msgid "Delete Bookmark?" msgstr "¿Eliminar marcadores?" msgid "Delete Branch" msgstr "Eliminar rama" msgid "Delete Files" msgstr "Eliminar archivos" msgid "Delete Files..." msgstr "Eliminar archivos..." msgid "Delete Files?" msgstr "¿Eliminar archivos?" msgid "Delete Remote" msgstr "Eliminar repositorio remoto" msgid "Delete Remote Branch" msgstr "Eliminar rama remota" msgid "Delete Remote Branch..." msgstr "Eliminar rama remota..." msgid "Delete remote" msgstr "Eliminar repositorio remoto" #, python-format msgid "Delete remote \"%s\"" msgstr "Eliminar repositorio remoto \"%s\"" msgid "Delete remote?" msgstr "¿Desea eliminar el repositorio remoto?" msgid "Delete selected branch?" msgstr "¿Desea eliminar la rama seleccionada?" msgid "Delete toolbar" msgstr "Eliminar barra de herramientas" msgid "Delete..." msgstr "Eliminar..." #, python-format msgid "Deleting \"%s\" failed" msgstr "Fallo intentando eliminar \"%s\"" msgid "Deletions" msgstr "Eliminaciones" msgid "Detach" msgstr "Separar" msgid "Detect Conflict Markers" msgstr "Detectar Conflict Markers" msgid "Detect conflict markers in unmerged files" msgstr "Detectar conflicto en marcadores en archivos en los que no se haya hecho merge" msgid "Developer" msgstr "Desarrollador" msgid "Diff" msgstr "Diferencia" msgid "Diff Against Predecessor..." msgstr "Diferencia respecto del predecesor..." msgid "Diff Options" msgstr "Opciones al mostrar las diferencias" msgid "Diff Tool" msgstr "Herramienta de diferencias (Diff)" msgid "Diff selected -> this" msgstr "Diferencia seleccionada -> esta" msgid "Diff this -> selected" msgstr "Comprobar diferencias en esta -> seleccionada" msgid "Diffstat" msgstr "Mostrar diferencias (Diffstat)" msgid "Difftool" msgstr "Herramienta Diff" msgid "Directory Exists" msgstr "La carpeta ya existe" msgid "Display Untracked Files" msgstr "Mostrar ficheros sin seguimiento" msgid "Documentation" msgstr "Documentación" msgid "Drop" msgstr "Abandonar" msgid "Drop Stash" msgstr "Abandonar Stash" msgid "Drop Stash?" msgstr "¿Abandonar Stash?" #, python-format msgid "Drop the \"%s\" stash?" msgstr "¿Abandonar el Stash \"%s\"?" msgid "Drop the selected stash" msgstr "Abandonar el Stash seleccionado" msgid "Edit" msgstr "Editar" msgid "Edit Rebase" msgstr "Editar Rebase" msgid "Edit Remotes" msgstr "Editar repositorios remotos" msgid "Edit Remotes..." msgstr "Editar repositorios remotos..." msgid "Edit remotes by selecting them from the list" msgstr "Editr repositorios remotos seleccionándolos de la lista" msgid "Edit selected paths" msgstr "Editar rutas seleccionadas" msgid "Edit..." msgstr "Editar..." msgid "Editor" msgstr "Editor" msgid "Email Address" msgstr "Dirección de correo electrónico" msgid "Email contributor" msgstr "Dirección de correo electrónico del colaborador" msgid "Enabled" msgstr "Habilitado" msgid "Enter New Branch Name" msgstr "Introducir el nombre de la rama" msgid "Enter a name for the new bare repo" msgstr "Introducir el nombre para el nuevo repositorio remoto básico" msgid "Enter a name for the stash" msgstr "Introducir el nombre para el Stash" msgid "Error" msgstr "Error" msgid "Error Cloning" msgstr "Error al clonar" msgid "Error Creating Branch" msgstr "Error al crear rama" msgid "Error Creating Repository" msgstr "Error al crear repositorio" msgid "Error Deleting Remote Branch" msgstr "Error al eliminar rama remota" msgid "Error Editing File" msgstr "Error al editar el archivo" msgid "Error Launching Blame Viewer" msgstr "Error al arrancar el Blame Viewer" msgid "Error Launching History Browser" msgstr "Error al arrancar el navegador del historial" #, python-format msgid "Error creating remote \"%s\"" msgstr "Error al crear el repositorio remoto \"%s\"" msgid "Error creating stash" msgstr "Error al Crear Stash" #, python-format msgid "Error deleting remote \"%s\"" msgstr "Error al eliminar el repositorio remoto \"%s\"" #, python-format msgid "Error renaming \"%(name)s\" to \"%(new_name)s\"" msgstr "Error al renombrar \"%(name)s\" a \"%(new_name)s\"" msgid "Error running prepare-commitmsg hook" msgstr "" #, python-format msgid "Error updating submodule %s" msgstr "Error al crear el archivo %s" msgid "Error updating submodules" msgstr "" msgid "Error: Cannot find commit template" msgstr "Error: No se pudo encontrar la plantilla para el commit" msgid "Error: Stash exists" msgstr "Error: ya existe el Stash" msgid "Error: Unconfigured commit template" msgstr "Error: Plantilla para el commit no configurada" #, python-format msgid "Error: could not clone \"%s\"" msgstr "Error: no se pudo clonar \"%s\"" #, python-format msgid "Error: could not create tag \"%s\"" msgstr "Error: no se pudo crear la etiqueta \"%s\"" #, python-format msgid "Executing action %s" msgstr "Ejecutando la acción %s" msgid "Expand all" msgstr "Expandir todo" msgid "Export Patches" msgstr "Exportar parches" msgid "Export Patches..." msgstr "Exportar parches..." msgid "Expression..." msgstr "Expresión..." msgid "Extended Regexp" msgstr "Extender Regexp" msgid "Extended description..." msgstr "Descripción extendida..." msgid "Fast Forward Only" msgstr "Sólo Fast Forward" msgid "Fast-forward only" msgstr "Sólo Fast-forward" msgid "Favorite repositories" msgstr "Repositorios favoritos" msgid "Favorites" msgstr "Favoritos" msgid "Fetch" msgstr "Extraer (Fetch)" msgid "Fetch Tracking Branch" msgstr "Extraer (Fetch) la rama en seguimiento" msgid "Fetch..." msgstr "Extraer (Fetch)..." msgid "File Browser..." msgstr "Navegador de archivos..." msgid "File Differences" msgstr "Diferencias de archivos" msgid "File Saved" msgstr "Archivo guardado" #, python-format msgid "File saved to \"%s\"" msgstr "Archivo guardado en \"%s\"" msgid "File system change monitoring: disabled because \"cola.inotify\" is false.\n" msgstr "Supervisión del cambio del sistema de archivo: está desactivada porque \"cola.inotify\" es falso\n" msgid "File system change monitoring: disabled because libc does not support the inotify system calls.\n" msgstr "Supervisión del cambio del sistema de archivo: está desactivada porque libc no es compatible con el sistema de llamadas de inotify.\n" msgid "File system change monitoring: disabled because pywin32 is not installed.\n" msgstr "Supervisión del cambio del sistema de archivo: está desactivada porque pywin32 no está instalada.\n" msgid "" "File system change monitoring: disabled because the limit on the total number of inotify watches was reached. You may be able to increase the limit on the number of watches by running:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" msgstr "" "Supervisión del cambio del sistema de archivo: está desactivada porque el límite del número total de los seguimientos que hace inotify se ha alcanzado. Debería incrementar el número del límite de seguimientos que se pueden ejecutar:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" msgid "File system change monitoring: enabled.\n" msgstr "Supervisión del cambio del sistema de archivo: activada.\n" msgid "Filename" msgstr "Nombre de archivo" msgid "Files" msgstr "Archivos" msgid "Filter branches..." msgstr "Filtrar ramas..." msgid "Filter paths..." msgstr "Filtrar rutas..." msgid "Find Files" msgstr "Encontrar archivos" msgid "Fixed String" msgstr "Cadena fijada" msgid "Fixed-Width Font" msgstr "Fijar ancho de fuente" msgid "Fixup" msgstr "Arreglar" msgid "Fixup Previous Commit" msgstr "Arreglar un Commit previo" msgid "Flat dark blue" msgstr "" msgid "Flat dark green" msgstr "" msgid "Flat dark grey" msgstr "" msgid "Flat dark red" msgstr "" msgid "Flat light blue" msgstr "" msgid "Flat light green" msgstr "" msgid "Flat light grey" msgstr "" msgid "Flat light red" msgstr "" msgid "Font Size" msgstr "Tamaño de fuente" msgid "Force" msgstr "Forzar" msgid "Force Fetch" msgstr "Forzar extracción (Fetch)" msgid "Force Fetch?" msgstr "¿Forzar extracción (Fetch)?" msgid "Force Push" msgstr "Forzar Push" msgid "Force Push?" msgstr "¿Forzar Push?" #, python-format msgid "Force fetching from %s?" msgstr "¿Forzar extracción desde %s?" #, python-format msgid "Force push to %s?" msgstr "¿Forzar Push a %s?" msgid "Format String" msgstr "Formato de cadena" msgid "French translation" msgstr "Traducción al Francés" msgid "GPG-sign the merge commit" msgstr "Firmar mediante GPG el Merge Commit" msgid "GUI theme" msgstr "" #, python-format msgid "Gathering info for \"%s\"..." msgstr "Runiendo información para \"%s\"..." msgid "German translation" msgstr "Traducción al Alemán" msgid "Get Commit Message Template" msgstr "Aplicar plantilla de mensaje de Commit" msgid "Go Down" msgstr "Bajar" msgid "Go Up" msgstr "Subir" msgid "Grab File..." msgstr "Tomar archivo..." msgid "Graph" msgstr "Gráfico" msgid "Grep" msgstr "Grep" msgid "Have you rebased/pulled lately?" msgstr "¿Ha realizado un rebase/pull recientemente?" msgid "Help" msgstr "Ayuda" msgid "Help - Custom Copy Actions" msgstr "Ayuda - Acciones de copiado personalizadas" msgid "Help - Find Files" msgstr "Ayuda - Encontrar archivos" msgid "Help - git-xbase" msgstr "Ayuda - git-xbase" msgid "Hide Details.." msgstr "Ocultar detalles..." msgid "High DPI" msgstr "" msgid "History Browser" msgstr "Navegador de historial" msgid "Hungarian translation" msgstr "Traducción al Húngaro" msgid "Icon theme" msgstr "" msgid "Ignore all whitespace" msgstr "Ignorar todos los espacios en blanco" msgid "Ignore changes in amount of whitespace" msgstr "Ignorar cambios en la cantidad de espacios en blanco" msgid "Ignore changes in whitespace at EOL" msgstr "Ignorar cambios de espacios en blanco en EOL" msgid "Ignore custom pattern" msgstr "Ignorar patrón personalizado" msgid "Ignore exact filename" msgstr "Ignorar el nombre de archivo exacto" msgid "Ignore filename or pattern" msgstr "Ignorar nombre de archivo o patrón" msgid "Include tags " msgstr "Incluir etiquetas " msgid "Indent Status paths" msgstr "" msgid "Indonesian translation" msgstr "Traducción al Indonesio" msgid "Initialize Git Annex" msgstr "Inicializar Git Annex" msgid "Initialize Git LFS" msgstr "Inicializar Git LFS" msgid "Inititalize submodules" msgstr "Inicializar submódulos" msgid "Insert spaces instead of tabs" msgstr "Insertar espacios en vez de tabulaciones" msgid "Interactive Rebase" msgstr "Rebase interactivo" msgid "Invalid Revision" msgstr "Revisión inválida" msgid "Keep *.orig Merge Backups" msgstr "Conservar Merge Backups *.orig" msgid "Keep Index" msgstr "Mantener Index" msgid "Keyboard Shortcuts" msgstr "Atajos de teclado" msgid "Launch Diff Tool" msgstr "Ejecutar la herramienta de comparación" msgid "Launch Directory Diff Tool" msgstr "Ejecutar la herramienta de comparación de carpetas" msgid "Launch Editor" msgstr "Abrir Editor" msgid "Launch Terminal" msgstr "Abrir Terminal" msgid "" "Launch external diff tool\n" "Shortcut: Ctrl+D" msgstr "" "Abrir una herramienta de diferencias externa\n" "Atajo de teclado: Ctrl+D" msgid "Launch git-cola" msgstr "Ejecutar git-cola" msgid "Launch git-difftool against previous versions" msgstr "Ejecutar git-difftool en versiones previas" msgid "Launch git-difftool on the current path" msgstr "Ejecutar git-difftool en la ruta actual" msgid "Light Theme" msgstr "" msgid "Load Commit Message" msgstr "Cargar el mensaje del Commit" msgid "Load Commit Message..." msgstr "Cargar el mensaje del Commit..." msgid "Load Previous Commit Message" msgstr "Cargar un mensaje del Commit previo" msgid "Loading..." msgstr "Cargando..." msgid "Local" msgstr "Local" msgid "Local Branch" msgstr "Rama local" msgid "Local branch" msgstr "Rama local" msgid "Lock Layout" msgstr "Bloquear paneles" msgid "Log" msgstr "Registro" msgid "Maintainer (since 2007) and developer" msgstr "Responsable (desde 2007) y desarrollador" msgid "Merge" msgstr "Merge" #, python-format msgid "Merge \"%(revision)s\" into \"%(branch)s\"" msgstr "Merge \"%(revision)s\" con \"%(branch)s\"" msgid "Merge Tool" msgstr "Herramienta Merge" msgid "Merge Verbosity" msgstr "Mostrar mensajes de salida de Merge" msgid "Merge failed. Conflict resolution is required." msgstr "Falló Merge. Se necesita resolver los conflictos." #, python-format msgid "Merge into \"%s\"" msgstr "Merge en \"%s\"" msgid "Merge into current branch" msgstr "Merge en la rama actual" msgid "Merge..." msgstr "Merge..." msgid "Merging" msgstr "Uniendo" msgid "Message" msgstr "Mensaje" msgid "Missing Commit Message" msgstr "Mensaje de commit ausente" msgid "Missing Data" msgstr "Datos ausentes" msgid "Missing Name" msgstr "Nombre ausente" msgid "Missing Revision" msgstr "Revisión ausente" msgid "Missing Tag Message" msgstr "Mensaje de etiqueta ausente" msgid "Modified" msgstr "Modificado" msgid "More..." msgstr "Más..." msgid "Move Down" msgstr "Bajar" msgid "Move Up" msgstr "Subir" msgid "Move files to trash" msgstr "Mover los archivos a la papelera" msgid "Name" msgstr "Nombre" msgid "Name for the new remote" msgstr "Nombre para el nuevo repositorio remoto" msgid "New Bare Repository..." msgstr "Nuevo repositorio..." msgid "New Repository..." msgstr "Nuevo repositorio..." msgid "New..." msgstr "Nuevo..." msgid "Next File" msgstr "Archivo siguiente" msgid "No" msgstr "No" msgid "No Revision Specified" msgstr "No se ha especificado una revisión" msgid "" "No changes to commit.\n" "\n" "You must stage at least 1 file before you can commit." msgstr "" "Sin cambios para hacer commit.\n" "\n" "Debe realizar al menos un cambio antes de poder hacer un commit." msgid "No commits exist in this branch." msgstr "No existen commits en esta rama." msgid "No fast forward" msgstr "Sin \"fast forward\"" msgid "No fast-forward" msgstr "Sin \"fast-forward\"" msgid "No repository selected." msgstr "Ningún repositorio ha sido seleccionado." msgid "Non-fast-forward fetch overwrites local history!" msgstr "¡Ningún \"fast-forward\" sobreescribe el historial local!" msgid "" "Non-fast-forward push overwrites published history!\n" "(Did you pull first?)" msgstr "" "¡Ningún \"fast-forward\" sobreescribe el historial publicado!\n" "(¿Ha ejecutado \"pull\" primero?)" msgid "Nothing to commit" msgstr "Nada para hace commit" msgid "Nothing to do" msgstr "Nada que hacer" msgid "Number of Diff Context Lines" msgstr "Numero de lineas de contexto Diff" msgid "Open" msgstr "Abrir" msgid "Open Git Repository..." msgstr "Abrir Repositorio Git..." msgid "Open Parent" msgstr "" msgid "Open Parent Directory" msgstr "Abrir carpeta padre" msgid "Open Recent" msgstr "Abrir recientes" msgid "Open Using Default Application" msgstr "Abrir utilizando la aplicación predeterminada" msgid "Open in New Window" msgstr "Abrir en una ventana nueva" msgid "Open in New Window..." msgstr "Abrir en una ventana nueva..." msgid "Open..." msgstr "Abrir..." msgid "Other branches" msgstr "Otras ramas" msgid "Overwrite" msgstr "Sobrescribir" #, python-format msgid "Overwrite \"%s\"?" msgstr "¿Desea sobrescribir \"%s\"?" msgid "Overwrite File?" msgstr "¿Desea sobrescribir el archivo?" msgid "" "Parse arguments using a shell.\n" "Queries with spaces will require \"double quotes\"." msgstr "" "Analizar los argumentos utilizando la línea de comandos.\n" "Las consultas con espacios requerirán \"comillas dobles\". " msgid "Partially Staged" msgstr "En \"Stage\" parcialmente" msgid "Paste" msgstr "Pegar" msgid "Patch(es) Applied" msgstr "Parche(s) aplicado(s)" msgid "Path" msgstr "Ruta" msgid "Path or URL to clone (Env. $VARS okay)" msgstr "Ruta o URL a clonar (Env. $VARS okay)" msgid "Pick" msgstr "Escoger" msgid "Pixel XOR" msgstr "Pixel XOR" msgid "Please provide both a branch name and revision expression." msgstr "Por favor proporcione tanto el nombre de la rama como la expresión de la revisión." msgid "Please select a file" msgstr "Por favor, seleccione un archivo" msgid "Please specify a name for the new tag." msgstr "Por favor, especifique un nombre para la nueva etiqueta." msgid "Please specify a revision to tag." msgstr "Por favor, especifique una revisión para etiquetar." msgid "" "Please supply a commit message.\n" "\n" "A good commit message has the following format:\n" "\n" "- First line: Describe in one sentence what you did.\n" "- Second line: Blank\n" "- Remaining lines: Describe why this change is good.\n" msgstr "" "Por favor, proporciones un mensaje para el commit.\n" "\n" "Un buen mensaje de commit tiene el siguiente formato:\n" "\n" "- Primera línea: Describa en una línea lo que ha realizado.\n" "- Segunda línea: En blanco.\n" "- Las líneas restantes: Describa porque este cambio es apropiado.\n" msgid "Point the current branch head to a new commit?" msgstr "¿Apuntar la el comienzo de la rama actual a un nuevo commit?" msgid "Polish translation" msgstr "Traducción al Polaco" msgid "Pop" msgstr "Pop" msgid "Preferences" msgstr "Preferencias" msgid "Prefix" msgstr "Prefijo" msgid "Prepare Commit Message" msgstr "Cargar mensaje de commit" msgid "Prevent \"Stage\" from staging all files when nothing is selected" msgstr "Evitar el \"Stage\" de todos los archivos cuando nada es seleccionado" msgid "Previous File" msgstr "Archivo anterior" msgid "Prompt on creation" msgstr "Solicitud de creación" msgid "Prompt when pushing creates new remote branches" msgstr "Solicitar que al hacer \"push\" cree nuevas ramas en el repositorio remoto" msgid "Prune " msgstr "Prune " msgid "Pull" msgstr "Pull" msgid "Pull..." msgstr "Pull..." msgid "Push" msgstr "Push" msgid "Push..." msgstr "Push..." msgid "Quit" msgstr "Salir" msgid "Rebase" msgstr "Rebase" #, python-format msgid "Rebase onto %s" msgstr "Rebase en %s" msgid "Rebase stopped" msgstr "Rebase detenido" msgid "Rebase the current branch instead of merging" msgstr "Hacer \"rebase\" de la rama actual en vez de unirlas (merge)" msgid "Rebasing" msgstr "Rebasing" msgid "Recent" msgstr "Reciente" msgid "Recent repositories" msgstr "Repositorios recientes" msgid "Recent repository count" msgstr "Enumerar los repositorios recientes" msgid "Recently Modified Files" msgstr "Archivos modificados recientemente" msgid "Recently Modified Files..." msgstr "Archivos modificados recientemente..." msgid "Recovering a dropped stash is not possible." msgstr "No es posible recuperar un \"stash\" eliminado." msgid "Recovering lost commits may not be easy." msgstr "Recuperar \"commits\" perdidos puede que no sea sencillo." msgid "Redo" msgstr "Rehacer" msgid "Reduce commit history to minimum" msgstr "Reducir el historial de \"commit\" al mínimo" msgid "Refresh" msgstr "Refrescar" msgid "Refuse to merge unless the current HEAD is already up-to-date or the merge can be resolved as a fast-forward" msgstr "Evite realizar un \"merge\" a menos que el HEAD actual ya esté actualizado o el \"merge\" se puede resolver como un \"fast-forward\"" msgid "Remote" msgstr "Repositorio Remoto" msgid "Remote Branch" msgstr "Rama remota" msgid "Remote Branch Deleted" msgstr "Rama remota eliminada" msgid "Remote git repositories - double-click to rename" msgstr "Repositorios de git remotos - doble clic para renombrar" msgid "Remove" msgstr "Eliminar" #, python-format msgid "Remove %s from the recent list?" msgstr "¿Eliminar %s de la lista de recientes?" msgid "Remove Element" msgstr "Eliminar elemento" msgid "Remove remote-tracking branches that no longer exist on the remote" msgstr "Eliminar el seguimiento de ramas remotas que ya no existen en el repositorio remoto" msgid "Remove selected (Delete)" msgstr "Eliminar seleccionados (Delete)" msgid "Rename" msgstr "Renombrar" #, python-format msgid "Rename \"%s\"" msgstr "Renombrar \"%s\"" msgid "Rename Branch" msgstr "Renombrar rama" msgid "Rename Branch..." msgstr "Renombrar rama..." msgid "Rename Existing Branch" msgstr "Renombrar una rama existente" msgid "Rename Remote" msgstr "Renombrar repositorio remoto" msgid "Rename Repository" msgstr "Renombrar repositorio" msgid "Rename branch" msgstr "Renombrar rama" #, python-format msgid "Rename remote \"%(current)s\" to \"%(new)s\"?" msgstr "¿Desea renombrar el repositorio remoto \"%(current)s\" como \"%(new)s\"?" msgid "Rename selected paths" msgstr "Renombrar las rutas seleccionadas" #, python-format msgid "Repository: %s" msgstr "Repositorio: %s" msgid "Reset" msgstr "Reiniciar" #, python-format msgid "Reset \"%(branch)s\" to \"%(revision)s\"?" msgstr "¿Reiniciar \"%(branch)s\" a \"%(revision)s\"?" msgid "Reset Branch" msgstr "Reiniciar rama" msgid "Reset Branch Head" msgstr "Reiniciar inicio (head) de rama" msgid "Reset Branch?" msgstr "¿Reiniciar rama?" msgid "Reset Hard" msgstr "Reinicio duro (hard)" msgid "Reset Merge" msgstr "Reiniciar \"merge\"" msgid "Reset Soft" msgstr "Reinicio suave (soft)" msgid "Reset Worktree" msgstr "Reiniciar el árbol de trabajo" msgid "Reset hard?" msgstr "¿Reinicio duro (hard)?" msgid "Reset merge?" msgstr "¿Reiniciar \"merge\"?" msgid "Reset soft?" msgstr "¿Reinicio suave (soft)?" msgid "Reset worktree?" msgstr "¿Reiniciar el árbol de trabajo de trabajo?" #, python-format msgid "Resetting \"%(branch)s\" to \"%(revision)s\" will lose commits." msgstr "Reiniciar \"%(branch)s\" a \"%(revision)s\" hara que se pierdan los \"commits\"." msgid "Restart the application after changing appearance settings." msgstr "" msgid "Revert" msgstr "Revertir" msgid "Revert Diff Hunk" msgstr "Revertir Diff Hunk" msgid "Revert Diff Hunk..." msgstr "Revertir Diff Hunk..." msgid "Revert Diff Hunk?" msgstr "¿Revertir Diff Hunk?" msgid "Revert Selected Lines" msgstr "Revertir las líneas seleccionadas" msgid "Revert Selected Lines..." msgstr "Revertir las líneas seleccionadas..." msgid "Revert Selected Lines?" msgstr "¿Revertir las líneas seleccionadas?" msgid "Revert Uncommitted Changes" msgstr "Revertir los cambios en los que no se haya hecho \"commit\"" msgid "Revert Uncommitted Changes?" msgstr "¿Revertir los cambios en los que no se haya hecho \"commit\"?" msgid "Revert Uncommitted Edits..." msgstr "Revertir las ediciones en las que no se haya hecho \"commit\"..." msgid "Revert Unstaged Changes" msgstr "Revertir cambios que no estén en \"stage\"" msgid "Revert Unstaged Changes?" msgstr "¿Revertir cambios que no estén en \"stage\"?" msgid "Revert Unstaged Edits..." msgstr "Revertir cambios que no estén en \"stage\"..." msgid "Revert the uncommitted changes?" msgstr "¿Revertir los cambios en los que no se haya hecho commit?" msgid "Revert the unstaged changes?" msgstr "¿Revertir cambios que no estén en \"stage\"?" msgid "Revert uncommitted changes to selected paths" msgstr "Revertir los cambios en los que no se haya hecho \"commit\" a las rutas seleccionadas" msgid "Revert unstaged changes to selected paths" msgstr "Revertir cambios que no estén en \"stage\" a las rutas seleccionadas" msgid "Review" msgstr "Revisar" msgid "Review..." msgstr "Revisar..." msgid "Revision" msgstr "Revisión" msgid "Revision Expression:" msgstr "Expresión de revisión:" msgid "Revision to Merge" msgstr "Revisión a unir (merge)" msgid "Reword" msgstr "Redactar de otra forma" msgid "Rewrite Published Commit?" msgstr "¿Reescribir el \"commit\" publicado?" msgid "Run" msgstr "Ejecutar" #, python-format msgid "Run \"%s\"?" msgstr "¿Desea ejecutar \"%s\"?" #, python-format msgid "Run %s?" msgstr "¿Desea ejecutar %s?" #, python-format msgid "Run the \"%s\" command?" msgstr "¿Desea ejecutar el comando \"%s\"?" #, python-format msgid "Running command: %s" msgstr "Ejecutando comando: %s" msgid "Russian translation" msgstr "Traducción al Ruso" msgid "SHA-1" msgstr "SHA-1" msgid "Safe Mode" msgstr "Modo seguro" msgid "Save" msgstr "Guardar" msgid "Save Archive" msgstr "Guardar archivo" msgid "Save As Tarball/Zip..." msgstr "Guardar como Tarball/Zip..." msgid "Save GUI Settings" msgstr "Guardar ajustes de la interfaz de usuario" msgid "Save Stash" msgstr "Guardar Stash" msgid "Save modified state to new stash" msgstr "Guardar el estado modificado a un nuevo \"stash\"" #, python-format msgid "Saved \"%(filename)s\" from \"%(ref)s\" to \"%(destination)s\"" msgstr "Se guardó \"%(filename)s\" de \"%(ref)s\" en \"%(destination)s\"" msgid "Search" msgstr "Buscar" msgid "Search Authors" msgstr "Buscar autores" msgid "Search Commit Messages" msgstr "Buscar mensajes de commit" msgid "Search Committers" msgstr "Buscar a quien ha realizado commits" msgid "Search Date Range" msgstr "Buscar en un rango de fechas" msgid "Search Diffs" msgstr "Buscar Diffs" msgid "Search by Expression" msgstr "Buscar por expresión" msgid "Search by Path" msgstr "Buscar por ruta" msgid "Search for a fixed string" msgstr "Buscar por una cadena fija" msgid "Search using a POSIX basic regular expression" msgstr "Buscar utilizando expresión regular básica POSIX " msgid "Search using a POSIX extended regular expression" msgstr "Buscar utilizando expresión regular extendida POSIX " msgid "Search..." msgstr "Buscar..." msgid "Select" msgstr "Seleccionar" msgid "Select All" msgstr "Seleccionar todo" msgid "Select Branch to Review" msgstr "Seleccionar rama para revisar" msgid "Select Child" msgstr "Seleccionar hijo" msgid "Select Commit" msgstr "Seleccionar commit" msgid "Select Directory..." msgstr "Seleccionar carpeta..." msgid "Select New Upstream" msgstr "Sleccionar un nuevo repositorio \"aguas arriba (upstream)" msgid "Select Newest Child" msgstr "Seleccionar hijo más reciente" msgid "Select Oldest Parent" msgstr "Seleccionar padre más antiguo" msgid "Select Parent" msgstr "Seleccionar padre" msgid "Select Previous Version" msgstr "Seleccionar una versión previa" msgid "Select Repository..." msgstr "Seleccionar repositorio..." msgid "Select a parent directory for the new clone" msgstr "Seleccione un directorio padre para el nuevo clonado" msgid "Select manually..." msgstr "Seleccionar manualmente..." msgid "Select output dir" msgstr "" msgid "Select output directory" msgstr "Seleccionar carpeta de salida" msgid "Select patch file(s)..." msgstr "Seleccionar archivo(s) de parche..." msgid "Select repository" msgstr "Seleccionar repositorio..." msgid "Set Default Repository" msgstr "Establecer el repositorio como predeterminado" msgid "Set Upstream Branch" msgstr "Establecer rama aguas arriba (upstream)" msgid "" "Set the sort order for branches and tags.\n" "Toggle between date-based and version-name-based sorting." msgstr "" msgid "Set upstream" msgstr "Establecer aguas arriba (upstream)" msgid "Settings" msgstr "Ajustes" msgid "Shell arguments" msgstr "Argumentos línea de comandos" msgid "Shift Down" msgstr "Desplazar hacia abajo" msgid "Shift Up" msgstr "Desplazar hacia arriba" msgid "Shortcuts" msgstr "Atajos" msgid "Show Details..." msgstr "Mostrar detalles..." msgid "Show Diffstat After Merge" msgstr "Mostrar \"Diffstat\" tras hacer \"merge\"" msgid "Show Full Paths in the Window Title" msgstr "Mostrar las rutas completas en el título de la ventana" msgid "Show Help" msgstr "Mostrar ayuda" msgid "Show History" msgstr "Mostrar historial" msgid "Show file counts in Status titles" msgstr "" msgid "" "Show help\n" "Shortcut: ?" msgstr "" "Mostrar ayuda\n" "Atajo de teclado: ?" msgid "Show icon? (if available)" msgstr "¿Mostrar icono? (si está disponible)" msgid "Show line numbers" msgstr "Mostrar el número de línea" msgid "Show whole surrounding functions of changes" msgstr "Mostrar todo lo que rodea las funciones de cambios" msgid "Showing changes since" msgstr "Mostrando cambios desde" msgid "Side by side" msgstr "Lado al lado" msgid "Sign Off" msgstr "Cerrar sesión" msgid "Sign Tag" msgstr "Firmar etiqueta" msgid "Sign off on this commit" msgstr "Cerrar sesión en este \"commit\"" msgid "Simplified Chinese translation" msgstr "Traducción al Chino simplificado" msgid "Skip" msgstr "Omitir" msgid "Skip Current Patch" msgstr "Omitir el parche actual" msgid "Sort bookmarks alphabetically" msgstr "Ordenar los marcadores alfabéticamente" msgid "Spanish translation" msgstr "Traducción al Español" msgid "Specifies the SHA-1 to tag" msgstr "Especifica la firma SHA-1 a la etiqueta" msgid "Specifies the tag message" msgstr "Especifica el mensaje de la etiqueta" msgid "Specifies the tag name" msgstr "Especifica el nombre de la etiqueta" msgid "Spelling Suggestions" msgstr "Sugerencias de ortografía" msgid "Squash" msgstr "Concentrar (squash)" msgid "Squash the merged commits into a single commit" msgstr "Concentrar los commits unidos (merged) en un único commit" msgid "Stage" msgstr "Stage" msgid "Stage / Unstage" msgstr "Stage / Unstage" msgid "Stage All Untracked" msgstr "" msgid "Stage Changed Files To Commit" msgstr "" msgid "Stage Diff Hunk" msgstr "" msgid "Stage Modified" msgstr "" msgid "Stage Selected" msgstr "" msgid "Stage Selected Lines" msgstr "" msgid "Stage Unmerged" msgstr "" msgid "Stage Untracked" msgstr "" msgid "Stage and Commit" msgstr "" msgid "Stage and commit?" msgstr "" msgid "Stage conflicts" msgstr "" msgid "Stage conflicts?" msgstr "" msgid "Stage/unstage selected paths for commit" msgstr "" msgid "Staged" msgstr "" #, python-format msgid "Staging: %s" msgstr "" msgid "Start Interactive Rebase..." msgstr "Comenzar rebase interactivo..." msgid "Starting Revision" msgstr "Comenzando revisión" msgid "Stash" msgstr "" msgid "Stash Index" msgstr "" msgid "Stash staged changes only" msgstr "" msgid "Stash unstaged changes only, keeping staged changes" msgstr "" msgid "Stash..." msgstr "" msgid "Status" msgstr "Estado" msgid "Stop tracking paths" msgstr "Dejar de seguir las rutas" msgid "Submodules" msgstr "" msgid "Summarize Merge Commits" msgstr "Sumario de Merge Commits" msgid "Summary" msgstr "Resumen" msgid "Tab Width" msgstr "Ancho de tabulación" msgid "Tag" msgstr "Etiqueta" msgid "Tag Created" msgstr "Etiqueta Creada" msgid "Tag message..." msgstr "Mensaje de etiqueta..." msgid "Tag-signing was requested but the tag message is empty." msgstr "Se necesitó una firma de la etiqueta pero el mensaje de la etiqueta está vacío." msgid "Tags" msgstr "Etiquetas" msgid "Text Width" msgstr "Ancho del texto" msgid "The branch will be no longer available." msgstr "La rama no volverá a estar disponible." #, python-format msgid "The branch will be reset using \"git reset --hard %s\"" msgstr "La rama será reiniciada utilizando \"git reset --hard %s\"" #, python-format msgid "The branch will be reset using \"git reset --merge %s\"" msgstr "La rama será reiniciada utilizando \"git reset --merge %s\"" #, python-format msgid "The branch will be reset using \"git reset --mixed %s\"" msgstr "La rama será reiniciada utilizando \"git reset --mixed %s\"" #, python-format msgid "The branch will be reset using \"git reset --soft %s\"" msgstr "La rama será reiniciada utilizando \"git reset --soft %s\"" msgid "The commit message will be cleared." msgstr "El mensaje del commit será borrado." #, python-format msgid "The file \"%s\" exists and will be overwritten." msgstr "El archivo \"%s\" ya existe y será sobrescrito." msgid "The following files will be deleted:" msgstr "Los siguientes archivos serán eliminados:" msgid "The revision expression cannot be empty." msgstr "La expresión de revisión no puede estar vacía." #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be reset using \"git reset --keep %s\"" msgstr "El árbol de trabajo será reiniciado utilizando \"git reset --keep %s\"" msgid "This cannot be undone. Clear commit message?" msgstr "Esto no puede ser deshecho. ¿Limpiar el mensaje del commit?" msgid "" "This commit has already been published.\n" "This operation will rewrite published history.\n" "You probably don't want to do this." msgstr "" "Este commit ya ha sido publicado.\n" "Esta operación reescribirá el historial publicado.\n" "Probablemente no quiere hacer esto." msgid "" "This operation drops uncommitted changes.\n" "These changes cannot be recovered." msgstr "" "Esta operación eliminará los cambios en los que no se haya hecho commit.\n" "Estos cambios no pueden ser recuperados." msgid "" "This operation removes uncommitted edits from selected files.\n" "These changes cannot be recovered." msgstr "" "Esta operación eliminará las ediciones en las que no se haya hecho commit de los archivos seleccionados.\n" "Estos cambios no pueden ser recuperados." msgid "" "This operation removes unstaged edits from selected files.\n" "These changes cannot be recovered." msgstr "" "Esta operación elimina ediciones que no estén en \"stage\" de los archivos seleccionados.\n" "Estos cambios no pueden ser recupuerados." msgid "" "This repository is currently being rebased.\n" "Resolve conflicts, commit changes, and run:\n" " Rebase > Continue" msgstr "" "Este repositorio está actualmente siendo rebasado.\n" "Resolver los conflictos, hacer commit con los cambios, y ejecutar:\n" " Rebase > Continue" msgid "" "This repository is in the middle of a merge.\n" "Resolve conflicts and commit changes." msgstr "" "Este repositorio está en el medio de un \"merge\".\n" "Resolver los conflictos y hacer commit con los cambios." msgid "Toggle Enabled" msgstr "Alternar habilitado" msgid "Toggle the branches filter" msgstr "Alternar el filtro de las ramas" msgid "Toggle the paths filter" msgstr "Alternar el filtro de las rutas" msgid "Tracking Branch" msgstr "Rama en seguimiento" msgid "Tracking branch" msgstr "Rama en seguimiento" msgid "Traditional Chinese (Taiwan) translation" msgstr "Traducción al Chino (Taiwan) tradicional" msgid "Translators" msgstr "Traductores" msgid "Turkish translation" msgstr "Traducción al Turco" msgid "URL" msgstr "URL" #, python-format msgid "URL: %s" msgstr "URL: %s" msgid "Ukranian translation" msgstr "Traducción al Ucraniano" msgid "Unable to rebase" msgstr "Incapaz de hacer rebase" #, python-format msgid "Unable to set URL for \"%(name)s\" to \"%(url)s\"" msgstr "Imposible especificar la URL para \"%(name)s\" a \"%(url)s\"" msgid "Undo" msgstr "Deshacer" msgid "Unmerged" msgstr "" msgid "Unstage" msgstr "" msgid "Unstage All" msgstr "" msgid "Unstage Diff Hunk" msgstr "" msgid "Unstage From Commit" msgstr "" msgid "Unstage Selected" msgstr "" msgid "Unstage Selected Lines" msgstr "" #, python-format msgid "Unstaging: %s" msgstr "" msgid "Untrack Selected" msgstr "" msgid "Untracked" msgstr "" #, python-format msgid "Untracking: %s" msgstr "" msgid "Update All Submodules..." msgstr "" msgid "Update Existing Branch:" msgstr "Actualizar rama existente:" msgid "Update Submodule" msgstr "" msgid "Update Submodule..." msgstr "" msgid "Update Submodules" msgstr "" msgid "Update all submodules?" msgstr "" msgid "Update submodules..." msgstr "" msgid "Update this submodule" msgstr "" msgid "Update this submodule?" msgstr "" msgid "Updating" msgstr "Actualizando" msgid "User Name" msgstr "Nombre de Usuario" msgid "Version" msgstr "Versión" msgid "View" msgstr "Ver" msgid "View History..." msgstr "Ver historial..." msgid "View history for selected paths" msgstr "Ver historial para las rutas seleccionadas" msgid "Visualize" msgstr "Visualizar" msgid "Visualize All Branches..." msgstr "Visualizar todas las ramas..." msgid "Visualize Current Branch..." msgstr "Visualizar la rama actual..." msgid "Whether to sign the tag (git tag -s)" msgstr "" msgid "Would you like to stage and commit all modified files?" msgstr "¿Le gustaría hacer stage y commit de todos los archivos modificados?" msgid "XOR" msgstr "XOR" msgid "Yes" msgstr "Sí" msgid "" "You are in the middle of a merge.\n" "Cannot amend while merging." msgstr "" "Está en medio de un merge.\n" "No se puede modificar mientras se ejecuta el merge." msgid "You cannot rebase with uncommitted changes." msgstr "No puede realizar rebase con cambios en los que no se ha hecho commit." msgid "You must specify a revision to merge." msgstr "Debe especificar una revisión para hacer merge." msgid "You must specify a revision to view." msgstr "Debe especificar una revisión para hacer ver." msgid "Zoom In" msgstr "Acercar" msgid "Zoom Out" msgstr "Alejar" msgid "Zoom to Fit" msgstr "Ajustar el zoom" msgid "command-line arguments" msgstr "argumentos de la línea de comandos" msgid "error: unable to execute git" msgstr "error: imposible ejecutar git" #, python-format msgid "exit code %s" msgstr "código de salida %s" #, python-format msgid "fatal: \"%s\" is not a directory. Please specify a correct --repo ." msgstr "fatal: \"%s\" no es una carpeta. Por favor especifique un correcto --repo ." #, python-format msgid "git cola version %s" msgstr "versión de git cola %s" msgid "git-cola" msgstr "git-cola" msgid "git-cola diff" msgstr "git-cola diff" msgid "grep result..." msgstr "resultados de grep..." msgid "hotkeys.html" msgstr "hotkeys.html" msgid "unknown" msgstr "desconocido" msgid "vX.Y.Z" msgstr "vX.Y.Z" msgid "x 1" msgstr "" msgid "x 1.5" msgstr "" msgid "x 2" msgstr "" msgid "yyyy-MM-dd" msgstr "aaaa-MM-dd" git-cola-3.6/po/fr.po000066400000000000000000001533221356743264500144730ustar00rootroot00000000000000# Translation of git-cola to French. # Copyright (C) 2008, 2011 Shawn Pearce, et al. # This file is distributed under the same license as the git-cola package. # # Christian Couder , 2008 # David Aguilar , 2011 # Mickael Albertus , 2017. # msgid "" msgstr "" "Project-Id-Version: git-cola VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-17 01:06-0700\n" "PO-Revision-Date: 2017-02-28 20:59+0100\n" "Last-Translator: Mickael Albertus \n" "Language-Team: français <>\n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Gtranslator 2.91.7\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" msgid "" "\n" "

\n" " Drag and drop or use the Add button to add\n" " patches to the list\n" "

\n" " " msgstr "" "\n" "

\n" " Effectuez un glisser-déposer ou appuyez sur le bouton Ajouter pour ajouter\n" " les patchs à la liste\n" "

\n" " " #, python-format msgid "" "\n" "
\n" " Git Cola has been translated into different languages thanks\n" " to the help of the individuals listed below.\n" "\n" "
\n" "

\n" " Translation is approximate. If you find a mistake,\n" " please let us know by opening an issue on Github:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " We invite you to participate in translation by adding or updating\n" " a translation and opening a pull request.\n" "

\n" "\n" "
\n" "\n" " " msgstr "" #, python-format msgid "" "\n" "
\n" " Git Cola version %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " msgstr "" "\n" "
\n" " Version Git Cola %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " #, python-format msgid "" "\n" "
\n" " Please use %(bug_link)s to report issues.\n" "
\n" " " msgstr "" "\n" "
\n" " Veuillez utiliser %(bug_link)s pour signaler des problèmes.\n" "
\n" " " #, python-format msgid "" "\n" " Format String Variables\n" " -----------------------\n" " %(path)s = relative file path\n" " %(abspath)s = absolute file path\n" " %(dirname)s = relative directory path\n" " %(absdirname)s = absolute directory path\n" " %(filename)s = file basename\n" " %(basename)s = file basename without extension\n" " %(ext)s = file extension\n" msgstr "" msgid "" "\n" "Commands\n" "--------\n" "pick = use commit\n" "reword = use commit, but edit the commit message\n" "edit = use commit, but stop for amending\n" "squash = use commit, but meld into previous commit\n" "fixup = like \"squash\", but discard this commit's log message\n" "exec = run command (the rest of the line) using shell\n" "\n" "These lines can be re-ordered; they are executed from top to bottom.\n" "\n" "If you disable a line here THAT COMMIT WILL BE LOST.\n" "\n" "However, if you disable everything, the rebase will be aborted.\n" "\n" "Keyboard Shortcuts\n" "------------------\n" "? = show help\n" "j = move down\n" "k = move up\n" "J = shift row down\n" "K = shift row up\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "spacebar = toggle enabled\n" "\n" "ctrl+enter = accept changes and rebase\n" "ctrl+q = cancel and abort the rebase\n" "ctrl+d = launch difftool\n" msgstr "" msgid "" "\n" "Keyboard Shortcuts\n" "------------------\n" "J, Down = Move Down\n" "K, Up = Move Up\n" "Enter = Edit Selected Files\n" "Spacebar = Open File Using Default Application\n" "Ctrl + L = Focus Text Entry Field\n" "? = Show Help\n" "\n" "The up and down arrows change focus between the text entry field\n" "and the results.\n" msgstr "" "\n" "Raccourcis clavier\n" "------------------\n" "J, Bas = Descendre\n" "K, Haut = Monter\n" "Entrée = Modifier les fichiers sélectionnés\n" "Barre d'espace = Ouvre le fichier avec l'application par défaut\n" "Ctrl + L = Mettre le curseur dans le champ d'entrée\n" "? = Afficher l'aide\n" "\n" "Les flèches du haut et du bas font naviguer le curseur entre les champs d'entrée et les résultats.\n" msgid " - DAG" msgstr " - DAG" msgid " commits ago" msgstr " commits avant" #, python-format msgid "\"%(branch)s\" has been deleted from \"%(remote)s\"." msgstr "« %(branch)s » a été supprimé de « %(remote)s »." #, python-format msgid "\"%(command)s\" returned exit status \"%(status)d\"" msgstr "« %(command)s » a retourné le statut de sortie  %(status)d »" #, python-format msgid "\"%(command)s\" returned exit status %(status)d" msgstr "La commande « %(command)s » a renvoyé le statut de sortie %(status)d" #, python-format msgid "\"%s\" already exists" msgstr "" #, python-format msgid "\"%s\" already exists, cola will create a new directory" msgstr "« %s » existe déjà, cola va créer un nouveau répertoire" #, python-format msgid "\"%s\" requires a selected file." msgstr "« %s » requiert de choisir un fichier." msgid "#" msgstr "" #, python-format msgid "%(project)s: %(branch)s - Browse" msgstr "%(project)s : %(branch)s - Naviguer" #, python-format msgid "%(project)s: %(ref)s - DAG" msgstr "%(project)s : %(ref)s - DAG" #, python-format msgid "%d days ago" msgstr "il y a %d jours" #, python-format msgid "%d hours ago" msgstr "il y a %d heures" #, python-format msgid "%d minutes ago" msgstr "il y a %d minutes" #, python-format msgid "%d patch(es) applied." msgstr "%s patch(s) appliqué(s)" #, python-format msgid "%d skipped" msgstr "%d passé(s)" #, python-format msgid "" "%s appears to contain merge conflicts.\n" "\n" "You should probably skip this file.\n" "Stage it anyways?" msgstr "" "%s semble contenir des problèmes de fusion.\n" "\n" "Vous devriez ignorer ce fichier.\n" "Le commiter malgré tout ?" #, python-format msgid "%s is not a Git repository." msgstr "%s n'est pas un dépôt Git" #, python-format msgid "%s will be removed from your bookmarks." msgstr "%s sera supprimé de vos marque-pages." #, python-format msgid "%s will be removed from your recent repositories." msgstr "%s sera supprimé de vos dépôts récents." #, python-format msgid "%s: No such file or directory." msgstr "%s : fichier ou répertoire inexistant." msgid "&Edit" msgstr "&Editer" msgid "&File" msgstr "&Fichier" msgid "(Amending)" msgstr "(Correction)" msgid "*** Branch Point ***" msgstr "*** Point de branchement ***" msgid "*** Sandbox ***" msgstr "*** Bac à sable ***" msgid "100%" msgstr "" msgid "200%" msgstr "" msgid "25%" msgstr "" msgid "400%" msgstr "" msgid "50%" msgstr "" msgid "800%" msgstr "" msgid " ..." msgstr "..." msgid "" "A commit template has not been configured.\n" "Use \"git config\" to define \"commit.template\"\n" "so that it points to a commit template." msgstr "" "Un modèle de commit n'a pas été configuré.\n" "Utilisez « git config » pour définir « commit.template »\n" "de sorte qu'il pointe vers un modèle de commit." #, python-format msgid "A hook must be provided at \"%s\"" msgstr "" #, python-format msgid "A stash named \"%s\" already exists" msgstr "Un remisage nommé « %s » existe déjà" msgid "Abort" msgstr "Abandonner" msgid "Abort Action" msgstr "Abandon de l'action" msgid "Abort Merge" msgstr "Abandonner fusion" msgid "Abort Merge..." msgstr "Abandonner fusion..." msgid "Abort the action?" msgstr "Abandonner l'action ?" msgid "" "Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" "Recovering uncommitted changes is not possible." msgstr "" "Abandonner la fusion courante entrainera la perte de TOUTES les modifications non commitées.\n" "La récupération des modifications non commités ne sera pas possible." msgid "Aborting the current merge?" msgstr "Abandonner la fusion actuelle ?" msgid "About" msgstr "A propos" msgid "About git-cola" msgstr "À propose de git-cola" msgid "Accept" msgstr "Accepter" msgid "" "Accept changes and rebase\n" "Shortcut: Ctrl+Enter" msgstr "" msgid "Action Name" msgstr "" msgid "Actions" msgstr "Actions" msgid "Actions..." msgstr "Actions..." msgid "Add" msgstr "Ajouter" msgid "Add Favorite" msgstr "Ajouter en favori" msgid "Add Remote" msgstr "Ajouter un élément distant" msgid "Add Separator" msgstr "" msgid "Add Toolbar" msgstr "" msgid "" "Add and remove remote repositories using the \n" "Add(+) and Delete(-) buttons on the left-hand side.\n" "\n" "Remotes can be renamed by selecting one from the list\n" "and pressing \"enter\", or by double-clicking." msgstr "" "Ajouter et supprimer des dépôts distants en utilisant les\n" "boutons ajouter (+) et supprimer (-) sur le côté gauche.\n" "\n" "Les éléments distants peuvent être renommés en les sélectionner dans la liste\n" "et en appuyant sur « Entrée », ou en double-cliquant." msgid "Add new remote git repository" msgstr "Ajouter un nouveau dépôt Git distant" msgid "Add patches (+)" msgstr "Ajouter les patchs (+)" msgid "Add remote" msgstr "Ajouter un élément distant" msgid "Add to .gitignore" msgstr "Ajouter à .gitignore" msgid "Add to Git Annex" msgstr "Ajouter à Git Annex" msgid "Add to Git LFS" msgstr "Ajouter à Git LFS" msgid "Additions" msgstr "Ajouts" msgid "Advanced" msgstr "Avancé" msgid "Age" msgstr "Age" msgid "All Repositories" msgstr "Tous les dépôts" #, python-format msgid "" "All submodules will be updated using\n" "\"%s\"" msgstr "" msgid "Allow non-fast-forward updates. Using \"force\" can cause the remote repository to lose commits; use it with care" msgstr "Autoriser les mises à jour non rapides. Utiliser « force » peut provoquer des pertes de commit au niveau du dépôt distant : utilisez le avec précaution" msgid "Always create a merge commit when enabled, even when the merge is a fast-forward update" msgstr "Toujours créer un commit fusionné quand cela est possible, même si la fusion est une mise à jour rapide" msgid "Amend" msgstr "Correction" msgid "Amend Commit" msgstr "Corriger commit" msgid "Amend Last Commit" msgstr "Corriger dernier commit" msgid "Amend the published commit?" msgstr "Corriger le commit publié ?" msgid "Amending" msgstr "Correction" msgid "" "An action is still running.\n" "Terminating it could result in data loss." msgstr "" "Une action est toujours en cours.\n" "L'interrompre pourrait entraîner une perte de données." msgid "" "An unsigned, lightweight tag will be created instead.\n" "Create an unsigned tag?" msgstr "" "Un marqueur non signé et léger sera créé à la place.\n" "Créer un tag non signé ?" msgid "Appearance" msgstr "" msgid "Apply" msgstr "Appliquer" msgid "Apply Patches" msgstr "Appliquer les patchs" msgid "Apply Patches..." msgstr "Appliquer les patchs..." msgid "Apply and drop the selected stash (git stash pop)" msgstr "" msgid "Apply the selected stash" msgstr "Appliquer la remise actuelle" msgid "Arguments" msgstr "Arguments" msgid "Attach" msgstr "Attacher" msgid "Author" msgstr "Auteur" msgid "Authors" msgstr "Auteurs" msgid "Auto" msgstr "" msgid "Auto-Wrap Lines" msgstr "Retour à la ligne automatique" msgid "Basic Regexp" msgstr "Regexp basic" msgid "Blame Viewer" msgstr "Visionneur de fichier" msgid "Blame selected paths" msgstr "" msgid "Blame..." msgstr "Visionner..." msgid "Bold on dark headers instead of italic" msgstr "Police en gras avec fond sombre au lieu d'en-têtes italiques" msgid "Branch" msgstr "Branche" #, python-format msgid "" "Branch \"%(branch)s\" does not exist in \"%(remote)s\".\n" "A new remote branch will be published." msgstr "" "La branche « %(branch)s » n'existe pas dans « %(remote)s ».\n" "Une nouvelle branche distante sera publiée." #, python-format msgid "Branch \"%s\" already exists." msgstr "La branche « %s » existe déjà." msgid "Branch Diff Viewer" msgstr "Aperçu des modifications de branche" msgid "Branch Exists" msgstr "La branche existe" msgid "Branch Name" msgstr "Nom de branche" #, python-format msgid "Branch: %s" msgstr "Branche : %s" msgid "Branches" msgstr "" msgid "Branches..." msgstr "Branches..." msgid "Brazilian translation" msgstr "Traduction brésilienne" msgid "Browse" msgstr "Parcourir" msgid "Browse Commits..." msgstr "Parcourir les commits..." msgid "Browse Current Branch..." msgstr "Parcourir la branche courante..." msgid "Browse Other Branch..." msgstr "Parcourir les autres branches..." msgid "Browse..." msgstr "Parcourir..." msgid "Browser" msgstr "Parcourir" #, python-format msgid "Browsing %s" msgstr "Parcours de %s" msgid "Bypass Commit Hooks" msgstr "Contourner le crochet de commit" msgid "Cancel" msgstr "Annuler" msgid "" "Cancel rebase\n" "Shortcut: Ctrl+Q" msgstr "" msgid "Cannot Amend" msgstr "Impossible de corriger" #, python-format msgid "Cannot exec \"%s\": please configure a blame viewer" msgstr "Impossible d'exécuter « %s » : veuillez configurer un visionneur de fichier" #, python-format msgid "Cannot exec \"%s\": please configure a history browser" msgstr "Impossible d'exécuter « %s » : veuillez configurer un navigateur d'historique" #, python-format msgid "Cannot exec \"%s\": please configure your editor" msgstr "Impossible d'exécuter « %s » : veuillez configurer votre éditeur" msgid "Changed Upstream" msgstr "Source modifiée" msgid "Check Spelling" msgstr "Vérifier l'orthographe" msgid "Checkout" msgstr "Emprunter" msgid "Checkout After Creation" msgstr "Emprunt après création" msgid "Checkout Branch" msgstr "Emprunter branche" msgid "Checkout Detached HEAD" msgstr "" msgid "Checkout as new branch" msgstr "" msgid "Checkout..." msgstr "Emprunter... " msgid "Cherry Pick" msgstr "Copier" msgid "Cherry-Pick Commit" msgstr "Copier commit" msgid "Cherry-Pick..." msgstr "Copier... " msgid "Choose Paths" msgstr "Choisir les chemins" msgid "Choose the \"git grep\" regular expression mode" msgstr "Choisissez le mode d'expression régulière « git grep »" msgid "Clear Default Repository" msgstr "Nettoyer le dépôt par défaut" msgid "Clear commit message" msgstr "Effacer le message de commit" msgid "Clear commit message?" msgstr "Effacer le message de commit ?" msgid "Clear..." msgstr "Effacer..." msgid "Clone" msgstr "Cloner" msgid "Clone Repository" msgstr "Cloner le dépôt" msgid "Clone..." msgstr "Cloner..." #, python-format msgid "Cloning repository at %s" msgstr "Cloner le dépôt à %s" msgid "Close" msgstr "Fermer" msgid "Close..." msgstr "Fermer..." msgid "Collapse all" msgstr "Tout réduire" msgid "Command" msgstr "" msgid "Commit" msgstr "Commit" msgid "Commit failed" msgstr "Le commit a échoué." msgid "Commit staged changes" msgstr "Commit des modifications..." msgid "" "Commit staged changes\n" "Shortcut: Ctrl+Enter" msgstr "" "Commit des modifications\n" "Raccourci : Ctrl+Entrée" msgid "Commit summary" msgstr "Résumé du commit" msgid "Commit the merge if there are no conflicts. Uncheck to leave the merge uncommitted" msgstr "Commiter la fusion s'il n'y a pas de conflits. Décocher pour laisser la fusion non commitée." msgid "Commit@@verb" msgstr "Commiter@@verb" msgid "Compare" msgstr "Comparer" msgid "Compare All" msgstr "Tout comparer" msgid "Configure the remote branch as the the new upstream" msgstr "Configurer la branche distante comme la nouvelle source" msgid "Configure toolbar" msgstr "" msgid "Console" msgstr "Terminal" msgid "Continue" msgstr "Continuer" msgid "Copy" msgstr "Copier" msgid "Copy Basename to Clipboard" msgstr "" msgid "Copy Leading Path to Clipboard" msgstr "" msgid "Copy Path to Clipboard" msgstr "Copier le chemin dans le presse-papiers" msgid "Copy Relative Path to Clipboard" msgstr "Copier le chemin relatif dans le presse-papier" msgid "Copy SHA-1" msgstr "Copier SHA-1" msgid "Copy..." msgstr "Copier..." #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "Impossible d'analyser l'URL Git : « %s »" msgid "Create Branch" msgstr "Créer branche" msgid "Create Patch" msgstr "Créer patch" msgid "Create Remote Branch" msgstr "Créer branche distante" msgid "Create Signed Commit" msgstr "Créer un commit signé" msgid "Create Tag" msgstr "Créer marque" msgid "Create Tag..." msgstr "Créer une marque..." msgid "Create Unsigned Tag" msgstr "Créer un marqueur non signé" msgid "Create a merge commit even when the merge resolves as a fast-forward" msgstr "Créer un commit fusionné même quand la fusion se résout rapidement" msgid "Create a new remote branch?" msgstr "Créer nouvelle branche distante ?" msgid "Create..." msgstr "Créer..." #, python-format msgid "Created a new tag named \"%s\"" msgstr "Créer un nouveau marqueur appelé « %s »" msgid "Current Repository" msgstr "Dépôt actuel" msgid "Custom Copy Actions" msgstr "" msgid "Customize..." msgstr "" msgid "Cut" msgstr "Couper" msgid "Czech translation" msgstr "" msgid "DAG..." msgstr "DAG..." msgid "Dark Theme" msgstr "" msgid "Date, Time" msgstr "Date, heure" msgid "Default" msgstr "" msgid "Delete" msgstr "Supprimer" #, python-format msgid "Delete %d file(s)?" msgstr "Supprimer %d fichier(s) ?" msgid "Delete Bookmark" msgstr "Supprimer marque-page" msgid "Delete Bookmark?" msgstr "Supprimer le marque-page ?" msgid "Delete Branch" msgstr "Supprimer branche" msgid "Delete Files" msgstr "Supprimer les fichiers" msgid "Delete Files..." msgstr "Supprimer les fichiers..." msgid "Delete Files?" msgstr "Supprimer les fichiers ?" msgid "Delete Remote" msgstr "Supprimer branche distante" msgid "Delete Remote Branch" msgstr "Supprimer branche distante" msgid "Delete Remote Branch..." msgstr "Supprimer branche distante..." msgid "Delete remote" msgstr "Supprimer élément distant" #, python-format msgid "Delete remote \"%s\"" msgstr "Supprimer la branche distante « %s »" msgid "Delete remote?" msgstr "Supprimer la branche distante ?" msgid "Delete selected branch?" msgstr "" msgid "Delete toolbar" msgstr "" msgid "Delete..." msgstr "Supprimer..." #, python-format msgid "Deleting \"%s\" failed" msgstr "Suppression de « %s » a échoué" msgid "Deletions" msgstr "Suppressions" msgid "Detach" msgstr "Détacher" msgid "Detect Conflict Markers" msgstr "Détecter marqueurs de conflit" msgid "Detect conflict markers in unmerged files" msgstr "Détecter des marqueurs de conflits dans les fichiers non fusionnés" msgid "Developer" msgstr "Développeur" msgid "Diff" msgstr "Différence" msgid "Diff Against Predecessor..." msgstr "Différence par rapport au prédécesseur..." msgid "Diff Options" msgstr "Options des différences" msgid "Diff Tool" msgstr "Outil de différence" msgid "Diff selected -> this" msgstr "Différence sélection -> ceci" msgid "Diff this -> selected" msgstr "Différence ceci -> sélection" msgid "Diffstat" msgstr "Statistiques des différences" msgid "Difftool" msgstr "" msgid "Directory Exists" msgstr "Répertoire existant" msgid "Display Untracked Files" msgstr "Afficher les fichiers non suivis" msgid "Documentation" msgstr "Documentation" msgid "Drop" msgstr "Supprimer" msgid "Drop Stash" msgstr "Supprimer le remisage" msgid "Drop Stash?" msgstr "Supprimer le remisage ?" #, python-format msgid "Drop the \"%s\" stash?" msgstr "Supprimer le remisage « %s » ?" msgid "Drop the selected stash" msgstr "Supprimer la remise sélectionnée" msgid "Edit" msgstr "Editer" msgid "Edit Rebase" msgstr "Éditer rétablissement" msgid "Edit Remotes" msgstr "Éditer les éléments distants" msgid "Edit Remotes..." msgstr "Éditer les éléments distants..." msgid "Edit remotes by selecting them from the list" msgstr "" msgid "Edit selected paths" msgstr "Éditer les chemins sélectionnés" msgid "Edit..." msgstr "Editer..." msgid "Editor" msgstr "Éditeur" msgid "Email Address" msgstr "Adresse email" msgid "Email contributor" msgstr "Courriels des contributeurs" msgid "Enabled" msgstr "" msgid "Enter New Branch Name" msgstr "Entrez le nouveau nom de la branche" msgid "Enter a name for the new bare repo" msgstr "" msgid "Enter a name for the stash" msgstr "Entrer un nom pour le remisage" msgid "Error" msgstr "Erreur" msgid "Error Cloning" msgstr "Erreur lors du clonage" msgid "Error Creating Branch" msgstr "Erreur lors de la création de la branche" msgid "Error Creating Repository" msgstr "Erreur lors de la création du dépôt" msgid "Error Deleting Remote Branch" msgstr "Erreur lors de la suppression de la branche distante" msgid "Error Editing File" msgstr "Erreur lors de la modification du fichier" msgid "Error Launching Blame Viewer" msgstr "Erreur lors de l'ouverture du visionneur de fichier" msgid "Error Launching History Browser" msgstr "Erreur lors de l'ouverture de l'historique" #, python-format msgid "Error creating remote \"%s\"" msgstr "Erreur lors de la création de la branche distante « %s »" msgid "Error creating stash" msgstr "" #, python-format msgid "Error deleting remote \"%s\"" msgstr "Erreur lors de la suppression de la branche distante « %s »" #, python-format msgid "Error renaming \"%(name)s\" to \"%(new_name)s\"" msgstr "" msgid "Error running prepare-commitmsg hook" msgstr "" #, python-format msgid "Error updating submodule %s" msgstr "" msgid "Error updating submodules" msgstr "" msgid "Error: Cannot find commit template" msgstr "Erreur : impossible de trouver un modèle de commit" msgid "Error: Stash exists" msgstr "Erreur : le remisage existe" msgid "Error: Unconfigured commit template" msgstr "Erreur : modèle de commit non configuré" #, python-format msgid "Error: could not clone \"%s\"" msgstr "Erreur : impossible de cloner « %s »" #, python-format msgid "Error: could not create tag \"%s\"" msgstr "Erreur : impossible de créer le tag « %s »" #, python-format msgid "Executing action %s" msgstr "" msgid "Expand all" msgstr "Tout développer" msgid "Export Patches" msgstr "Exporter les patchs" msgid "Export Patches..." msgstr "Exporter les patchs" msgid "Expression..." msgstr "Expression..." msgid "Extended Regexp" msgstr "Regexp approfondi" msgid "Extended description..." msgstr "Description approfondie" msgid "Fast Forward Only" msgstr "Avance rapide seulement" msgid "Fast-forward only" msgstr "Avance rapide seulement" msgid "Favorite repositories" msgstr "Dépôts favoris" msgid "Favorites" msgstr "Favoris" msgid "Fetch" msgstr "Récupération" msgid "Fetch Tracking Branch" msgstr "Branche suivant récupération" msgid "Fetch..." msgstr "Récupérer..." msgid "File Browser..." msgstr "Navigateur de fichier..." msgid "File Differences" msgstr "Différences de fichier" msgid "File Saved" msgstr "Fichier enregistré" #, python-format msgid "File saved to \"%s\"" msgstr "Fichier enregistré sous « %s »" msgid "File system change monitoring: disabled because \"cola.inotify\" is false.\n" msgstr "Surveillance du changement de système de fichiers : désactivé car « cola.inotify » vaut « false ».\n" msgid "File system change monitoring: disabled because libc does not support the inotify system calls.\n" msgstr "Surveillance du système de fichiers : désactivé car libc ne supporte pas le système d'appels de inotify.\n" msgid "File system change monitoring: disabled because pywin32 is not installed.\n" msgstr "Surveillance du changement de système de fichiers : désactivé car pywin32 n'est pas installé.\n" msgid "" "File system change monitoring: disabled because the limit on the total number of inotify watches was reached. You may be able to increase the limit on the number of watches by running:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" msgstr "" "Surveillance du changement de système de fichiers : désactivé car la limite sur le nombre total d'aperçu inotify a été atteint. Vous devriez être capable d'augmenter la limite d'aperçu en exécutant :\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" msgid "File system change monitoring: enabled.\n" msgstr "Surveillance du changement de système de fichiers : activé.\n" msgid "Filename" msgstr "Nom de fichier" msgid "Files" msgstr "Fichiers" msgid "Filter branches..." msgstr "" msgid "Filter paths..." msgstr "Filtrer les chemins..." msgid "Find Files" msgstr "Trouver des fichiers" msgid "Fixed String" msgstr "Chaîne donnée" msgid "Fixed-Width Font" msgstr "Police à largeur fixe" msgid "Fixup" msgstr "" msgid "Fixup Previous Commit" msgstr "Réparer le commit précédent" msgid "Flat dark blue" msgstr "" msgid "Flat dark green" msgstr "" msgid "Flat dark grey" msgstr "" msgid "Flat dark red" msgstr "" msgid "Flat light blue" msgstr "" msgid "Flat light green" msgstr "" msgid "Flat light grey" msgstr "" msgid "Flat light red" msgstr "" msgid "Font Size" msgstr "Taille de police" msgid "Force" msgstr "Forcer" msgid "Force Fetch" msgstr "Forcer la récupération" msgid "Force Fetch?" msgstr "Forcer la récupération ?" msgid "Force Push" msgstr "Forcer la poussée" msgid "Force Push?" msgstr "Forcer la pousée" #, python-format msgid "Force fetching from %s?" msgstr "Forcer la récupération à partir de %s ?" #, python-format msgid "Force push to %s?" msgstr "Forcer la poussée vers %s ?" msgid "Format String" msgstr "" msgid "French translation" msgstr "" msgid "GPG-sign the merge commit" msgstr "GPG-signer le commit fusionné" msgid "GUI theme" msgstr "" #, python-format msgid "Gathering info for \"%s\"..." msgstr "Rassemblement des informations de %s..." msgid "German translation" msgstr "Traduction allemande" msgid "Get Commit Message Template" msgstr "Obtenir un modèle de message de commit" msgid "Go Down" msgstr "Descendre" msgid "Go Up" msgstr "Monter" msgid "Grab File..." msgstr "Maintenir le fichier..." msgid "Graph" msgstr "Graphe" msgid "Grep" msgstr "Grep" msgid "Have you rebased/pulled lately?" msgstr "Avez-vous restauré/tiré dernièrement ?" msgid "Help" msgstr "Aide" msgid "Help - Custom Copy Actions" msgstr "" msgid "Help - Find Files" msgstr "Aide - Trouver des fichiers" msgid "Help - git-xbase" msgstr "" msgid "Hide Details.." msgstr "" msgid "High DPI" msgstr "" msgid "History Browser" msgstr "Navigateur de l'historique" msgid "Hungarian translation" msgstr "" msgid "Icon theme" msgstr "" msgid "Ignore all whitespace" msgstr "Ignorer tous les espaces blancs" msgid "Ignore changes in amount of whitespace" msgstr "Ignorer les changements de quantités d'espaces blancs" msgid "Ignore changes in whitespace at EOL" msgstr "Ignorer les changements d'espaces blancs à la fin des lignes" msgid "Ignore custom pattern" msgstr "" msgid "Ignore exact filename" msgstr "" msgid "Ignore filename or pattern" msgstr "" msgid "Include tags " msgstr "Inclure les marques" msgid "Indent Status paths" msgstr "" msgid "Indonesian translation" msgstr "Traduction indonésienne" msgid "Initialize Git Annex" msgstr "" msgid "Initialize Git LFS" msgstr "" msgid "Inititalize submodules" msgstr "" msgid "Insert spaces instead of tabs" msgstr "" msgid "Interactive Rebase" msgstr "Rétablissement interactif" msgid "Invalid Revision" msgstr "Révision invalide" msgid "Keep *.orig Merge Backups" msgstr "Conserver les sauvegardes de fusion *.orig" msgid "Keep Index" msgstr "Conserver l'index" msgid "Keyboard Shortcuts" msgstr "Raccourcis clavier" msgid "Launch Diff Tool" msgstr "Lancer l'outil de différence" msgid "Launch Directory Diff Tool" msgstr "Lancer l'outil de différence de répertoire" msgid "Launch Editor" msgstr "Lancer l'éditeur" msgid "Launch Terminal" msgstr "Lancer le terminal" msgid "" "Launch external diff tool\n" "Shortcut: Ctrl+D" msgstr "" msgid "Launch git-cola" msgstr "Lancer git-cola" msgid "Launch git-difftool against previous versions" msgstr "Lancer git-difftool par rapport aux versions précédentes" msgid "Launch git-difftool on the current path" msgstr "Lancer git-difftool sur le chemin actuel" msgid "Light Theme" msgstr "" msgid "Load Commit Message" msgstr "Charger le message de commit" msgid "Load Commit Message..." msgstr "Charger le message de commit..." msgid "Load Previous Commit Message" msgstr "Charger le message de commit précédent" msgid "Loading..." msgstr "Chargement..." msgid "Local" msgstr "Local" msgid "Local Branch" msgstr "Branche locale" msgid "Local branch" msgstr "Branche locale" msgid "Lock Layout" msgstr "Verrouillage" msgid "Log" msgstr "Journaux " msgid "Maintainer (since 2007) and developer" msgstr "Mainteneur (depuis 2007) et developpeur" msgid "Merge" msgstr "Fusionner" #, python-format msgid "Merge \"%(revision)s\" into \"%(branch)s\"" msgstr "Fusion de « %(revision)s » vers « %(branch)s »" msgid "Merge Tool" msgstr "Outil de fusion" msgid "Merge Verbosity" msgstr "Fusion bavarde" msgid "Merge failed. Conflict resolution is required." msgstr "La fusion a echouée. Il est nécessaire de résoudre les conflicts." #, python-format msgid "Merge into \"%s\"" msgstr "Fusion dans « %s »" msgid "Merge into current branch" msgstr "" msgid "Merge..." msgstr "Fusionner..." msgid "Merging" msgstr "Fusion" msgid "Message" msgstr "Message" msgid "Missing Commit Message" msgstr "Message de commit manquant" msgid "Missing Data" msgstr "Donnée manquante" msgid "Missing Name" msgstr "Nom manquant" msgid "Missing Revision" msgstr "Révision manquante" msgid "Missing Tag Message" msgstr "Message du marqueur manquant" msgid "Modified" msgstr "Modifié" msgid "More..." msgstr "Plus..." msgid "Move Down" msgstr "Déplacer vers le bas" msgid "Move Up" msgstr "Déplacer vers le haut" msgid "Move files to trash" msgstr "Mettre les fichiers à la corbeille" msgid "Name" msgstr "Nom :" msgid "Name for the new remote" msgstr "Nom pour le nouvel élément distant" msgid "New Bare Repository..." msgstr "" msgid "New Repository..." msgstr "Nouveau dépôt..." msgid "New..." msgstr "Nouveau..." msgid "Next File" msgstr "Fichier suivant" msgid "No" msgstr "Non" msgid "No Revision Specified" msgstr "Pas de révision sélectionnée." msgid "" "No changes to commit.\n" "\n" "You must stage at least 1 file before you can commit." msgstr "" "Pas de modification à commiter.\n" "\n" "Vous devez pré-commiter au moins 1 fichier avant de pouvoir commiter." msgid "No commits exist in this branch." msgstr "Aucun commit n'existe dans cette branche" msgid "No fast forward" msgstr "Pas d'avance rapide" msgid "No fast-forward" msgstr "Pas d'avance rapide" msgid "No repository selected." msgstr "Aucun dépôt n'est sélectionné." msgid "Non-fast-forward fetch overwrites local history!" msgstr "La récupération non rapide écrase l'historique local !" msgid "" "Non-fast-forward push overwrites published history!\n" "(Did you pull first?)" msgstr "" "La poussée non rapide écrase l'historique publié !\n" "(Voulez-vous tirer en premier ?)" msgid "Nothing to commit" msgstr "Pas de modifications à commiter." msgid "Nothing to do" msgstr "Il n'y a rien à faire" msgid "Number of Diff Context Lines" msgstr "Nombre de lignes de contexte dans les diffs" msgid "Open" msgstr "Ouvrir" msgid "Open Git Repository..." msgstr "Ouvrir le dépôt Git..." msgid "Open Parent" msgstr "" msgid "Open Parent Directory" msgstr "Ouvrir le répertoire parent" msgid "Open Recent" msgstr "Ouvrir récent" msgid "Open Using Default Application" msgstr "Ouvrir en utilisant l'application par défaut" msgid "Open in New Window" msgstr "Ouvrir dans une nouvelle fenêtre" msgid "Open in New Window..." msgstr "Ouvrir dans une nouvelle fenêtre..." msgid "Open..." msgstr "Ouvrir..." msgid "Other branches" msgstr "" msgid "Overwrite" msgstr "Écrasement" #, python-format msgid "Overwrite \"%s\"?" msgstr "Écraser « %s » ?" msgid "Overwrite File?" msgstr "Écraser le fichier ?" msgid "" "Parse arguments using a shell.\n" "Queries with spaces will require \"double quotes\"." msgstr "" "Analyser les arguments en utilisant un shell.\n" "Les requêtes comportant des espaces nécessiteront des guillemets doubles." msgid "Partially Staged" msgstr "Partiellement pré-commité" msgid "Paste" msgstr "Coller" msgid "Patch(es) Applied" msgstr "Patch(s) appliqué(s)" msgid "Path" msgstr "Chemin" msgid "Path or URL to clone (Env. $VARS okay)" msgstr "Chemin ou URL à cloner (Env. $VARS ok)" msgid "Pick" msgstr "" msgid "Pixel XOR" msgstr "" msgid "Please provide both a branch name and revision expression." msgstr "Veuillez donner un nom de branche et une expression de révision." msgid "Please select a file" msgstr "Veuillez choisir un fichier" msgid "Please specify a name for the new tag." msgstr "Veuillez spécifier un nom pour le nouveau marqueur." msgid "Please specify a revision to tag." msgstr "Veuillez spécifier une révision au marqueur." msgid "" "Please supply a commit message.\n" "\n" "A good commit message has the following format:\n" "\n" "- First line: Describe in one sentence what you did.\n" "- Second line: Blank\n" "- Remaining lines: Describe why this change is good.\n" msgstr "" "Merci de fournir un message de commit.\n" "\n" "Un bon message de commit a le format suivant :\n" "\n" "- Première ligne : décrire en une phrase ce que vous avez fait.\n" "- Deuxième ligne : rien.\n" "- Lignes suivantes : Décrire pourquoi ces modifications sont bonnes.\n" msgid "Point the current branch head to a new commit?" msgstr "Pointer la tête de branche actuelle vers un nouveau commit ?" msgid "Polish translation" msgstr "Traduction polonaise" msgid "Pop" msgstr "" msgid "Preferences" msgstr "Préférences" msgid "Prefix" msgstr "Préfixe" msgid "Prepare Commit Message" msgstr "" msgid "Prevent \"Stage\" from staging all files when nothing is selected" msgstr "" msgid "Previous File" msgstr "Fichier précédent" msgid "Prompt on creation" msgstr "Confirmation à la création" msgid "Prompt when pushing creates new remote branches" msgstr "Confirmation lorsque la poussée créé des nouvelles branches distantes" msgid "Prune " msgstr "" msgid "Pull" msgstr "Tirer" msgid "Pull..." msgstr "Tirer..." msgid "Push" msgstr "Pousser" msgid "Push..." msgstr "Pousser..." msgid "Quit" msgstr "Quitter" msgid "Rebase" msgstr "Rétablir" #, python-format msgid "Rebase onto %s" msgstr "Rétablir sur %s" msgid "Rebase stopped" msgstr "" msgid "Rebase the current branch instead of merging" msgstr "Rétablir la branche courante au lieu de la fusion" msgid "Rebasing" msgstr "Rétablir" msgid "Recent" msgstr "Récent" msgid "Recent repositories" msgstr "Dépôts récents" msgid "Recent repository count" msgstr "" msgid "Recently Modified Files" msgstr "Fichiers récemment modifiés" msgid "Recently Modified Files..." msgstr "Fichiers récemment modifiés..." msgid "Recovering a dropped stash is not possible." msgstr "Restaurer un remisage supprimé ne sera pas possible." msgid "Recovering lost commits may not be easy." msgstr "Récupérer les commits perdus ne sera peut être pas facile." msgid "Redo" msgstr "Refaire" msgid "Reduce commit history to minimum" msgstr "" msgid "Refresh" msgstr "Rafraichir" msgid "Refuse to merge unless the current HEAD is already up-to-date or the merge can be resolved as a fast-forward" msgstr "Refuser de fusionner à moins que l'en-tête actuelle est déjà mis à jour ou bien que la fusion peut être résolue rapidement" msgid "Remote" msgstr "Branche distante" msgid "Remote Branch" msgstr "Branche distante" msgid "Remote Branch Deleted" msgstr "Branche distante supprimée" msgid "Remote git repositories - double-click to rename" msgstr "Dépôts Git distants - double-cliquez pour renommer." msgid "Remove" msgstr "Supprimer" #, python-format msgid "Remove %s from the recent list?" msgstr "Supprimer %s de la liste des dépôts récents ?" msgid "Remove Element" msgstr "" msgid "Remove remote-tracking branches that no longer exist on the remote" msgstr "" msgid "Remove selected (Delete)" msgstr "Supprimer la sélection" msgid "Rename" msgstr "Renommer" #, python-format msgid "Rename \"%s\"" msgstr "" msgid "Rename Branch" msgstr "" msgid "Rename Branch..." msgstr "Renommer branche..." msgid "Rename Existing Branch" msgstr "Renommer la branche existante" msgid "Rename Remote" msgstr "Renommer branche distante" msgid "Rename Repository" msgstr "Cloner le dépôt" msgid "Rename branch" msgstr "" #, python-format msgid "Rename remote \"%(current)s\" to \"%(new)s\"?" msgstr "Renommage de la branche distante « %(current)s » en « %(new)s » ?" msgid "Rename selected paths" msgstr "" #, python-format msgid "Repository: %s" msgstr "Dépôt : %s" msgid "Reset" msgstr "Réinitialiser" #, python-format msgid "Reset \"%(branch)s\" to \"%(revision)s\"?" msgstr "Réinitialiser « %(branch)s » vers « %(revision)s » ?" msgid "Reset Branch" msgstr "Réinitialiser la branche" msgid "Reset Branch Head" msgstr "Supprimer la branche principale" msgid "Reset Branch?" msgstr "Réinitialiser la branche ?" msgid "Reset Hard" msgstr "" msgid "Reset Merge" msgstr "" msgid "Reset Soft" msgstr "" msgid "Reset Worktree" msgstr "Réinitialiser l'arbre de travail" msgid "Reset hard?" msgstr "" msgid "Reset merge?" msgstr "" msgid "Reset soft?" msgstr "" msgid "Reset worktree?" msgstr "Réinitialiser l'arbre de travail ?" #, python-format msgid "Resetting \"%(branch)s\" to \"%(revision)s\" will lose commits." msgstr "Réinitialiser « %s » à « %s » va faire perdre les commits." msgid "Restart the application after changing appearance settings." msgstr "" msgid "Revert" msgstr "" msgid "Revert Diff Hunk" msgstr "Rétablir section de différences" msgid "Revert Diff Hunk..." msgstr "Rétablir la section de différences..." msgid "Revert Diff Hunk?" msgstr "Rétablir la section de différences ?" msgid "Revert Selected Lines" msgstr "Inverser lignes sélectionnées" msgid "Revert Selected Lines..." msgstr "Inverser lignes sélectionnées..." msgid "Revert Selected Lines?" msgstr "Inverser les lignes sélectionnées ?" msgid "Revert Uncommitted Changes" msgstr "Rétablir les modifications non commitées" msgid "Revert Uncommitted Changes?" msgstr "Rétablir les modifications non commitées ?" msgid "Revert Uncommitted Edits..." msgstr "Rétablir modifications non commitées" msgid "Revert Unstaged Changes" msgstr "Rétablir modifications non pré-commités" msgid "Revert Unstaged Changes?" msgstr "Rétablir les modifications pré-commités ?" msgid "Revert Unstaged Edits..." msgstr "Rétablir les modifications pré-commités..." msgid "Revert the uncommitted changes?" msgstr "Rétablir les modifications non commitées ?" msgid "Revert the unstaged changes?" msgstr "Rétablir les modifications non pré-commités ?" msgid "Revert uncommitted changes to selected paths" msgstr "Rétablir les changements non commités dans les chemins sélectionnés" msgid "Revert unstaged changes to selected paths" msgstr "Rétablir les changements non pré-commités dans les chemins sélectionnés" msgid "Review" msgstr "Examiner" msgid "Review..." msgstr "Examiner..." msgid "Revision" msgstr "Révision" msgid "Revision Expression:" msgstr "Expression de révision :" msgid "Revision to Merge" msgstr "Révision à fusionner" msgid "Reword" msgstr "" msgid "Rewrite Published Commit?" msgstr "Réécrire les commits publiés ?" msgid "Run" msgstr "Exécuter" #, python-format msgid "Run \"%s\"?" msgstr "Exécuter « %s » ?" #, python-format msgid "Run %s?" msgstr "Exécuter %s ?" #, python-format msgid "Run the \"%s\" command?" msgstr "Exécuter la commande « %s » ?" #, python-format msgid "Running command: %s" msgstr "Exécution de la commande : %s" msgid "Russian translation" msgstr "Traduction russe" msgid "SHA-1" msgstr "SHA-1" msgid "Safe Mode" msgstr "" msgid "Save" msgstr "Sauvegarder" msgid "Save Archive" msgstr "Enregistrer l'archive" msgid "Save As Tarball/Zip..." msgstr "Enregistrer sous Tarball/Zip..." msgid "Save GUI Settings" msgstr "Sauvegarder les paramètres de l'interface" msgid "Save Stash" msgstr "Enregistrer la remise" msgid "Save modified state to new stash" msgstr "Enregistrer l'état modifié dans une nouvelle remise" #, python-format msgid "Saved \"%(filename)s\" from \"%(ref)s\" to \"%(destination)s\"" msgstr "Fichier(s) « %(filename)s » enregistré(s) à partir de « %(ref)s » vers « %(destination)s »" msgid "Search" msgstr "Chercher" msgid "Search Authors" msgstr "Chercher les auteurs" msgid "Search Commit Messages" msgstr "Chercher par messages de commit" msgid "Search Committers" msgstr "Chercher les commiteurs" msgid "Search Date Range" msgstr "Chercher une période ciblée" msgid "Search Diffs" msgstr "Chercher les différences" msgid "Search by Expression" msgstr "Chercher par expression" msgid "Search by Path" msgstr "Chercher par chemin" msgid "Search for a fixed string" msgstr "Chercher pour une chaîne donnée" msgid "Search using a POSIX basic regular expression" msgstr "Chercher en utilisant une expression régulière basique POSIX" msgid "Search using a POSIX extended regular expression" msgstr "Chercher en utilisant une expression régulière approfondie POSIX" msgid "Search..." msgstr "Chercher..." msgid "Select" msgstr "Sélectionner" msgid "Select All" msgstr "Tout sélectionner" msgid "Select Branch to Review" msgstr "Sélectionner une branche à examiner" msgid "Select Child" msgstr "Sélectionner un enfant" msgid "Select Commit" msgstr "Sélectionner commit" msgid "Select Directory..." msgstr "" msgid "Select New Upstream" msgstr "Sélectionner une nouvelle source" msgid "Select Newest Child" msgstr "Sélectionner un enfant plus récent" msgid "Select Oldest Parent" msgstr "Sélectionner un parent plus ancien" msgid "Select Parent" msgstr "Sélectionner un parent" msgid "Select Previous Version" msgstr "Sélectionner la version précédente" msgid "Select Repository..." msgstr "Sélectionner le dépôt" msgid "Select a parent directory for the new clone" msgstr "Sélectionner un répertoire parent pour le nouveau clonage" msgid "Select manually..." msgstr "Sélectionner manuellement" msgid "Select output dir" msgstr "" msgid "Select output directory" msgstr "" msgid "Select patch file(s)..." msgstr "" msgid "Select repository" msgstr "" msgid "Set Default Repository" msgstr "Modifier le dépôt par défaut" msgid "Set Upstream Branch" msgstr "" msgid "" "Set the sort order for branches and tags.\n" "Toggle between date-based and version-name-based sorting." msgstr "" msgid "Set upstream" msgstr "Modifier la source" msgid "Settings" msgstr "Paramètres" msgid "Shell arguments" msgstr "Arguments Shell" msgid "Shift Down" msgstr "" msgid "Shift Up" msgstr "" msgid "Shortcuts" msgstr "Raccourcis" msgid "Show Details..." msgstr "" msgid "Show Diffstat After Merge" msgstr "Montrer statistiques de diff après fusion" msgid "Show Full Paths in the Window Title" msgstr "" msgid "Show Help" msgstr "Afficher l'aide" msgid "Show History" msgstr "Afficher l'historique" msgid "Show file counts in Status titles" msgstr "" msgid "" "Show help\n" "Shortcut: ?" msgstr "" "Afficher l'aide\n" "Raccourci : ?" msgid "Show icon? (if available)" msgstr "" msgid "Show line numbers" msgstr "" msgid "Show whole surrounding functions of changes" msgstr "Afficher toutes les fonctions environnantes des changements" msgid "Showing changes since" msgstr "Afficher les modifications depuis" msgid "Side by side" msgstr "" msgid "Sign Off" msgstr "Approuver" msgid "Sign Tag" msgstr "Signer le marqueur" msgid "Sign off on this commit" msgstr "Signer ce commit" msgid "Simplified Chinese translation" msgstr "" msgid "Skip" msgstr "Ignorer" msgid "Skip Current Patch" msgstr "Sauter le patch actuel" msgid "Sort bookmarks alphabetically" msgstr "Trier les marque-pages par ordre alphabétique" msgid "Spanish translation" msgstr "Traduction espagnole" msgid "Specifies the SHA-1 to tag" msgstr "Spécifie le SHA-1 au marqueur" msgid "Specifies the tag message" msgstr "Spécifie le message du marqueur" msgid "Specifies the tag name" msgstr "Spécifie le nom du marqueur" msgid "Spelling Suggestions" msgstr "Suggestions d'orthographe" msgid "Squash" msgstr "Écraser" msgid "Squash the merged commits into a single commit" msgstr "Écraser les commits fusionnés en un seul commit" msgid "Stage" msgstr "Commit" msgid "Stage / Unstage" msgstr "Pré-commité/non pré-commité" msgid "Stage All Untracked" msgstr "Commiter tous les fichiers non suivis" msgid "Stage Changed Files To Commit" msgstr "Commiter fichiers modifiés dans pré-commit" msgid "Stage Diff Hunk" msgstr "Commiter section de différences" msgid "Stage Modified" msgstr "Pré-commit modifié" msgid "Stage Selected" msgstr "Pré-commiter sélection" msgid "Stage Selected Lines" msgstr "Pré-commiter lignes sélectionnées" msgid "Stage Unmerged" msgstr "Pré-commit défusionné" msgid "Stage Untracked" msgstr "Pré-commit démarqué" msgid "Stage and Commit" msgstr "Pré-commiter et commiter" msgid "Stage and commit?" msgstr "Pré-commiter et commiter ?" msgid "Stage conflicts" msgstr "Conflits de commit" msgid "Stage conflicts?" msgstr "Conflits de commit ?" msgid "Stage/unstage selected paths for commit" msgstr "Commiter chemins sélectionnés" msgid "Staged" msgstr "Pré-commité" #, python-format msgid "Staging: %s" msgstr "Commit : %s" msgid "Start Interactive Rebase..." msgstr "Commencer le rétablissement interactif" msgid "Starting Revision" msgstr "Début de révision" msgid "Stash" msgstr "Remiser" msgid "Stash Index" msgstr "" msgid "Stash staged changes only" msgstr "" msgid "Stash unstaged changes only, keeping staged changes" msgstr "" msgid "Stash..." msgstr "Cacher..." msgid "Status" msgstr "Statut" msgid "Stop tracking paths" msgstr "Stopper le suivi des chemins" msgid "Submodules" msgstr "" msgid "Summarize Merge Commits" msgstr "Résumer les commits de fusion" msgid "Summary" msgstr "Résumé" msgid "Tab Width" msgstr "Largeur de l'onglet" msgid "Tag" msgstr "Marque" msgid "Tag Created" msgstr "Marqueur créé" msgid "Tag message..." msgstr "Message du marqueur..." msgid "Tag-signing was requested but the tag message is empty." msgstr "La signature du marqueur a été demandée mais le message du marqueur est vide." msgid "Tags" msgstr "" msgid "Text Width" msgstr "Largeur du texte" msgid "The branch will be no longer available." msgstr "" #, python-format msgid "The branch will be reset using \"git reset --hard %s\"" msgstr "La branche sera réinitialisée en utilisant « git reset --hard %s »" #, python-format msgid "The branch will be reset using \"git reset --merge %s\"" msgstr "La branche sera réinitialisée en utilisant « git reset --merge %s »" #, python-format msgid "The branch will be reset using \"git reset --mixed %s\"" msgstr "La branche sera réinitialisée en utilisant « git reset --mixed %s »" #, python-format msgid "The branch will be reset using \"git reset --soft %s\"" msgstr "La branche sera réinitialisée en utilisant « git reset --soft %s »" msgid "The commit message will be cleared." msgstr "Le message de commit sera effacé." #, python-format msgid "The file \"%s\" exists and will be overwritten." msgstr "Le fichier « %s » existe et sera écrasé." msgid "The following files will be deleted:" msgstr "Les fichiers suivants seront effacés :" msgid "The revision expression cannot be empty." msgstr "L'expression de révision est vide." #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be reset using \"git reset --keep %s\"" msgstr "Cet arbre de travail sera réinitialisé en utilisant « git reset --keep %s »" msgid "This cannot be undone. Clear commit message?" msgstr "Cela ne peut pas être annulé. Effacer le message de commit ?" msgid "" "This commit has already been published.\n" "This operation will rewrite published history.\n" "You probably don't want to do this." msgstr "" "Ce commit a déjà été publié.\n" "Cette opération réécrira l'historique publié.\n" "Vous ne voulez probablement pas effectuer cela." msgid "" "This operation drops uncommitted changes.\n" "These changes cannot be recovered." msgstr "" "Cette opération supprime les modifications non commitées.\n" "Ces modifications ne peuvent pas être récupérées." msgid "" "This operation removes uncommitted edits from selected files.\n" "These changes cannot be recovered." msgstr "" "Cette opération supprime les modifications non commitées.\n" "Ces modifications ne peuvent pas être récupérées." msgid "" "This operation removes unstaged edits from selected files.\n" "These changes cannot be recovered." msgstr "" "Cette opération supprime les modifications pré-commitées.\n" "Ces modifications ne peuvent pas être récupérées." msgid "" "This repository is currently being rebased.\n" "Resolve conflicts, commit changes, and run:\n" " Rebase > Continue" msgstr "" "Ce dépôt est en cours de rétablissement.\n" "Résolvez les conflits, commitez les changements et exécutez :\n" " Rétablir > Continuer" msgid "" "This repository is in the middle of a merge.\n" "Resolve conflicts and commit changes." msgstr "" "Ce dépôt est en cours de fusion.\n" "Résolvez les conflits et commitez les changements." msgid "Toggle Enabled" msgstr "" msgid "Toggle the branches filter" msgstr "" msgid "Toggle the paths filter" msgstr "Alterner les filtres de chemins" msgid "Tracking Branch" msgstr "Suivi de branche" msgid "Tracking branch" msgstr "Suivi de branche" msgid "Traditional Chinese (Taiwan) translation" msgstr "Traduction chinois traditionnel (Taïwan)" msgid "Translators" msgstr "Traducteurs" msgid "Turkish translation" msgstr "Traduction turque" msgid "URL" msgstr "URL" #, python-format msgid "URL: %s" msgstr "URL : %s" msgid "Ukranian translation" msgstr "" msgid "Unable to rebase" msgstr "Impossible de rétablir" #, python-format msgid "Unable to set URL for \"%(name)s\" to \"%(url)s\"" msgstr "" msgid "Undo" msgstr "Défaire" msgid "Unmerged" msgstr "Non fusionné" msgid "Unstage" msgstr "Supprimer du pré-commit" msgid "Unstage All" msgstr "Tout pré-commiter" msgid "Unstage Diff Hunk" msgstr "Retirer section de différences du pré-commit" msgid "Unstage From Commit" msgstr "Commit vers pré-commit" msgid "Unstage Selected" msgstr "Retirer sélection du pré-commit" msgid "Unstage Selected Lines" msgstr "Retirer lignes sélectionnées du pré-commit" #, python-format msgid "Unstaging: %s" msgstr "Supprimer %s du pré-commit" msgid "Untrack Selected" msgstr "Ne plus suivre la sélection" msgid "Untracked" msgstr "Non suivi" #, python-format msgid "Untracking: %s" msgstr "Démarquage de %s du commit" msgid "Update All Submodules..." msgstr "" msgid "Update Existing Branch:" msgstr "Mettre à jour branche existante :" msgid "Update Submodule" msgstr "" msgid "Update Submodule..." msgstr "" msgid "Update Submodules" msgstr "" msgid "Update all submodules?" msgstr "" msgid "Update submodules..." msgstr "" msgid "Update this submodule" msgstr "" msgid "Update this submodule?" msgstr "" msgid "Updating" msgstr "Mise à jour" msgid "User Name" msgstr "Nom d'utilisateur" msgid "Version" msgstr "Version" msgid "View" msgstr "Affichage" msgid "View History..." msgstr "Afficher l'historique..." msgid "View history for selected paths" msgstr "Afficher l'historique pour les chemins selectionnés" msgid "Visualize" msgstr "Visualiser" msgid "Visualize All Branches..." msgstr "Visualiser toutes les branches" msgid "Visualize Current Branch..." msgstr "Visualiser la branche courante..." msgid "Whether to sign the tag (git tag -s)" msgstr "Si vous voulez signer le marqueur (git tag -s)" msgid "Would you like to stage and commit all modified files?" msgstr "Voulez-vous pré-commiter et commiter tous les fichiers modifiés ?" msgid "XOR" msgstr "" msgid "Yes" msgstr "" msgid "" "You are in the middle of a merge.\n" "Cannot amend while merging." msgstr "" "Vous êtes en cours de fusion.\n" "Impossible de corriger durant la fusion." msgid "You cannot rebase with uncommitted changes." msgstr "Vous ne pouvez pas rétablir avec des modifications non commités" msgid "You must specify a revision to merge." msgstr "Vous devez spécifier une révision à fusionner." msgid "You must specify a revision to view." msgstr "Vous devez spécifier une révision à afficher." msgid "Zoom In" msgstr "Zoomer" msgid "Zoom Out" msgstr "Dézoomer " msgid "Zoom to Fit" msgstr "Ajuster à la largeur" msgid "command-line arguments" msgstr "Arguments en ligne de commande" msgid "error: unable to execute git" msgstr "" #, python-format msgid "exit code %s" msgstr "code de sortie %s" #, python-format msgid "fatal: \"%s\" is not a directory. Please specify a correct --repo ." msgstr "Erreur fatale : « %s » n'est pas un répertoire. Veuillez sélectionner un --repo correct ." #, python-format msgid "git cola version %s" msgstr "Version git cola %s" msgid "git-cola" msgstr "git-cola" msgid "git-cola diff" msgstr "git-cola diff" msgid "grep result..." msgstr "Résultat de grep..." msgid "hotkeys.html" msgstr "hotkeys.html" msgid "unknown" msgstr "inconnu" msgid "vX.Y.Z" msgstr "vX.Y.Z" msgid "x 1" msgstr "" msgid "x 1.5" msgstr "" msgid "x 2" msgstr "" msgid "yyyy-MM-dd" msgstr "dd/MM/yyyy" git-cola-3.6/po/git-cola.pot000066400000000000000000001042401356743264500157420ustar00rootroot00000000000000msgid "" "\n" "

\n" " Drag and drop or use the Add button to add\n" " patches to the list\n" "

\n" " " msgstr "" #, python-format msgid "" "\n" "
\n" " Git Cola has been translated into different languages thanks\n" " to the help of the individuals listed below.\n" "\n" "
\n" "

\n" " Translation is approximate. If you find a mistake,\n" " please let us know by opening an issue on Github:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " We invite you to participate in translation by adding or updating\n" " a translation and opening a pull request.\n" "

\n" "\n" "
\n" "\n" " " msgstr "" #, python-format msgid "" "\n" "
\n" " Git Cola version %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " msgstr "" #, python-format msgid "" "\n" "
\n" " Please use %(bug_link)s to report issues.\n" "
\n" " " msgstr "" #, python-format msgid "" "\n" " Format String Variables\n" " -----------------------\n" " %(path)s = relative file path\n" " %(abspath)s = absolute file path\n" " %(dirname)s = relative directory path\n" " %(absdirname)s = absolute directory path\n" " %(filename)s = file basename\n" " %(basename)s = file basename without extension\n" " %(ext)s = file extension\n" msgstr "" msgid "" "\n" "Commands\n" "--------\n" "pick = use commit\n" "reword = use commit, but edit the commit message\n" "edit = use commit, but stop for amending\n" "squash = use commit, but meld into previous commit\n" "fixup = like \"squash\", but discard this commit's log message\n" "exec = run command (the rest of the line) using shell\n" "\n" "These lines can be re-ordered; they are executed from top to bottom.\n" "\n" "If you disable a line here THAT COMMIT WILL BE LOST.\n" "\n" "However, if you disable everything, the rebase will be aborted.\n" "\n" "Keyboard Shortcuts\n" "------------------\n" "? = show help\n" "j = move down\n" "k = move up\n" "J = shift row down\n" "K = shift row up\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "spacebar = toggle enabled\n" "\n" "ctrl+enter = accept changes and rebase\n" "ctrl+q = cancel and abort the rebase\n" "ctrl+d = launch difftool\n" msgstr "" msgid "" "\n" "Keyboard Shortcuts\n" "------------------\n" "J, Down = Move Down\n" "K, Up = Move Up\n" "Enter = Edit Selected Files\n" "Spacebar = Open File Using Default Application\n" "Ctrl + L = Focus Text Entry Field\n" "? = Show Help\n" "\n" "The up and down arrows change focus between the text entry field\n" "and the results.\n" msgstr "" msgid " - DAG" msgstr "" msgid " commits ago" msgstr "" #, python-format msgid "\"%(branch)s\" has been deleted from \"%(remote)s\"." msgstr "" #, python-format msgid "\"%(command)s\" returned exit status \"%(status)d\"" msgstr "" #, python-format msgid "\"%(command)s\" returned exit status %(status)d" msgstr "" #, python-format msgid "\"%s\" already exists" msgstr "" #, python-format msgid "\"%s\" already exists, cola will create a new directory" msgstr "" #, python-format msgid "\"%s\" requires a selected file." msgstr "" msgid "#" msgstr "" #, python-format msgid "%(project)s: %(branch)s - Browse" msgstr "" #, python-format msgid "%(project)s: %(ref)s - DAG" msgstr "" #, python-format msgid "%d days ago" msgstr "" #, python-format msgid "%d hours ago" msgstr "" #, python-format msgid "%d minutes ago" msgstr "" #, python-format msgid "%d patch(es) applied." msgstr "" #, python-format msgid "%d skipped" msgstr "" #, python-format msgid "" "%s appears to contain merge conflicts.\n" "\n" "You should probably skip this file.\n" "Stage it anyways?" msgstr "" #, python-format msgid "%s is not a Git repository." msgstr "" #, python-format msgid "%s will be removed from your bookmarks." msgstr "" #, python-format msgid "%s will be removed from your recent repositories." msgstr "" #, python-format msgid "%s: No such file or directory." msgstr "" msgid "&Edit" msgstr "" msgid "&File" msgstr "" msgid "(Amending)" msgstr "" msgid "*** Branch Point ***" msgstr "" msgid "*** Sandbox ***" msgstr "" msgid "100%" msgstr "" msgid "200%" msgstr "" msgid "25%" msgstr "" msgid "400%" msgstr "" msgid "50%" msgstr "" msgid "800%" msgstr "" msgid " ..." msgstr "" msgid "" "A commit template has not been configured.\n" "Use \"git config\" to define \"commit.template\"\n" "so that it points to a commit template." msgstr "" #, python-format msgid "A hook must be provided at \"%s\"" msgstr "" #, python-format msgid "A stash named \"%s\" already exists" msgstr "" msgid "Abort" msgstr "" msgid "Abort Action" msgstr "" msgid "Abort Merge" msgstr "" msgid "Abort Merge..." msgstr "" msgid "Abort the action?" msgstr "" msgid "" "Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" "Recovering uncommitted changes is not possible." msgstr "" msgid "Aborting the current merge?" msgstr "" msgid "About" msgstr "" msgid "About git-cola" msgstr "" msgid "Accept" msgstr "" msgid "" "Accept changes and rebase\n" "Shortcut: Ctrl+Enter" msgstr "" msgid "Action Name" msgstr "" msgid "Actions" msgstr "" msgid "Actions..." msgstr "" msgid "Add" msgstr "" msgid "Add Favorite" msgstr "" msgid "Add Remote" msgstr "" msgid "Add Separator" msgstr "" msgid "Add Toolbar" msgstr "" msgid "" "Add and remove remote repositories using the \n" "Add(+) and Delete(-) buttons on the left-hand side.\n" "\n" "Remotes can be renamed by selecting one from the list\n" "and pressing \"enter\", or by double-clicking." msgstr "" msgid "Add new remote git repository" msgstr "" msgid "Add patches (+)" msgstr "" msgid "Add remote" msgstr "" msgid "Add to .gitignore" msgstr "" msgid "Add to Git Annex" msgstr "" msgid "Add to Git LFS" msgstr "" msgid "Additions" msgstr "" msgid "Advanced" msgstr "" msgid "Age" msgstr "" msgid "All Repositories" msgstr "" #, python-format msgid "" "All submodules will be updated using\n" "\"%s\"" msgstr "" msgid "Allow non-fast-forward updates. Using \"force\" can cause the remote repository to lose commits; use it with care" msgstr "" msgid "Always create a merge commit when enabled, even when the merge is a fast-forward update" msgstr "" msgid "Amend" msgstr "" msgid "Amend Commit" msgstr "" msgid "Amend Last Commit" msgstr "" msgid "Amend the published commit?" msgstr "" msgid "Amending" msgstr "" msgid "" "An action is still running.\n" "Terminating it could result in data loss." msgstr "" msgid "" "An unsigned, lightweight tag will be created instead.\n" "Create an unsigned tag?" msgstr "" msgid "Appearance" msgstr "" msgid "Apply" msgstr "" msgid "Apply Patches" msgstr "" msgid "Apply Patches..." msgstr "" msgid "Apply and drop the selected stash (git stash pop)" msgstr "" msgid "Apply the selected stash" msgstr "" msgid "Arguments" msgstr "" msgid "Attach" msgstr "" msgid "Author" msgstr "" msgid "Authors" msgstr "" msgid "Auto" msgstr "" msgid "Auto-Wrap Lines" msgstr "" msgid "Basic Regexp" msgstr "" msgid "Blame Viewer" msgstr "" msgid "Blame selected paths" msgstr "" msgid "Blame..." msgstr "" msgid "Bold on dark headers instead of italic" msgstr "" msgid "Branch" msgstr "" #, python-format msgid "" "Branch \"%(branch)s\" does not exist in \"%(remote)s\".\n" "A new remote branch will be published." msgstr "" #, python-format msgid "Branch \"%s\" already exists." msgstr "" msgid "Branch Diff Viewer" msgstr "" msgid "Branch Exists" msgstr "" msgid "Branch Name" msgstr "" #, python-format msgid "Branch: %s" msgstr "" msgid "Branches" msgstr "" msgid "Branches..." msgstr "" msgid "Brazilian translation" msgstr "" msgid "Browse" msgstr "" msgid "Browse Commits..." msgstr "" msgid "Browse Current Branch..." msgstr "" msgid "Browse Other Branch..." msgstr "" msgid "Browse..." msgstr "" msgid "Browser" msgstr "" #, python-format msgid "Browsing %s" msgstr "" msgid "Bypass Commit Hooks" msgstr "" msgid "Cancel" msgstr "" msgid "" "Cancel rebase\n" "Shortcut: Ctrl+Q" msgstr "" msgid "Cannot Amend" msgstr "" #, python-format msgid "Cannot exec \"%s\": please configure a blame viewer" msgstr "" #, python-format msgid "Cannot exec \"%s\": please configure a history browser" msgstr "" #, python-format msgid "Cannot exec \"%s\": please configure your editor" msgstr "" msgid "Changed Upstream" msgstr "" msgid "Check Spelling" msgstr "" msgid "Check spelling" msgstr "" msgid "Checkout" msgstr "" msgid "Checkout After Creation" msgstr "" msgid "Checkout Branch" msgstr "" msgid "Checkout Detached HEAD" msgstr "" msgid "Checkout as new branch" msgstr "" msgid "Checkout..." msgstr "" msgid "Cherry Pick" msgstr "" msgid "Cherry-Pick Commit" msgstr "" msgid "Cherry-Pick..." msgstr "" msgid "Choose Paths" msgstr "" msgid "Choose the \"git grep\" regular expression mode" msgstr "" msgid "Clear Default Repository" msgstr "" msgid "Clear commit message" msgstr "" msgid "Clear commit message?" msgstr "" msgid "Clear..." msgstr "" msgid "Clone" msgstr "" msgid "Clone Repository" msgstr "" msgid "Clone..." msgstr "" #, python-format msgid "Cloning repository at %s" msgstr "" msgid "Close" msgstr "" msgid "Close..." msgstr "" msgid "Collapse all" msgstr "" msgid "Command" msgstr "" msgid "Commit" msgstr "" msgid "Commit failed" msgstr "" msgid "Commit staged changes" msgstr "" msgid "" "Commit staged changes\n" "Shortcut: Ctrl+Enter" msgstr "" msgid "Commit summary" msgstr "" msgid "Commit the merge if there are no conflicts. Uncheck to leave the merge uncommitted" msgstr "" msgid "Commit@@verb" msgstr "" msgid "Compare" msgstr "" msgid "Compare All" msgstr "" msgid "Configure the remote branch as the the new upstream" msgstr "" msgid "Configure toolbar" msgstr "" msgid "Console" msgstr "" msgid "Continue" msgstr "" msgid "Copy" msgstr "" msgid "Copy Basename to Clipboard" msgstr "" msgid "Copy Leading Path to Clipboard" msgstr "" msgid "Copy Path to Clipboard" msgstr "" msgid "Copy Relative Path to Clipboard" msgstr "" msgid "Copy SHA-1" msgstr "" msgid "Copy..." msgstr "" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "" msgid "Create Branch" msgstr "" msgid "Create Patch" msgstr "" msgid "Create Remote Branch" msgstr "" msgid "Create Signed Commit" msgstr "" msgid "Create Tag" msgstr "" msgid "Create Tag..." msgstr "" msgid "Create Unsigned Tag" msgstr "" msgid "Create a merge commit even when the merge resolves as a fast-forward" msgstr "" msgid "Create a new remote branch?" msgstr "" msgid "Create..." msgstr "" #, python-format msgid "Created a new tag named \"%s\"" msgstr "" msgid "Current Repository" msgstr "" msgid "Custom Copy Actions" msgstr "" msgid "Customize..." msgstr "" msgid "Cut" msgstr "" msgid "Czech translation" msgstr "" msgid "DAG..." msgstr "" msgid "Dark Theme" msgstr "" msgid "Date, Time" msgstr "" msgid "Default" msgstr "" msgid "Delete" msgstr "" #, python-format msgid "Delete %d file(s)?" msgstr "" msgid "Delete Bookmark" msgstr "" msgid "Delete Bookmark?" msgstr "" msgid "Delete Branch" msgstr "" msgid "Delete Files" msgstr "" msgid "Delete Files..." msgstr "" msgid "Delete Files?" msgstr "" msgid "Delete Remote" msgstr "" msgid "Delete Remote Branch" msgstr "" msgid "Delete Remote Branch..." msgstr "" msgid "Delete remote" msgstr "" #, python-format msgid "Delete remote \"%s\"" msgstr "" msgid "Delete remote?" msgstr "" msgid "Delete selected branch?" msgstr "" msgid "Delete toolbar" msgstr "" msgid "Delete..." msgstr "" #, python-format msgid "Deleting \"%s\" failed" msgstr "" msgid "Deletions" msgstr "" msgid "Detach" msgstr "" msgid "Detect Conflict Markers" msgstr "" msgid "Detect conflict markers in unmerged files" msgstr "" msgid "Developer" msgstr "" msgid "Diff" msgstr "" msgid "Diff Against Predecessor..." msgstr "" msgid "Diff Options" msgstr "" msgid "Diff Tool" msgstr "" msgid "Diff selected -> this" msgstr "" msgid "Diff this -> selected" msgstr "" msgid "Diffstat" msgstr "" msgid "Difftool" msgstr "" msgid "Directory Exists" msgstr "" msgid "Display Untracked Files" msgstr "" msgid "Documentation" msgstr "" msgid "Drop" msgstr "" msgid "Drop Stash" msgstr "" msgid "Drop Stash?" msgstr "" #, python-format msgid "Drop the \"%s\" stash?" msgstr "" msgid "Drop the selected stash" msgstr "" msgid "Edit" msgstr "" msgid "Edit Rebase" msgstr "" msgid "Edit Remotes" msgstr "" msgid "Edit Remotes..." msgstr "" msgid "Edit remotes by selecting them from the list" msgstr "" msgid "Edit selected paths" msgstr "" msgid "Edit..." msgstr "" msgid "Editor" msgstr "" msgid "Email Address" msgstr "" msgid "Email contributor" msgstr "" msgid "Enabled" msgstr "" msgid "Enter New Branch Name" msgstr "" msgid "Enter a name for the new bare repo" msgstr "" msgid "Enter a name for the stash" msgstr "" msgid "Error" msgstr "" msgid "Error Cloning" msgstr "" msgid "Error Creating Branch" msgstr "" msgid "Error Creating Repository" msgstr "" msgid "Error Deleting Remote Branch" msgstr "" msgid "Error Editing File" msgstr "" msgid "Error Launching Blame Viewer" msgstr "" msgid "Error Launching History Browser" msgstr "" #, python-format msgid "Error creating remote \"%s\"" msgstr "" msgid "Error creating stash" msgstr "" #, python-format msgid "Error deleting remote \"%s\"" msgstr "" #, python-format msgid "Error renaming \"%(name)s\" to \"%(new_name)s\"" msgstr "" msgid "Error running prepare-commitmsg hook" msgstr "" #, python-format msgid "Error updating submodule %s" msgstr "" msgid "Error updating submodules" msgstr "" msgid "Error: Cannot find commit template" msgstr "" msgid "Error: Stash exists" msgstr "" msgid "Error: Unconfigured commit template" msgstr "" #, python-format msgid "Error: could not clone \"%s\"" msgstr "" #, python-format msgid "Error: could not create tag \"%s\"" msgstr "" #, python-format msgid "Executing action %s" msgstr "" msgid "Expand all" msgstr "" msgid "Export Patches" msgstr "" msgid "Export Patches..." msgstr "" msgid "Expression..." msgstr "" msgid "Extended Regexp" msgstr "" msgid "Extended description..." msgstr "" msgid "Fast Forward Only" msgstr "" msgid "Fast-forward only" msgstr "" msgid "Favorite repositories" msgstr "" msgid "Favorites" msgstr "" msgid "Fetch" msgstr "" msgid "Fetch Tracking Branch" msgstr "" msgid "Fetch..." msgstr "" msgid "File Browser..." msgstr "" msgid "File Differences" msgstr "" msgid "File Saved" msgstr "" #, python-format msgid "File saved to \"%s\"" msgstr "" msgid "File system change monitoring: disabled because \"cola.inotify\" is false.\n" msgstr "" msgid "File system change monitoring: disabled because libc does not support the inotify system calls.\n" msgstr "" msgid "File system change monitoring: disabled because pywin32 is not installed.\n" msgstr "" msgid "" "File system change monitoring: disabled because the limit on the total number of inotify watches was reached. You may be able to increase the limit on the number of watches by running:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" msgstr "" msgid "File system change monitoring: enabled.\n" msgstr "" msgid "Filename" msgstr "" msgid "Files" msgstr "" msgid "Filter branches..." msgstr "" msgid "Filter paths..." msgstr "" msgid "Find Files" msgstr "" msgid "Fixed String" msgstr "" msgid "Fixed-Width Font" msgstr "" msgid "Fixup" msgstr "" msgid "Fixup Previous Commit" msgstr "" msgid "Flat dark blue" msgstr "" msgid "Flat dark green" msgstr "" msgid "Flat dark grey" msgstr "" msgid "Flat dark red" msgstr "" msgid "Flat light blue" msgstr "" msgid "Flat light green" msgstr "" msgid "Flat light grey" msgstr "" msgid "Flat light red" msgstr "" msgid "Font Size" msgstr "" msgid "Force" msgstr "" msgid "Force Fetch" msgstr "" msgid "Force Fetch?" msgstr "" msgid "Force Push" msgstr "" msgid "Force Push?" msgstr "" #, python-format msgid "Force fetching from %s?" msgstr "" #, python-format msgid "Force push to %s?" msgstr "" msgid "Format String" msgstr "" msgid "French translation" msgstr "" msgid "GPG-sign the merge commit" msgstr "" msgid "GUI theme" msgstr "" #, python-format msgid "Gathering info for \"%s\"..." msgstr "" msgid "German translation" msgstr "" msgid "Get Commit Message Template" msgstr "" msgid "Go Down" msgstr "" msgid "Go Up" msgstr "" msgid "Grab File..." msgstr "" msgid "Graph" msgstr "" msgid "Grep" msgstr "" msgid "Have you rebased/pulled lately?" msgstr "" msgid "Help" msgstr "" msgid "Help - Custom Copy Actions" msgstr "" msgid "Help - Find Files" msgstr "" msgid "Help - git-xbase" msgstr "" msgid "Hide Details.." msgstr "" msgid "High DPI" msgstr "" msgid "History Browser" msgstr "" msgid "Hungarian translation" msgstr "" msgid "Icon theme" msgstr "" msgid "Ignore all whitespace" msgstr "" msgid "Ignore changes in amount of whitespace" msgstr "" msgid "Ignore changes in whitespace at EOL" msgstr "" msgid "Ignore custom pattern" msgstr "" msgid "Ignore exact filename" msgstr "" msgid "Ignore filename or pattern" msgstr "" msgid "Include tags " msgstr "" msgid "Indent Status paths" msgstr "" msgid "Indonesian translation" msgstr "" msgid "Initialize Git Annex" msgstr "" msgid "Initialize Git LFS" msgstr "" msgid "Inititalize submodules" msgstr "" msgid "Insert spaces instead of tabs" msgstr "" msgid "Interactive Rebase" msgstr "" msgid "Invalid Revision" msgstr "" msgid "Keep *.orig Merge Backups" msgstr "" msgid "Keep Index" msgstr "" msgid "Keyboard Shortcuts" msgstr "" msgid "Launch Diff Tool" msgstr "" msgid "Launch Directory Diff Tool" msgstr "" msgid "Launch Editor" msgstr "" msgid "Launch Terminal" msgstr "" msgid "" "Launch external diff tool\n" "Shortcut: Ctrl+D" msgstr "" msgid "Launch git-cola" msgstr "" msgid "Launch git-difftool against previous versions" msgstr "" msgid "Launch git-difftool on the current path" msgstr "" msgid "Light Theme" msgstr "" msgid "Load Commit Message" msgstr "" msgid "Load Commit Message..." msgstr "" msgid "Load Previous Commit Message" msgstr "" msgid "Loading..." msgstr "" msgid "Local" msgstr "" msgid "Local Branch" msgstr "" msgid "Local branch" msgstr "" msgid "Lock Layout" msgstr "" msgid "Log" msgstr "" msgid "Maintainer (since 2007) and developer" msgstr "" msgid "Merge" msgstr "" #, python-format msgid "Merge \"%(revision)s\" into \"%(branch)s\"" msgstr "" msgid "Merge Tool" msgstr "" msgid "Merge Verbosity" msgstr "" msgid "Merge failed. Conflict resolution is required." msgstr "" #, python-format msgid "Merge into \"%s\"" msgstr "" msgid "Merge into current branch" msgstr "" msgid "Merge..." msgstr "" msgid "Merging" msgstr "" msgid "Message" msgstr "" msgid "Missing Commit Message" msgstr "" msgid "Missing Data" msgstr "" msgid "Missing Name" msgstr "" msgid "Missing Revision" msgstr "" msgid "Missing Tag Message" msgstr "" msgid "Modified" msgstr "" msgid "More..." msgstr "" msgid "Move Down" msgstr "" msgid "Move Up" msgstr "" msgid "Move files to trash" msgstr "" msgid "Name" msgstr "" msgid "Name for the new remote" msgstr "" msgid "New Bare Repository..." msgstr "" msgid "New Repository..." msgstr "" msgid "New..." msgstr "" msgid "Next File" msgstr "" msgid "No" msgstr "" msgid "No Revision Specified" msgstr "" msgid "" "No changes to commit.\n" "\n" "You must stage at least 1 file before you can commit." msgstr "" msgid "No commits exist in this branch." msgstr "" msgid "No fast forward" msgstr "" msgid "No fast-forward" msgstr "" msgid "No repository selected." msgstr "" msgid "Non-fast-forward fetch overwrites local history!" msgstr "" msgid "" "Non-fast-forward push overwrites published history!\n" "(Did you pull first?)" msgstr "" msgid "Nothing to commit" msgstr "" msgid "Nothing to do" msgstr "" msgid "Number of Diff Context Lines" msgstr "" msgid "Open" msgstr "" msgid "Open Git Repository..." msgstr "" msgid "Open Parent" msgstr "" msgid "Open Parent Directory" msgstr "" msgid "Open Recent" msgstr "" msgid "Open Using Default Application" msgstr "" msgid "Open in New Window" msgstr "" msgid "Open in New Window..." msgstr "" msgid "Open..." msgstr "" msgid "Other branches" msgstr "" msgid "Overwrite" msgstr "" #, python-format msgid "Overwrite \"%s\"?" msgstr "" msgid "Overwrite File?" msgstr "" msgid "" "Parse arguments using a shell.\n" "Queries with spaces will require \"double quotes\"." msgstr "" msgid "Partially Staged" msgstr "" msgid "Paste" msgstr "" msgid "Patch(es) Applied" msgstr "" msgid "Path" msgstr "" msgid "Path or URL to clone (Env. $VARS okay)" msgstr "" msgid "Pick" msgstr "" msgid "Pixel XOR" msgstr "" msgid "Please provide both a branch name and revision expression." msgstr "" msgid "Please select a file" msgstr "" msgid "Please specify a name for the new tag." msgstr "" msgid "Please specify a revision to tag." msgstr "" msgid "" "Please supply a commit message.\n" "\n" "A good commit message has the following format:\n" "\n" "- First line: Describe in one sentence what you did.\n" "- Second line: Blank\n" "- Remaining lines: Describe why this change is good.\n" msgstr "" msgid "Point the current branch head to a new commit?" msgstr "" msgid "Polish translation" msgstr "" msgid "Pop" msgstr "" msgid "Preferences" msgstr "" msgid "Prefix" msgstr "" msgid "Prepare Commit Message" msgstr "" msgid "Prevent \"Stage\" from staging all files when nothing is selected" msgstr "" msgid "Previous File" msgstr "" msgid "Prompt on creation" msgstr "" msgid "Prompt when pushing creates new remote branches" msgstr "" msgid "Prune " msgstr "" msgid "Pull" msgstr "" msgid "Pull..." msgstr "" msgid "Push" msgstr "" msgid "Push..." msgstr "" msgid "Quit" msgstr "" msgid "Rebase" msgstr "" #, python-format msgid "Rebase onto %s" msgstr "" msgid "Rebase stopped" msgstr "" msgid "Rebase the current branch instead of merging" msgstr "" msgid "Rebasing" msgstr "" msgid "Recent" msgstr "" msgid "Recent repositories" msgstr "" msgid "Recent repository count" msgstr "" msgid "Recently Modified Files" msgstr "" msgid "Recently Modified Files..." msgstr "" msgid "Recovering a dropped stash is not possible." msgstr "" msgid "Recovering lost commits may not be easy." msgstr "" msgid "Redo" msgstr "" msgid "Reduce commit history to minimum" msgstr "" msgid "Refresh" msgstr "" msgid "Refuse to merge unless the current HEAD is already up-to-date or the merge can be resolved as a fast-forward" msgstr "" msgid "Remote" msgstr "" msgid "Remote Branch" msgstr "" msgid "Remote Branch Deleted" msgstr "" msgid "Remote git repositories - double-click to rename" msgstr "" msgid "Remove" msgstr "" #, python-format msgid "Remove %s from the recent list?" msgstr "" msgid "Remove Element" msgstr "" msgid "Remove remote-tracking branches that no longer exist on the remote" msgstr "" msgid "Remove selected (Delete)" msgstr "" msgid "Rename" msgstr "" #, python-format msgid "Rename \"%s\"" msgstr "" msgid "Rename Branch" msgstr "" msgid "Rename Branch..." msgstr "" msgid "Rename Existing Branch" msgstr "" msgid "Rename Remote" msgstr "" msgid "Rename Repository" msgstr "" msgid "Rename branch" msgstr "" #, python-format msgid "Rename remote \"%(current)s\" to \"%(new)s\"?" msgstr "" msgid "Rename selected paths" msgstr "" #, python-format msgid "Repository: %s" msgstr "" msgid "Reset" msgstr "" #, python-format msgid "Reset \"%(branch)s\" to \"%(revision)s\"?" msgstr "" msgid "Reset Branch" msgstr "" msgid "Reset Branch Head" msgstr "" msgid "Reset Branch?" msgstr "" msgid "Reset Hard" msgstr "" msgid "Reset Merge" msgstr "" msgid "Reset Soft" msgstr "" msgid "Reset Worktree" msgstr "" msgid "Reset hard?" msgstr "" msgid "Reset merge?" msgstr "" msgid "Reset soft?" msgstr "" msgid "Reset worktree?" msgstr "" #, python-format msgid "Resetting \"%(branch)s\" to \"%(revision)s\" will lose commits." msgstr "" msgid "Restart the application after changing appearance settings." msgstr "" msgid "Revert" msgstr "" msgid "Revert Diff Hunk" msgstr "" msgid "Revert Diff Hunk..." msgstr "" msgid "Revert Diff Hunk?" msgstr "" msgid "Revert Selected Lines" msgstr "" msgid "Revert Selected Lines..." msgstr "" msgid "Revert Selected Lines?" msgstr "" msgid "Revert Uncommitted Changes" msgstr "" msgid "Revert Uncommitted Changes?" msgstr "" msgid "Revert Uncommitted Edits..." msgstr "" msgid "Revert Unstaged Changes" msgstr "" msgid "Revert Unstaged Changes?" msgstr "" msgid "Revert Unstaged Edits..." msgstr "" msgid "Revert the uncommitted changes?" msgstr "" msgid "Revert the unstaged changes?" msgstr "" msgid "Revert uncommitted changes to selected paths" msgstr "" msgid "Revert unstaged changes to selected paths" msgstr "" msgid "Review" msgstr "" msgid "Review..." msgstr "" msgid "Revision" msgstr "" msgid "Revision Expression:" msgstr "" msgid "Revision to Merge" msgstr "" msgid "Reword" msgstr "" msgid "Rewrite Published Commit?" msgstr "" msgid "Run" msgstr "" #, python-format msgid "Run \"%s\"?" msgstr "" #, python-format msgid "Run %s?" msgstr "" #, python-format msgid "Run the \"%s\" command?" msgstr "" #, python-format msgid "Running command: %s" msgstr "" msgid "Russian translation" msgstr "" msgid "SHA-1" msgstr "" msgid "Safe Mode" msgstr "" msgid "Save" msgstr "" msgid "Save Archive" msgstr "" msgid "Save As Tarball/Zip..." msgstr "" msgid "Save GUI Settings" msgstr "" msgid "Save Stash" msgstr "" msgid "Save modified state to new stash" msgstr "" #, python-format msgid "Saved \"%(filename)s\" from \"%(ref)s\" to \"%(destination)s\"" msgstr "" msgid "Search" msgstr "" msgid "Search Authors" msgstr "" msgid "Search Commit Messages" msgstr "" msgid "Search Committers" msgstr "" msgid "Search Date Range" msgstr "" msgid "Search Diffs" msgstr "" msgid "Search by Expression" msgstr "" msgid "Search by Path" msgstr "" msgid "Search for a fixed string" msgstr "" msgid "Search using a POSIX basic regular expression" msgstr "" msgid "Search using a POSIX extended regular expression" msgstr "" msgid "Search..." msgstr "" msgid "Select" msgstr "" msgid "Select All" msgstr "" msgid "Select Branch to Review" msgstr "" msgid "Select Child" msgstr "" msgid "Select Commit" msgstr "" msgid "Select Directory..." msgstr "" msgid "Select New Upstream" msgstr "" msgid "Select Newest Child" msgstr "" msgid "Select Oldest Parent" msgstr "" msgid "Select Parent" msgstr "" msgid "Select Previous Version" msgstr "" msgid "Select Repository..." msgstr "" msgid "Select a parent directory for the new clone" msgstr "" msgid "Select manually..." msgstr "" msgid "Select output dir" msgstr "" msgid "Select output directory" msgstr "" msgid "Select patch file(s)..." msgstr "" msgid "Select repository" msgstr "" msgid "Set Default Repository" msgstr "" msgid "Set Upstream Branch" msgstr "" msgid "" "Set the sort order for branches and tags.\n" "Toggle between date-based and version-name-based sorting." msgstr "" msgid "Set upstream" msgstr "" msgid "Settings" msgstr "" msgid "Shell arguments" msgstr "" msgid "Shift Down" msgstr "" msgid "Shift Up" msgstr "" msgid "Shortcuts" msgstr "" msgid "Show Details..." msgstr "" msgid "Show Diffstat After Merge" msgstr "" msgid "Show Full Paths in the Window Title" msgstr "" msgid "Show Help" msgstr "" msgid "Show History" msgstr "" msgid "Show file counts in Status titles" msgstr "" msgid "" "Show help\n" "Shortcut: ?" msgstr "" msgid "Show icon? (if available)" msgstr "" msgid "Show line numbers" msgstr "" msgid "Show whole surrounding functions of changes" msgstr "" msgid "Showing changes since" msgstr "" msgid "Side by side" msgstr "" msgid "Sign Off" msgstr "" msgid "Sign Tag" msgstr "" msgid "Sign off on this commit" msgstr "" msgid "Simplified Chinese translation" msgstr "" msgid "Skip" msgstr "" msgid "Skip Current Patch" msgstr "" msgid "Sort bookmarks alphabetically" msgstr "" msgid "Spanish translation" msgstr "" msgid "Specifies the SHA-1 to tag" msgstr "" msgid "Specifies the tag message" msgstr "" msgid "Specifies the tag name" msgstr "" msgid "Spelling Suggestions" msgstr "" msgid "Squash" msgstr "" msgid "Squash the merged commits into a single commit" msgstr "" msgid "Stage" msgstr "" msgid "Stage / Unstage" msgstr "" msgid "Stage All Untracked" msgstr "" msgid "Stage Changed Files To Commit" msgstr "" msgid "Stage Diff Hunk" msgstr "" msgid "Stage Modified" msgstr "" msgid "Stage Selected" msgstr "" msgid "Stage Selected Lines" msgstr "" msgid "Stage Unmerged" msgstr "" msgid "Stage Untracked" msgstr "" msgid "Stage and Commit" msgstr "" msgid "Stage and commit?" msgstr "" msgid "Stage conflicts" msgstr "" msgid "Stage conflicts?" msgstr "" msgid "Stage/unstage selected paths for commit" msgstr "" msgid "Staged" msgstr "" #, python-format msgid "Staging: %s" msgstr "" msgid "Start Interactive Rebase..." msgstr "" msgid "Starting Revision" msgstr "" msgid "Stash" msgstr "" msgid "Stash Index" msgstr "" msgid "Stash staged changes only" msgstr "" msgid "Stash unstaged changes only, keeping staged changes" msgstr "" msgid "Stash..." msgstr "" msgid "Status" msgstr "" msgid "Stop tracking paths" msgstr "" msgid "Submodules" msgstr "" msgid "Summarize Merge Commits" msgstr "" msgid "Summary" msgstr "" msgid "Tab Width" msgstr "" msgid "Tag" msgstr "" msgid "Tag Created" msgstr "" msgid "Tag message..." msgstr "" msgid "Tag-signing was requested but the tag message is empty." msgstr "" msgid "Tags" msgstr "" msgid "Text Width" msgstr "" msgid "The branch will be no longer available." msgstr "" #, python-format msgid "The branch will be reset using \"git reset --hard %s\"" msgstr "" #, python-format msgid "The branch will be reset using \"git reset --merge %s\"" msgstr "" #, python-format msgid "The branch will be reset using \"git reset --mixed %s\"" msgstr "" #, python-format msgid "The branch will be reset using \"git reset --soft %s\"" msgstr "" msgid "The commit message will be cleared." msgstr "" #, python-format msgid "The file \"%s\" exists and will be overwritten." msgstr "" msgid "The following files will be deleted:" msgstr "" msgid "The revision expression cannot be empty." msgstr "" #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be reset using \"git reset --keep %s\"" msgstr "" msgid "This cannot be undone. Clear commit message?" msgstr "" msgid "" "This commit has already been published.\n" "This operation will rewrite published history.\n" "You probably don't want to do this." msgstr "" msgid "" "This operation drops uncommitted changes.\n" "These changes cannot be recovered." msgstr "" msgid "" "This operation removes uncommitted edits from selected files.\n" "These changes cannot be recovered." msgstr "" msgid "" "This operation removes unstaged edits from selected files.\n" "These changes cannot be recovered." msgstr "" msgid "" "This repository is currently being rebased.\n" "Resolve conflicts, commit changes, and run:\n" " Rebase > Continue" msgstr "" msgid "" "This repository is in the middle of a merge.\n" "Resolve conflicts and commit changes." msgstr "" msgid "Toggle Enabled" msgstr "" msgid "Toggle the branches filter" msgstr "" msgid "Toggle the paths filter" msgstr "" msgid "Tracking Branch" msgstr "" msgid "Tracking branch" msgstr "" msgid "Traditional Chinese (Taiwan) translation" msgstr "" msgid "Translators" msgstr "" msgid "Turkish translation" msgstr "" msgid "URL" msgstr "" #, python-format msgid "URL: %s" msgstr "" msgid "Ukranian translation" msgstr "" msgid "Unable to rebase" msgstr "" #, python-format msgid "Unable to set URL for \"%(name)s\" to \"%(url)s\"" msgstr "" msgid "Undo" msgstr "" msgid "Unmerged" msgstr "" msgid "Unstage" msgstr "" msgid "Unstage All" msgstr "" msgid "Unstage Diff Hunk" msgstr "" msgid "Unstage From Commit" msgstr "" msgid "Unstage Selected" msgstr "" msgid "Unstage Selected Lines" msgstr "" #, python-format msgid "Unstaging: %s" msgstr "" msgid "Untrack Selected" msgstr "" msgid "Untracked" msgstr "" #, python-format msgid "Untracking: %s" msgstr "" msgid "Update All Submodules..." msgstr "" msgid "Update Existing Branch:" msgstr "" msgid "Update Submodule" msgstr "" msgid "Update Submodule..." msgstr "" msgid "Update Submodules" msgstr "" msgid "Update all submodules?" msgstr "" msgid "Update submodules..." msgstr "" msgid "Update this submodule" msgstr "" msgid "Update this submodule?" msgstr "" msgid "Updating" msgstr "" msgid "User Name" msgstr "" msgid "Version" msgstr "" msgid "View" msgstr "" msgid "View History..." msgstr "" msgid "View history for selected paths" msgstr "" msgid "Visualize" msgstr "" msgid "Visualize All Branches..." msgstr "" msgid "Visualize Current Branch..." msgstr "" msgid "Whether to sign the tag (git tag -s)" msgstr "" msgid "Would you like to stage and commit all modified files?" msgstr "" msgid "XOR" msgstr "" msgid "Yes" msgstr "" msgid "" "You are in the middle of a merge.\n" "Cannot amend while merging." msgstr "" msgid "You cannot rebase with uncommitted changes." msgstr "" msgid "You must specify a revision to merge." msgstr "" msgid "You must specify a revision to view." msgstr "" msgid "Zoom In" msgstr "" msgid "Zoom Out" msgstr "" msgid "Zoom to Fit" msgstr "" msgid "command-line arguments" msgstr "" msgid "error: unable to execute git" msgstr "" #, python-format msgid "exit code %s" msgstr "" #, python-format msgid "fatal: \"%s\" is not a directory. Please specify a correct --repo ." msgstr "" #, python-format msgid "git cola version %s" msgstr "" msgid "git-cola" msgstr "" msgid "git-cola diff" msgstr "" msgid "grep result..." msgstr "" msgid "hotkeys.html" msgstr "" msgid "unknown" msgstr "" msgid "vX.Y.Z" msgstr "" msgid "x 1" msgstr "" msgid "x 1.5" msgstr "" msgid "x 2" msgstr "" msgid "yyyy-MM-dd" msgstr "" git-cola-3.6/po/glossary/000077500000000000000000000000001356743264500153615ustar00rootroot00000000000000git-cola-3.6/po/glossary/de.po000066400000000000000000000130211356743264500163060ustar00rootroot00000000000000# Translation of git-cola glossary to German # Copyright (C) 2007 Shawn Pearce, et al. # This file is distributed under the same license as the git-cola package. # Christian Stimming , 2007 # msgid "" msgstr "" "Project-Id-Version: git-cola glossary\n" "POT-Creation-Date: 2007-10-19 21:43+0200\n" "PO-Revision-Date: 2007-10-20 15:24+0200\n" "Last-Translator: Christian Stimming \n" "Language-Team: German \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. "English Definition (Dear translator: This file will never be visible to the user! It should only serve as a tool for you, the translator. Nothing more.)" msgid "" "English Term (Dear translator: This file will never be visible to the user!)" msgstr "" "Deutsche Übersetzung.\n" "Andere deutsche SCM:\n" " http://tortoisesvn.net/docs/release/TortoiseSVN_de/index.html und http://" "tortoisesvn.tigris.org/svn/tortoisesvn/trunk/Languages/Tortoise_de.po " "(username=guest, password empty, gut),\n" " http://msdn.microsoft.com/de-de/library/ms181038(vs.80).aspx (MS Visual " "Source Safe, kommerziell),\n" " http://cvsbook.red-bean.com/translations/german/Kap_06.html " "(mittelmäßig),\n" " http://tortoisecvs.cvs.sourceforge.net/tortoisecvs/po/TortoiseCVS/de_DE.po?" "view=markup (mittelmäßig),\n" " http://rapidsvn.tigris.org/svn/rapidsvn/trunk/src/locale/de/rapidsvn.po " "(username=guest, password empty, schlecht)" #. "" msgid "amend" msgstr "nachbessern (ergänzen)" #. "" msgid "annotate" msgstr "annotieren" #. "A 'branch' is an active line of development." msgid "branch [noun]" msgstr "Zweig" #. "" msgid "branch [verb]" msgstr "verzweigen" #. "" msgid "checkout [noun]" msgstr "" "Arbeitskopie (Erstellung einer Arbeitskopie; Auscheck? Ausspielung? Abruf? " "Source Safe: Auscheckvorgang)" #. "The action of updating the working tree to a revision which was stored in the object database." msgid "checkout [verb]" msgstr "" "Arbeitskopie erstellen; Zweig umstellen [checkout a branch] (auschecken? " "ausspielen? abrufen? Source Safe: auschecken)" #. "" msgid "clone [verb]" msgstr "kopieren" #. "A single point in the git history." msgid "commit [noun]" msgstr "" "Version; Eintragung; Änderung (Buchung?, Eintragung?, Übertragung?, " "Sendung?, Übergabe?, Einspielung?, Ablagevorgang?)" #. "The action of storing a new snapshot of the project's state in the git history." msgid "commit [verb]" msgstr "" "eintragen (TortoiseSVN: übertragen; Source Safe: einchecken; senden?, " "übergeben?, einspielen?, einpflegen?, ablegen?)" #. "" msgid "diff [noun]" msgstr "Vergleich (Source Safe: Unterschiede)" #. "" msgid "diff [verb]" msgstr "vergleichen" #. "A fast-forward is a special type of merge where you have a revision and you are merging another branch's changes that happen to be a descendant of what you have." msgid "fast forward merge" msgstr "Schnellzusammenführung" #. "Fetching a branch means to get the branch's head from a remote repository, to find out which objects are missing from the local object database, and to get them, too." msgid "fetch" msgstr "anfordern (holen?)" #. "A collection of files. The index is a stored version of your working tree." msgid "index (in git-gui: staging area)" msgstr "Bereitstellung" #. "A successful merge results in the creation of a new commit representing the result of the merge." msgid "merge [noun]" msgstr "Zusammenführung" #. "To bring the contents of another branch into the current branch." msgid "merge [verb]" msgstr "zusammenführen" #. "" msgid "message" msgstr "Beschreibung (Meldung?, Nachricht?; Source Safe: Kommentar)" #. "Deletes all stale tracking branches under . These stale branches have already been removed from the remote repository referenced by , but are still locally available in 'remotes/'." msgid "prune" msgstr "entfernen" #. "Pulling a branch means to fetch it and merge it." msgid "pull" msgstr "übernehmen (ziehen?)" #. "Pushing a branch means to get the branch's head ref from a remote repository, and ... (well, can someone please explain it for mere mortals?)" msgid "push" msgstr "versenden (ausliefern? hochladen? verschicken? schieben?)" #. "" msgid "redo" msgstr "wiederholen" #. "An other repository ('remote'). One might have a set of remotes whose branches one tracks." msgid "remote" msgstr "Andere Archive (Gegenseite?, Entfernte?, Server?)" #. "A collection of refs (?) together with an object database containing all objects which are reachable from the refs... (oops, you've lost me here. Again, please an explanation for mere mortals?)" msgid "repository" msgstr "Projektarchiv" #. "" msgid "reset" msgstr "zurücksetzen (zurückkehren?)" #. "" msgid "revert" msgstr "revidieren" #. "A particular state of files and directories which was stored in the object database." msgid "revision" msgstr "Version (TortoiseSVN: Revision; Source Safe: Version)" #. "" msgid "sign off" msgstr "abzeichnen (gegenzeichnen?, freizeichnen?, absegnen?)" #. "" msgid "staging area" msgstr "Bereitstellung" #. "" msgid "status" msgstr "Status" #. "A ref pointing to a tag or commit object" msgid "tag [noun]" msgstr "Markierung" #. "" msgid "tag [verb]" msgstr "markieren" #. "A regular git branch that is used to follow changes from another repository." msgid "tracking branch" msgstr "Übernahmezweig" #. "" msgid "undo" msgstr "rückgängig" #. "" msgid "update" msgstr "aktualisieren" #. "" msgid "verify" msgstr "überprüfen" #. "The tree of actual checked out files." msgid "working copy, working tree" msgstr "Arbeitskopie" git-cola-3.6/po/glossary/it.po000066400000000000000000000131271356743264500163410ustar00rootroot00000000000000# Translation of git-cola glossary to Italian # Copyright (C) 2007 Shawn Pearce, et al. # This file is distributed under the same license as the git-cola package. # Christian Stimming , 2007 # msgid "" msgstr "" "Project-Id-Version: git-cola glossary\n" "POT-Creation-Date: 2007-10-19 21:43+0200\n" "PO-Revision-Date: 2007-10-10 15:24+0200\n" "Last-Translator: Michele Ballabio \n" "Language-Team: Italian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. "English Definition (Dear translator: This file will never be visible to the user! It should only serve as a tool for you, the translator. Nothing more.)" msgid "" "English Term (Dear translator: This file will never be visible to the user!)" msgstr "" "Traduzione italiana.\n" "Altri SCM in italiano:\n" " http://tortoisesvn.tigris.org/svn/tortoisesvn/trunk/Languages/Tortoise_it." "po (username=guest, password empty),\n" " http://tortoisecvs.cvs.sourceforge.net/tortoisecvs/po/TortoiseCVS/it_IT.po?" "view=markup ,\n" " http://rapidsvn.tigris.org/svn/rapidsvn/trunk/src/locale/it_IT/rapidsvn.po " "(username=guest, password empty)" #. "" msgid "amend" msgstr "correggere, correzione" #. "" msgid "annotate" msgstr "annotare, annotazione" #. "A 'branch' is an active line of development." msgid "branch [noun]" msgstr "ramo, diramazione, ramificazione" #. "" msgid "branch [verb]" msgstr "creare ramo, ramificare, diramare" #. "" msgid "checkout [noun]" msgstr "attivazione, checkout, revisione attiva, prelievo (TortoiseCVS)?" #. "The action of updating the working tree to a revision which was stored in the object database." msgid "checkout [verb]" msgstr "" "attivare, effettuare un checkout, attivare revisione, prelevare " "(TortoiseCVS), ritirare (TSVN)?" #. "" msgid "clone [verb]" msgstr "clonare" #. "A single point in the git history." msgid "commit [noun]" msgstr "revisione, commit, deposito (TortoiseCVS), invio (TSVN)?" #. "The action of storing a new snapshot of the project's state in the git history." msgid "commit [verb]" msgstr "" "creare una nuova revisione, archiviare, effettuare un commit, depositare " "(nel server), fare un deposito (TortoiseCVS), inviare (TSVN)?" #. "" msgid "diff [noun]" msgstr "differenza, confronto, comparazione, raffronto" #. "" msgid "diff [verb]" msgstr "confronta, mostra le differenze" #. "A fast-forward is a special type of merge where you have a revision and you are merging another branch's changes that happen to be a descendant of what you have." msgid "fast forward merge" msgstr "fusione in 'fast-forward', fusione in avanti veloce" #. "Fetching a branch means to get the branch's head from a remote repository, to find out which objects are missing from the local object database, and to get them, too." msgid "fetch" msgstr "recuperare, prelevare, prendere da, recuperare (TSVN)" #. "A collection of files. The index is a stored version of your working tree." msgid "index (in git-gui: staging area)" msgstr "indice" #. "A successful merge results in the creation of a new commit representing the result of the merge." msgid "merge [noun]" msgstr "fusione, unione" #. "To bring the contents of another branch into the current branch." msgid "merge [verb]" msgstr "effettuare la fusione, unire, fondere, eseguire la fusione" #. "" msgid "message" msgstr "messaggio, commento" #. "Deletes all stale tracking branches under . These stale branches have already been removed from the remote repository referenced by , but are still locally available in 'remotes/'." msgid "prune" msgstr "potatura" #. "Pulling a branch means to fetch it and merge it." msgid "pull" msgstr "" "prendi (recupera) e fondi (unisci)? (in pratica una traduzione di fetch + " "merge)" #. "Pushing a branch means to get the branch's head ref from a remote repository, and ... (well, can someone please explain it for mere mortals?)" msgid "push" msgstr "propaga" #. "" msgid "redo" msgstr "ripeti, rifai" #. "An other repository ('remote'). One might have a set of remotes whose branches one tracks." msgid "remote" msgstr "remoto" #. "A collection of refs (?) together with an object database containing all objects which are reachable from the refs... (oops, you've lost me here. Again, please an explanation for mere mortals?)" msgid "repository" msgstr "archivio, repository, database? deposito (rapidsvn)?" #. "" msgid "reset" msgstr "ripristinare, annullare, azzerare, ripristinare" #. "" msgid "revert" msgstr "" "annullare, inverti (rapidsvn), ritorna allo stato precedente, annulla le " "modifiche della revisione" #. "A particular state of files and directories which was stored in the object database." msgid "revision" msgstr "revisione (TortoiseSVN)" #. "" msgid "sign off" msgstr "sign off, firma" #. "" msgid "staging area" msgstr "" "area di preparazione, zona di preparazione, modifiche in preparazione? " "modifiche in allestimento?" #. "" msgid "status" msgstr "stato" #. "A ref pointing to a tag or commit object" msgid "tag [noun]" msgstr "etichetta, etichettatura (TortoiseCVS)" #. "" msgid "tag [verb]" msgstr "etichettare" #. "A regular git branch that is used to follow changes from another repository." msgid "tracking branch" msgstr "" "duplicato locale di ramo remoto, ramo in 'tracking', ramo inseguitore? ramo " "di {inseguimento,allineamento,rilevamento,puntamento}?" #. "" msgid "undo" msgstr "annulla" #. "" msgid "update" msgstr "aggiornamento, aggiornare" #. "" msgid "verify" msgstr "verifica, verificare" #. "The tree of actual checked out files." msgid "working copy, working tree" msgstr "directory di lavoro, copia di lavoro" git-cola-3.6/po/glossary/zh_cn.po000066400000000000000000000122401356743264500170210ustar00rootroot00000000000000# Translation of git-cola glossary to Simplified Chinese # Copyright (C) 2007 Shawn Pearce, et al. # This file is distributed under the same license as the git-cola package. # Xudong Guan and the zh-kernel.org mailing list, 2007 # ZH , 2015 # msgid "" msgstr "" "Project-Id-Version: git-cola glossary\n" "PO-Revision-Date: 2007-07-23 22:07+0200\n" "Last-Translator: ZH \n" "Language-Team: Simplified Chinese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. "English Definition (Dear translator: This file will never be visible to the user! It should only serve as a tool for you, the translator. Nothing more.)" msgid "" "English Term (Dear translator: This file will never be visible to the user!)" msgstr "注:这个文件是为了帮助翻译人员统一名词术语。最终用户不会关心这个文件。" #. "" #. amend指用户修改最近一次commit的操作,修订?修改?修正? #. [WANG Cong]: 根据我的了解,这个词似乎翻译成“修订”多一些。“修正”也可以,“修改”再次之。 #. [ZHANG Le]: 修订,感觉一般指对一些大型出版物的大规模升级,比如修订新华字典 # 修正,其实每次amend的结果也不一定就是最后结果,说不定还需要修改。所以不 # 如就叫修改 msgid "amend" msgstr "修订" #. "" #. git annotate 文件名:用来标注文件的每一行在什么时候被谁最后修改。 #. [WANG Cong]: "标记"一般是mark。;) #. [ZHANG Le]: 标注,或者干脆用原意:注解,或注释 msgid "annotate" msgstr "标注" #. "A 'branch' is an active line of development." msgid "branch [noun]" msgstr "分支" #. "" msgid "branch [verb]" msgstr "建立分支" #. "" #. [WANG Cong]: 网上有人翻译成“检出”,我感觉更好一些,毕竟把check的意思翻译出来了。 #. [ZHNAG Le]: 提取吧,提取分支/版本 #. [rae l]: 签出。subversion软件中的大多词汇已有翻译,既然git与subversion同是SCM管理,可以参考同类软件的翻译也不错。 msgid "checkout [noun]" msgstr "签出" #. "The action of updating the working tree to a revision which was stored in the object database." msgid "checkout [verb]" msgstr "进行签出" #. "A single point in the git history." msgid "commit [noun]" msgstr "提交" #. "The action of storing a new snapshot of the project's state in the git history." msgid "commit [verb]" msgstr "进行提交" #. "" #. 差异?差别? #. [ZHANG Le]: 个人感觉差别更加中性一些 msgid "diff [noun]" msgstr "差别" #. "" msgid "diff [verb]" msgstr "比较" #. "A fast-forward is a special type of merge where you have a revision and you are merging another branch's changes that happen to be a descendant of what you have." msgid "fast forward merge" msgstr "快进式合并" #. "Fetching a branch means to get the branch's head from a remote repository, to find out which objects are missing from the local object database, and to get them, too." #. 获取?取得?下载?更新?注意和update的区分 msgid "fetch" msgstr "获取" #. "A collection of files. The index is a stored version of your working tree." #. index是working tree和repository之间的缓存 msgid "index (in git-gui: staging area)" msgstr "工作缓存?" #. "A successful merge results in the creation of a new commit representing the result of the merge." msgid "merge [noun]" msgstr "合并" #. "To bring the contents of another branch into the current branch." msgid "merge [verb]" msgstr "进行合并" #. "" #. message是指commit中的文字信息 msgid "message" msgstr "描述" #. "Pulling a branch means to fetch it and merge it." msgid "pull" msgstr "拉取" #. "Pushing a branch means to get the branch's head ref from a remote repository, and ... (well, can someone please explain it for mere mortals?)" msgid "push" msgstr "推入" #. "" msgid "redo" msgstr "重做" #. "A collection of refs (?) together with an object database containing all objects which are reachable from the refs... (oops, you've lost me here. Again, please an explanation for mere mortals?)" msgid "repository" msgstr "仓库" #. "" msgid "reset" msgstr "重置" #. "" msgid "revert" msgstr "恢复" #. "A particular state of files and directories which was stored in the object database." msgid "revision" msgstr "版本" #. "" msgid "sign off" msgstr "签名" #. "" #. 似乎是git-gui里面显示的本次提交的文件清单区域 msgid "staging area" msgstr "提交暂存区" #. "" msgid "status" msgstr "状态" #. "A ref pointing to a tag or commit object" msgid "tag [noun]" msgstr "标签" #. "" msgid "tag [verb]" msgstr "添加标签" #. "A regular git branch that is used to follow changes from another repository." msgid "tracking branch" msgstr "跟踪分支" #. "" msgid "undo" msgstr "撤销" #. "" msgid "update" msgstr "更新。注意和fetch的区分" #. "" msgid "verify" msgstr "验证" #. "The tree of actual checked out files." #. "工作副本?工作区域?工作目录" #. [LI Yang]: 当前副本, 当前源码树? msgid "working copy, working tree" msgstr "工作副本,工作源码树" git-cola-3.6/po/glossary/zh_tw.po000066400000000000000000000157611356743264500170660ustar00rootroot00000000000000# Translation of git-cola glossary to Traditional Chinese(Taiwan) # Copyright (C) 2007 Shawn Pearce, et al. # This file is distributed under the same license as the git-cola package. # V字龍(Vdragon) , 2014, 2018. msgid "" msgstr "" "Project-Id-Version: git-cola glossary\n" "PO-Revision-Date: 2018-06-27 23:50+0800\n" "Last-Translator: V字龍(Vdragon) \n" "Language-Team: Chinese l10n \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: zh_TW\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" #. "English Definition (Dear translator: This file will never be visible to the user! It should only serve as a tool for you, the translator. Nothing more.)" msgid "" "English Term (Dear translator: This file will never be visible to the user!)" msgstr "註:這個文件是為了幫助翻譯人員統一名詞術語。終端使用者不用關心這個文件。" #. "" #. amend指用戶修改最近一次commit的操作,修訂?修改?修正? #. [WANG Cong]: 根據我的瞭解,這個詞似乎翻譯成「修訂」多一些。「修正」也可以,「修改」再次之。 #. [ZHANG Le]: 修訂,感覺一般指對一些大型出版物的大規模升級,比如修訂新華字典 # 修正,其實每次amend的結果也不一定就是最後結果,說不定還需要修改。所以不 # 如就叫修改 msgid "amend" msgstr "修正前一次的修訂版提交" #. "" #. git annotate 文件名:用來標註文件的每一行在什麼時候被誰最後修改。 #. [WANG Cong]: "標記"一般是mark。;) #. [ZHANG Le]: 標註,或者乾脆用原意:註解,或註釋 #, fuzzy msgid "annotate" msgstr "標註" #. "A 'branch' is an active line of development." msgid "branch [noun]" msgstr "分支" #. "" msgid "branch [verb]" msgstr "建立新分支" #. "" #. [WANG Cong]: 網上有人翻譯成「檢出」,我感覺更好一些,畢竟把check的意思翻譯出來了。 #. [ZHNAG Le]: 提取吧,提取分支/版本 #. [rae l]: 簽出。subversion軟件中的大多詞彙已有翻譯,既然git與subversion同是SCM管理,可以參考同類軟件的翻譯也不錯。 msgid "checkout [noun]" msgstr "取出" #. "The action of updating the working tree to a revision which was stored in the object database." msgid "checkout [verb]" msgstr "取出" #. "A single point in the git history." msgid "commit [noun]" msgstr "修訂版提交" #. "The action of storing a new snapshot of the project's state in the git history." msgid "commit [verb]" msgstr "提交(至版控庫)" #. "" #. 差異?差別? #. [ZHANG Le]: 個人感覺差別更加中性一些 msgid "diff [noun]" msgstr "內容差異" #. "" msgid "diff [verb]" msgstr "比較內容差異" #. "A fast-forward is a special type of merge where you have a revision and you are merging another branch's changes that happen to be a descendant of what you have." msgid "fast forward merge" msgstr "快速前移式合併" #. "Fetching a branch means to get the branch's head from a remote repository, to find out which objects are missing from the local object database, and to get them, too." #. 獲取?取得?下載?更新?注意和update的區分 msgid "fetch" msgstr "撈取" #. "A collection of files. The index is a stored version of your working tree." #. index是working tree和repository之間的緩存 msgid "index (in git-gui: staging area)" msgstr "新修訂版準備區域" #. "A successful merge results in the creation of a new commit representing the result of the merge." msgid "merge [noun]" msgstr "分支合併" #. "To bring the contents of another branch into the current branch." msgid "merge [verb]" msgstr "合併" #. "" #. message是指commit中的文字信息 msgid "message" msgstr "訊息" #. "Pulling a branch means to fetch it and merge it." msgid "pull" msgstr "撈取並合併至本地版控庫中" #. "Pushing a branch means to get the branch's head ref from a remote repository, and ... (well, can someone please explain it for mere mortals?)" msgid "push" msgstr "推送至遠端版控庫" # 相對於「復原(undo)」 #. "" msgid "redo" msgstr "重做" #. "A collection of refs (?) together with an object database containing all objects which are reachable from the refs... (oops, you've lost me here. Again, please an explanation for mere mortals?)" #. In revision control systems, a repository[1] is an on-disk data structure which stores metadata for a set of files and/or directory structure.(摘錄自 [Repository (version control) - Wikipedia](https://en.wikipedia.org/wiki/Repository_(version_control))) #. V字龍:過去所採用的「版本倉庫」翻譯之理解為「存放版本的倉庫」並不符合 VCS Repo 除了版本之外保存其他版本控制需要的詮釋資料的實際情況,所以被棄用) #. V字龍:「版控庫」為「因版本控制目的而建立的倉庫(至於倉庫內存了什麼哪些東西不是一般使用者該關心的細節)」的簡寫 msgid "repository" msgstr "版控庫" #. "" msgid "reset" msgstr "重設" #. "" msgid "revert" msgstr "撤銷" #. "A particular state of files and directories which was stored in the object database." #. V字龍:修訂版(revision)指得是版本控制系統控管內容修改的最小單位,與「版本(version)」的差異為「修訂版」微不足道到作者沒必要給它指定一個有意義的識別名稱(Vx.y.z)而是使用版本控制系統隨機產生的識別名稱(如 a3dfe84...)或是編號(如 Build 12345) msgid "revision" msgstr "修訂版" #. "" msgid "sign off" msgstr "簽名" # 意思應該是 commit 的準備區域的樣子 #. "" #. 似乎是git-gui裡面顯示的本次提交的文件清單區域 msgid "staging area" msgstr "新修訂版準備區域" # 意思應該是 commit 的準備區域的樣子 #. "" #. 似乎是git-gui裡面顯示的本次提交的文件清單區域 msgid "stage" msgstr "移入新修訂版準備區域" #. "" msgid "status" msgstr "狀態" #. "A ref pointing to a tag or commit object" msgid "tag [noun]" msgstr "標籤" #. "" msgid "tag [verb]" msgstr "加上標籤" #. "A regular git branch that is used to follow changes from another repository." msgid "tracking branch" msgstr "追蹤分支" #. "" msgid "undo" msgstr "復原" # 注意和fetch的區分 #. "" msgid "update" msgstr "更新" #. "" msgid "verify" msgstr "驗證" #. "The tree of actual checked out files." #. "工作副本?工作區域?工作目錄" #. [LI Yang]: 當前副本, 當前源碼樹? msgid "working copy, working tree" msgstr "當前工作目錄" #. "" msgid "rebase" msgstr "變更基底" #. "" msgid "patch(noun)" msgstr "修正" #. "" msgid "patch(verb)" msgstr "套用修正" #. "" msgid "clone" msgstr "克隆" #. "" msgid "(merge) conflict" msgstr "合併衝突" #. "" msgid "stash" msgstr "珍藏項目" #. "Cherry-picking, moving only some revisions from one branch to another in version control" msgid "cherry-pick" msgstr "揀選" git-cola-3.6/po/hu.po000066400000000000000000001715621356743264500145060ustar00rootroot00000000000000# Hungarian translations for git-cola package. # Copyright (C) 2007 THE git-cola'S Miklos Vajna at el. # This file is distributed under the same license as the git-cola package. # Miklos Vajna , 2007 # Gyuris Gellért , 2019. # Meskó Balázs , 2019. # msgid "" msgstr "" "Project-Id-Version: git-cola 3.4\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-17 01:06-0700\n" "PO-Revision-Date: 2019-11-22 19:01+0100\n" "Last-Translator: Meskó Balázs \n" "Language-Team: Hungarian \n" "Language: hu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 2.2.4\n" msgid "" "\n" "

\n" " Drag and drop or use the Add button to add\n" " patches to the list\n" "

\n" " " msgstr "" "\n" "

\n" " A foltok listához való hozzáadása fogd és vidd módszerrel,\n" " vagy a Hozzáadás gombbal végezhető el\n" "

\n" " " #, python-format msgid "" "\n" "
\n" " Git Cola has been translated into different languages thanks\n" " to the help of the individuals listed below.\n" "\n" "
\n" "

\n" " Translation is approximate. If you find a mistake,\n" " please let us know by opening an issue on Github:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " We invite you to participate in translation by adding or " "updating\n" " a translation and opening a pull request.\n" "

\n" "\n" "
\n" "\n" " " msgstr "" "\n" "
\n" " A Git Cola az alábbi személyeknek köszönhetően lett több nyelvre " "lefordítva.\n" "\n" "
\n" "

\n" " A fordítás megközelítő. Hiba felfedezése esetén, kérjük vegyen " "fel egy hibajegyet a GitHubon.\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " Kérjük, vegyen részt a fordításban egy új fordítás hozzáadásával " "vagy egy \n" " meglévő frissítésével, valamint egy beolvasztási kérés " "nyitásával.\n" "

\n" "\n" "
\n" "\n" " " #, python-format msgid "" "\n" "
\n" " Git Cola version %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " msgstr "" "\n" "
\n" " Git Cola %(cola_version)s %(build_version)s verzió\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " #, python-format msgid "" "\n" "
\n" " Please use %(bug_link)s to report issues.\n" "
\n" " " msgstr "" "\n" "
\n" " Kérjük, itt jelentse a hibákat: %(bug_link)s.\n" "
\n" " " #, python-format msgid "" "\n" " Format String Variables\n" " -----------------------\n" " %(path)s = relative file path\n" " %(abspath)s = absolute file path\n" " %(dirname)s = relative directory path\n" " %(absdirname)s = absolute directory path\n" " %(filename)s = file basename\n" " %(basename)s = file basename without extension\n" " %(ext)s = file extension\n" msgstr "" "\n" " Formázó karakterlánc változók\n" " -----------------------------\n" " %(path)s = relatív fájlútvonal\n" " %(abspath)s = abszolút fájlútvonal\n" " %(dirname)s = mappa relatív útvonala\n" " %(absdirname)s = mappa abszolút útvonala\n" " %(filename)s = fájl alapnév\n" " %(basename)s = fájl alapnév, kiterjesztés nélkül\n" " %(ext)s = fájl kiterjesztése\n" msgid "" "\n" "Commands\n" "--------\n" "pick = use commit\n" "reword = use commit, but edit the commit message\n" "edit = use commit, but stop for amending\n" "squash = use commit, but meld into previous commit\n" "fixup = like \"squash\", but discard this commit's log message\n" "exec = run command (the rest of the line) using shell\n" "\n" "These lines can be re-ordered; they are executed from top to bottom.\n" "\n" "If you disable a line here THAT COMMIT WILL BE LOST.\n" "\n" "However, if you disable everything, the rebase will be aborted.\n" "\n" "Keyboard Shortcuts\n" "------------------\n" "? = show help\n" "j = move down\n" "k = move up\n" "J = shift row down\n" "K = shift row up\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "spacebar = toggle enabled\n" "\n" "ctrl+enter = accept changes and rebase\n" "ctrl+q = cancel and abort the rebase\n" "ctrl+d = launch difftool\n" msgstr "" "\n" "Parancsok\n" "---------\n" "pick = véglegesítés felhasználása\n" "reword = véglegesítés felhasználása, de a véglegesítési üzenet " "szerkesztésével\n" "edit = véglegesítés felhasználása, de a javítás leállítása\n" "squash = véglegesítés felhasználása, és beolvasztás az előző véglegesítésbe\n" "fixup = mint a „squash”, de a véglegesítési naplóüzenet elvetése\n" "exec = parancs (a sor hátralévő része) futtatása parancsértelmezőben\n" "\n" "A sorok újrarendezhetők; fentről lefelé lesznek végrehajtva.\n" "\n" "Egy sor letiltása itt a VÉGLEGESÍTÉS ELVESZTÉSÉT jelenti.\n" "\n" "Azonban, az összes letiltása az újraalapozás megszakításához vezet.\n" "\n" "Gyorsbillentyűk\n" "------------------\n" "? = súgó megjelenítése\n" "j = mozgatás lefelé\n" "k = mozgatás felfelé\n" "J = sor lefelé mozgatása\n" "K = sor felfelé mozgatása\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "szóköz = átváltás engedélyezése\n" "\n" "ctrl+enter = módosítások elfogadása és újraalapozás\n" "ctrl+q = mégse és az újraalapozás megszakítása\n" "ctrl+d = összehasonlító eszköz indítása\n" msgid "" "\n" "Keyboard Shortcuts\n" "------------------\n" "J, Down = Move Down\n" "K, Up = Move Up\n" "Enter = Edit Selected Files\n" "Spacebar = Open File Using Default Application\n" "Ctrl + L = Focus Text Entry Field\n" "? = Show Help\n" "\n" "The up and down arrows change focus between the text entry field\n" "and the results.\n" msgstr "" "\n" "Gyorsbillentyűk\n" "------------------\n" "J, Lefelé = Mozgatás lefelé\n" "K, Felfelé = Mozgatás felfelé\n" "Enter = Kijelölt fájlok szerkesztése\n" "Szóköz = Fájl megnyitása az alapértelmezett alkalmazással\n" "Ctrl + L = Szövegelemmező fókuszba helyezése\n" "? = Súgó megjelenítése\n" "\n" "A felfelé és lefelé billentyűk módosítják a szövegelem-mezők közti\n" "fókuszt, valamint az eredményeket.\n" msgid " - DAG" msgstr " - DAG" msgid " commits ago" msgstr " véglegesítéssel ezelőtt" #, python-format msgid "\"%(branch)s\" has been deleted from \"%(remote)s\"." msgstr "A(z) „%(branch)s” ág törölve lett erről: „%(remote)s”" #, python-format msgid "\"%(command)s\" returned exit status \"%(status)d\"" msgstr "" "A(z) „%(command)s” ezzel a kilépési állapottal tért vissza: „%(status)d”" #, python-format msgid "\"%(command)s\" returned exit status %(status)d" msgstr "A(z) „%(command)s” ezzel a kilépési állapottal tért vissza: %(status)d" #, python-format msgid "\"%s\" already exists" msgstr "A(z) „%s” már létezik" #, python-format msgid "\"%s\" already exists, cola will create a new directory" msgstr "A(z) „%s” már létezik, ezért a cola új mappát hoz létre" #, python-format msgid "\"%s\" requires a selected file." msgstr "A(z) „%s” kijelölt fájlt igényel." msgid "#" msgstr "#" #, python-format msgid "%(project)s: %(branch)s - Browse" msgstr "%(project)s: %(branch)s – tallózás" #, python-format msgid "%(project)s: %(ref)s - DAG" msgstr "%(project)s: %(ref)s - DAG" #, python-format msgid "%d days ago" msgstr "%d napja" #, python-format msgid "%d hours ago" msgstr "%d órája" #, python-format msgid "%d minutes ago" msgstr "%d perce" #, python-format msgid "%d patch(es) applied." msgstr "%d folt alkalmazva." #, python-format msgid "%d skipped" msgstr "%d kihagyva" #, python-format msgid "" "%s appears to contain merge conflicts.\n" "\n" "You should probably skip this file.\n" "Stage it anyways?" msgstr "" "Úgy tűnik, hogy a(z) %s beolvasztási ütközéseket tartalmaz.\n" "\n" "Valószínűleg ki kellene hagyni ezt a fájlt.\n" "Biztosan kiszemelésre kerüljön?" #, python-format msgid "%s is not a Git repository." msgstr "A(z) %s nem git tároló." #, python-format msgid "%s will be removed from your bookmarks." msgstr "A(z) %s el lesz távolítva a könyvjelzők közül." #, python-format msgid "%s will be removed from your recent repositories." msgstr "A(z) %s el lesz távolítva a legutóbbi tárolókból." #, python-format msgid "%s: No such file or directory." msgstr "%s: Nincs ilyen fájl vagy könyvtár." msgid "&Edit" msgstr "Sz&erkesztés" msgid "&File" msgstr "&Fájl" msgid "(Amending)" msgstr "(Javítás)" msgid "*** Branch Point ***" msgstr "*** Elágazás ***" msgid "*** Sandbox ***" msgstr "*** Homokozó ***" msgid "100%" msgstr "100%" msgid "200%" msgstr "200%" msgid "25%" msgstr "25%" msgid "400%" msgstr "400%" msgid "50%" msgstr "50%" msgid "800%" msgstr "800%" msgid " ..." msgstr " …" msgid "" "A commit template has not been configured.\n" "Use \"git config\" to define \"commit.template\"\n" "so that it points to a commit template." msgstr "" "A véglegesítési sablon nem lett még beállítva.\n" "A „git config” használatával hozható létre a „commit.template”,\n" "hogy az egy véglegesítési sablonra mutasson." #, python-format msgid "A hook must be provided at \"%s\"" msgstr "Egy hurkot kell létrehozni itt: „%s”" #, python-format msgid "A stash named \"%s\" already exists" msgstr "Már létezik egy ilyen nevű félretett változat: „%s”" msgid "Abort" msgstr "Megszakítás" msgid "Abort Action" msgstr "Művelet megszakítása" msgid "Abort Merge" msgstr "Beolvasztás megszakítása" msgid "Abort Merge..." msgstr "Beolvasztás megszakítása…" msgid "Abort the action?" msgstr "Megszakítja a műveletet?" msgid "" "Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" "Recovering uncommitted changes is not possible." msgstr "" "A jelenlegi beolvasztás megszakítása *MINDEN* nem véglegesített módosítás " "elvesztését jelenti.\n" "A nem véglegesített módosítások helyreállítása nem lehetséges." msgid "Aborting the current merge?" msgstr "Megszakítja a jelenlegi beolvasztást?" msgid "About" msgstr "Névjegy" msgid "About git-cola" msgstr "A git-cola névjegye" msgid "Accept" msgstr "Elfogadás" msgid "" "Accept changes and rebase\n" "Shortcut: Ctrl+Enter" msgstr "" "Változások elfogadása és újraalapozás\n" "Gyorsbillentyű: Ctrl+Enter" msgid "Action Name" msgstr "Művelet neve" msgid "Actions" msgstr "Műveletek" msgid "Actions..." msgstr "Műveletek…" msgid "Add" msgstr "Hozzáadás" msgid "Add Favorite" msgstr "Kedvenc hozzáadása" msgid "Add Remote" msgstr "Távoli hozzáadása" msgid "Add Separator" msgstr "Elválasztó hozzáadása" msgid "Add Toolbar" msgstr "Eszköztár hozzáadása" msgid "" "Add and remove remote repositories using the \n" "Add(+) and Delete(-) buttons on the left-hand side.\n" "\n" "Remotes can be renamed by selecting one from the list\n" "and pressing \"enter\", or by double-clicking." msgstr "" "A bal oldali hozzáadás(+) és törlés(-) gombokkal lehet\n" "hozzáadni és törölni távoli tárolókat.\n" "\n" "A távoli tárolók átnevezhetők a listából való kijelöléssel\n" "majd az Enter lenyomásával vagy dupla kattintással." msgid "Add new remote git repository" msgstr "Új távoli git tároló hozzáadása" msgid "Add patches (+)" msgstr "Foltok hozzáadása (+)" msgid "Add remote" msgstr "Távoli hozzáadása" msgid "Add to .gitignore" msgstr "Hozzáadás a .gitignore-hoz" msgid "Add to Git Annex" msgstr "Hozzáadás a Git Annexhez" msgid "Add to Git LFS" msgstr "Hozzáadás a Git LFS-hez" msgid "Additions" msgstr "Kiegészítések" msgid "Advanced" msgstr "Speciális" msgid "Age" msgstr "Kor" msgid "All Repositories" msgstr "Minden tároló" #, python-format msgid "" "All submodules will be updated using\n" "\"%s\"" msgstr "" "Az összes almodul frissítve lesz ezzel:\n" "„%s”" msgid "" "Allow non-fast-forward updates. Using \"force\" can cause the remote " "repository to lose commits; use it with care" msgstr "" "Nem előrepörgetett frissítések engedélyezése. A kényszerítés a távoli " "tárolón a véglegesítések elvesztéséhez vezethet. Óvatosan érdemes használni." msgid "" "Always create a merge commit when enabled, even when the merge is a fast-" "forward update" msgstr "" "Engedélyezve mindig beolvasztással történik a véglegesítés, akkor is, ha a " "beolvasztás előrepörgetett frissítés" msgid "Amend" msgstr "Javítás" msgid "Amend Commit" msgstr "Véglegesítés javítása" msgid "Amend Last Commit" msgstr "Utolsó véglegesítés javítása" msgid "Amend the published commit?" msgstr "Javítja a közzétett véglegesítést?" msgid "Amending" msgstr "Javítás" msgid "" "An action is still running.\n" "Terminating it could result in data loss." msgstr "" "Egy művelet épp fut.\n" "A megszakítása adatvesztéshez vezethet." msgid "" "An unsigned, lightweight tag will be created instead.\n" "Create an unsigned tag?" msgstr "" "Ehelyett csak egy aláíratlan, könnyűsúlyú címke lesz csak létrehozva.\n" "Készüljön egy aláíratlan címke?" msgid "Appearance" msgstr "Megjelenés" msgid "Apply" msgstr "Alkalmaz" msgid "Apply Patches" msgstr "Foltok alkalmazása" msgid "Apply Patches..." msgstr "Foltok alkalmazása…" msgid "Apply and drop the selected stash (git stash pop)" msgstr "Kijelölt félretett változat alkalmazása és eldobása (git stash pop)" msgid "Apply the selected stash" msgstr "Kijelölt félretett változat alkalmazása" msgid "Arguments" msgstr "Argumentumok" msgid "Attach" msgstr "Csatolás" msgid "Author" msgstr "Szerző" msgid "Authors" msgstr "Szerzők" msgid "Auto" msgstr "Automatikus" msgid "Auto-Wrap Lines" msgstr "Sorok automatikus tördelése" msgid "Basic Regexp" msgstr "Egyszerű regexp" msgid "Blame Viewer" msgstr "Hibáztatás megjelenítő" msgid "Blame selected paths" msgstr "Kijelölt útvonalak hibáztatása" msgid "Blame..." msgstr "Hibáztatás…" msgid "Bold on dark headers instead of italic" msgstr "Félkövéren szedett és sötét fejlécek a dőlt helyett" msgid "Branch" msgstr "Elágazás" #, python-format msgid "" "Branch \"%(branch)s\" does not exist in \"%(remote)s\".\n" "A new remote branch will be published." msgstr "" "A(z) „%(branch)s” nem létezik itt: „%(remote)s”.\n" "Új távoli ág lesz közzétéve." #, python-format msgid "Branch \"%s\" already exists." msgstr "A(z) „%s” ág már létezik." msgid "Branch Diff Viewer" msgstr "Ág-összehasonlító megjelenítő" msgid "Branch Exists" msgstr "Létező ág" msgid "Branch Name" msgstr "Ág neve" #, python-format msgid "Branch: %s" msgstr "Ág: %s" msgid "Branches" msgstr "Ágak" msgid "Branches..." msgstr "Ágak…" msgid "Brazilian translation" msgstr "Brazil fordítás" msgid "Browse" msgstr "Tallózás" msgid "Browse Commits..." msgstr "Véglegesítések tallózása…" msgid "Browse Current Branch..." msgstr "Jelenlegi ág tallózása…" msgid "Browse Other Branch..." msgstr "Egyéb ágak tallózása…" msgid "Browse..." msgstr "Tallózás…" msgid "Browser" msgstr "Böngésző" #, python-format msgid "Browsing %s" msgstr "%s tallózása" msgid "Bypass Commit Hooks" msgstr "Véglegesítési hurkok kikerülése" msgid "Cancel" msgstr "Mégse" msgid "" "Cancel rebase\n" "Shortcut: Ctrl+Q" msgstr "" "Újraalapozás megszakítása\n" "Gyorsbillentyű: Ctrl+Q" msgid "Cannot Amend" msgstr "A javítás nem lehetséges" #, python-format msgid "Cannot exec \"%s\": please configure a blame viewer" msgstr "A(z) „%s” nem futtatható: állítson be egy hibáztatás megjelenítőt" #, python-format msgid "Cannot exec \"%s\": please configure a history browser" msgstr "A(z) „%s” nem futtatható: állítson be egy történetböngészőt" #, python-format msgid "Cannot exec \"%s\": please configure your editor" msgstr "A(z) „%s” nem futtatható: állítsa be a szerkesztőjét" msgid "Changed Upstream" msgstr "Módosítva a távoli tárolóban" msgid "Check Spelling" msgstr "Helyesírás-ellenőrzés" msgid "Check spelling" msgstr "Helyesírás-ellenőrzés" msgid "Checkout" msgstr "Átváltás" msgid "Checkout After Creation" msgstr "Átváltás a létrehozás után" msgid "Checkout Branch" msgstr "Ág átváltása" msgid "Checkout Detached HEAD" msgstr "Átváltás a leválasztott FEJ-re" msgid "Checkout as new branch" msgstr "Átváltás új ágként" msgid "Checkout..." msgstr "Átváltás…" msgid "Cherry Pick" msgstr "Mazsolázás" msgid "Cherry-Pick Commit" msgstr "Mazsolázó véglegesítés" msgid "Cherry-Pick..." msgstr "Mazsolázás…" msgid "Choose Paths" msgstr "Válasszon útvonalakat" msgid "Choose the \"git grep\" regular expression mode" msgstr "Válassza ki a „git grep” reguláris kifejezés módját" msgid "Clear Default Repository" msgstr "Alapértelmezett tároló tisztítása" msgid "Clear commit message" msgstr "Véglegesítő üzenet tisztítása" msgid "Clear commit message?" msgstr "Tisztítja a véglegesítő üzenetet?" msgid "Clear..." msgstr "Tisztítás…" msgid "Clone" msgstr "Klónozás" msgid "Clone Repository" msgstr "Tároló klónozása" msgid "Clone..." msgstr "Klónozás…" #, python-format msgid "Cloning repository at %s" msgstr "Tároló klónozása ide: %s" msgid "Close" msgstr "Bezárás" msgid "Close..." msgstr "Bezárás…" msgid "Collapse all" msgstr "Összes összecsukása" msgid "Command" msgstr "Parancs" msgid "Commit" msgstr "Véglegesítés" msgid "Commit failed" msgstr "Véglegesítés sikertelen" msgid "Commit staged changes" msgstr "Kiszemelt módosítások véglegesítése" msgid "" "Commit staged changes\n" "Shortcut: Ctrl+Enter" msgstr "" "Kiszemelt módosítások véglegesítése\n" "Gyorsbillentyű: Ctrl+Enter" msgid "Commit summary" msgstr "Véglegesítés összegzése" msgid "" "Commit the merge if there are no conflicts. Uncheck to leave the merge " "uncommitted" msgstr "" "Beolvasztás véglegesítése, ha nincsenek ütközések. Bejelöletlenül hagyva a " "beolvasztás nem lesz véglegesítve" msgid "Commit@@verb" msgstr "Véglegesítés" msgid "Compare" msgstr "Összehasonlítás" msgid "Compare All" msgstr "Mind összehasonlítása" msgid "Configure the remote branch as the the new upstream" msgstr "A távoli ág beállítása új távoli tárolóként" msgid "Configure toolbar" msgstr "Eszköztár beállítása" msgid "Console" msgstr "Konzol" msgid "Continue" msgstr "Folytatás" msgid "Copy" msgstr "Másolás" msgid "Copy Basename to Clipboard" msgstr "Alapnév másolása a vágólapra" msgid "Copy Leading Path to Clipboard" msgstr "Kezdő útvonal másolása a vágólapra" msgid "Copy Path to Clipboard" msgstr "Útvonal másolása a vágólapra" msgid "Copy Relative Path to Clipboard" msgstr "Relatív útvonal másolása a vágólapra" msgid "Copy SHA-1" msgstr "SHA-1 másolása" msgid "Copy..." msgstr "Másolás…" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "Nem lehet feldolgozni a git URL-t: „%s”" msgid "Create Branch" msgstr "Ág létrehozása" msgid "Create Patch" msgstr "Folt létrehozása" msgid "Create Remote Branch" msgstr "Távoli ág létrehozása" msgid "Create Signed Commit" msgstr "Aláírt véglegesítés létrehozása" msgid "Create Tag" msgstr "Címke létrehozása" msgid "Create Tag..." msgstr "Címke (tag) létrehozása…" msgid "Create Unsigned Tag" msgstr "Aláíratlan címke létrehozása" msgid "Create a merge commit even when the merge resolves as a fast-forward" msgstr "" "Beolvasztásos véglegesítést hoz létre akkor is, ha a beolvasztás " "előrepörgetett lenne" msgid "Create a new remote branch?" msgstr "Létrehozza az új távoli ágat?" msgid "Create..." msgstr "Létrehozás…" #, python-format msgid "Created a new tag named \"%s\"" msgstr "„%s” nevű címke létrehozva" msgid "Current Repository" msgstr "Jelenlegi tároló" msgid "Custom Copy Actions" msgstr "Egyéni másolási műveletek" msgid "Customize..." msgstr "Testreszabás…" msgid "Cut" msgstr "Kivágás" msgid "Czech translation" msgstr "Cseh fordítás" msgid "DAG..." msgstr "DAG…" msgid "Dark Theme" msgstr "Sötét téma" msgid "Date, Time" msgstr "Dátum és idő" msgid "Default" msgstr "Alapértelmezett" msgid "Delete" msgstr "Törlés" #, python-format msgid "Delete %d file(s)?" msgstr "Törli a(z) %d fájlt?" msgid "Delete Bookmark" msgstr "Könyvjelző törlése" msgid "Delete Bookmark?" msgstr "Törli a könyvjelzőt?" msgid "Delete Branch" msgstr "Ág törlése" msgid "Delete Files" msgstr "Fájlok törlése" msgid "Delete Files..." msgstr "Fájlok törlése…" msgid "Delete Files?" msgstr "Törli a fájlokat?" msgid "Delete Remote" msgstr "Távoli törlése" msgid "Delete Remote Branch" msgstr "Távoli ág törlése" msgid "Delete Remote Branch..." msgstr "Távoli ág törlése…" msgid "Delete remote" msgstr "Távoli törlése" #, python-format msgid "Delete remote \"%s\"" msgstr "„%s” távoli törlése" msgid "Delete remote?" msgstr "Törli a távolit?" msgid "Delete selected branch?" msgstr "Törli a kijelölt ágat?" msgid "Delete toolbar" msgstr "Eszköztár törlése" msgid "Delete..." msgstr "Törlés…" #, python-format msgid "Deleting \"%s\" failed" msgstr "„%s” törlése sikertelen" msgid "Deletions" msgstr "Törlések" msgid "Detach" msgstr "Leválasztás" msgid "Detect Conflict Markers" msgstr "Ütközésjelölők észlelése" msgid "Detect conflict markers in unmerged files" msgstr "Ütközésjelölők észlelése a nem beolvasztott fájlokban" msgid "Developer" msgstr "Fejlesztő" msgid "Diff" msgstr "Összehasonlítás" msgid "Diff Against Predecessor..." msgstr "Összehasonlítás az előddel…" msgid "Diff Options" msgstr "Összehasonlítási lehetőségek" msgid "Diff Tool" msgstr "Összehasonlító eszköz" msgid "Diff selected -> this" msgstr "Kijelölt összehasonlítása → ezzel" msgid "Diff this -> selected" msgstr "Ez összehasonlítása → a kijelölttel" msgid "Diffstat" msgstr "Összehasonlítási statisztika" msgid "Difftool" msgstr "Összehasonlító eszköz" msgid "Directory Exists" msgstr "Könyvtár létezik" msgid "Display Untracked Files" msgstr "Nem követett fájlok megjelenítése" msgid "Documentation" msgstr "Dokumentáció" msgid "Drop" msgstr "Eldobás" msgid "Drop Stash" msgstr "Félretett változat eldobása" msgid "Drop Stash?" msgstr "Eldobja a félrerakott változatot?" #, python-format msgid "Drop the \"%s\" stash?" msgstr "Eldobja a(z) „%s” félretett változatot?" msgid "Drop the selected stash" msgstr "Kijelölt félretett változat eldobása" msgid "Edit" msgstr "Szerkesztés" msgid "Edit Rebase" msgstr "Újraalapozás szerkesztése" msgid "Edit Remotes" msgstr "Távolik szerkesztése" msgid "Edit Remotes..." msgstr "Távolik szerkesztése…" msgid "Edit remotes by selecting them from the list" msgstr "Távoli szerkesztése a listából való kijelöléssel" msgid "Edit selected paths" msgstr "Kijelölt útvonalak szerkesztése" msgid "Edit..." msgstr "Szerkesztés…" msgid "Editor" msgstr "Szerkesztő" msgid "Email Address" msgstr "E-mail cím" msgid "Email contributor" msgstr "E-mail közreműködő" msgid "Enabled" msgstr "Engedélyezett" msgid "Enter New Branch Name" msgstr "Adja meg az új ág nevét" msgid "Enter a name for the new bare repo" msgstr "Adja meg az új csupasz tároló nevét" msgid "Enter a name for the stash" msgstr "Adjon meg egy nevet a félrerakáshoz" msgid "Error" msgstr "Hiba" msgid "Error Cloning" msgstr "Hiba a klónozáskor" msgid "Error Creating Branch" msgstr "Hiba az ág létrehozásakor" msgid "Error Creating Repository" msgstr "Hiba a tároló létrehozásakor" msgid "Error Deleting Remote Branch" msgstr "Hiba a távoli ág törlésekor" msgid "Error Editing File" msgstr "Hiba a fájl szerkesztésekor" msgid "Error Launching Blame Viewer" msgstr "Hiba a gyanúsító megjelenítő indítása közben" msgid "Error Launching History Browser" msgstr "Hiba a történetböngésző indításakor" #, python-format msgid "Error creating remote \"%s\"" msgstr "Hiba a(z) „%s” távoli létrehozásakor" msgid "Error creating stash" msgstr "Hiba a félretett változat létrehozásakor" #, python-format msgid "Error deleting remote \"%s\"" msgstr "Hiba a(z) „%s” távoli törlésekor" #, python-format msgid "Error renaming \"%(name)s\" to \"%(new_name)s\"" msgstr "Hiba az átnevezéskor: „%(name)s” → „%(new_name)s”" msgid "Error running prepare-commitmsg hook" msgstr "Hiba a prepare-commitmsg hurok futtatásakor" #, python-format msgid "Error updating submodule %s" msgstr "Hiba a(z) %s almodul frissítésekor" msgid "Error updating submodules" msgstr "Hiba az almodulok frissítésekor" msgid "Error: Cannot find commit template" msgstr "Hiba: Nem található véglegesítési üzenetsablon" msgid "Error: Stash exists" msgstr "Hiba: A félretett változat már létezik" msgid "Error: Unconfigured commit template" msgstr "Hiba: Nincs beállítva véglegesítési sablon" #, python-format msgid "Error: could not clone \"%s\"" msgstr "Hiba: A(z) „%s” nem klónozható" #, python-format msgid "Error: could not create tag \"%s\"" msgstr "Hiba: A(z) „%s” címke nem hozható létre" #, python-format msgid "Executing action %s" msgstr "Művelet végrehajtása: %s" msgid "Expand all" msgstr "Összes kibontása" msgid "Export Patches" msgstr "Foltok exportálása" msgid "Export Patches..." msgstr "Foltok exportálása…" msgid "Expression..." msgstr "Kifejezés…" msgid "Extended Regexp" msgstr "Bővített regexp" msgid "Extended description..." msgstr "Bővített leírás…" msgid "Fast Forward Only" msgstr "Csak előrepörgetés" msgid "Fast-forward only" msgstr "Csak előrepörgetés" msgid "Favorite repositories" msgstr "Kedvenc tárolók" msgid "Favorites" msgstr "Kedvencek" msgid "Fetch" msgstr "Letöltés" msgid "Fetch Tracking Branch" msgstr "Követett ág letöltése" msgid "Fetch..." msgstr "Letöltés…" msgid "File Browser..." msgstr "Fájlböngésző…" msgid "File Differences" msgstr "Fájlok különbségei" msgid "File Saved" msgstr "Fájl mentve" #, python-format msgid "File saved to \"%s\"" msgstr "Fájl mentve: „%s”" msgid "" "File system change monitoring: disabled because \"cola.inotify\" is false.\n" msgstr "" "A fájlrendszer változásainak figyelése: letiltva, mivel a „cola.inotify” " "hamis.\n" msgid "" "File system change monitoring: disabled because libc does not support the " "inotify system calls.\n" msgstr "" "A fájlrendszer változásainak figyelése: letiltva, mivel a libc nem támogatja " "az inotify rendszerhívásait.\n" msgid "" "File system change monitoring: disabled because pywin32 is not installed.\n" msgstr "" "A fájlrendszer változásainak figyelése: letiltva, mivel a pywin32 nincs " "telepítve.\n" msgid "" "File system change monitoring: disabled because the limit on the total " "number of inotify watches was reached. You may be able to increase the " "limit on the number of watches by running:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf " "&& sudo sysctl -p\n" msgstr "" "A fájlrendszer változásainak figyelése: letiltva, mivel az inotify " "megfigyelő elérte a teljes létszám korlátját. Ezt a korlátot meg lehet " "növelni az alábbi futtatásával:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf " "&& sudo sysctl -p\n" msgid "File system change monitoring: enabled.\n" msgstr "A fájlrendszer változásainak figyelése: engedélyezve\n" msgid "Filename" msgstr "Fájlnév" msgid "Files" msgstr "Fájlok" msgid "Filter branches..." msgstr "Ágak szűrése…" msgid "Filter paths..." msgstr "Útvonalak szűrése…" msgid "Find Files" msgstr "Fájlok keresése" msgid "Fixed String" msgstr "Rögzített szöveg" msgid "Fixed-Width Font" msgstr "Rögzített szélességű betűkészlet" msgid "Fixup" msgstr "Gyorsjavítás" msgid "Fixup Previous Commit" msgstr "Előző véglegesítés gyorsjavítása" msgid "Flat dark blue" msgstr "Lapos sötétkék" msgid "Flat dark green" msgstr "Lapos sötétzöld" msgid "Flat dark grey" msgstr "Lapos sötétszürke" msgid "Flat dark red" msgstr "Lapos sötétvörös" msgid "Flat light blue" msgstr "Lapos világoskék" msgid "Flat light green" msgstr "Lapos világoszöld" msgid "Flat light grey" msgstr "Lapos világosszürke" msgid "Flat light red" msgstr "Lapos világos vörös" msgid "Font Size" msgstr "Betűméret" msgid "Force" msgstr "Kényszerítés" msgid "Force Fetch" msgstr "Letöltés kényszerítése" msgid "Force Fetch?" msgstr "Kényszeríti a letöltést?" msgid "Force Push" msgstr "Felküldés kényszerítése" msgid "Force Push?" msgstr "Kényszeríti a felküldést?" #, python-format msgid "Force fetching from %s?" msgstr "Kényszeríti a letöltést innen: %s?" #, python-format msgid "Force push to %s?" msgstr "Kényszeríti a felküldést ide: %s?" msgid "Format String" msgstr "Formázó karakterlánc" msgid "French translation" msgstr "Francia fordítás" msgid "GPG-sign the merge commit" msgstr "A beolvasztási véglegesítés GPG-aláírása" msgid "GUI theme" msgstr "Felhasználói felület témája" #, python-format msgid "Gathering info for \"%s\"..." msgstr "Információk gyűjtése erről: „%s”…" msgid "German translation" msgstr "Német fordítás" msgid "Get Commit Message Template" msgstr "Véglegesítő üzenetsablon lekérdezése" msgid "Go Down" msgstr "Lefelé" msgid "Go Up" msgstr "Felfelé" msgid "Grab File..." msgstr "Fájl megfogása…" msgid "Graph" msgstr "Grafikon" msgid "Grep" msgstr "Grep" msgid "Have you rebased/pulled lately?" msgstr "Újraalapozott vagy lekért nemrégiben?" msgid "Help" msgstr "Súgó" msgid "Help - Custom Copy Actions" msgstr "Súgó – Egyéni másolási műveletek" msgid "Help - Find Files" msgstr "Súgó – Fájlok keresése" msgid "Help - git-xbase" msgstr "Súgó – git-xbase" msgid "Hide Details.." msgstr "Részletek elrejtése…" msgid "High DPI" msgstr "Magas DPI" msgid "History Browser" msgstr "Történetböngésző" msgid "Hungarian translation" msgstr "Magyar fordítás" msgid "Icon theme" msgstr "Ikontéma" msgid "Ignore all whitespace" msgstr "Üres helyek mellőzése" msgid "Ignore changes in amount of whitespace" msgstr "Üres helyek mennyiségváltozásának mellőzése" msgid "Ignore changes in whitespace at EOL" msgstr "Sorvégi üres helyek változásának mellőzése" msgid "Ignore custom pattern" msgstr "Egyéni minta mellőzése" msgid "Ignore exact filename" msgstr "Pontos fájlnév mellőzése" msgid "Ignore filename or pattern" msgstr "Fájlnév vagy minta mellőzése" msgid "Include tags " msgstr "Címkéket is" msgid "Indent Status paths" msgstr "Státuszútvonalak behúzása" msgid "Indonesian translation" msgstr "Indonéz fordítás" msgid "Initialize Git Annex" msgstr "Git Annex előkészítése" msgid "Initialize Git LFS" msgstr "Git LFS előkészítése" msgid "Inititalize submodules" msgstr "Almodulok előkészítése" msgid "Insert spaces instead of tabs" msgstr "Szóközök a tabulátorok helyett" msgid "Interactive Rebase" msgstr "Interaktív újraalapozás" msgid "Invalid Revision" msgstr "Érvénytelen revízió" msgid "Keep *.orig Merge Backups" msgstr "Beolvasztási *.orig biztonsági tartalék megtartása" msgid "Keep Index" msgstr "Jegyzék megtartása" msgid "Keyboard Shortcuts" msgstr "Gyorsbillentyűk" msgid "Launch Diff Tool" msgstr "Összehasonlító eszköz indítása" msgid "Launch Directory Diff Tool" msgstr "Könyvtár-összehasonlító eszköz indítása" msgid "Launch Editor" msgstr "Szerkesztő indítása" msgid "Launch Terminal" msgstr "Terminál indítása" msgid "" "Launch external diff tool\n" "Shortcut: Ctrl+D" msgstr "" "Külső összehasonlító eszköz indítása\n" "Gyorsbillentyű: Ctrl+D" msgid "Launch git-cola" msgstr "git-cola indítása" msgid "Launch git-difftool against previous versions" msgstr "git-difftool indítása az előző verzión" msgid "Launch git-difftool on the current path" msgstr "git-difftool indítása a jelenlegi útvonalon" msgid "Light Theme" msgstr "Világos téma" msgid "Load Commit Message" msgstr "Véglegesítő üzenet betöltése" msgid "Load Commit Message..." msgstr "Véglegesítő üzenet betöltése…" msgid "Load Previous Commit Message" msgstr "Előző véglegesítő üzenet betöltése" msgid "Loading..." msgstr "Betöltés…" msgid "Local" msgstr "Helyi" msgid "Local Branch" msgstr "Helyi ág" msgid "Local branch" msgstr "Helyi ág" msgid "Lock Layout" msgstr "Elrendezés zárolása" msgid "Log" msgstr "Napló" msgid "Maintainer (since 2007) and developer" msgstr "Karbantartó (2007 óta) és fejlesztő" msgid "Merge" msgstr "Beolvasztás" #, python-format msgid "Merge \"%(revision)s\" into \"%(branch)s\"" msgstr "„%(revision)s” beolvasztása az ágba: „%(branch)s”" msgid "Merge Tool" msgstr "Beolvasztó eszköz" msgid "Merge Verbosity" msgstr "Beolvasztás beszédessége" msgid "Merge failed. Conflict resolution is required." msgstr "A beolvasztás sikertelen. Fel kell oldani az ütközéseket." #, python-format msgid "Merge into \"%s\"" msgstr "Beolvasztás a következőbe: „%s”" msgid "Merge into current branch" msgstr "Beolvasztás a jelenlegi ágba" msgid "Merge..." msgstr "Beolvasztás…" msgid "Merging" msgstr "Beolvasztás" msgid "Message" msgstr "Üzenet" msgid "Missing Commit Message" msgstr "Hiányzó véglegesítési üzenet" msgid "Missing Data" msgstr "Hiányzó adat" msgid "Missing Name" msgstr "Hiányzó név" msgid "Missing Revision" msgstr "Hiányzó revízió" msgid "Missing Tag Message" msgstr "Hiányzó címkeüzenet" msgid "Modified" msgstr "Módosított" msgid "More..." msgstr "További…" msgid "Move Down" msgstr "Mozgatás lefelé" msgid "Move Up" msgstr "Mozgatás felfelé" msgid "Move files to trash" msgstr "Fájlok kukába dobása" msgid "Name" msgstr "Név" msgid "Name for the new remote" msgstr "Az új távoli neve" msgid "New Bare Repository..." msgstr "Új csupasz tároló…" msgid "New Repository..." msgstr "Új tároló…" msgid "New..." msgstr "Új…" msgid "Next File" msgstr "Következő fájl" msgid "No" msgstr "Nem" msgid "No Revision Specified" msgstr "Nincs revízió megadva" msgid "" "No changes to commit.\n" "\n" "You must stage at least 1 file before you can commit." msgstr "" "Nincs véglegesíthető változtatás.\n" "\n" "Legalább egy fájl ki kell szemelni, hogy véglegesíteni lehessen." msgid "No commits exist in this branch." msgstr "Nincsenek véglegesítések ebben az ágban." msgid "No fast forward" msgstr "Nincs előrepörgetés" msgid "No fast-forward" msgstr "Nincs előrepörgetés" msgid "No repository selected." msgstr "Nincs tároló kiválasztva." msgid "Non-fast-forward fetch overwrites local history!" msgstr "A nem előrepörgetett letöltés felülírja a helyi történetet!" msgid "" "Non-fast-forward push overwrites published history!\n" "(Did you pull first?)" msgstr "" "A nem előrepörgetett felküldés felülírja a közzétett történetet!\n" "(Csinált előtte lekérést?)" msgid "Nothing to commit" msgstr "Nincs véglegesíthető változás" msgid "Nothing to do" msgstr "Nincs teendő" msgid "Number of Diff Context Lines" msgstr "A diff környezeti sorok száma" msgid "Open" msgstr "Megnyitás" msgid "Open Git Repository..." msgstr "Git tároló megnyitása…" msgid "Open Parent" msgstr "Szülő megnyitása" msgid "Open Parent Directory" msgstr "Szülő könyvtár megnyitása" msgid "Open Recent" msgstr "Legutóbbiak megnyitása" msgid "Open Using Default Application" msgstr "Megnyitás az alapértelmezett alkalmazással" msgid "Open in New Window" msgstr "Megnyitás új ablakban" msgid "Open in New Window..." msgstr "Megnyitás új ablakban…" msgid "Open..." msgstr "Megnyitás…" msgid "Other branches" msgstr "Egyéb ágak" msgid "Overwrite" msgstr "Felülírás" #, python-format msgid "Overwrite \"%s\"?" msgstr "Felülírja: „%s”?" msgid "Overwrite File?" msgstr "Felülírja a fájlt?" msgid "" "Parse arguments using a shell.\n" "Queries with spaces will require \"double quotes\"." msgstr "" "Argumentumok feldolgozása parancsértelmezővel.\n" "A szóközökkel rendelkező lekérdezéseket \"dupla idézőjelekkel\" kell " "levédeni." msgid "Partially Staged" msgstr "Részlegesen kiszemelve" msgid "Paste" msgstr "Beillesztés" msgid "Patch(es) Applied" msgstr "Alkalmazott folt(ok)" msgid "Path" msgstr "Útvonal" msgid "Path or URL to clone (Env. $VARS okay)" msgstr "Klónozandó útvonal vagy URL ($VARS környezeti változó rendben)" msgid "Pick" msgstr "Kiválasztás" msgid "Pixel XOR" msgstr "Pixel alapú logikai kizáró vagy" msgid "Please provide both a branch name and revision expression." msgstr "Adjon meg ágnevet és revíziókifejezést is." msgid "Please select a file" msgstr "Jelöljön ki egy fájlt" msgid "Please specify a name for the new tag." msgstr "Adjon meg egy nevet az új címke számára." msgid "Please specify a revision to tag." msgstr "Jelöljön ki egy megcímkézendő revíziót." msgid "" "Please supply a commit message.\n" "\n" "A good commit message has the following format:\n" "\n" "- First line: Describe in one sentence what you did.\n" "- Second line: Blank\n" "- Remaining lines: Describe why this change is good.\n" msgstr "" "Adjon meg egy véglegesítési üzenetet.\n" "\n" "Egy jó véglegesítő üzenet formátuma:\n" "\n" "- Első sor: Egy mondat arról, hogy mit csinált.\n" "- Második sor: Üres\n" "- A többi sor: Leírás arról, hogy miért jó ez a változtatás.\n" msgid "Point the current branch head to a new commit?" msgstr "A jelenlegi ág fejét az új véglegesítésre állítja?" msgid "Polish translation" msgstr "Lengyel fordítás" msgid "Pop" msgstr "Alkalmazás és eldobás" msgid "Preferences" msgstr "Beállítások" msgid "Prefix" msgstr "Előtag" msgid "Prepare Commit Message" msgstr "Véglegesítési üzenet előkészítése" msgid "Prevent \"Stage\" from staging all files when nothing is selected" msgstr "" "Az összes fájl kiszemelésének megakadályozása a „kiszemelés” számára, ha " "semmi sincs kijelölve" msgid "Previous File" msgstr "Előző fájl" msgid "Prompt on creation" msgstr "Kérdés létrehozáskor" msgid "Prompt when pushing creates new remote branches" msgstr "Kérdés, ha a felküldés új távoli ágat hozna létre" msgid "Prune " msgstr "Tisztogatás" msgid "Pull" msgstr "Lekérés" msgid "Pull..." msgstr "Lekérés…" msgid "Push" msgstr "Felküldés" msgid "Push..." msgstr "Felküldés…" msgid "Quit" msgstr "Kilépés" msgid "Rebase" msgstr "Újraalapozás" #, python-format msgid "Rebase onto %s" msgstr "Újraalapozás erre: %s" msgid "Rebase stopped" msgstr "Újraalapozás leállítva" msgid "Rebase the current branch instead of merging" msgstr "Újraalapozás – beolvasztás helyett – a jelenlegi ágra" msgid "Rebasing" msgstr "Újraalapozás" msgid "Recent" msgstr "Legutóbbiak" msgid "Recent repositories" msgstr "Legutóbbi tárolók" msgid "Recent repository count" msgstr "Legutóbbi tárolók száma" msgid "Recently Modified Files" msgstr "Legutóbb módosított fájlok" msgid "Recently Modified Files..." msgstr "Legutóbb módosított fájlok…" msgid "Recovering a dropped stash is not possible." msgstr "Az eldobott félretett változatok helyreállítása nem lehetséges." msgid "Recovering lost commits may not be easy." msgstr "Az elveszett véglegesítések helyreállítása nem biztos, hogy egyszerű." msgid "Redo" msgstr "Mégis" msgid "Reduce commit history to minimum" msgstr "Véglegesítési üzenetek történetének minimalizálása" msgid "Refresh" msgstr "Frissítés" msgid "" "Refuse to merge unless the current HEAD is already up-to-date or the merge " "can be resolved as a fast-forward" msgstr "" "A beolvasztás visszautasítása, kivéve, ha a jelenlegi FEJ már friss, vagy a " "beolvasztást előrepörgetéssel lehet végezni" msgid "Remote" msgstr "Távoli" msgid "Remote Branch" msgstr "Távoli ág" msgid "Remote Branch Deleted" msgstr "Távoli ág törölve" msgid "Remote git repositories - double-click to rename" msgstr "Távoli git tárolók – dupla kattintás az átnevezéshez" msgid "Remove" msgstr "Eltávolítás" #, python-format msgid "Remove %s from the recent list?" msgstr "Eltávolítja a legutóbbiak listájáról: %s?" msgid "Remove Element" msgstr "Elem eltávolítása" msgid "Remove remote-tracking branches that no longer exist on the remote" msgstr "Távoli követett ágak eltávolítása, melyek már nem léteznek a távolin" msgid "Remove selected (Delete)" msgstr "Kijelöltek eltávolítása (Törlés)" msgid "Rename" msgstr "Átnevezés" #, python-format msgid "Rename \"%s\"" msgstr "„%s” átnevezése" msgid "Rename Branch" msgstr "Ág átnevezése" msgid "Rename Branch..." msgstr "Ág átnevezése…" msgid "Rename Existing Branch" msgstr "Létező ág átnevezése" msgid "Rename Remote" msgstr "Távoli átnevezése" msgid "Rename Repository" msgstr "Tároló átnevezése" msgid "Rename branch" msgstr "Ág átnevezése" #, python-format msgid "Rename remote \"%(current)s\" to \"%(new)s\"?" msgstr "Átnevezi a(z) „%(current)s” távolit erre: „%(new)s”?" msgid "Rename selected paths" msgstr "Kijelölt útvonalak átnevezése" #, python-format msgid "Repository: %s" msgstr "Tároló: %s" msgid "Reset" msgstr "Visszaállítás" #, python-format msgid "Reset \"%(branch)s\" to \"%(revision)s\"?" msgstr "Visszaállítja a(z) „%(branch)s” ágat erre: „%(revision)s”?" msgid "Reset Branch" msgstr "Ág visszaállítása" msgid "Reset Branch Head" msgstr "Ág fejének visszaállítása" msgid "Reset Branch?" msgstr "Visszaállítja az ágat?" msgid "Reset Hard" msgstr "Teljes visszaállítás" msgid "Reset Merge" msgstr "Beolvasztás visszaállítása" msgid "Reset Soft" msgstr "Nyugodt visszaállítás" msgid "Reset Worktree" msgstr "Munkafa visszaállítása" msgid "Reset hard?" msgstr "Elindítja a teljes visszaállítást?" msgid "Reset merge?" msgstr "Elindítja a beolvasztás visszaállítását?" msgid "Reset soft?" msgstr "Elindítja a nyugodt visszaállítást?" msgid "Reset worktree?" msgstr "Elindítja a munkafa visszaállítását?" #, python-format msgid "Resetting \"%(branch)s\" to \"%(revision)s\" will lose commits." msgstr "" "A(z) „%(branch)s” visszaállítása a(z) „%(revision)s” revízióra a " "véglegesítések elvesztéséhez vezet." msgid "Restart the application after changing appearance settings." msgstr "A megjelenési beállítások módosítása után indítsa újra az alkalmazást." msgid "Revert" msgstr "Visszavonás" msgid "Revert Diff Hunk" msgstr "Összehasonlítási egység visszavonása" msgid "Revert Diff Hunk..." msgstr "Összehasonlítási egység visszavonása…" msgid "Revert Diff Hunk?" msgstr "Visszavonja az összehasonítási egységeket?" msgid "Revert Selected Lines" msgstr "Kijelölt sorok visszavonása" msgid "Revert Selected Lines..." msgstr "Kijelölt sorok visszavonása…" msgid "Revert Selected Lines?" msgstr "Visszavonja a kijelölt sorokat?" msgid "Revert Uncommitted Changes" msgstr "Nem véglegesített módosítások visszavonása" msgid "Revert Uncommitted Changes?" msgstr "Visszavonja a nem véglegesített módosításokat?" msgid "Revert Uncommitted Edits..." msgstr "Nem véglegesített szerkesztések visszavonása…" msgid "Revert Unstaged Changes" msgstr "Elengedett módosítások visszavonása" msgid "Revert Unstaged Changes?" msgstr "Visszavonja az elengedett módosításokat?" msgid "Revert Unstaged Edits..." msgstr "Elengedett szerkesztések visszavonása…" msgid "Revert the uncommitted changes?" msgstr "Visszavonja a nem véglegesített módosításokat?" msgid "Revert the unstaged changes?" msgstr "Visszavonja az elengedett módosításokat?" msgid "Revert uncommitted changes to selected paths" msgstr "Nem véglegesített módosítások visszavonása a kijelölt útvonalakon" msgid "Revert unstaged changes to selected paths" msgstr "Elengedett módosítások visszavonása a kijelölt útvonalakon" msgid "Review" msgstr "Áttekintés" msgid "Review..." msgstr "Áttekintés…" msgid "Revision" msgstr "Revízió" msgid "Revision Expression:" msgstr "Revízió kifejezés:" msgid "Revision to Merge" msgstr "Beolvasztani kívánt revízió" msgid "Reword" msgstr "Átfogalmazás" msgid "Rewrite Published Commit?" msgstr "Újraírja a közzétett véglegesítést?" msgid "Run" msgstr "Futtatás" #, python-format msgid "Run \"%s\"?" msgstr "Futtatja ezt: „%s”?" #, python-format msgid "Run %s?" msgstr "Futtatja ezt: %s?" #, python-format msgid "Run the \"%s\" command?" msgstr "Futtatja a(z) „%s” parancsot?" #, python-format msgid "Running command: %s" msgstr "Parancs futtatása: %s" msgid "Russian translation" msgstr "Orosz fordítás" msgid "SHA-1" msgstr "SHA-1" msgid "Safe Mode" msgstr "Biztonságos mód" msgid "Save" msgstr "Mentés" msgid "Save Archive" msgstr "Mentés archívumként" msgid "Save As Tarball/Zip..." msgstr "Mentés tar-archívumként/zipként…" msgid "Save GUI Settings" msgstr "Felhasználói felület beállításainak mentése" msgid "Save Stash" msgstr "Félretett változat mentése" msgid "Save modified state to new stash" msgstr "A módosított állapot mentése új félretett változatként" #, python-format msgid "Saved \"%(filename)s\" from \"%(ref)s\" to \"%(destination)s\"" msgstr "" "A(z) „%(ref)s” a(z) „%(filename)s” helyről ide lett mentve: „%(destination)s”" msgid "Search" msgstr "Keresés" msgid "Search Authors" msgstr "Szerzők keresése" msgid "Search Commit Messages" msgstr "Véglegesítési üzenetek keresése" msgid "Search Committers" msgstr "Véglegesítők keresése" msgid "Search Date Range" msgstr "Dátumintervallum keresése" msgid "Search Diffs" msgstr "Összehasonlítások keresése" msgid "Search by Expression" msgstr "Keresés kifejezésre" msgid "Search by Path" msgstr "Keresés útvonal alapján" msgid "Search for a fixed string" msgstr "Keresés rögzített szövegre" msgid "Search using a POSIX basic regular expression" msgstr "Keresés POSIX alapszintű reguláris kifejezéssel" msgid "Search using a POSIX extended regular expression" msgstr "Keresés POSIX bővített reguláris kifejezéssel" msgid "Search..." msgstr "Keresés…" msgid "Select" msgstr "Kijelölés" msgid "Select All" msgstr "Összes kijelölése" msgid "Select Branch to Review" msgstr "Ág kijelölése áttekintéshez" msgid "Select Child" msgstr "Gyermek kijelölése" msgid "Select Commit" msgstr "Véglegesítés kijelölése" msgid "Select Directory..." msgstr "Könyvtár kijelölése…" msgid "Select New Upstream" msgstr "Új távoli tároló kijelölése" msgid "Select Newest Child" msgstr "Legújabb gyermek kijelölése" msgid "Select Oldest Parent" msgstr "Legöregebb szülő kijelölése" msgid "Select Parent" msgstr "Szülő kijelölése" msgid "Select Previous Version" msgstr "Előző verzió kijelölése" msgid "Select Repository..." msgstr "Tároló kijelölése…" msgid "Select a parent directory for the new clone" msgstr "Válasszon szülő mappát az új klón számára" msgid "Select manually..." msgstr "Kézi kijelölés…" msgid "Select output dir" msgstr "Kimeneti könyvtár kijelölése" msgid "Select output directory" msgstr "Kimeneti könyvtár kijelölése" msgid "Select patch file(s)..." msgstr "Foltfájl(ok) kijelölése…" msgid "Select repository" msgstr "Tároló kijelölése" msgid "Set Default Repository" msgstr "Alapértelmezett tároló beállítása" msgid "Set Upstream Branch" msgstr "Távoli tároló ág beállítása" msgid "" "Set the sort order for branches and tags.\n" "Toggle between date-based and version-name-based sorting." msgstr "" "Az ágak és címkék rendezési sorrendjének beállítása.\n" "Váltás a dátum alapú és a verziónév alapú rendezési sorrend között." msgid "Set upstream" msgstr "Beállítás távoli tárolóként" msgid "Settings" msgstr "Beállítások" msgid "Shell arguments" msgstr "Parancsértelmező argumentumai" msgid "Shift Down" msgstr "Mozgatás lefelé" msgid "Shift Up" msgstr "Mozgatás felfelé" msgid "Shortcuts" msgstr "Gyorsbillentyűk" msgid "Show Details..." msgstr "Részletek megjelenítése…" msgid "Show Diffstat After Merge" msgstr "Diffstat megjelenítése a beolvasztás után" msgid "Show Full Paths in the Window Title" msgstr "Teljes útvonal megjelenítése az ablakok címsorában" msgid "Show Help" msgstr "Súgó megjelenítse" msgid "Show History" msgstr "Történet megjelenítése" msgid "Show file counts in Status titles" msgstr "Fájlok számának megjelentése az állapotcímekben" msgid "" "Show help\n" "Shortcut: ?" msgstr "" "Súgó megjelenítése\n" "Gyorsbillentyű: ?" msgid "Show icon? (if available)" msgstr "Megjeleníti az ikonokat (ha vannak)?" msgid "Show line numbers" msgstr "Sorok számának megjelenítése" msgid "Show whole surrounding functions of changes" msgstr "A módosításokat érintő funkciók teljes környezetének megjelenítése" msgid "Showing changes since" msgstr "Változások megjelenítése ekkortól:" msgid "Side by side" msgstr "Egymás mellett" msgid "Sign Off" msgstr "Aláírás" msgid "Sign Tag" msgstr "Címke aláírása" msgid "Sign off on this commit" msgstr "A véglegesítés aláírása" msgid "Simplified Chinese translation" msgstr "Egyszerűsített kínai fordítás" msgid "Skip" msgstr "Kihagyás" msgid "Skip Current Patch" msgstr "Jelenlegi folt kihagyása" msgid "Sort bookmarks alphabetically" msgstr "Könyvjelzők rendezése ábécésorrendben" msgid "Spanish translation" msgstr "Spanyol fordítás" msgid "Specifies the SHA-1 to tag" msgstr "Megadja a címke SHA-1 értékét" msgid "Specifies the tag message" msgstr "Megadja a címkeüzenetet" msgid "Specifies the tag name" msgstr "Megadja a címke nevét" msgid "Spelling Suggestions" msgstr "Helyesírási javaslatok" msgid "Squash" msgstr "Összevonás" msgid "Squash the merged commits into a single commit" msgstr "Az beolvasztott véglegesítések összevonása egyetlen véglegesítésbe" msgid "Stage" msgstr "Kiszemelés" msgid "Stage / Unstage" msgstr "Kiszemelés/elengedés" msgid "Stage All Untracked" msgstr "Minden nem követett változás kiszemelése" msgid "Stage Changed Files To Commit" msgstr "Módosított fájlok kiszemelése véglegesítésre" msgid "Stage Diff Hunk" msgstr "Összehasonlítási egység kiszemelése" msgid "Stage Modified" msgstr "Módosítottak kiszemelése" msgid "Stage Selected" msgstr "Kijelöltek kiszemelése" msgid "Stage Selected Lines" msgstr "Kijelölt sorok kiszemelése" msgid "Stage Unmerged" msgstr "Nem beolvasztottak kiszemelése" msgid "Stage Untracked" msgstr "Nem követett változások kiszemelése" msgid "Stage and Commit" msgstr "Kiszemelés és véglegesítés" msgid "Stage and commit?" msgstr "Kiszemeli és véglegesíti?" msgid "Stage conflicts" msgstr "Ütközések kiszemelése" msgid "Stage conflicts?" msgstr "Kiszemeli az ütközéseket?" msgid "Stage/unstage selected paths for commit" msgstr "A kijelölt útvonalak kijelölése/elengedése véglegesítésre" msgid "Staged" msgstr "Kiszemelve" #, python-format msgid "Staging: %s" msgstr "Kiszemelés: %s" msgid "Start Interactive Rebase..." msgstr "Interaktív újraalapozás indítása…" msgid "Starting Revision" msgstr "A következő revíziótól" msgid "Stash" msgstr "Félrerakás" msgid "Stash Index" msgstr "Félrerakási jegyzék" msgid "Stash staged changes only" msgstr "Csak a kiszemelt módosítások félrerakása" msgid "Stash unstaged changes only, keeping staged changes" msgstr "" "Csak az elengedett módosítások félrerakása, a kiszemelt módosítások " "megtartása" msgid "Stash..." msgstr "Félrerakás…" msgid "Status" msgstr "Állapot" msgid "Stop tracking paths" msgstr "Útvonalak követésének leállítása" msgid "Submodules" msgstr "Almodulok" msgid "Summarize Merge Commits" msgstr "A beolvasztási véglegesítések összegzése" msgid "Summary" msgstr "Összegzés" msgid "Tab Width" msgstr "Tabulátorszélesség" msgid "Tag" msgstr "Címke" msgid "Tag Created" msgstr "Címke létrehozva" msgid "Tag message..." msgstr "Címkeüzenet…" msgid "Tag-signing was requested but the tag message is empty." msgstr "Címkealáírás lett kérve, de a címkeüzenet üres." msgid "Tags" msgstr "Címkék" msgid "Text Width" msgstr "Szövegszélesség" msgid "The branch will be no longer available." msgstr "Az ág nem lesz többé elérhető." #, python-format msgid "The branch will be reset using \"git reset --hard %s\"" msgstr "Az ág visszaállítása ezzel a paranccsal: „git reset --hard %s”" #, python-format msgid "The branch will be reset using \"git reset --merge %s\"" msgstr "Az ág visszaállítása ezzel a paranccsal: „git reset --merge %s”" #, python-format msgid "The branch will be reset using \"git reset --mixed %s\"" msgstr "Az ág visszaállítása ezzel a paranccsal: „git reset --mixed %s”" #, python-format msgid "The branch will be reset using \"git reset --soft %s\"" msgstr "Az ág visszaállítása ezzel a paranccsal: „git reset --soft %s”" msgid "The commit message will be cleared." msgstr "A véglegesítési üzenet meg lett tisztítva." #, python-format msgid "The file \"%s\" exists and will be overwritten." msgstr "A(z) „%s” fájl létezik és felül lesz írva." msgid "The following files will be deleted:" msgstr "A következő fájlok törölve lesznek:" msgid "The revision expression cannot be empty." msgstr "A revíziókifejezés nem lehet üres." #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" "Az almodul frissítve lesz ezzel:\n" "„%s”" #, python-format msgid "The worktree will be reset using \"git reset --keep %s\"" msgstr "A munkafa visszaáll ezzel a paranccsal: „git reset --keep %s”" msgid "This cannot be undone. Clear commit message?" msgstr "Ez nem vonható vissza. Megtisztítja a véglegesítési üzenetet?" msgid "" "This commit has already been published.\n" "This operation will rewrite published history.\n" "You probably don't want to do this." msgstr "" "A véglegesítés már közzé lett téve.\n" "Ez a művelet felülírja a közzétett történetet.\n" "Valószínűleg nem ezt akarja tenni." msgid "" "This operation drops uncommitted changes.\n" "These changes cannot be recovered." msgstr "" "Ez a művelet kidobja a nem véglegesített módosításokat.\n" "Ezek a módosítások nem állíthatók vissza." msgid "" "This operation removes uncommitted edits from selected files.\n" "These changes cannot be recovered." msgstr "" "Ez a művelet eltávolítja a nem véglegesített szerkesztések a kijelölt " "fájlokban.\n" "Ezek a módosítások nem állíthatók vissza." msgid "" "This operation removes unstaged edits from selected files.\n" "These changes cannot be recovered." msgstr "" "Ez a művelet eltávolítja az elengedett szerkesztéseket a kijelölt fájlokon.\n" "Ezek a módosítások nem állíthatók vissza." msgid "" "This repository is currently being rebased.\n" "Resolve conflicts, commit changes, and run:\n" " Rebase > Continue" msgstr "" "A tároló épp újraalapozás alatt áll.\n" "Oldja fel az ütközéseket, véglegesítse a módosításokat és futtassa:\n" " Újralapozás > Folytatás" msgid "" "This repository is in the middle of a merge.\n" "Resolve conflicts and commit changes." msgstr "" "A tároló épp egy beolvasztás alatt áll.\n" "Oldja fel az ütközéseket és véglegesítse a változásokat." msgid "Toggle Enabled" msgstr "Engedélyezés átváltása" msgid "Toggle the branches filter" msgstr "Elágazásszűrő átváltása" msgid "Toggle the paths filter" msgstr "Útvonalszűrő átváltása" msgid "Tracking Branch" msgstr "Követett ág" msgid "Tracking branch" msgstr "Követett ágak" msgid "Traditional Chinese (Taiwan) translation" msgstr "Tradicionális kínai (Tajvan) fordítás" msgid "Translators" msgstr "Fordítók" msgid "Turkish translation" msgstr "Török fordítás" msgid "URL" msgstr "URL" #, python-format msgid "URL: %s" msgstr "URL: %s" msgid "Ukranian translation" msgstr "Ukrán fordítás" msgid "Unable to rebase" msgstr "Nem lehet újraalapozni" #, python-format msgid "Unable to set URL for \"%(name)s\" to \"%(url)s\"" msgstr "Nem állítható be URL a(z) „%(name)s” számára: „%(url)s”" msgid "Undo" msgstr "Visszavonás" msgid "Unmerged" msgstr "Nem beolvasztottak" msgid "Unstage" msgstr "Elengedés" msgid "Unstage All" msgstr "Összes elengedése" msgid "Unstage Diff Hunk" msgstr "Összehasonlítási egység elengedése" msgid "Unstage From Commit" msgstr "Elengedés a véglegesítésből" msgid "Unstage Selected" msgstr "Kijelöltek elengedése" msgid "Unstage Selected Lines" msgstr "Kijelölt sorok elengedése" #, python-format msgid "Unstaging: %s" msgstr "Elengedés: %s" msgid "Untrack Selected" msgstr "Kijelöltek követésének törlése" msgid "Untracked" msgstr "Nem követett" #, python-format msgid "Untracking: %s" msgstr "Követés törlése: %s" msgid "Update All Submodules..." msgstr "Összes almodul frissítése…" msgid "Update Existing Branch:" msgstr "Létező ág frissítése:" msgid "Update Submodule" msgstr "Almodul frissítése" msgid "Update Submodule..." msgstr "Almodul frissítése…" msgid "Update Submodules" msgstr "Almodulok frissítése" msgid "Update all submodules?" msgstr "Frissíti az összes almodult?" msgid "Update submodules..." msgstr "Almodulok frissítése…" msgid "Update this submodule" msgstr "Ezen almodul frissítése" msgid "Update this submodule?" msgstr "Frissíti ezt az almodult?" msgid "Updating" msgstr "Frissítés" msgid "User Name" msgstr "Felhasználónév" msgid "Version" msgstr "Verzió" msgid "View" msgstr "Nézet" msgid "View History..." msgstr "Történet megjelenítése…" msgid "View history for selected paths" msgstr "A kijelölt útvonal történetének megjelenítése" msgid "Visualize" msgstr "Vizualizálás" msgid "Visualize All Branches..." msgstr "Összes ág vizualizálása…" msgid "Visualize Current Branch..." msgstr "Jelenlegi ág vizualizálása…" msgid "Whether to sign the tag (git tag -s)" msgstr "Aláírásra kerüljön-e a címke (git tag -s)" msgid "Would you like to stage and commit all modified files?" msgstr "Valóban kiszemeli és véglegesíti az összes módosított fájlt?" msgid "XOR" msgstr "Logikai kizáró vagy" msgid "Yes" msgstr "Igen" msgid "" "You are in the middle of a merge.\n" "Cannot amend while merging." msgstr "" "Egy beolvasztás közepén van.\n" "Nem lehet javítani beolvasztás közben." msgid "You cannot rebase with uncommitted changes." msgstr "Nem lehet újraalapozni nem véglegesített módosításokkal." msgid "You must specify a revision to merge." msgstr "Meg kell adni egy revíziót a beolvasztáshoz." msgid "You must specify a revision to view." msgstr "Meg kell adni egy revíziót a megjelenítéshez." msgid "Zoom In" msgstr "Nagyítás" msgid "Zoom Out" msgstr "Kicsinyítés" msgid "Zoom to Fit" msgstr "Nagyítás, hogy elférjen" msgid "command-line arguments" msgstr "parancssori argumentumok" msgid "error: unable to execute git" msgstr "hiba: a git nem hajtható végre" #, python-format msgid "exit code %s" msgstr "%s kilépési kód" #, python-format msgid "" "fatal: \"%s\" is not a directory. Please specify a correct --repo ." msgstr "" "végzetes: „%s” nem könyvtár. Adjon meg egy helyes útvonalat: --repo ." #, python-format msgid "git cola version %s" msgstr "git cola %s verzió" msgid "git-cola" msgstr "git-cola" msgid "git-cola diff" msgstr "git-cola diff" msgid "grep result..." msgstr "grep eredmény…" msgid "hotkeys.html" msgstr "hotkeys.html" msgid "unknown" msgstr "ismeretlen" msgid "vX.Y.Z" msgstr "vX.Y.Z" msgid "x 1" msgstr "×1" msgid "x 1.5" msgstr "×1,5" msgid "x 2" msgstr "×2" msgid "yyyy-MM-dd" msgstr "yyyy-MM-dd" git-cola-3.6/po/id_ID.po000066400000000000000000001456261356743264500150440ustar00rootroot00000000000000# Indonesian translations for PACKAGE package. # Copyright (C) 2014 THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Samsul Ma'arif , 2014. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-17 01:06-0700\n" "PO-Revision-Date: 2014-06-30 14:21+0700\n" "Last-Translator: Samsul Ma'arif \n" "Language-Team: Indonesian\n" "Language: id\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ASCII\n" "Content-Transfer-Encoding: 8bit\n" msgid "" "\n" "

\n" " Drag and drop or use the Add button to add\n" " patches to the list\n" "

\n" " " msgstr "" "\n" "

\n" " Drag dan drop atau gunakan tombol Tambah untuk menambah\n" " patch ke daftar\n" "

\n" " " #, python-format msgid "" "\n" "
\n" " Git Cola has been translated into different languages thanks\n" " to the help of the individuals listed below.\n" "\n" "
\n" "

\n" " Translation is approximate. If you find a mistake,\n" " please let us know by opening an issue on Github:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " We invite you to participate in translation by adding or updating\n" " a translation and opening a pull request.\n" "

\n" "\n" "
\n" "\n" " " msgstr "" #, python-format msgid "" "\n" "
\n" " Git Cola version %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " msgstr "" #, python-format msgid "" "\n" "
\n" " Please use %(bug_link)s to report issues.\n" "
\n" " " msgstr "" #, python-format msgid "" "\n" " Format String Variables\n" " -----------------------\n" " %(path)s = relative file path\n" " %(abspath)s = absolute file path\n" " %(dirname)s = relative directory path\n" " %(absdirname)s = absolute directory path\n" " %(filename)s = file basename\n" " %(basename)s = file basename without extension\n" " %(ext)s = file extension\n" msgstr "" msgid "" "\n" "Commands\n" "--------\n" "pick = use commit\n" "reword = use commit, but edit the commit message\n" "edit = use commit, but stop for amending\n" "squash = use commit, but meld into previous commit\n" "fixup = like \"squash\", but discard this commit's log message\n" "exec = run command (the rest of the line) using shell\n" "\n" "These lines can be re-ordered; they are executed from top to bottom.\n" "\n" "If you disable a line here THAT COMMIT WILL BE LOST.\n" "\n" "However, if you disable everything, the rebase will be aborted.\n" "\n" "Keyboard Shortcuts\n" "------------------\n" "? = show help\n" "j = move down\n" "k = move up\n" "J = shift row down\n" "K = shift row up\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "spacebar = toggle enabled\n" "\n" "ctrl+enter = accept changes and rebase\n" "ctrl+q = cancel and abort the rebase\n" "ctrl+d = launch difftool\n" msgstr "" msgid "" "\n" "Keyboard Shortcuts\n" "------------------\n" "J, Down = Move Down\n" "K, Up = Move Up\n" "Enter = Edit Selected Files\n" "Spacebar = Open File Using Default Application\n" "Ctrl + L = Focus Text Entry Field\n" "? = Show Help\n" "\n" "The up and down arrows change focus between the text entry field\n" "and the results.\n" msgstr "" msgid " - DAG" msgstr " - DAG" msgid " commits ago" msgstr " commit yang lalu" #, python-format msgid "\"%(branch)s\" has been deleted from \"%(remote)s\"." msgstr "\"%(branch)s\" telah dihapus dari \"%(remote)s\"." #, python-format msgid "\"%(command)s\" returned exit status \"%(status)d\"" msgstr "\"%(command)s\" menghasilkan exit status \"%(status)d\"" #, python-format msgid "\"%(command)s\" returned exit status %(status)d" msgstr "\"%(command)s\" keluar dengan status %(status)d" #, fuzzy, python-format msgid "\"%s\" already exists" msgstr "Cabang \"%s\" sudah ada." #, python-format msgid "\"%s\" already exists, cola will create a new directory" msgstr "\"%s\" sudah ada, cola akan membuat direktori baru" #, python-format msgid "\"%s\" requires a selected file." msgstr "\"%s\" berkas terpilih diperlukan." msgid "#" msgstr "" #, python-format msgid "%(project)s: %(branch)s - Browse" msgstr "%(project)s: %(branch)s - Jelajah" #, python-format msgid "%(project)s: %(ref)s - DAG" msgstr "" #, python-format msgid "%d days ago" msgstr "%d hari lalu" #, python-format msgid "%d hours ago" msgstr "%d jam lalu" #, python-format msgid "%d minutes ago" msgstr "%d menit lalu" #, python-format msgid "%d patch(es) applied." msgstr "%d patch diterapkan." #, python-format msgid "%d skipped" msgstr "%d dilewati" #, python-format msgid "" "%s appears to contain merge conflicts.\n" "\n" "You should probably skip this file.\n" "Stage it anyways?" msgstr "" #, fuzzy, python-format msgid "%s is not a Git repository." msgstr "Masukkan Repositori Git" #, python-format msgid "%s will be removed from your bookmarks." msgstr "" #, python-format msgid "%s will be removed from your recent repositories." msgstr "" #, python-format msgid "%s: No such file or directory." msgstr "%s: Berkas atau direktori tidak ada." msgid "&Edit" msgstr "Sunting" msgid "&File" msgstr "Berkas" msgid "(Amending)" msgstr "(Mengubah)" msgid "*** Branch Point ***" msgstr "*** Poin Cabang ***" msgid "*** Sandbox ***" msgstr "*** Bak Pasir ***" msgid "100%" msgstr "" msgid "200%" msgstr "" msgid "25%" msgstr "" msgid "400%" msgstr "" msgid "50%" msgstr "" msgid "800%" msgstr "" msgid " ..." msgstr "" msgid "" "A commit template has not been configured.\n" "Use \"git config\" to define \"commit.template\"\n" "so that it points to a commit template." msgstr "" "Templat commit belum dikonfigurasi.\n" "Gunakan \"git config\" untuk menentukan \"commit.template\"\n" "agar mengarah ke templat commit." #, python-format msgid "A hook must be provided at \"%s\"" msgstr "" #, python-format msgid "A stash named \"%s\" already exists" msgstr "Stash dengan nama \"%s\" sudah ada" msgid "Abort" msgstr "Batal" msgid "Abort Action" msgstr "Batalkan Aksi" msgid "Abort Merge" msgstr "Batalkan Merge" msgid "Abort Merge..." msgstr "Batalkan Penggabungan..." msgid "Abort the action?" msgstr "Batalkan aksi?" msgid "" "Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" "Recovering uncommitted changes is not possible." msgstr "" "Membatalkan merge saat ini akan menghilangkan *SEMUA* perubahan commit.\n" "Mengembalikan perubahan yang belum dicommit tidak dimungkinkan." msgid "Aborting the current merge?" msgstr "Batalkan merge saat ini?" msgid "About" msgstr "Tentang" msgid "About git-cola" msgstr "Tentang git-cola" msgid "Accept" msgstr "" #, fuzzy msgid "" "Accept changes and rebase\n" "Shortcut: Ctrl+Enter" msgstr "" "Commit perubahan stage\n" "Pintasan: Ctrl+Enter" #, fuzzy msgid "Action Name" msgstr "Aksi" msgid "Actions" msgstr "Aksi" msgid "Actions..." msgstr "Aksi..." msgid "Add" msgstr "Tambah" #, fuzzy msgid "Add Favorite" msgstr "Tambahkan Hulu" msgid "Add Remote" msgstr "Tambahkan Hulu" msgid "Add Separator" msgstr "" msgid "Add Toolbar" msgstr "" msgid "" "Add and remove remote repositories using the \n" "Add(+) and Delete(-) buttons on the left-hand side.\n" "\n" "Remotes can be renamed by selecting one from the list\n" "and pressing \"enter\", or by double-clicking." msgstr "" "Tambah dan hapus repositori hulu menggunakan tombol \n" "Tambah(+) dan Hapus(-) pada sisi sebelah kiri.\n" "Hulu dapat diganti nama dengan memilih salah satu dari \n" "daftar dan tekan \"enter\", atau dobel-klik." msgid "Add new remote git repository" msgstr "Tambahkan repositori git hulu" msgid "Add patches (+)" msgstr "Tambahkan patch (+)" msgid "Add remote" msgstr "Tambahkan hulu" msgid "Add to .gitignore" msgstr "Tambahkan ke .gitignore" #, fuzzy msgid "Add to Git Annex" msgstr "Tambahkan ke .gitignore" msgid "Add to Git LFS" msgstr "" msgid "Additions" msgstr "Penambahan" msgid "Advanced" msgstr "Mahir" msgid "Age" msgstr "Usia" msgid "All Repositories" msgstr "Semua Repositori" #, python-format msgid "" "All submodules will be updated using\n" "\"%s\"" msgstr "" msgid "Allow non-fast-forward updates. Using \"force\" can cause the remote repository to lose commits; use it with care" msgstr "" msgid "Always create a merge commit when enabled, even when the merge is a fast-forward update" msgstr "" msgid "Amend" msgstr "Ubah" msgid "Amend Commit" msgstr "Ubah Commit" msgid "Amend Last Commit" msgstr "Ubah Commit Terakhir" msgid "Amend the published commit?" msgstr "Ubah penerbitan commit?" msgid "Amending" msgstr "Mengubah" msgid "" "An action is still running.\n" "Terminating it could result in data loss." msgstr "" "Aksi ini masih berjalan.\n" "Mengakhiri ini dapat menghilangkan data." msgid "" "An unsigned, lightweight tag will be created instead.\n" "Create an unsigned tag?" msgstr "" "Tak bertanda, tag ringan akan dibuat.\n" "Buat tag tak bertanda?" msgid "Appearance" msgstr "" msgid "Apply" msgstr "Terapkan" msgid "Apply Patches" msgstr "Terapkan Patch" msgid "Apply Patches..." msgstr "Terapkan Patch..." #, fuzzy msgid "Apply and drop the selected stash (git stash pop)" msgstr "Terapkan stash terpilih" msgid "Apply the selected stash" msgstr "Terapkan stash terpilih" msgid "Arguments" msgstr "Argumen" msgid "Attach" msgstr "Lampirkan" msgid "Author" msgstr "Penulis" #, fuzzy msgid "Authors" msgstr "Penulis" msgid "Auto" msgstr "" msgid "Auto-Wrap Lines" msgstr "Auto-Wrap Baris" msgid "Basic Regexp" msgstr "Regexp Dasar" #, fuzzy msgid "Blame Viewer" msgstr "Penampil Diff Cabang" #, fuzzy msgid "Blame selected paths" msgstr "Sunting lokasi terpilih" #, fuzzy msgid "Blame..." msgstr "Tutup..." msgid "Bold on dark headers instead of italic" msgstr "" msgid "Branch" msgstr "Cabang" #, python-format msgid "" "Branch \"%(branch)s\" does not exist in \"%(remote)s\".\n" "A new remote branch will be published." msgstr "" "Cabang \"%(branch)s\" tidak ada di \"%(remote)s\".\n" "Cabang hulu baru akan di publikasikan." #, python-format msgid "Branch \"%s\" already exists." msgstr "Cabang \"%s\" sudah ada." msgid "Branch Diff Viewer" msgstr "Penampil Diff Cabang" msgid "Branch Exists" msgstr "Cabang Sudah Ada" msgid "Branch Name" msgstr "Nama Cabang" #, python-format msgid "Branch: %s" msgstr "Cabang: %s" #, fuzzy msgid "Branches" msgstr "Cabang" msgid "Branches..." msgstr "Cabang..." msgid "Brazilian translation" msgstr "" msgid "Browse" msgstr "Ramban" msgid "Browse Commits..." msgstr "Ramban Commit..." msgid "Browse Current Branch..." msgstr "Jelajah Cabang Saat ini..." msgid "Browse Other Branch..." msgstr "Jelajah Cabang Lain..." msgid "Browse..." msgstr "Jelajah..." msgid "Browser" msgstr "Jelajah" #, python-format msgid "Browsing %s" msgstr "Ramban %s" msgid "Bypass Commit Hooks" msgstr "" msgid "Cancel" msgstr "Batalkan" #, fuzzy msgid "" "Cancel rebase\n" "Shortcut: Ctrl+Q" msgstr "" "Commit perubahan stage\n" "Pintasan: Ctrl+Enter" msgid "Cannot Amend" msgstr "Tidak dapat diubah" #, fuzzy, python-format msgid "Cannot exec \"%s\": please configure a blame viewer" msgstr "Tidak dapat mengeksekusi \"%s\": silahkan konfigurasi editor Anda" #, python-format msgid "Cannot exec \"%s\": please configure a history browser" msgstr "Tidak dapat menjalankan \"%s\": silahkan konfigurasi peramban histori" #, python-format msgid "Cannot exec \"%s\": please configure your editor" msgstr "Tidak dapat mengeksekusi \"%s\": silahkan konfigurasi editor Anda" msgid "Changed Upstream" msgstr "Ubah Upstream" msgid "Check Spelling" msgstr "Periksa Ejaan" #, fuzzy msgid "Check spelling" msgstr "Periksa Ejaan" msgid "Checkout" msgstr "Checkout" msgid "Checkout After Creation" msgstr "Checkout Setelah Dibuat" msgid "Checkout Branch" msgstr "Checkout Cabang" #, fuzzy msgid "Checkout Detached HEAD" msgstr "Checkout Cabang" #, fuzzy msgid "Checkout as new branch" msgstr "Checkout Cabang" msgid "Checkout..." msgstr "Checkout..." msgid "Cherry Pick" msgstr "Cherry Pick" msgid "Cherry-Pick Commit" msgstr "Commit Cherry-Pick" msgid "Cherry-Pick..." msgstr "Cherry-Pick..." msgid "Choose Paths" msgstr "Pilih Lokasi" msgid "Choose the \"git grep\" regular expression mode" msgstr "Pilih mode ekspresi reguler \"git grep\"" #, fuzzy msgid "Clear Default Repository" msgstr "Repositori Saat Ini" #, fuzzy msgid "Clear commit message" msgstr "Cari Pesan Commit" #, fuzzy msgid "Clear commit message?" msgstr "Cari Pesan Commit" #, fuzzy msgid "Clear..." msgstr "Tutup..." #, fuzzy msgid "Clone" msgstr "Clon...." #, fuzzy msgid "Clone Repository" msgstr "Repositori Saat Ini" msgid "Clone..." msgstr "Clon...." #, fuzzy, python-format msgid "Cloning repository at %s" msgstr "Repositori: %s" msgid "Close" msgstr "Tutup" msgid "Close..." msgstr "Tutup..." msgid "Collapse all" msgstr "Gulung semua" #, fuzzy msgid "Command" msgstr "Commit" msgid "Commit" msgstr "Commit" msgid "Commit failed" msgstr "Commit gagal" msgid "Commit staged changes" msgstr "Commit perubahan stage" msgid "" "Commit staged changes\n" "Shortcut: Ctrl+Enter" msgstr "" "Commit perubahan stage\n" "Pintasan: Ctrl+Enter" msgid "Commit summary" msgstr "Ringkasan commit" msgid "Commit the merge if there are no conflicts. Uncheck to leave the merge uncommitted" msgstr "" msgid "Commit@@verb" msgstr "Commit@@verb" msgid "Compare" msgstr "Bandingkan" #, fuzzy msgid "Compare All" msgstr "Bandingkan" msgid "Configure the remote branch as the the new upstream" msgstr "" msgid "Configure toolbar" msgstr "" msgid "Console" msgstr "Konsol" msgid "Continue" msgstr "Lanjutkan" msgid "Copy" msgstr "Salin" #, fuzzy msgid "Copy Basename to Clipboard" msgstr "Salin Lokasi ke Papan klip" #, fuzzy msgid "Copy Leading Path to Clipboard" msgstr "Salin Lokasi ke Papan klip" msgid "Copy Path to Clipboard" msgstr "Salin Lokasi ke Papan klip" #, fuzzy msgid "Copy Relative Path to Clipboard" msgstr "Salin Lokasi ke Papan klip" msgid "Copy SHA-1" msgstr "Salin SHA-1" #, fuzzy msgid "Copy..." msgstr "Salin" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "Tidak dapat mengurai URL Git: \"%s\"" msgid "Create Branch" msgstr "Buat Cabang" msgid "Create Patch" msgstr "Buat Patch" msgid "Create Remote Branch" msgstr "Buat Cabang Hulu" #, fuzzy msgid "Create Signed Commit" msgstr "Buat commit: %s" msgid "Create Tag" msgstr "Buat Tag" msgid "Create Tag..." msgstr "Buat Tag..." msgid "Create Unsigned Tag" msgstr "Buat Tag tak Bertanda" msgid "Create a merge commit even when the merge resolves as a fast-forward" msgstr "" msgid "Create a new remote branch?" msgstr "Buat cabang baru di hulu?" msgid "Create..." msgstr "Buat..." #, python-format msgid "Created a new tag named \"%s\"" msgstr "Buat tag baru bernama \"%s\"" msgid "Current Repository" msgstr "Repositori Saat Ini" msgid "Custom Copy Actions" msgstr "" #, fuzzy msgid "Customize..." msgstr "Tutup..." msgid "Cut" msgstr "" msgid "Czech translation" msgstr "" msgid "DAG..." msgstr "DAG..." msgid "Dark Theme" msgstr "" msgid "Date, Time" msgstr "Tanggal, Waktu" msgid "Default" msgstr "" msgid "Delete" msgstr "Hapus" #, python-format msgid "Delete %d file(s)?" msgstr "Hapus %d berkas?" #, fuzzy msgid "Delete Bookmark" msgstr "Markah" #, fuzzy msgid "Delete Bookmark?" msgstr "Markah" msgid "Delete Branch" msgstr "Hapus Cabang" msgid "Delete Files" msgstr "Hapus Berkas" msgid "Delete Files..." msgstr "Hapus Berkas...?" msgid "Delete Files?" msgstr "Hapus Berkas?" msgid "Delete Remote" msgstr "Hapus Hulu" msgid "Delete Remote Branch" msgstr "Hapus Cabang Hulu" msgid "Delete Remote Branch..." msgstr "Hapus Cabang Hulu..." msgid "Delete remote" msgstr "Hapus hulu" #, python-format msgid "Delete remote \"%s\"" msgstr "Hapus hulu \"%s\"" msgid "Delete remote?" msgstr "Hapus hulu?" #, fuzzy msgid "Delete selected branch?" msgstr "Hapus Cabang Hulu" #, fuzzy msgid "Delete toolbar" msgstr "Markah" msgid "Delete..." msgstr "Hapus..." #, python-format msgid "Deleting \"%s\" failed" msgstr "Gagal menghapus \"%s\"" msgid "Deletions" msgstr "Penghapusan" msgid "Detach" msgstr "Lepaskan" msgid "Detect Conflict Markers" msgstr "" msgid "Detect conflict markers in unmerged files" msgstr "" msgid "Developer" msgstr "" msgid "Diff" msgstr "Diff" msgid "Diff Against Predecessor..." msgstr "Diff Pada Predessor..." msgid "Diff Options" msgstr "Pilihan Diff" msgid "Diff Tool" msgstr "Alat Diff" msgid "Diff selected -> this" msgstr "Diff terpilih -> ini" msgid "Diff this -> selected" msgstr "Diff ini -> terpilih" msgid "Diffstat" msgstr "Diffstat" #, fuzzy msgid "Difftool" msgstr "Alat Diff" msgid "Directory Exists" msgstr "Direktori Sudah Ada" msgid "Display Untracked Files" msgstr "Tampilkan Berkas Tak Terlacak" msgid "Documentation" msgstr "Dokumentasi" msgid "Drop" msgstr "Buang" msgid "Drop Stash" msgstr "Buang Stash" msgid "Drop Stash?" msgstr "Buang Stash?" #, python-format msgid "Drop the \"%s\" stash?" msgstr "Buang stash \"%s\"?" msgid "Drop the selected stash" msgstr "Buang stash terpilih" #, fuzzy msgid "Edit" msgstr "Sunting" msgid "Edit Rebase" msgstr "Sunting Rebase" msgid "Edit Remotes" msgstr "Sunting Hulu" msgid "Edit Remotes..." msgstr "Sunting Hulu..." msgid "Edit remotes by selecting them from the list" msgstr "" msgid "Edit selected paths" msgstr "Sunting lokasi terpilih" msgid "Edit..." msgstr "Sunting..." msgid "Editor" msgstr "Penyunting" msgid "Email Address" msgstr "Alamat Email" msgid "Email contributor" msgstr "" msgid "Enabled" msgstr "" #, fuzzy msgid "Enter New Branch Name" msgstr "Nama Cabang" #, fuzzy msgid "Enter a name for the new bare repo" msgstr "Masukkan nama untuk stash" msgid "Enter a name for the stash" msgstr "Masukkan nama untuk stash" msgid "Error" msgstr "Error" msgid "Error Cloning" msgstr "Error Kloning" msgid "Error Creating Branch" msgstr "Erroe Membuat Cabang" msgid "Error Creating Repository" msgstr "Error Membuat Repositori" msgid "Error Deleting Remote Branch" msgstr "Error menghapus Cabang Hulu" msgid "Error Editing File" msgstr "Error Menyunting Berkas" #, fuzzy msgid "Error Launching Blame Viewer" msgstr "Errot Menjalankan Peramban Histori" msgid "Error Launching History Browser" msgstr "Errot Menjalankan Peramban Histori" #, python-format msgid "Error creating remote \"%s\"" msgstr "Error membuat hulu \"%s\"" #, fuzzy msgid "Error creating stash" msgstr "Erroe Membuat Cabang" #, python-format msgid "Error deleting remote \"%s\"" msgstr "Error menghapus hulu \"%s\"" #, fuzzy, python-format msgid "Error renaming \"%(name)s\" to \"%(new_name)s\"" msgstr "Menandai \"%(revision)s\" sebagai \"%(name)s\"" msgid "Error running prepare-commitmsg hook" msgstr "" #, fuzzy, python-format msgid "Error updating submodule %s" msgstr "Error membuat hulu \"%s\"" #, fuzzy msgid "Error updating submodules" msgstr "Error Menyunting Berkas" msgid "Error: Cannot find commit template" msgstr "Error: Tidak dapat melakukan commit templat" msgid "Error: Stash exists" msgstr "Error: Stash sudah ada" msgid "Error: Unconfigured commit template" msgstr "Error: Commit templat belum dikonfigurasi" #, python-format msgid "Error: could not clone \"%s\"" msgstr "Error: tidak bisa kloning \"%s\"" #, python-format msgid "Error: could not create tag \"%s\"" msgstr "Error: tidak dapat membuat tag \"%s\"" #, python-format msgid "Executing action %s" msgstr "" msgid "Expand all" msgstr "Bentangkan semua" msgid "Export Patches" msgstr "Ekspor Patch" msgid "Export Patches..." msgstr "Ekspor Patch..." msgid "Expression..." msgstr "Ekspresi..." msgid "Extended Regexp" msgstr "Regexp Perluasan" msgid "Extended description..." msgstr "Perluaskan penjelasan..." msgid "Fast Forward Only" msgstr "Hanya Fast Forward" #, fuzzy msgid "Fast-forward only" msgstr "Hanya Fast Forward" #, fuzzy msgid "Favorite repositories" msgstr "Semua Repositori" msgid "Favorites" msgstr "" #, fuzzy msgid "Fetch" msgstr "Ambil..." msgid "Fetch Tracking Branch" msgstr "Fetch Cabang Terlacak" msgid "Fetch..." msgstr "Ambil..." msgid "File Browser..." msgstr "Jelajah Berkas..." msgid "File Differences" msgstr "Perbedaan Berkas" msgid "File Saved" msgstr "Berkas Tersimpan" #, python-format msgid "File saved to \"%s\"" msgstr "Berkas disimpan di \"%s\"" #, fuzzy msgid "File system change monitoring: disabled because \"cola.inotify\" is false.\n" msgstr "inotify dinonaktifkan karena \"cola.inotify\" ialah false\n" msgid "File system change monitoring: disabled because libc does not support the inotify system calls.\n" msgstr "" msgid "File system change monitoring: disabled because pywin32 is not installed.\n" msgstr "" msgid "" "File system change monitoring: disabled because the limit on the total number of inotify watches was reached. You may be able to increase the limit on the number of watches by running:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" msgstr "" #, fuzzy msgid "File system change monitoring: enabled.\n" msgstr "Pemberitahuan berkas diaktifkan.\n" msgid "Filename" msgstr "Namaberkas" msgid "Files" msgstr "Berkas" #, fuzzy msgid "Filter branches..." msgstr "Ambil..." #, fuzzy msgid "Filter paths..." msgstr "Ambil..." #, fuzzy msgid "Find Files" msgstr "Berkas" msgid "Fixed String" msgstr "String Tetap" msgid "Fixed-Width Font" msgstr "Lebar-Tetap Font" msgid "Fixup" msgstr "" msgid "Fixup Previous Commit" msgstr "Perbaiki Commit Sebelumnya" msgid "Flat dark blue" msgstr "" msgid "Flat dark green" msgstr "" msgid "Flat dark grey" msgstr "" msgid "Flat dark red" msgstr "" msgid "Flat light blue" msgstr "" msgid "Flat light green" msgstr "" msgid "Flat light grey" msgstr "" msgid "Flat light red" msgstr "" msgid "Font Size" msgstr "Ukuran Font" #, fuzzy msgid "Force" msgstr "Paksa Push" msgid "Force Fetch" msgstr "Paksa Fetch" msgid "Force Fetch?" msgstr "Paksa Fetch?" msgid "Force Push" msgstr "Paksa Push" msgid "Force Push?" msgstr "Paksa Push?" #, python-format msgid "Force fetching from %s?" msgstr "Paksa fetch dari %s?" #, python-format msgid "Force push to %s?" msgstr "Paksa push ke %s?" #, fuzzy msgid "Format String" msgstr "String Tetap" msgid "French translation" msgstr "" msgid "GPG-sign the merge commit" msgstr "" msgid "GUI theme" msgstr "" #, python-format msgid "Gathering info for \"%s\"..." msgstr "Mengumpulkan info untuk \"%s\"..." msgid "German translation" msgstr "" msgid "Get Commit Message Template" msgstr "Ambil Templat Pesan Commit" msgid "Go Down" msgstr "Ke Bawah" msgid "Go Up" msgstr "Ke Atas" msgid "Grab File..." msgstr "Ambil Berkas..." msgid "Graph" msgstr "Grafik" msgid "Grep" msgstr "Grep" msgid "Have you rebased/pulled lately?" msgstr "Sudahkan Anda rebase/tarik baru-baru ini?" msgid "Help" msgstr "Bantuan" msgid "Help - Custom Copy Actions" msgstr "" msgid "Help - Find Files" msgstr "" msgid "Help - git-xbase" msgstr "" msgid "Hide Details.." msgstr "" msgid "High DPI" msgstr "" msgid "History Browser" msgstr "Penjelajah Histori" msgid "Hungarian translation" msgstr "" msgid "Icon theme" msgstr "" msgid "Ignore all whitespace" msgstr "Abaikan semua spasi" msgid "Ignore changes in amount of whitespace" msgstr "Abaikan perubahan jumlah spasi" msgid "Ignore changes in whitespace at EOL" msgstr "Abaikan perubahan spasi pada EOL" msgid "Ignore custom pattern" msgstr "" #, fuzzy msgid "Ignore exact filename" msgstr "Abaikan semua spasi" msgid "Ignore filename or pattern" msgstr "" msgid "Include tags " msgstr "Sertakan tag " msgid "Indent Status paths" msgstr "" msgid "Indonesian translation" msgstr "" msgid "Initialize Git Annex" msgstr "" msgid "Initialize Git LFS" msgstr "" msgid "Inititalize submodules" msgstr "" msgid "Insert spaces instead of tabs" msgstr "" msgid "Interactive Rebase" msgstr "rebase Interaktif" msgid "Invalid Revision" msgstr "Revisi Salah" msgid "Keep *.orig Merge Backups" msgstr "Biarkan *.orig Merge Backup" msgid "Keep Index" msgstr "Pertahankan Index" msgid "Keyboard Shortcuts" msgstr "Pintasan Papan Tik" msgid "Launch Diff Tool" msgstr "Jalankan Alat Diff" #, fuzzy msgid "Launch Directory Diff Tool" msgstr "Jalankan Alat Diff" msgid "Launch Editor" msgstr "Jalankan Penyunting" msgid "Launch Terminal" msgstr "Jalankan Terminal" msgid "" "Launch external diff tool\n" "Shortcut: Ctrl+D" msgstr "" msgid "Launch git-cola" msgstr "Jalankan git-cola" #, fuzzy msgid "Launch git-difftool against previous versions" msgstr "Jalankan git-difftool pada versi sebelumnya." #, fuzzy msgid "Launch git-difftool on the current path" msgstr "Jalankan git-difftool pada lokasi saat ini." msgid "Light Theme" msgstr "" msgid "Load Commit Message" msgstr "Muat Pesan Commit" msgid "Load Commit Message..." msgstr "Muat Pesan Commit..." msgid "Load Previous Commit Message" msgstr "Muat Pesan Commit Sebelumnya" msgid "Loading..." msgstr "Memuat..." msgid "Local" msgstr "Lokal" msgid "Local Branch" msgstr "Cabang Lokal" msgid "Local branch" msgstr "Cabang Lokal" msgid "Lock Layout" msgstr "Kunci Tata Letak" msgid "Log" msgstr "Log" msgid "Maintainer (since 2007) and developer" msgstr "" msgid "Merge" msgstr "Merge" #, python-format msgid "Merge \"%(revision)s\" into \"%(branch)s\"" msgstr "Merge \"%(revision)s\" ke \"%(branch)s\"" msgid "Merge Tool" msgstr "Alat Merger" msgid "Merge Verbosity" msgstr "Verbositas Merge" msgid "Merge failed. Conflict resolution is required." msgstr "" #, python-format msgid "Merge into \"%s\"" msgstr "Merge ke \"%s\"" #, fuzzy msgid "Merge into current branch" msgstr "Jelajah Cabang Saat ini..." msgid "Merge..." msgstr "Gabung..." msgid "Merging" msgstr "Menggabungkan" msgid "Message" msgstr "Pesan" msgid "Missing Commit Message" msgstr "Pesan Commit Tidak Ada" msgid "Missing Data" msgstr "Data Hilang" msgid "Missing Name" msgstr "Nama Tidak Ditemukan" msgid "Missing Revision" msgstr "Revisi Tidak Ditemukan" msgid "Missing Tag Message" msgstr "Pesan Tag Tidak Ditemukan" msgid "Modified" msgstr "Berubah" msgid "More..." msgstr "Lanjut..." msgid "Move Down" msgstr "Pindah Ke Bawah" msgid "Move Up" msgstr "Pindah Ke Atas" msgid "Move files to trash" msgstr "" msgid "Name" msgstr "Nama" msgid "Name for the new remote" msgstr "Nama untuk hulu baru" #, fuzzy msgid "New Bare Repository..." msgstr "Repositori Baru..." msgid "New Repository..." msgstr "Repositori Baru..." msgid "New..." msgstr "Baru..." #, fuzzy msgid "Next File" msgstr "Pilih Berkas" msgid "No" msgstr "Tidak" msgid "No Revision Specified" msgstr "Revisi tidak Ditentukan" msgid "" "No changes to commit.\n" "\n" "You must stage at least 1 file before you can commit." msgstr "" "Tidak ada perubahan untuk dicommit.\n" "\n" "Anda harus menstag setidaknya 1 berkas sebelum Anda commit." msgid "No commits exist in this branch." msgstr "Tidak ada commit di cabang ini." #, fuzzy msgid "No fast forward" msgstr "Hanya Fast Forward" #, fuzzy msgid "No fast-forward" msgstr "Hanya Fast Forward" msgid "No repository selected." msgstr "Tidak ada repositori terpilih" msgid "Non-fast-forward fetch overwrites local history!" msgstr "Nonfast-forward fetch menimpa histori lokal!" msgid "" "Non-fast-forward push overwrites published history!\n" "(Did you pull first?)" msgstr "" "Non-fast-forward push menimpa histori terpublikasi!\n" "(Apakah sudah ditarik sebelumnya?)" msgid "Nothing to commit" msgstr "Tidak ada yang dicommit" msgid "Nothing to do" msgstr "Tak ada yang perlu dilakukan" msgid "Number of Diff Context Lines" msgstr "Jumlah Baris Context Diff" msgid "Open" msgstr "Buka" msgid "Open Git Repository..." msgstr "Bukan Repositori Git..." #, fuzzy msgid "Open Parent" msgstr "Buka yang Terkini" msgid "Open Parent Directory" msgstr "Bukan Direktori di Atasnya" msgid "Open Recent" msgstr "Buka yang Terkini" msgid "Open Using Default Application" msgstr "Buka dengan Aplikasi Bawaan" msgid "Open in New Window" msgstr "Bukan di Jendela Baru" msgid "Open in New Window..." msgstr "Buka di Jendela Baru..." msgid "Open..." msgstr "Buka..." #, fuzzy msgid "Other branches" msgstr "Ambil..." msgid "Overwrite" msgstr "Timpa" #, python-format msgid "Overwrite \"%s\"?" msgstr "Timpa \"%s\"" msgid "Overwrite File?" msgstr "Timpa Berkas?" msgid "" "Parse arguments using a shell.\n" "Queries with spaces will require \"double quotes\"." msgstr "" "Uraikan argumen menggunakan sebuah shell.\n" "Queri dengan spasi memerlukan \"tanda kutip dua\"." msgid "Partially Staged" msgstr "Sebagian Stagged" msgid "Paste" msgstr "" msgid "Patch(es) Applied" msgstr "Patch Diterapkan" msgid "Path" msgstr "" msgid "Path or URL to clone (Env. $VARS okay)" msgstr "Lokasi atau URL untuk kloning (Env. $VARS oke)" msgid "Pick" msgstr "" msgid "Pixel XOR" msgstr "" msgid "Please provide both a branch name and revision expression." msgstr "Silahkan tentukan nama cabang dan ekspresi revisi." msgid "Please select a file" msgstr "Silahkan pilih berkas" msgid "Please specify a name for the new tag." msgstr "Silahkan tentukan nama untuk tag baru." msgid "Please specify a revision to tag." msgstr "Tentukan revisi untuk di-tag" msgid "" "Please supply a commit message.\n" "\n" "A good commit message has the following format:\n" "\n" "- First line: Describe in one sentence what you did.\n" "- Second line: Blank\n" "- Remaining lines: Describe why this change is good.\n" msgstr "" "Silahkan lengkapi pesan commit.\n" "\n" "Pesan commit yang baik memiliki format berikut:\n" "\n" "- Baris pertama: Jelaskan dalam satu kalimat apa yang telah Anda lakukan.\n" "- Baris kedua: Kosong\n" "- Baris selanjutnya : Jelaskan mengapa perubahan ini bagus.\n" msgid "Point the current branch head to a new commit?" msgstr "" msgid "Polish translation" msgstr "" msgid "Pop" msgstr "" msgid "Preferences" msgstr "Preferensi" msgid "Prefix" msgstr "Awalan" #, fuzzy msgid "Prepare Commit Message" msgstr "Cari Pesan Commit" msgid "Prevent \"Stage\" from staging all files when nothing is selected" msgstr "" msgid "Previous File" msgstr "" msgid "Prompt on creation" msgstr "" #, fuzzy msgid "Prompt when pushing creates new remote branches" msgstr "Buat cabang baru di hulu?" msgid "Prune " msgstr "" #, fuzzy msgid "Pull" msgstr "Tarik..." msgid "Pull..." msgstr "Tarik..." msgid "Push" msgstr "Push" msgid "Push..." msgstr "Tekan..." msgid "Quit" msgstr "Tutup" msgid "Rebase" msgstr "Rebase" #, python-format msgid "Rebase onto %s" msgstr "Rebase ke %s" #, fuzzy msgid "Rebase stopped" msgstr "Rebase" msgid "Rebase the current branch instead of merging" msgstr "" msgid "Rebasing" msgstr "Me-rebase" #, fuzzy msgid "Recent" msgstr "Reset" #, fuzzy msgid "Recent repositories" msgstr "Semua Repositori" #, fuzzy msgid "Recent repository count" msgstr "Semua Repositori" msgid "Recently Modified Files" msgstr "Berkas yang Baru Dimodifikasi" msgid "Recently Modified Files..." msgstr "Berkas Baru Dimodifikasi..." msgid "Recovering a dropped stash is not possible." msgstr "Tidak mungkin mengembalikan stash yang dibuang." msgid "Recovering lost commits may not be easy." msgstr "Mengembalikan commit yang hilang tidak akan mudah." msgid "Redo" msgstr "" msgid "Reduce commit history to minimum" msgstr "" msgid "Refresh" msgstr "Segarkan" msgid "Refuse to merge unless the current HEAD is already up-to-date or the merge can be resolved as a fast-forward" msgstr "" msgid "Remote" msgstr "Hulu" msgid "Remote Branch" msgstr "Cabang Hulu" msgid "Remote Branch Deleted" msgstr "Cabang Hulu Dihapus" msgid "Remote git repositories - double-click to rename" msgstr "Repositori hulu git - dobel-klik untuk mengganti nama" msgid "Remove" msgstr "Hapus" #, python-format msgid "Remove %s from the recent list?" msgstr "" #, fuzzy msgid "Remove Element" msgstr "Hapus" msgid "Remove remote-tracking branches that no longer exist on the remote" msgstr "" msgid "Remove selected (Delete)" msgstr "Hapus yang terpilih (Hapus)" msgid "Rename" msgstr "Ganti nama" #, fuzzy, python-format msgid "Rename \"%s\"" msgstr "Ganti nama" #, fuzzy msgid "Rename Branch" msgstr "Cabang Hulu" #, fuzzy msgid "Rename Branch..." msgstr "Cabang Hulu" #, fuzzy msgid "Rename Existing Branch" msgstr "Perbarui Cabang yang Ada:" msgid "Rename Remote" msgstr "Ganti Nama Hulu" #, fuzzy msgid "Rename Repository" msgstr "Repositori Saat Ini" #, fuzzy msgid "Rename branch" msgstr "Cabang Hulu" #, python-format msgid "Rename remote \"%(current)s\" to \"%(new)s\"?" msgstr "Ganti nama hulu \"%(current)s\" ke \"%(new)s\"?" #, fuzzy msgid "Rename selected paths" msgstr "Sunting lokasi terpilih" #, python-format msgid "Repository: %s" msgstr "Repositori: %s" msgid "Reset" msgstr "Reset" #, python-format msgid "Reset \"%(branch)s\" to \"%(revision)s\"?" msgstr "Atur Ulang \"%(branch)s\" ke \"%(revision)s\"?" msgid "Reset Branch" msgstr "Atur Ulang Cabang" #, fuzzy msgid "Reset Branch Head" msgstr "Atur Ulang Cabang" msgid "Reset Branch?" msgstr "Atur Ulang Cabang?" #, fuzzy msgid "Reset Hard" msgstr "Atur Ulang Cabang" #, fuzzy msgid "Reset Merge" msgstr "Revisi untuk Dimerge" #, fuzzy msgid "Reset Soft" msgstr "Reset" msgid "Reset Worktree" msgstr "" #, fuzzy msgid "Reset hard?" msgstr "Atur Ulang Cabang?" #, fuzzy msgid "Reset merge?" msgstr "Atur Ulang Cabang?" #, fuzzy msgid "Reset soft?" msgstr "Reset" msgid "Reset worktree?" msgstr "" #, python-format msgid "Resetting \"%(branch)s\" to \"%(revision)s\" will lose commits." msgstr "Mengatur ulang \"%(branch)s\" ke \"%(revision)s\" akan menghilangkan commit." msgid "Restart the application after changing appearance settings." msgstr "" msgid "Revert" msgstr "" msgid "Revert Diff Hunk" msgstr "Kembalikan Area Diff" msgid "Revert Diff Hunk..." msgstr "Kembalikan Area Diff..." msgid "Revert Diff Hunk?" msgstr "Kembalikan Area Diff?" msgid "Revert Selected Lines" msgstr "Kembalikan Baris Terpilih" msgid "Revert Selected Lines..." msgstr "Kembalikan Baris Terpilih..." msgid "Revert Selected Lines?" msgstr "Kembalikan Baris Terpilih?" msgid "Revert Uncommitted Changes" msgstr "Kembalikan Perubahan Tak Tercommit" msgid "Revert Uncommitted Changes?" msgstr "Kembalikan Perubahan Tak Tercommit?" #, fuzzy msgid "Revert Uncommitted Edits..." msgstr "Kembalikan Suntingan Belum dicommmit..." msgid "Revert Unstaged Changes" msgstr "Kembalikan Perubahan Belum Distag" msgid "Revert Unstaged Changes?" msgstr "Kembalikan Perubahan Belum Distag?" msgid "Revert Unstaged Edits..." msgstr "Kembalikan Suntingan tak distag..." msgid "Revert the uncommitted changes?" msgstr "Kembalikan perubahan tak tercommit?" msgid "Revert the unstaged changes?" msgstr "Kembalikan perubahan belum distag?" #, fuzzy msgid "Revert uncommitted changes to selected paths" msgstr "Kembalikan perubahan ke lokasi terpilih." #, fuzzy msgid "Revert unstaged changes to selected paths" msgstr "Kembalikan perubahan ke lokasi terpilih." msgid "Review" msgstr "Tinjau" msgid "Review..." msgstr "Pratampil..." msgid "Revision" msgstr "Revisi" msgid "Revision Expression:" msgstr "Ekspresi Revisi:" msgid "Revision to Merge" msgstr "Revisi untuk Dimerge" msgid "Reword" msgstr "" msgid "Rewrite Published Commit?" msgstr "Tulis Ulang Penerbit Commit?" msgid "Run" msgstr "Jalankan" #, python-format msgid "Run \"%s\"?" msgstr "Jalankan \"%s\"?" #, python-format msgid "Run %s?" msgstr "Jalankan %s?" #, python-format msgid "Run the \"%s\" command?" msgstr "Jalankan perintah \"%s\"?" #, python-format msgid "Running command: %s" msgstr "Menjalankan perintah: %s" msgid "Russian translation" msgstr "" #, fuzzy msgid "SHA-1" msgstr "Salin SHA-1" #, fuzzy msgid "Safe Mode" msgstr "Stage Berubah" msgid "Save" msgstr "Simpan" msgid "Save Archive" msgstr "Simpan Arsip" msgid "Save As Tarball/Zip..." msgstr "Simpan Sebagai Tarball/Zip.." msgid "Save GUI Settings" msgstr "Simpan Pengaturan GUI" msgid "Save Stash" msgstr "Simpan Stash" msgid "Save modified state to new stash" msgstr "Simpan perubahan ke stash baru" #, python-format msgid "Saved \"%(filename)s\" from \"%(ref)s\" to \"%(destination)s\"" msgstr "Simpan \"%(filename)s\" dari \"%(ref)s\" ke \"%(destination)s\"" msgid "Search" msgstr "Cari" msgid "Search Authors" msgstr "Cari Penulis" msgid "Search Commit Messages" msgstr "Cari Pesan Commit" msgid "Search Committers" msgstr "Cari Commiter" msgid "Search Date Range" msgstr "Cari Rentang Tanggal" msgid "Search Diffs" msgstr "Cari Diff" msgid "Search by Expression" msgstr "Cari berdasarkan Ekspresi" msgid "Search by Path" msgstr "Cari berdasarkan Lokasi" msgid "Search for a fixed string" msgstr "Cari teks tetap" msgid "Search using a POSIX basic regular expression" msgstr "Cari menggunakan ekspresi reguler POSIX dasar" msgid "Search using a POSIX extended regular expression" msgstr "Cari menggunakan ekspresi reguler POSIX perluasan" msgid "Search..." msgstr "Cari..." msgid "Select" msgstr "Pilih" msgid "Select All" msgstr "Pilih Semua" msgid "Select Branch to Review" msgstr "Pilih Cabang untuk Ditinjau" msgid "Select Child" msgstr "Pilih Anakan" msgid "Select Commit" msgstr "Pilih Commit" #, fuzzy msgid "Select Directory..." msgstr "Pilih Repository..." msgid "Select New Upstream" msgstr "Pilih Upstream Baru" msgid "Select Newest Child" msgstr "Pilih Anakan Terbaru" msgid "Select Oldest Parent" msgstr "Pilih Indukan Tertua" msgid "Select Parent" msgstr "Pilih Indukan" msgid "Select Previous Version" msgstr "Pilih Versi Sebelumnya" msgid "Select Repository..." msgstr "Pilih Repository..." msgid "Select a parent directory for the new clone" msgstr "Pilih direktori di atasnya untuk klon baru" msgid "Select manually..." msgstr "Pilih secara manual..." #, fuzzy msgid "Select output dir" msgstr "Pilih Commit" #, fuzzy msgid "Select output directory" msgstr "Pilih Repository..." #, fuzzy msgid "Select patch file(s)..." msgstr "Pilih berkas patch..." #, fuzzy msgid "Select repository" msgstr "Pilih Repository..." #, fuzzy msgid "Set Default Repository" msgstr "Pilih Repository..." #, fuzzy msgid "Set Upstream Branch" msgstr "Pilih Upstream Baru" msgid "" "Set the sort order for branches and tags.\n" "Toggle between date-based and version-name-based sorting." msgstr "" #, fuzzy msgid "Set upstream" msgstr "Pilih Upstream Baru" msgid "Settings" msgstr "Pengaturan" msgid "Shell arguments" msgstr "Argumen shell" msgid "Shift Down" msgstr "" msgid "Shift Up" msgstr "" msgid "Shortcuts" msgstr "Pintasan" #, fuzzy msgid "Show Details..." msgstr "Hapus Berkas...?" msgid "Show Diffstat After Merge" msgstr "Tampilkan Diffstat setelah Merge" msgid "Show Full Paths in the Window Title" msgstr "" #, fuzzy msgid "Show Help" msgstr "Bantuan" msgid "Show History" msgstr "Tunjukan sejarah" msgid "Show file counts in Status titles" msgstr "" msgid "" "Show help\n" "Shortcut: ?" msgstr "" msgid "Show icon? (if available)" msgstr "" msgid "Show line numbers" msgstr "" msgid "Show whole surrounding functions of changes" msgstr "Tampilkan seluruh sekitar fungsi perubahan" msgid "Showing changes since" msgstr "Menampilkan perubahan sejak" msgid "Side by side" msgstr "" msgid "Sign Off" msgstr "Sign Off" msgid "Sign Tag" msgstr "Tandai Tag" msgid "Sign off on this commit" msgstr "Tanda tangani commit ini" msgid "Simplified Chinese translation" msgstr "" msgid "Skip" msgstr "" msgid "Skip Current Patch" msgstr "Lewati Cabang Saat Ini" msgid "Sort bookmarks alphabetically" msgstr "" msgid "Spanish translation" msgstr "" msgid "Specifies the SHA-1 to tag" msgstr "Tentukan SHA-1 untuk di-tag" msgid "Specifies the tag message" msgstr "Tentukan pesan tag" msgid "Specifies the tag name" msgstr "Tentukan nama tag" msgid "Spelling Suggestions" msgstr "Saran Ejaan" msgid "Squash" msgstr "Squash" msgid "Squash the merged commits into a single commit" msgstr "" msgid "Stage" msgstr "Stage" msgid "Stage / Unstage" msgstr "Stage / Unstage" msgid "Stage All Untracked" msgstr "Stage Semua yang tak terlacak" msgid "Stage Changed Files To Commit" msgstr "Stage Berkas yang Berubah untuk di-commit" msgid "Stage Diff Hunk" msgstr "Stage Area Diff" msgid "Stage Modified" msgstr "Stage Berubah" msgid "Stage Selected" msgstr "Stage Terpilih" #, fuzzy msgid "Stage Selected Lines" msgstr "Stage Batis &Terpilih" msgid "Stage Unmerged" msgstr "Stage Tak Termerge" msgid "Stage Untracked" msgstr "Stage Tak Terlacak" msgid "Stage and Commit" msgstr "Stage dan Commit" msgid "Stage and commit?" msgstr "Stage dan commit?" #, fuzzy msgid "Stage conflicts" msgstr "Stage dan commit?" #, fuzzy msgid "Stage conflicts?" msgstr "Stage dan commit?" #, fuzzy msgid "Stage/unstage selected paths for commit" msgstr "Stage lokasi terpilih untuk commit" msgid "Staged" msgstr "Stagged" #, python-format msgid "Staging: %s" msgstr "Staging: %s" msgid "Start Interactive Rebase..." msgstr "Mulai Rebase Interaktif..." msgid "Starting Revision" msgstr "Memulai Revisi" msgid "Stash" msgstr "Stash" #, fuzzy msgid "Stash Index" msgstr "Stash" #, fuzzy msgid "Stash staged changes only" msgstr "Commit perubahan stage" #, fuzzy msgid "Stash unstaged changes only, keeping staged changes" msgstr "Kembalikan perubahan ke lokasi terpilih." msgid "Stash..." msgstr "Stash..." msgid "Status" msgstr "Status" msgid "Stop tracking paths" msgstr "Hentikan melacak lokasi" msgid "Submodules" msgstr "" msgid "Summarize Merge Commits" msgstr "Ringkasan Merge Commit" msgid "Summary" msgstr "Ringkasan" msgid "Tab Width" msgstr "Lebar Tab" msgid "Tag" msgstr "Tag" msgid "Tag Created" msgstr "Tag Telah Dibuat" msgid "Tag message..." msgstr "Pesan tag..." msgid "Tag-signing was requested but the tag message is empty." msgstr "Penandaan tag diperlukan tetapi pesan tag kosong." msgid "Tags" msgstr "" msgid "Text Width" msgstr "Lebar Teks" msgid "The branch will be no longer available." msgstr "" #, python-format msgid "The branch will be reset using \"git reset --hard %s\"" msgstr "" #, python-format msgid "The branch will be reset using \"git reset --merge %s\"" msgstr "" #, python-format msgid "The branch will be reset using \"git reset --mixed %s\"" msgstr "" #, python-format msgid "The branch will be reset using \"git reset --soft %s\"" msgstr "" #, fuzzy msgid "The commit message will be cleared." msgstr "Berkas berikut akan dihapus:" #, python-format msgid "The file \"%s\" exists and will be overwritten." msgstr "Berkas \"%s\" sudah ada dan akan ditimpa." msgid "The following files will be deleted:" msgstr "Berkas berikut akan dihapus:" msgid "The revision expression cannot be empty." msgstr "Ekspresi revisi tidak boleh kosong." #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be reset using \"git reset --keep %s\"" msgstr "" msgid "This cannot be undone. Clear commit message?" msgstr "" msgid "" "This commit has already been published.\n" "This operation will rewrite published history.\n" "You probably don't want to do this." msgstr "" "Commit ini telah diterbitkan.\n" "Operasi ini akan menulis ulang sejarah publikasi.\n" "Mungkin Anda tidak ingin melakukan ini." #, fuzzy msgid "" "This operation drops uncommitted changes.\n" "These changes cannot be recovered." msgstr "" "Operasi ini akan menghilangkan perubahan tak tercommit.\n" "Perubahan ini tidak dapat direkoveri." msgid "" "This operation removes uncommitted edits from selected files.\n" "These changes cannot be recovered." msgstr "" "Operasi ini akan menghilangkan perubahan tak tercommit.\n" "Perubahan ini tidak dapat direkoveri." msgid "" "This operation removes unstaged edits from selected files.\n" "These changes cannot be recovered." msgstr "" "Operasi ini membuang perubahan belum distag.\n" "Perubahan ini tidak dapat dikembalikan" msgid "" "This repository is currently being rebased.\n" "Resolve conflicts, commit changes, and run:\n" " Rebase > Continue" msgstr "" "Repositori ini sedang direbase.\n" "Perbaiki konflik, commitkan perubahan, dan jalankan:\n" " Rebase > Lanjutkan" msgid "" "This repository is in the middle of a merge.\n" "Resolve conflicts and commit changes." msgstr "" "Repositori ini sedang dimerge.\n" "Perbaiki konflik dan commitkan perubahan." msgid "Toggle Enabled" msgstr "" msgid "Toggle the branches filter" msgstr "" msgid "Toggle the paths filter" msgstr "" msgid "Tracking Branch" msgstr "Melacak Cabang" msgid "Tracking branch" msgstr "Melacak cabang" msgid "Traditional Chinese (Taiwan) translation" msgstr "" msgid "Translators" msgstr "" msgid "Turkish translation" msgstr "" msgid "URL" msgstr "URL" #, python-format msgid "URL: %s" msgstr "URL: %s" msgid "Ukranian translation" msgstr "" msgid "Unable to rebase" msgstr "" #, python-format msgid "Unable to set URL for \"%(name)s\" to \"%(url)s\"" msgstr "" msgid "Undo" msgstr "" msgid "Unmerged" msgstr "Tak termerjer" msgid "Unstage" msgstr "Unstage" msgid "Unstage All" msgstr "Unstage Semua" msgid "Unstage Diff Hunk" msgstr "Unstage Area Diff" msgid "Unstage From Commit" msgstr "Unstage dari Commit" msgid "Unstage Selected" msgstr "Unstage Terpilih" #, fuzzy msgid "Unstage Selected Lines" msgstr "Unstage Baris &Terpilih" #, python-format msgid "Unstaging: %s" msgstr "Unstaging: %s" msgid "Untrack Selected" msgstr "Jangan Lacak Terpilih" msgid "Untracked" msgstr "Tak Terlacak" #, python-format msgid "Untracking: %s" msgstr "Untracking: %s" msgid "Update All Submodules..." msgstr "" msgid "Update Existing Branch:" msgstr "Perbarui Cabang yang Ada:" msgid "Update Submodule" msgstr "" msgid "Update Submodule..." msgstr "" msgid "Update Submodules" msgstr "" msgid "Update all submodules?" msgstr "" msgid "Update submodules..." msgstr "" msgid "Update this submodule" msgstr "" msgid "Update this submodule?" msgstr "" msgid "Updating" msgstr "Sedang memperbarui" msgid "User Name" msgstr "Nama Pengguna" #, fuzzy msgid "Version" msgstr "Revisi" msgid "View" msgstr "Tampil" msgid "View History..." msgstr "Tampilkan Histori..." #, fuzzy msgid "View history for selected paths" msgstr "Tampilkan histori untuk lokasi terpilih" msgid "Visualize" msgstr "Visualisasikan" msgid "Visualize All Branches..." msgstr "Visualisasikan Semua Cabang..." msgid "Visualize Current Branch..." msgstr "Visualisasikan Cabang Saat ini..." msgid "Whether to sign the tag (git tag -s)" msgstr "Kalau menandai tag (git tag -s)" msgid "Would you like to stage and commit all modified files?" msgstr "Apakah Anda ingin menstage dan commit semua berkas yang berubah?" msgid "XOR" msgstr "" msgid "Yes" msgstr "" msgid "" "You are in the middle of a merge.\n" "Cannot amend while merging." msgstr "" "Anda sedang melakukan merjer.\n" "Tidak dapat mengubah ketika merjer" #, fuzzy msgid "You cannot rebase with uncommitted changes." msgstr "Kembalikan perubahan tak tercommit?" msgid "You must specify a revision to merge." msgstr "Anda harus tentukan revisi untuk dimerge." msgid "You must specify a revision to view." msgstr "Anda harus tentukan revisi untuk ditampilkan." msgid "Zoom In" msgstr "Perbesar" msgid "Zoom Out" msgstr "Perkecil" msgid "Zoom to Fit" msgstr "Zoom agar Sesuai" msgid "command-line arguments" msgstr "argumen baris-perintah" msgid "error: unable to execute git" msgstr "" #, python-format msgid "exit code %s" msgstr "kode keluar %s" #, fuzzy, python-format msgid "fatal: \"%s\" is not a directory. Please specify a correct --repo ." msgstr "fatal: \"%s\" bukan direktori. Silahkan tentukan --repo ." #, python-format msgid "git cola version %s" msgstr "git cola versi %s" msgid "git-cola" msgstr "git-cola" msgid "git-cola diff" msgstr "git-cola diff" msgid "grep result..." msgstr "hasil grep..." msgid "hotkeys.html" msgstr "hotkeys.html" msgid "unknown" msgstr "tidak diketahui" msgid "vX.Y.Z" msgstr "vX.Y.Z" msgid "x 1" msgstr "" msgid "x 1.5" msgstr "" msgid "x 2" msgstr "" msgid "yyyy-MM-dd" msgstr "dd-MM-yyyy" #, fuzzy #~ msgid "\"%s\" returned exit status %d" #~ msgstr "\"%(command)s\" keluar dengan status %(status)d" #~ msgid "\"git commit\" returned exit code %s" #~ msgstr "\"git commit\" returned exit code %s" #~ msgid "Already up-to-date." #~ msgstr "Sudah up-to-date." #~ msgid "Apply Diff Selection to Work Tree" #~ msgstr "Terapkan Diff Terpilih ke Work Tree" #~ msgid "Bookmarks" #~ msgstr "Markah" #~ msgid "Bookmarks..." #~ msgstr "Markah..." #~ msgid "Commit failed: %s" #~ msgstr "Commit gagal: %s" #~ msgid "Created commit: %s" #~ msgstr "Buat commit: %s" #~ msgid "Enter Git Repository" #~ msgstr "Masukkan Repositori Git" #, fuzzy #~ msgid "Error %s" #~ msgstr "Error: %s" #~ msgid "Errors: %s" #~ msgstr "Error: %s" #~ msgid "Exit code: %s" #~ msgstr "Kode exit: %s" #~ msgid "Fast Forward Only " #~ msgstr "Hanya Fast Forward" #~ msgid "Filter" #~ msgstr "Saring" #~ msgid "GPG-signed" #~ msgstr "tandatangan-GPG" #, fuzzy #~ msgid "Local Branches" #~ msgstr "Cabang Lokal" #~ msgid "No files selected for checkout from HEAD." #~ msgstr "Tidak ada berkas terpilih untuk checkout dari HEAD." #, fuzzy #~ msgid "On Debian-based systems try: sudo apt-get install python-pyinotify" #~ msgstr "Pada sistem Debian: sudo apt-get install python-pyinotify" #~ msgid "Options" #~ msgstr "Pilihan" #~ msgid "" #~ "Output:\n" #~ "%s" #~ msgstr "" #~ "Keluaran:\n" #~ "%s" #~ msgid "Output: %s" #~ msgstr "Keluaran: %s" #~ msgid "PATCH %(current)d/%(count)d" #~ msgstr "PATCH %(current)d/%(count)d" #~ msgid "Path to git repository" #~ msgstr "Lokasi repositori git" #~ msgid "Process Diff Hunk" #~ msgstr "Proses Area Diff" #~ msgid "Process Selection" #~ msgstr "Proses Pilihan" #, fuzzy #~ msgid "Remote Branches" #~ msgstr "Cabang Hulu" #~ msgid "Remove selected paths from the staging area" #~ msgstr "Buang lokasi terpilih dari staging area" #~ msgid "Rename remote?" #~ msgstr "Ganti nama hulu?" #~ msgid "Revert Uncommitted Changes..." #~ msgstr "Kembalikan Perubahan Tak Tercommit..." #~ msgid "Select File" #~ msgstr "Pilih Berkas" #~ msgid "Select file from \"%s\"" #~ msgstr "Pilih berkas dari \"%s\"" #~ msgid "Staging Area" #~ msgstr "Area Stagnan" #~ msgid "Summary:" #~ msgstr "Ringkasan:" #~ msgid "" #~ "This PyQt4 does not include QtWebKit.\n" #~ "The keyboard shortcuts feature is unavailable." #~ msgstr "" #~ "PyQt4 ini tidak menyertakan QtWebKit.\n" #~ "Fitur pintasan papan tik tak tersedia." #~ msgid "Updating..." #~ msgstr "Memperbarui..." #~ msgid "" #~ "file notification: disabled\n" #~ "Note: install pywin32 to enable.\n" #~ msgstr "" #~ "berkas pemberitahuan: dinonaktifkan\n" #~ "Catatan: install pywin32 untuk mengaktifkan.\n" #~ msgid "git clone returned exit code %s" #~ msgstr "git clone keluar kode %s" #~ msgid "git tag returned exit code %s" #~ msgstr "git tag menghasilkan kode exit %s" #~ msgid "inotify enabled." #~ msgstr "inotify diaktifkan." #~ msgid "" #~ "inotify: disabled\n" #~ "Note: install python-pyinotify to enable inotify.\n" #~ msgstr "" #~ "inotify: dinonaktifkan\n" #~ "Catatan: install python-pyinotify untuk mengaktifkan inotify.\n" git-cola-3.6/po/it.po000066400000000000000000002167371356743264500145120ustar00rootroot00000000000000# Translation of git-cola to Italian # Copyright (C) 2007 Shawn Pearce at el. # This file is distributed under the same license as the git-cola package. # Paolo Ciarrocchi , 2007 # Michele Ballabio , 2007. # msgid "" msgstr "" "Project-Id-Version: git-cola VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-17 01:06-0700\n" "PO-Revision-Date: 2008-03-12 22:12+0100\n" "Last-Translator: David Aguilar \n" "Language-Team: Italian\n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "" "\n" "

\n" " Drag and drop or use the Add button to add\n" " patches to the list\n" "

\n" " " msgstr "" #, python-format msgid "" "\n" "
\n" " Git Cola has been translated into different languages thanks\n" " to the help of the individuals listed below.\n" "\n" "
\n" "

\n" " Translation is approximate. If you find a mistake,\n" " please let us know by opening an issue on Github:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " We invite you to participate in translation by adding or updating\n" " a translation and opening a pull request.\n" "

\n" "\n" "
\n" "\n" " " msgstr "" #, python-format msgid "" "\n" "
\n" " Git Cola version %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " msgstr "" #, python-format msgid "" "\n" "
\n" " Please use %(bug_link)s to report issues.\n" "
\n" " " msgstr "" #, python-format msgid "" "\n" " Format String Variables\n" " -----------------------\n" " %(path)s = relative file path\n" " %(abspath)s = absolute file path\n" " %(dirname)s = relative directory path\n" " %(absdirname)s = absolute directory path\n" " %(filename)s = file basename\n" " %(basename)s = file basename without extension\n" " %(ext)s = file extension\n" msgstr "" msgid "" "\n" "Commands\n" "--------\n" "pick = use commit\n" "reword = use commit, but edit the commit message\n" "edit = use commit, but stop for amending\n" "squash = use commit, but meld into previous commit\n" "fixup = like \"squash\", but discard this commit's log message\n" "exec = run command (the rest of the line) using shell\n" "\n" "These lines can be re-ordered; they are executed from top to bottom.\n" "\n" "If you disable a line here THAT COMMIT WILL BE LOST.\n" "\n" "However, if you disable everything, the rebase will be aborted.\n" "\n" "Keyboard Shortcuts\n" "------------------\n" "? = show help\n" "j = move down\n" "k = move up\n" "J = shift row down\n" "K = shift row up\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "spacebar = toggle enabled\n" "\n" "ctrl+enter = accept changes and rebase\n" "ctrl+q = cancel and abort the rebase\n" "ctrl+d = launch difftool\n" msgstr "" msgid "" "\n" "Keyboard Shortcuts\n" "------------------\n" "J, Down = Move Down\n" "K, Up = Move Up\n" "Enter = Edit Selected Files\n" "Spacebar = Open File Using Default Application\n" "Ctrl + L = Focus Text Entry Field\n" "? = Show Help\n" "\n" "The up and down arrows change focus between the text entry field\n" "and the results.\n" msgstr "" msgid " - DAG" msgstr "" #, fuzzy msgid " commits ago" msgstr "Messaggio di fusione:" #, python-format msgid "\"%(branch)s\" has been deleted from \"%(remote)s\"." msgstr "" #, python-format msgid "\"%(command)s\" returned exit status \"%(status)d\"" msgstr "" #, python-format msgid "\"%(command)s\" returned exit status %(status)d" msgstr "" #, fuzzy, python-format msgid "\"%s\" already exists" msgstr "Il ramo '%s' esiste già." #, python-format msgid "\"%s\" already exists, cola will create a new directory" msgstr "" #, python-format msgid "\"%s\" requires a selected file." msgstr "" msgid "#" msgstr "" #, python-format msgid "%(project)s: %(branch)s - Browse" msgstr "" #, python-format msgid "%(project)s: %(ref)s - DAG" msgstr "" #, python-format msgid "%d days ago" msgstr "" #, python-format msgid "%d hours ago" msgstr "" #, python-format msgid "%d minutes ago" msgstr "" #, python-format msgid "%d patch(es) applied." msgstr "" #, python-format msgid "%d skipped" msgstr "" #, python-format msgid "" "%s appears to contain merge conflicts.\n" "\n" "You should probably skip this file.\n" "Stage it anyways?" msgstr "" #, fuzzy, python-format msgid "%s is not a Git repository." msgstr "Archivio Git" #, python-format msgid "%s will be removed from your bookmarks." msgstr "" #, python-format msgid "%s will be removed from your recent repositories." msgstr "" #, fuzzy, python-format msgid "%s: No such file or directory." msgstr "errore grave: impossibile effettuare lo stat del path %s: file o directory non trovata" msgid "&Edit" msgstr "Modifica" #, fuzzy msgid "&File" msgstr "&File" msgid "(Amending)" msgstr "" msgid "*** Branch Point ***" msgstr "" msgid "*** Sandbox ***" msgstr "" msgid "100%" msgstr "" msgid "200%" msgstr "" msgid "25%" msgstr "" msgid "400%" msgstr "" msgid "50%" msgstr "" msgid "800%" msgstr "" msgid " ..." msgstr "" msgid "" "A commit template has not been configured.\n" "Use \"git config\" to define \"commit.template\"\n" "so that it points to a commit template." msgstr "" #, python-format msgid "A hook must be provided at \"%s\"" msgstr "" #, fuzzy, python-format msgid "A stash named \"%s\" already exists" msgstr "Il file %s esiste già." #, fuzzy msgid "Abort" msgstr "Interruzione" #, fuzzy msgid "Abort Action" msgstr "Interruzione" #, fuzzy msgid "Abort Merge" msgstr "Interrompi fusione..." msgid "Abort Merge..." msgstr "Interrompi fusione..." msgid "Abort the action?" msgstr "" #, fuzzy msgid "" "Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" "Recovering uncommitted changes is not possible." msgstr "" "Interrompere fusione?\n" "\n" "L'interruzione della fusione attuale causerà la perdita di *TUTTE* le modifiche non ancora presenti nell'archivio.\n" "\n" "Continuare con l'interruzione della fusione attuale?" msgid "Aborting the current merge?" msgstr "" #, fuzzy msgid "About" msgstr "Informazioni su %s" msgid "About git-cola" msgstr "" msgid "Accept" msgstr "" msgid "" "Accept changes and rebase\n" "Shortcut: Ctrl+Enter" msgstr "" #, fuzzy msgid "Action Name" msgstr "Opzioni" #, fuzzy msgid "Actions" msgstr "Opzioni" #, fuzzy msgid "Actions..." msgstr "Opzioni..." msgid "Add" msgstr "" #, fuzzy msgid "Add Favorite" msgstr "Remoto" #, fuzzy msgid "Add Remote" msgstr "Remoto" msgid "Add Separator" msgstr "" msgid "Add Toolbar" msgstr "" msgid "" "Add and remove remote repositories using the \n" "Add(+) and Delete(-) buttons on the left-hand side.\n" "\n" "Remotes can be renamed by selecting one from the list\n" "and pressing \"enter\", or by double-clicking." msgstr "" #, fuzzy msgid "Add new remote git repository" msgstr "%s non è un archivio Git." msgid "Add patches (+)" msgstr "" #, fuzzy msgid "Add remote" msgstr "Remoto" msgid "Add to .gitignore" msgstr "" msgid "Add to Git Annex" msgstr "" msgid "Add to Git LFS" msgstr "" #, fuzzy msgid "Additions" msgstr "Opzioni" msgid "Advanced" msgstr "" msgid "Age" msgstr "" #, fuzzy msgid "All Repositories" msgstr "Tutti gli archivi" #, python-format msgid "" "All submodules will be updated using\n" "\"%s\"" msgstr "" msgid "Allow non-fast-forward updates. Using \"force\" can cause the remote repository to lose commits; use it with care" msgstr "" msgid "Always create a merge commit when enabled, even when the merge is a fast-forward update" msgstr "" msgid "Amend" msgstr "" #, fuzzy msgid "Amend Commit" msgstr "Correggi l'ultima revisione" msgid "Amend Last Commit" msgstr "Correggi l'ultima revisione" msgid "Amend the published commit?" msgstr "" msgid "Amending" msgstr "" msgid "" "An action is still running.\n" "Terminating it could result in data loss." msgstr "" msgid "" "An unsigned, lightweight tag will be created instead.\n" "Create an unsigned tag?" msgstr "" msgid "Appearance" msgstr "" #, fuzzy msgid "Apply" msgstr "Apple" msgid "Apply Patches" msgstr "" msgid "Apply Patches..." msgstr "" msgid "Apply and drop the selected stash (git stash pop)" msgstr "" msgid "Apply the selected stash" msgstr "" msgid "Arguments" msgstr "" msgid "Attach" msgstr "" #, fuzzy msgid "Author" msgstr "Autore:" #, fuzzy msgid "Authors" msgstr "Autore:" msgid "Auto" msgstr "" msgid "Auto-Wrap Lines" msgstr "" msgid "Basic Regexp" msgstr "" #, fuzzy msgid "Blame Viewer" msgstr "Mostra file" #, fuzzy msgid "Blame selected paths" msgstr "Rinomina ramo" #, fuzzy msgid "Blame..." msgstr "Rinomina" msgid "Bold on dark headers instead of italic" msgstr "" msgid "Branch" msgstr "Ramo" #, python-format msgid "" "Branch \"%(branch)s\" does not exist in \"%(remote)s\".\n" "A new remote branch will be published." msgstr "" #, fuzzy, python-format msgid "Branch \"%s\" already exists." msgstr "Il ramo '%s' esiste già." msgid "Branch Diff Viewer" msgstr "" #, fuzzy msgid "Branch Exists" msgstr "Rami" msgid "Branch Name" msgstr "Nome del ramo" #, fuzzy, python-format msgid "Branch: %s" msgstr "Ramo:" #, fuzzy msgid "Branches" msgstr "Ramo" #, fuzzy msgid "Branches..." msgstr "Rami" msgid "Brazilian translation" msgstr "" #, fuzzy msgid "Browse" msgstr "Esplora" #, fuzzy msgid "Browse Commits..." msgstr "Esplora" #, fuzzy msgid "Browse Current Branch..." msgstr "Esplora i file del ramo attuale" #, fuzzy msgid "Browse Other Branch..." msgstr "Esplora i file del ramo..." #, fuzzy msgid "Browse..." msgstr "Esplora" #, fuzzy msgid "Browser" msgstr "Esplora" #, fuzzy, python-format msgid "Browsing %s" msgstr "Aggiunta di %s in corso" msgid "Bypass Commit Hooks" msgstr "" msgid "Cancel" msgstr "Annulla" msgid "" "Cancel rebase\n" "Shortcut: Ctrl+Q" msgstr "" #, fuzzy msgid "Cannot Amend" msgstr "Impossibile scrivere icona:" #, python-format msgid "Cannot exec \"%s\": please configure a blame viewer" msgstr "" #, python-format msgid "Cannot exec \"%s\": please configure a history browser" msgstr "" #, python-format msgid "Cannot exec \"%s\": please configure your editor" msgstr "" msgid "Changed Upstream" msgstr "" msgid "Check Spelling" msgstr "" msgid "Check spelling" msgstr "" msgid "Checkout" msgstr "Attiva" msgid "Checkout After Creation" msgstr "Attiva dopo la creazione" msgid "Checkout Branch" msgstr "Attiva ramo" #, fuzzy msgid "Checkout Detached HEAD" msgstr "Attiva ramo" #, fuzzy msgid "Checkout as new branch" msgstr "Attiva ramo" msgid "Checkout..." msgstr "Attiva..." msgid "Cherry Pick" msgstr "" #, fuzzy msgid "Cherry-Pick Commit" msgstr "Copia revisione" #, fuzzy msgid "Cherry-Pick..." msgstr "Attiva..." #, fuzzy msgid "Choose Paths" msgstr "Scegli %s" msgid "Choose the \"git grep\" regular expression mode" msgstr "" #, fuzzy msgid "Clear Default Repository" msgstr "Crea nuovo archivio" #, fuzzy msgid "Clear commit message" msgstr "Messaggio di fusione:" #, fuzzy msgid "Clear commit message?" msgstr "Messaggio di fusione:" #, fuzzy msgid "Clear..." msgstr "Clona..." msgid "Clone" msgstr "Clona" #, fuzzy msgid "Clone Repository" msgstr "Clona archivio esistente" msgid "Clone..." msgstr "Clona..." #, fuzzy, python-format msgid "Cloning repository at %s" msgstr "Clona archivio esistente" msgid "Close" msgstr "Chiudi" #, fuzzy msgid "Close..." msgstr "Clona..." #, fuzzy msgid "Collapse all" msgstr "Chiudi" #, fuzzy msgid "Command" msgstr "Revisione:" #, fuzzy msgid "Commit" msgstr "Revisione:" #, fuzzy msgid "Commit failed" msgstr "Impossibile creare una nuova revisione." #, fuzzy msgid "Commit staged changes" msgstr "Archiviazione modifiche..." msgid "" "Commit staged changes\n" "Shortcut: Ctrl+Enter" msgstr "" #, fuzzy msgid "Commit summary" msgstr "Messaggio di revisione:" msgid "Commit the merge if there are no conflicts. Uncheck to leave the merge uncommitted" msgstr "" msgid "Commit@@verb" msgstr "Nuova revisione" msgid "Compare" msgstr "" msgid "Compare All" msgstr "" msgid "Configure the remote branch as the the new upstream" msgstr "" msgid "Configure toolbar" msgstr "" #, fuzzy msgid "Console" msgstr "Chiudi" msgid "Continue" msgstr "Continua" msgid "Copy" msgstr "Copia" msgid "Copy Basename to Clipboard" msgstr "" msgid "Copy Leading Path to Clipboard" msgstr "" msgid "Copy Path to Clipboard" msgstr "" msgid "Copy Relative Path to Clipboard" msgstr "" #, fuzzy msgid "Copy SHA-1" msgstr "Copia tutto" #, fuzzy msgid "Copy..." msgstr "Copia" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "" msgid "Create Branch" msgstr "Crea ramo" #, fuzzy msgid "Create Patch" msgstr "Crea ramo" #, fuzzy msgid "Create Remote Branch" msgstr "Cancella ramo remoto" #, fuzzy msgid "Create Signed Commit" msgstr "Creata revisione %s: %s" #, fuzzy msgid "Create Tag" msgstr "Crea" #, fuzzy msgid "Create Tag..." msgstr "Crea..." msgid "Create Unsigned Tag" msgstr "" msgid "Create a merge commit even when the merge resolves as a fast-forward" msgstr "" #, fuzzy msgid "Create a new remote branch?" msgstr "Crea nuovo ramo" msgid "Create..." msgstr "Crea..." #, python-format msgid "Created a new tag named \"%s\"" msgstr "" #, fuzzy msgid "Current Repository" msgstr "Crea nuovo archivio" msgid "Custom Copy Actions" msgstr "" #, fuzzy msgid "Customize..." msgstr "Clona..." msgid "Cut" msgstr "Taglia" msgid "Czech translation" msgstr "" msgid "DAG..." msgstr "" msgid "Dark Theme" msgstr "" msgid "Date, Time" msgstr "" #, fuzzy msgid "Default" msgstr "Ripristina valori predefiniti" msgid "Delete" msgstr "Elimina" #, fuzzy, python-format msgid "Delete %d file(s)?" msgstr "Elimina" #, fuzzy msgid "Delete Bookmark" msgstr "Elimina ramo" #, fuzzy msgid "Delete Bookmark?" msgstr "Elimina ramo" msgid "Delete Branch" msgstr "Elimina ramo" #, fuzzy msgid "Delete Files" msgstr "Elimina" #, fuzzy msgid "Delete Files..." msgstr "Elimina..." #, fuzzy msgid "Delete Files?" msgstr "Elimina" #, fuzzy msgid "Delete Remote" msgstr "Cancella ramo remoto" #, fuzzy msgid "Delete Remote Branch" msgstr "Cancella ramo remoto" #, fuzzy msgid "Delete Remote Branch..." msgstr "Cancella ramo remoto" #, fuzzy msgid "Delete remote" msgstr "Cancella ramo remoto" #, fuzzy, python-format msgid "Delete remote \"%s\"" msgstr "Cancella ramo remoto" #, fuzzy msgid "Delete remote?" msgstr "Cancella ramo remoto" #, fuzzy msgid "Delete selected branch?" msgstr "Cancella ramo remoto" #, fuzzy msgid "Delete toolbar" msgstr "Elimina ramo" msgid "Delete..." msgstr "Elimina..." #, python-format msgid "Deleting \"%s\" failed" msgstr "" #, fuzzy msgid "Deletions" msgstr "Elimina" #, fuzzy msgid "Detach" msgstr "Elimina ramo" msgid "Detect Conflict Markers" msgstr "" msgid "Detect conflict markers in unmerged files" msgstr "" msgid "Developer" msgstr "" msgid "Diff" msgstr "" msgid "Diff Against Predecessor..." msgstr "" #, fuzzy msgid "Diff Options" msgstr "Opzioni" msgid "Diff Tool" msgstr "" msgid "Diff selected -> this" msgstr "" msgid "Diff this -> selected" msgstr "" msgid "Diffstat" msgstr "" #, fuzzy msgid "Difftool" msgstr "Opzioni" #, fuzzy msgid "Directory Exists" msgstr "Directory:" msgid "Display Untracked Files" msgstr "" #, fuzzy msgid "Documentation" msgstr "Documentazione sul web" msgid "Drop" msgstr "" msgid "Drop Stash" msgstr "" msgid "Drop Stash?" msgstr "" #, python-format msgid "Drop the \"%s\" stash?" msgstr "" msgid "Drop the selected stash" msgstr "" #, fuzzy msgid "Edit" msgstr "Modifica" #, fuzzy msgid "Edit Rebase" msgstr "Ripristina" #, fuzzy msgid "Edit Remotes" msgstr "Remoto" msgid "Edit Remotes..." msgstr "" msgid "Edit remotes by selecting them from the list" msgstr "" msgid "Edit selected paths" msgstr "" #, fuzzy msgid "Edit..." msgstr "Modifica" #, fuzzy msgid "Editor" msgstr "Modifica" msgid "Email Address" msgstr "Indirizzo Email" msgid "Email contributor" msgstr "" msgid "Enabled" msgstr "" #, fuzzy msgid "Enter New Branch Name" msgstr "Nome del ramo" msgid "Enter a name for the new bare repo" msgstr "" msgid "Enter a name for the stash" msgstr "" #, fuzzy msgid "Error" msgstr "errore" #, fuzzy msgid "Error Cloning" msgstr "Errore nel caricamento del file:" #, fuzzy msgid "Error Creating Branch" msgstr "Crea ramo" #, fuzzy msgid "Error Creating Repository" msgstr "Crea nuovo archivio" #, fuzzy msgid "Error Deleting Remote Branch" msgstr "Crea ramo" #, fuzzy msgid "Error Editing File" msgstr "Errore nel caricamento delle differenze:" #, fuzzy msgid "Error Launching Blame Viewer" msgstr "File browser" #, fuzzy msgid "Error Launching History Browser" msgstr "File browser" #, python-format msgid "Error creating remote \"%s\"" msgstr "" #, fuzzy msgid "Error creating stash" msgstr "Crea ramo" #, python-format msgid "Error deleting remote \"%s\"" msgstr "" #, python-format msgid "Error renaming \"%(name)s\" to \"%(new_name)s\"" msgstr "" #, fuzzy msgid "Error running prepare-commitmsg hook" msgstr "Avvio pre-commit hook..." #, fuzzy, python-format msgid "Error updating submodule %s" msgstr "Errore nel caricamento delle differenze:" #, fuzzy msgid "Error updating submodules" msgstr "Errore nel caricamento delle differenze:" msgid "Error: Cannot find commit template" msgstr "" msgid "Error: Stash exists" msgstr "" msgid "Error: Unconfigured commit template" msgstr "" #, python-format msgid "Error: could not clone \"%s\"" msgstr "" #, python-format msgid "Error: could not create tag \"%s\"" msgstr "" #, fuzzy, python-format msgid "Executing action %s" msgstr "Il dizionario è stato reimpostato su %s." msgid "Expand all" msgstr "" msgid "Export Patches" msgstr "" msgid "Export Patches..." msgstr "" #, fuzzy msgid "Expression..." msgstr "Opzioni..." msgid "Extended Regexp" msgstr "" msgid "Extended description..." msgstr "" msgid "Fast Forward Only" msgstr "Solo fast forward" #, fuzzy msgid "Fast-forward only" msgstr "Solo fast forward" #, fuzzy msgid "Favorite repositories" msgstr "Archivi recenti" msgid "Favorites" msgstr "" #, fuzzy msgid "Fetch" msgstr "Ripristina..." msgid "Fetch Tracking Branch" msgstr "Recupera duplicato locale di ramo remoto" #, fuzzy msgid "Fetch..." msgstr "Ripristina..." #, fuzzy msgid "File Browser..." msgstr "Esplora" #, fuzzy msgid "File Differences" msgstr "Preferenze" msgid "File Saved" msgstr "" #, python-format msgid "File saved to \"%s\"" msgstr "" msgid "File system change monitoring: disabled because \"cola.inotify\" is false.\n" msgstr "" msgid "File system change monitoring: disabled because libc does not support the inotify system calls.\n" msgstr "" msgid "File system change monitoring: disabled because pywin32 is not installed.\n" msgstr "" msgid "" "File system change monitoring: disabled because the limit on the total number of inotify watches was reached. You may be able to increase the limit on the number of watches by running:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" msgstr "" #, fuzzy msgid "File system change monitoring: enabled.\n" msgstr "Fidati delle date di modifica dei file\n" #, fuzzy msgid "Filename" msgstr "Rinomina" #, fuzzy msgid "Files" msgstr "File:" #, fuzzy msgid "Filter branches..." msgstr "Ripristina..." #, fuzzy msgid "Filter paths..." msgstr "Ripristina..." #, fuzzy msgid "Find Files" msgstr "File:" msgid "Fixed String" msgstr "" msgid "Fixed-Width Font" msgstr "" msgid "Fixup" msgstr "" #, fuzzy msgid "Fixup Previous Commit" msgstr "Messaggio di fusione:" msgid "Flat dark blue" msgstr "" msgid "Flat dark green" msgstr "" msgid "Flat dark grey" msgstr "" msgid "Flat dark red" msgstr "" msgid "Flat light blue" msgstr "" msgid "Flat light green" msgstr "" msgid "Flat light grey" msgstr "" msgid "Flat light red" msgstr "" msgid "Font Size" msgstr "Dimensione caratteri" msgid "Force" msgstr "" msgid "Force Fetch" msgstr "" msgid "Force Fetch?" msgstr "" msgid "Force Push" msgstr "" msgid "Force Push?" msgstr "" #, fuzzy, python-format msgid "Force fetching from %s?" msgstr "Recupero %s da %s" #, python-format msgid "Force push to %s?" msgstr "" msgid "Format String" msgstr "" msgid "French translation" msgstr "" msgid "GPG-sign the merge commit" msgstr "" msgid "GUI theme" msgstr "" #, fuzzy, python-format msgid "Gathering info for \"%s\"..." msgstr "Caricamento delle differenze di %s..." msgid "German translation" msgstr "" #, fuzzy msgid "Get Commit Message Template" msgstr "Larghezza del messaggio di revisione" msgid "Go Down" msgstr "" msgid "Go Up" msgstr "" msgid "Grab File..." msgstr "" msgid "Graph" msgstr "" msgid "Grep" msgstr "" msgid "Have you rebased/pulled lately?" msgstr "" msgid "Help" msgstr "Aiuto" msgid "Help - Custom Copy Actions" msgstr "" msgid "Help - Find Files" msgstr "" msgid "Help - git-xbase" msgstr "" msgid "Hide Details.." msgstr "" msgid "High DPI" msgstr "" #, fuzzy msgid "History Browser" msgstr "File browser" msgid "Hungarian translation" msgstr "" msgid "Icon theme" msgstr "" msgid "Ignore all whitespace" msgstr "" msgid "Ignore changes in amount of whitespace" msgstr "" msgid "Ignore changes in whitespace at EOL" msgstr "" msgid "Ignore custom pattern" msgstr "" msgid "Ignore exact filename" msgstr "" msgid "Ignore filename or pattern" msgstr "" #, fuzzy msgid "Include tags " msgstr "Includi etichette" msgid "Indent Status paths" msgstr "" msgid "Indonesian translation" msgstr "" #, fuzzy msgid "Initialize Git Annex" msgstr "Inizializzazione..." #, fuzzy msgid "Initialize Git LFS" msgstr "Inizializzazione..." msgid "Inititalize submodules" msgstr "" msgid "Insert spaces instead of tabs" msgstr "" msgid "Interactive Rebase" msgstr "" #, fuzzy msgid "Invalid Revision" msgstr "Revisione non valida: %s" msgid "Keep *.orig Merge Backups" msgstr "" msgid "Keep Index" msgstr "" msgid "Keyboard Shortcuts" msgstr "" msgid "Launch Diff Tool" msgstr "" msgid "Launch Directory Diff Tool" msgstr "" msgid "Launch Editor" msgstr "" msgid "Launch Terminal" msgstr "" msgid "" "Launch external diff tool\n" "Shortcut: Ctrl+D" msgstr "" msgid "Launch git-cola" msgstr "" msgid "Launch git-difftool against previous versions" msgstr "" msgid "Launch git-difftool on the current path" msgstr "" msgid "Light Theme" msgstr "" #, fuzzy msgid "Load Commit Message" msgstr "Messaggio di revisione:" #, fuzzy msgid "Load Commit Message..." msgstr "Messaggio di revisione:" #, fuzzy msgid "Load Previous Commit Message" msgstr "Messaggio di fusione:" #, fuzzy msgid "Loading..." msgstr "Caricamento %s..." msgid "Local" msgstr "" msgid "Local Branch" msgstr "Ramo locale" #, fuzzy msgid "Local branch" msgstr "Ramo locale" msgid "Lock Layout" msgstr "" msgid "Log" msgstr "" msgid "Maintainer (since 2007) and developer" msgstr "" msgid "Merge" msgstr "Fusione (Merge)" #, python-format msgid "Merge \"%(revision)s\" into \"%(branch)s\"" msgstr "" #, fuzzy msgid "Merge Tool" msgstr "Fusione (Merge)" msgid "Merge Verbosity" msgstr "Prolissità della fusione" msgid "Merge failed. Conflict resolution is required." msgstr "Fusione non riuscita. Bisogna risolvere i conflitti." #, fuzzy, python-format msgid "Merge into \"%s\"" msgstr "Fusione in %s" #, fuzzy msgid "Merge into current branch" msgstr "Esplora i file del ramo attuale" #, fuzzy msgid "Merge..." msgstr "Fusione (Merge)" #, fuzzy msgid "Merging" msgstr "Fusione (Merge)" #, fuzzy msgid "Message" msgstr "Fusione (Merge)" #, fuzzy msgid "Missing Commit Message" msgstr "Messaggio di fusione:" #, fuzzy msgid "Missing Data" msgstr "Mancante" #, fuzzy msgid "Missing Name" msgstr "Mancante" #, fuzzy msgid "Missing Revision" msgstr "Revisione iniziale" #, fuzzy msgid "Missing Tag Message" msgstr "Revisione da fondere" #, fuzzy msgid "Modified" msgstr "Non modificato" #, fuzzy msgid "More..." msgstr "Clona..." msgid "Move Down" msgstr "" msgid "Move Up" msgstr "" msgid "Move files to trash" msgstr "" #, fuzzy msgid "Name" msgstr "Nome:" msgid "Name for the new remote" msgstr "" #, fuzzy msgid "New Bare Repository..." msgstr "Archivio Git" #, fuzzy msgid "New Repository..." msgstr "Archivio Git" msgid "New..." msgstr "Nuovo..." #, fuzzy msgid "Next File" msgstr "Seleziona tutto" msgid "No" msgstr "No" #, fuzzy msgid "No Revision Specified" msgstr "Nessuna revisione selezionata." #, fuzzy msgid "" "No changes to commit.\n" "\n" "You must stage at least 1 file before you can commit." msgstr "" "Nessuna modifica per la nuova revisione.\n" "\n" "Devi preparare per una nuova revisione almeno 1 file prima di effettuare questa operazione." msgid "No commits exist in this branch." msgstr "" #, fuzzy msgid "No fast forward" msgstr "Solo fast forward" #, fuzzy msgid "No fast-forward" msgstr "Solo fast forward" msgid "No repository selected." msgstr "Nessun archivio selezionato." msgid "Non-fast-forward fetch overwrites local history!" msgstr "" msgid "" "Non-fast-forward push overwrites published history!\n" "(Did you pull first?)" msgstr "" #, fuzzy msgid "Nothing to commit" msgstr "Nessuna modifica per la nuova revisione." #, fuzzy msgid "Nothing to do" msgstr "Niente da clonare da %s." msgid "Number of Diff Context Lines" msgstr "Numero di linee di contesto nelle differenze" msgid "Open" msgstr "Apri" #, fuzzy msgid "Open Git Repository..." msgstr "Apri archivio esistente" #, fuzzy msgid "Open Parent" msgstr "Apri archivio recente:" #, fuzzy msgid "Open Parent Directory" msgstr "Apri archivio recente:" #, fuzzy msgid "Open Recent" msgstr "Apri archivio recente:" msgid "Open Using Default Application" msgstr "" msgid "Open in New Window" msgstr "" #, fuzzy msgid "Open in New Window..." msgstr "Apri archivio esistente" msgid "Open..." msgstr "Apri..." #, fuzzy msgid "Other branches" msgstr "Ripristina..." msgid "Overwrite" msgstr "" #, python-format msgid "Overwrite \"%s\"?" msgstr "" msgid "Overwrite File?" msgstr "" msgid "" "Parse arguments using a shell.\n" "Queries with spaces will require \"double quotes\"." msgstr "" msgid "Partially Staged" msgstr "" msgid "Paste" msgstr "Incolla" msgid "Patch(es) Applied" msgstr "" msgid "Path" msgstr "" msgid "Path or URL to clone (Env. $VARS okay)" msgstr "" msgid "Pick" msgstr "" msgid "Pixel XOR" msgstr "" msgid "Please provide both a branch name and revision expression." msgstr "" #, fuzzy msgid "Please select a file" msgstr "Scegliere un duplicato locale di ramo remoto" msgid "Please specify a name for the new tag." msgstr "" #, fuzzy msgid "Please specify a revision to tag." msgstr "Scegliere un ramo da rinominare." msgid "" "Please supply a commit message.\n" "\n" "A good commit message has the following format:\n" "\n" "- First line: Describe in one sentence what you did.\n" "- Second line: Blank\n" "- Remaining lines: Describe why this change is good.\n" msgstr "" "Bisogna fornire un messaggio di revisione.\n" "\n" "Un buon messaggio di revisione ha il seguente formato:\n" "\n" "- Prima linea: descrivi in una frase ciò che hai fatto.\n" "- Seconda linea: vuota.\n" "- Terza linea: spiega a cosa serve la tua modifica.\n" msgid "Point the current branch head to a new commit?" msgstr "" msgid "Polish translation" msgstr "" msgid "Pop" msgstr "" msgid "Preferences" msgstr "Preferenze" msgid "Prefix" msgstr "" #, fuzzy msgid "Prepare Commit Message" msgstr "Messaggio di fusione:" msgid "Prevent \"Stage\" from staging all files when nothing is selected" msgstr "" msgid "Previous File" msgstr "" msgid "Prompt on creation" msgstr "" #, fuzzy msgid "Prompt when pushing creates new remote branches" msgstr "Crea nuovo ramo" #, fuzzy msgid "Prune " msgstr "Effettua potatura da" #, fuzzy msgid "Pull" msgstr "Propaga..." #, fuzzy msgid "Pull..." msgstr "Propaga..." msgid "Push" msgstr "Propaga (Push)" msgid "Push..." msgstr "Propaga..." msgid "Quit" msgstr "Esci" #, fuzzy msgid "Rebase" msgstr "Ripristina" #, fuzzy, python-format msgid "Rebase onto %s" msgstr "Ripristina" #, fuzzy msgid "Rebase stopped" msgstr "Ripristina" msgid "Rebase the current branch instead of merging" msgstr "" #, fuzzy msgid "Rebasing" msgstr "Ripristina" #, fuzzy msgid "Recent" msgstr "Ripristina" #, fuzzy msgid "Recent repositories" msgstr "Archivi recenti" #, fuzzy msgid "Recent repository count" msgstr "Archivi recenti" msgid "Recently Modified Files" msgstr "" #, fuzzy msgid "Recently Modified Files..." msgstr "Ricerca di file modificati in corso..." #, fuzzy msgid "Recovering a dropped stash is not possible." msgstr "Ricomporre le revisioni perdute potrebbe non essere semplice." msgid "Recovering lost commits may not be easy." msgstr "Ricomporre le revisioni perdute potrebbe non essere semplice." msgid "Redo" msgstr "Ripeti" msgid "Reduce commit history to minimum" msgstr "" msgid "Refresh" msgstr "Rinfresca" msgid "Refuse to merge unless the current HEAD is already up-to-date or the merge can be resolved as a fast-forward" msgstr "" msgid "Remote" msgstr "Remoto" #, fuzzy msgid "Remote Branch" msgstr "Rinomina ramo" #, fuzzy msgid "Remote Branch Deleted" msgstr "Rinomina ramo" msgid "Remote git repositories - double-click to rename" msgstr "" #, fuzzy msgid "Remove" msgstr "Remoto" #, python-format msgid "Remove %s from the recent list?" msgstr "" #, fuzzy msgid "Remove Element" msgstr "Remoto" msgid "Remove remote-tracking branches that no longer exist on the remote" msgstr "" #, fuzzy msgid "Remove selected (Delete)" msgstr "Rinomina ramo" msgid "Rename" msgstr "Rinomina" #, fuzzy, python-format msgid "Rename \"%s\"" msgstr "Rinomina" #, fuzzy msgid "Rename Branch" msgstr "Rinomina ramo" #, fuzzy msgid "Rename Branch..." msgstr "Rinomina ramo" #, fuzzy msgid "Rename Existing Branch" msgstr "Aggiorna ramo esistente:" #, fuzzy msgid "Rename Remote" msgstr "Remoto" #, fuzzy msgid "Rename Repository" msgstr "Clona archivio esistente" #, fuzzy msgid "Rename branch" msgstr "Rinomina ramo" #, python-format msgid "Rename remote \"%(current)s\" to \"%(new)s\"?" msgstr "" #, fuzzy msgid "Rename selected paths" msgstr "Rinomina ramo" #, fuzzy, python-format msgid "Repository: %s" msgstr "Archivio:" msgid "Reset" msgstr "Ripristina" #, python-format msgid "Reset \"%(branch)s\" to \"%(revision)s\"?" msgstr "" #, fuzzy msgid "Reset Branch" msgstr "Elimina ramo" #, fuzzy msgid "Reset Branch Head" msgstr "Elimina ramo" #, fuzzy msgid "Reset Branch?" msgstr "Elimina ramo" #, fuzzy msgid "Reset Hard" msgstr "Elimina ramo" #, fuzzy msgid "Reset Merge" msgstr "Revisione da fondere" #, fuzzy msgid "Reset Soft" msgstr "Ripristina" msgid "Reset Worktree" msgstr "" #, fuzzy msgid "Reset hard?" msgstr "Elimina ramo" #, fuzzy msgid "Reset merge?" msgstr "Elimina ramo" #, fuzzy msgid "Reset soft?" msgstr "Ripristinare '%s'?" msgid "Reset worktree?" msgstr "" #, fuzzy, python-format msgid "Resetting \"%(branch)s\" to \"%(revision)s\" will lose commits." msgstr "Ripristinare '%s' a '%s' comporterà la perdita delle seguenti revisioni:" msgid "Restart the application after changing appearance settings." msgstr "" msgid "Revert" msgstr "" msgid "Revert Diff Hunk" msgstr "" msgid "Revert Diff Hunk..." msgstr "" msgid "Revert Diff Hunk?" msgstr "" msgid "Revert Selected Lines" msgstr "" msgid "Revert Selected Lines..." msgstr "" #, fuzzy msgid "Revert Selected Lines?" msgstr "Annullare le modifiche nel file %s?" #, fuzzy msgid "Revert Uncommitted Changes" msgstr "Annulla modifiche" #, fuzzy msgid "Revert Uncommitted Changes?" msgstr "Annulla modifiche" #, fuzzy msgid "Revert Uncommitted Edits..." msgstr "Annulla modifiche" #, fuzzy msgid "Revert Unstaged Changes" msgstr "Modifiche non preparate" #, fuzzy msgid "Revert Unstaged Changes?" msgstr "Modifiche non preparate" msgid "Revert Unstaged Edits..." msgstr "" msgid "Revert the uncommitted changes?" msgstr "" #, fuzzy msgid "Revert the unstaged changes?" msgstr "Modifiche non preparate" #, fuzzy msgid "Revert uncommitted changes to selected paths" msgstr "Annullare le modifiche nel file %s?" #, fuzzy msgid "Revert unstaged changes to selected paths" msgstr "Annullare le modifiche nel file %s?" msgid "Review" msgstr "" #, fuzzy msgid "Review..." msgstr "Ripristina..." msgid "Revision" msgstr "Revisione" msgid "Revision Expression:" msgstr "Espressione di revisione:" msgid "Revision to Merge" msgstr "Revisione da fondere" msgid "Reword" msgstr "" msgid "Rewrite Published Commit?" msgstr "" msgid "Run" msgstr "" #, python-format msgid "Run \"%s\"?" msgstr "" #, python-format msgid "Run %s?" msgstr "" #, python-format msgid "Run the \"%s\" command?" msgstr "" #, python-format msgid "Running command: %s" msgstr "" msgid "Russian translation" msgstr "" #, fuzzy msgid "SHA-1" msgstr "Copia tutto" msgid "Safe Mode" msgstr "" msgid "Save" msgstr "Salva" msgid "Save Archive" msgstr "" msgid "Save As Tarball/Zip..." msgstr "" msgid "Save GUI Settings" msgstr "" msgid "Save Stash" msgstr "" msgid "Save modified state to new stash" msgstr "" #, python-format msgid "Saved \"%(filename)s\" from \"%(ref)s\" to \"%(destination)s\"" msgstr "" msgid "Search" msgstr "" msgid "Search Authors" msgstr "" #, fuzzy msgid "Search Commit Messages" msgstr "Messaggio di fusione:" #, fuzzy msgid "Search Committers" msgstr "Revisione creata da:" msgid "Search Date Range" msgstr "" msgid "Search Diffs" msgstr "" #, fuzzy msgid "Search by Expression" msgstr "Espressione di revisione:" msgid "Search by Path" msgstr "" msgid "Search for a fixed string" msgstr "" msgid "Search using a POSIX basic regular expression" msgstr "" msgid "Search using a POSIX extended regular expression" msgstr "" #, fuzzy msgid "Search..." msgstr "Avvio in corso..." msgid "Select" msgstr "Seleziona" msgid "Select All" msgstr "Seleziona tutto" #, fuzzy msgid "Select Branch to Review" msgstr "Elimina ramo" #, fuzzy msgid "Select Child" msgstr "Seleziona tutto" #, fuzzy msgid "Select Commit" msgstr "Messaggio di fusione:" #, fuzzy msgid "Select Directory..." msgstr "Archivio Git" #, fuzzy msgid "Select New Upstream" msgstr "Seleziona" msgid "Select Newest Child" msgstr "" msgid "Select Oldest Parent" msgstr "" #, fuzzy msgid "Select Parent" msgstr "Seleziona" msgid "Select Previous Version" msgstr "" #, fuzzy msgid "Select Repository..." msgstr "Archivio Git" msgid "Select a parent directory for the new clone" msgstr "" #, fuzzy msgid "Select manually..." msgstr "Seleziona tutto" #, fuzzy msgid "Select output dir" msgstr "Messaggio di fusione:" #, fuzzy msgid "Select output directory" msgstr "Archivio Git" #, fuzzy msgid "Select patch file(s)..." msgstr "Elimina..." #, fuzzy msgid "Select repository" msgstr "Archivio Git" #, fuzzy msgid "Set Default Repository" msgstr "Archivio Git" #, fuzzy msgid "Set Upstream Branch" msgstr "Seleziona" msgid "" "Set the sort order for branches and tags.\n" "Toggle between date-based and version-name-based sorting." msgstr "" #, fuzzy msgid "Set upstream" msgstr "Seleziona" #, fuzzy msgid "Settings" msgstr "Avvio in corso..." msgid "Shell arguments" msgstr "" msgid "Shift Down" msgstr "" msgid "Shift Up" msgstr "" msgid "Shortcuts" msgstr "" #, fuzzy msgid "Show Details..." msgstr "Elimina..." msgid "Show Diffstat After Merge" msgstr "Mostra statistiche delle differenze dopo la fusione" msgid "Show Full Paths in the Window Title" msgstr "" #, fuzzy msgid "Show Help" msgstr "Aiuto" msgid "Show History" msgstr "" msgid "Show file counts in Status titles" msgstr "" msgid "" "Show help\n" "Shortcut: ?" msgstr "" msgid "Show icon? (if available)" msgstr "" msgid "Show line numbers" msgstr "" msgid "Show whole surrounding functions of changes" msgstr "" #, fuzzy msgid "Showing changes since" msgstr "Propagazione modifiche a %s" msgid "Side by side" msgstr "" msgid "Sign Off" msgstr "Sign Off" #, fuzzy msgid "Sign Tag" msgstr "Sign Off" #, fuzzy msgid "Sign off on this commit" msgstr "Preparato per una nuova revisione" msgid "Simplified Chinese translation" msgstr "" msgid "Skip" msgstr "" #, fuzzy msgid "Skip Current Patch" msgstr "Crea ramo" msgid "Sort bookmarks alphabetically" msgstr "" msgid "Spanish translation" msgstr "" msgid "Specifies the SHA-1 to tag" msgstr "" msgid "Specifies the tag message" msgstr "" msgid "Specifies the tag name" msgstr "" #, fuzzy msgid "Spelling Suggestions" msgstr "Nessun suggerimento" #, fuzzy msgid "Squash" msgstr "Propaga (Push)" msgid "Squash the merged commits into a single commit" msgstr "" #, fuzzy msgid "Stage" msgstr "Salva" #, fuzzy msgid "Stage / Unstage" msgstr "Prepara modificati" msgid "Stage All Untracked" msgstr "" msgid "Stage Changed Files To Commit" msgstr "Prepara i file modificati per una nuova revisione" #, fuzzy msgid "Stage Diff Hunk" msgstr "Revisione iniziale" msgid "Stage Modified" msgstr "" #, fuzzy msgid "Stage Selected" msgstr "Seleziona" #, fuzzy msgid "Stage Selected Lines" msgstr "Modifiche non preparate" #, fuzzy msgid "Stage Unmerged" msgstr "Prepara modificati" #, fuzzy msgid "Stage Untracked" msgstr "Prepara modificati" #, fuzzy msgid "Stage and Commit" msgstr "Prepara per una nuova revisione" #, fuzzy msgid "Stage and commit?" msgstr "Preparato per una nuova revisione" #, fuzzy msgid "Stage conflicts" msgstr "Preparato per una nuova revisione" #, fuzzy msgid "Stage conflicts?" msgstr "Preparato per una nuova revisione" #, fuzzy msgid "Stage/unstage selected paths for commit" msgstr "Preparato per una nuova revisione" #, fuzzy msgid "Staged" msgstr "Prepara modificati" #, fuzzy, python-format msgid "Staging: %s" msgstr "Analisi in corso %s..." msgid "Start Interactive Rebase..." msgstr "" msgid "Starting Revision" msgstr "Revisione iniziale" msgid "Stash" msgstr "" #, fuzzy msgid "Stash Index" msgstr "Errore nell'indice" #, fuzzy msgid "Stash staged changes only" msgstr "Archiviazione modifiche..." #, fuzzy msgid "Stash unstaged changes only, keeping staged changes" msgstr "Annullare le modifiche nel file %s?" #, fuzzy msgid "Stash..." msgstr "Propaga..." msgid "Status" msgstr "" msgid "Stop tracking paths" msgstr "" msgid "Submodules" msgstr "" msgid "Summarize Merge Commits" msgstr "Riepilogo nelle revisioni di fusione" msgid "Summary" msgstr "" msgid "Tab Width" msgstr "" msgid "Tag" msgstr "Etichetta" #, fuzzy msgid "Tag Created" msgstr "Crea" msgid "Tag message..." msgstr "" msgid "Tag-signing was requested but the tag message is empty." msgstr "" msgid "Tags" msgstr "" msgid "Text Width" msgstr "" msgid "The branch will be no longer available." msgstr "" #, python-format msgid "The branch will be reset using \"git reset --hard %s\"" msgstr "" #, python-format msgid "The branch will be reset using \"git reset --merge %s\"" msgstr "" #, python-format msgid "The branch will be reset using \"git reset --mixed %s\"" msgstr "" #, python-format msgid "The branch will be reset using \"git reset --soft %s\"" msgstr "" #, fuzzy msgid "The commit message will be cleared." msgstr "Larghezza del messaggio di revisione" #, python-format msgid "The file \"%s\" exists and will be overwritten." msgstr "" msgid "The following files will be deleted:" msgstr "" #, fuzzy msgid "The revision expression cannot be empty." msgstr "L'espressione di revisione è vuota." #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be reset using \"git reset --keep %s\"" msgstr "" msgid "This cannot be undone. Clear commit message?" msgstr "" msgid "" "This commit has already been published.\n" "This operation will rewrite published history.\n" "You probably don't want to do this." msgstr "" msgid "" "This operation drops uncommitted changes.\n" "These changes cannot be recovered." msgstr "" msgid "" "This operation removes uncommitted edits from selected files.\n" "These changes cannot be recovered." msgstr "" msgid "" "This operation removes unstaged edits from selected files.\n" "These changes cannot be recovered." msgstr "" msgid "" "This repository is currently being rebased.\n" "Resolve conflicts, commit changes, and run:\n" " Rebase > Continue" msgstr "" msgid "" "This repository is in the middle of a merge.\n" "Resolve conflicts and commit changes." msgstr "" msgid "Toggle Enabled" msgstr "" msgid "Toggle the branches filter" msgstr "" msgid "Toggle the paths filter" msgstr "" msgid "Tracking Branch" msgstr "Duplicato locale di ramo remoto" #, fuzzy msgid "Tracking branch" msgstr "Duplicato locale di ramo remoto" msgid "Traditional Chinese (Taiwan) translation" msgstr "" msgid "Translators" msgstr "" msgid "Turkish translation" msgstr "" msgid "URL" msgstr "URL" #, fuzzy, python-format msgid "URL: %s" msgstr "URL:" msgid "Ukranian translation" msgstr "" #, fuzzy msgid "Unable to rebase" msgstr "Impossibile ripulire %s" #, python-format msgid "Unable to set URL for \"%(name)s\" to \"%(url)s\"" msgstr "" msgid "Undo" msgstr "Annulla" #, fuzzy msgid "Unmerged" msgstr "Fusione (Merge)" #, fuzzy msgid "Unstage" msgstr "Modifiche non preparate" msgid "Unstage All" msgstr "" msgid "Unstage Diff Hunk" msgstr "" msgid "Unstage From Commit" msgstr "Annulla preparazione" msgid "Unstage Selected" msgstr "" #, fuzzy msgid "Unstage Selected Lines" msgstr "Modifiche non preparate" #, fuzzy, python-format msgid "Unstaging: %s" msgstr "%s non farà parte della prossima revisione" msgid "Untrack Selected" msgstr "" #, fuzzy msgid "Untracked" msgstr "Non tracciato, non preparato per una nuova revisione" #, python-format msgid "Untracking: %s" msgstr "" msgid "Update All Submodules..." msgstr "" msgid "Update Existing Branch:" msgstr "Aggiorna ramo esistente:" #, fuzzy msgid "Update Submodule" msgstr "Aggiornato" msgid "Update Submodule..." msgstr "" msgid "Update Submodules" msgstr "" msgid "Update all submodules?" msgstr "" msgid "Update submodules..." msgstr "" msgid "Update this submodule" msgstr "" msgid "Update this submodule?" msgstr "" #, fuzzy msgid "Updating" msgstr "Avvio in corso..." msgid "User Name" msgstr "Nome utente" #, fuzzy msgid "Version" msgstr "Revisione" msgid "View" msgstr "" msgid "View History..." msgstr "" #, fuzzy msgid "View history for selected paths" msgstr "Annullare le modifiche nel file %s?" msgid "Visualize" msgstr "Visualizza" #, fuzzy msgid "Visualize All Branches..." msgstr "Visualizza la cronologia di tutti i rami" #, fuzzy msgid "Visualize Current Branch..." msgstr "Visualizza la cronologia del ramo attuale" msgid "Whether to sign the tag (git tag -s)" msgstr "" msgid "Would you like to stage and commit all modified files?" msgstr "" msgid "XOR" msgstr "" msgid "Yes" msgstr "" msgid "" "You are in the middle of a merge.\n" "Cannot amend while merging." msgstr "" #, fuzzy msgid "You cannot rebase with uncommitted changes." msgstr "Annulla modifiche" msgid "You must specify a revision to merge." msgstr "" msgid "You must specify a revision to view." msgstr "" msgid "Zoom In" msgstr "" msgid "Zoom Out" msgstr "" msgid "Zoom to Fit" msgstr "" msgid "command-line arguments" msgstr "" msgid "error: unable to execute git" msgstr "" #, fuzzy, python-format msgid "exit code %s" msgstr "recupera da %s" #, python-format msgid "fatal: \"%s\" is not a directory. Please specify a correct --repo ." msgstr "" #, python-format msgid "git cola version %s" msgstr "" msgid "git-cola" msgstr "" msgid "git-cola diff" msgstr "" msgid "grep result..." msgstr "" msgid "hotkeys.html" msgstr "" msgid "unknown" msgstr "" msgid "vX.Y.Z" msgstr "" msgid "x 1" msgstr "" msgid "x 1.5" msgstr "" msgid "x 2" msgstr "" msgid "yyyy-MM-dd" msgstr "" #~ msgid "" #~ "\n" #~ "\n" #~ "A good replacement for %s\n" #~ "is placing values for the user.name and\n" #~ "user.email settings into your personal\n" #~ "~/.gitconfig file.\n" #~ msgstr "" #~ "\n" #~ "\n" #~ "Una buona alternativa a %s\n" #~ "consiste nell'assegnare valori alle variabili di configurazione\n" #~ "user.name e user.email nel tuo file ~/.gitconfig personale.\n" #~ msgid "" #~ "\n" #~ "This is due to a known issue with the\n" #~ "Tcl binary distributed by Cygwin." #~ msgstr "" #~ "\n" #~ "Ciò è dovuto a un problema conosciuto\n" #~ "causato dall'eseguibile Tcl distribuito da Cygwin." #~ msgid "%s ... %*i of %*i %s (%3i%%)" #~ msgstr "%1$s ... %6$s: %2$*i di %4$*i (%7$3i%%)" #~ msgid "%s Repository" #~ msgstr "Archivio di %s" #~ msgid "%s of %s" #~ msgstr "%s di %s" #~ msgid "'%s' is not an acceptable branch name." #~ msgstr "'%s' non è utilizzabile come nome di ramo." #~ msgid "* Binary file (not showing content)." #~ msgstr "* File binario (il contenuto non sarà mostrato)." #~ msgid "A branch is required for 'Merged Into'." #~ msgstr "Si richiede un ramo per 'Fuso in'." #~ msgid "Abort completed. Ready." #~ msgstr "Interruzione completata. Pronto." #~ msgid "Abort failed." #~ msgstr "Interruzione non riuscita." #~ msgid "Aborted checkout of '%s' (file level merging is required)." #~ msgstr "Attivazione di '%s' fallita (richiesta una fusione a livello file)." #~ msgid "Always (Do not perform merge checks)" #~ msgstr "Sempre (non verificare le fusioni)" #~ msgid "Always (Do not perform merge test.)" #~ msgstr "Sempre (Non effettuare verifiche di fusione)." #~ msgid "Amended Commit Message:" #~ msgstr "Messaggio di revisione corretto:" #~ msgid "Amended Initial Commit Message:" #~ msgstr "Messaggio iniziale di revisione corretto:" #~ msgid "Amended Merge Commit Message:" #~ msgstr "Messaggio di fusione corretto:" #~ msgid "Annotation complete." #~ msgstr "Annotazione completata." #~ msgid "Any unstaged changes will be permanently lost by the revert." #~ msgstr "Tutte le modifiche non preparate per una nuova revisione saranno perse per sempre." #~ msgid "Apply/Reverse Hunk" #~ msgstr "Applica/Inverti sezione" #~ msgid "Arbitrary URL:" #~ msgstr "URL specifico:" #~ msgid "" #~ "Branch '%s' already exists.\n" #~ "\n" #~ "It cannot fast-forward to %s.\n" #~ "A merge is required." #~ msgstr "" #~ "Il ramo '%s' esiste già.\n" #~ "\n" #~ "Non può effettuare un 'fast-forward' a %s.\n" #~ "E' necessaria una fusione." #~ msgid "Branch '%s' does not exist." #~ msgstr "Il ramo '%s' non esiste." #, fuzzy #~ msgid "Branch created" #~ msgstr "Nome del ramo" #~ msgid "Browse %s's Files" #~ msgstr "Esplora i file di %s" #~ msgid "Browse Branch Files" #~ msgstr "Esplora i file del ramo" #, fuzzy #~ msgid "Browse Revision..." #~ msgstr "Revisione" #~ msgid "Calling commit-msg hook..." #~ msgstr "Avvio commit-msg hook..." #~ msgid "" #~ "Cannot abort while amending.\n" #~ "\n" #~ "You must finish amending this commit.\n" #~ msgstr "" #~ "Interruzione impossibile durante una correzione.\n" #~ "\n" #~ "Bisogna finire di correggere questa revisione.\n" #~ msgid "" #~ "Cannot amend while merging.\n" #~ "\n" #~ "You are currently in the middle of a merge that has not been fully completed. You cannot amend the prior commit unless you first abort the current merge activity.\n" #~ msgstr "" #~ "Non è possibile effettuare una correzione durante una fusione.\n" #~ "\n" #~ "In questo momento si sta effettuando una fusione che non è stata del tutto completata. Non puoi correggere la revisione precedente a meno che prima tu non interrompa l'operazione di fusione in corso.\n" #~ msgid "Cannot determine HEAD. See console output for details." #~ msgstr "Impossibile determinare HEAD. Controllare i dettagli forniti dalla console." #~ msgid "Cannot fetch branches and objects. See console output for details." #~ msgstr "Impossibile recuperare rami e oggetti. Controllare i dettagli forniti dalla console." #~ msgid "Cannot fetch tags. See console output for details." #~ msgstr "Impossibile recuperare le etichette. Controllare i dettagli forniti dalla console." #~ msgid "Cannot find git in PATH." #~ msgstr "Impossibile trovare git nel PATH" #~ msgid "" #~ "Cannot merge while amending.\n" #~ "\n" #~ "You must finish amending this commit before starting any type of merge.\n" #~ msgstr "" #~ "Non posso effettuare fusioni durante una correzione.\n" #~ "\n" #~ "Bisogna finire di correggere questa revisione prima di iniziare una qualunque fusione.\n" #~ msgid "Cannot move to top of working directory:" #~ msgstr "Impossibile spostarsi sulla directory principale del progetto:" #~ msgid "Cannot parse Git version string:" #~ msgstr "Impossibile determinare la versione di Git:" #~ msgid "Cannot resolve %s as a commit." #~ msgstr "Impossibile risolvere %s come una revisione." #~ msgid "Cannot use funny .git directory:" #~ msgstr "Impossibile usare una .git directory strana:" #~ msgid "Cannot write shortcut:" #~ msgstr "Impossibile scrivere shortcut:" #~ msgid "Change Font" #~ msgstr "Cambia caratteri" #~ msgid "Checked out '%s'." #~ msgstr "Attivazione di '%s' completata." #~ msgid "Clone Type:" #~ msgstr "Tipo di clone:" #~ msgid "Clone failed." #~ msgstr "Clonazione non riuscita." #~ msgid "Cloning from %s" #~ msgstr "Clonazione da %s" #~ msgid "Commit %s appears to be corrupt" #~ msgstr "La revisione %s sembra essere danneggiata" #~ msgid "Commit declined by commit-msg hook." #~ msgstr "Revisione rifiutata dal commit-msg hook." #~ msgid "Commit declined by pre-commit hook." #~ msgstr "Revisione rifiutata dal pre-commit hook." #, fuzzy #~ msgid "Commit failed: %s" #~ msgstr "Impossibile creare una nuova revisione." #~ msgid "Commit@@noun" #~ msgstr "Revisione" #~ msgid "Compress Database" #~ msgstr "Comprimi l'archivio" #~ msgid "Compressing the object database" #~ msgstr "Compressione dell'archivio in corso" #~ msgid "Copied Or Moved Here By:" #~ msgstr "Copiato o spostato qui da:" #~ msgid "Copying objects" #~ msgstr "Copia degli oggetti" #~ msgid "Counting objects" #~ msgstr "Calcolo oggetti" #~ msgid "Create Desktop Icon" #~ msgstr "Crea icona desktop" #, fuzzy #~ msgid "Created commit: %s" #~ msgstr "Creata revisione %s: %s" #~ msgid "Creating working directory" #~ msgstr "Creazione directory di lavoro" #~ msgid "Current Branch:" #~ msgstr "Ramo attuale:" #~ msgid "Database Statistics" #~ msgstr "Statistiche dell'archivio" #~ msgid "Decrease Font Size" #~ msgstr "Diminuisci dimensione caratteri" #~ msgid "Delete Local Branch" #~ msgstr "Elimina ramo locale" #~ msgid "Delete Only If" #~ msgstr "Elimina solo se" #~ msgid "Delete Only If Merged Into" #~ msgstr "Cancella solo se fuso con un altro ramo" #~ msgid "Destination Repository" #~ msgstr "Archivio di destinazione" #~ msgid "Detach From Local Branch" #~ msgstr "Stacca da ramo locale" #~ msgid "Diff/Console Font" #~ msgstr "Caratteri per confronti e terminale" #~ msgid "Directory %s already exists." #~ msgstr "La directory %s esiste già." #~ msgid "Disk space used by loose objects" #~ msgstr "Spazio su disco utilizzato da oggetti slegati" #~ msgid "Disk space used by packed objects" #~ msgstr "Spazio su disco utilizzato da oggetti impacchettati" #~ msgid "Do Nothing" #~ msgstr "Non fare niente" #, fuzzy #~ msgid "Enter Git Repository" #~ msgstr "Archivio Git" #, fuzzy #~ msgid "Error %s" #~ msgstr "errore" #~ msgid "Error loading commit data for amend:" #~ msgstr "Errore durante il caricamento dei dati della revisione da correggere:" #~ msgid "Error: Command Failed" #~ msgstr "Errore: comando non riuscito" #~ msgid "Failed to completely save options:" #~ msgstr "Impossibile salvare completamente le opzioni:" #~ msgid "Failed to configure origin" #~ msgstr "Impossibile configurare origin" #~ msgid "Failed to create repository %s:" #~ msgstr "Impossibile creare l'archivio %s:" #~ msgid "" #~ "Failed to delete branches:\n" #~ "%s" #~ msgstr "" #~ "Impossibile cancellare i rami:\n" #~ "%s" #~ msgid "Failed to open repository %s:" #~ msgstr "Impossibile accedere all'archivio %s:" #~ msgid "Failed to rename '%s'." #~ msgstr "Impossibile rinominare '%s'." #~ msgid "" #~ "Failed to set current branch.\n" #~ "\n" #~ "This working directory is only partially switched. We successfully updated your files, but failed to update an internal Git file.\n" #~ "\n" #~ "This should not have occurred. %s will now close and give up." #~ msgstr "" #~ "Impossibile preparare il ramo attuale.\n" #~ "\n" #~ "Questa directory di lavoro è stata convertita solo parzialmente. I file sono stati aggiornati correttamente, ma l'aggiornamento di un file di Git ha prodotto degli errori.\n" #~ "\n" #~ "Questo non sarebbe dovuto succedere. %s ora terminerà senza altre azioni." #~ msgid "Failed to stage selected hunk." #~ msgstr "Impossibile preparare la sezione scelta per una nuova revisione." #~ msgid "Failed to unstage selected hunk." #~ msgstr "Impossibile rimuovere la sezione scelta dalla nuova revisione." #~ msgid "Failed to update '%s'." #~ msgstr "Impossibile aggiornare '%s'." #, fuzzy #~ msgid "Fast Forward Only " #~ msgstr "Solo fast forward" #~ msgid "Fetch from" #~ msgstr "Recupera da" #~ msgid "Fetching new changes from %s" #~ msgstr "Recupero nuove modifiche da %s" #~ msgid "File level merge required." #~ msgstr "E' richiesta una fusione a livello file." #~ msgid "Font Example" #~ msgstr "Esempio caratteri" #~ msgid "Font Family" #~ msgstr "Famiglia di caratteri" #~ msgid "Force overwrite existing branch (may discard changes)" #~ msgstr "Sovrascrivi ramo esistente (alcune modifiche potrebbero essere perse)" #~ msgid "From Repository" #~ msgstr "Da archivio" #~ msgid "Full Copy (Slower, Redundant Backup)" #~ msgstr "Copia completa (più lento, backup ridondante)" #~ msgid "Garbage files" #~ msgstr "File inutili" #~ msgid "Git Gui" #~ msgstr "Git Gui" #~ msgid "Git Repository (subproject)" #~ msgstr "Archivio Git (sottoprogetto)" #~ msgid "Git directory not found:" #~ msgstr "Non trovo la directory di git: " #~ msgid "" #~ "Git version cannot be determined.\n" #~ "\n" #~ "%s claims it is version '%s'.\n" #~ "\n" #~ "%s requires at least Git 1.5.0 or later.\n" #~ "\n" #~ "Assume '%s' is version 1.5.0?\n" #~ msgstr "" #~ "La versione di Git non può essere determinata.\n" #~ "\n" #~ "%s riporta che la versione è '%s'.\n" #~ "\n" #~ "%s richiede almeno Git 1.5.0 o superiore.\n" #~ "\n" #~ "Assumere che '%s' sia alla versione 1.5.0?\n" #~ msgid "Hardlinks are unavailable. Falling back to copying." #~ msgstr "Impossibile utilizzare gli hardlink. Si ricorrerà alla copia." #~ msgid "In File:" #~ msgstr "Nel file:" #~ msgid "Increase Font Size" #~ msgstr "Aumenta dimensione caratteri" #~ msgid "Initial Commit Message:" #~ msgstr "Messaggio di revisione iniziale:" #~ msgid "Initial file checkout failed." #~ msgstr "Attivazione iniziale non riuscita." #~ msgid "Invalid GIT_COMMITTER_IDENT:" #~ msgstr "GIT_COMMITTER_IDENT non valida:" #~ msgid "Invalid date from Git: %s" #~ msgstr "Git ha restituito una data non valida: %s" #~ msgid "Invalid font specified in %s:" #~ msgstr "Caratteri non validi specificati in %s:" #~ msgid "Invalid spell checking configuration" #~ msgstr "La configurazione del correttore ortografico non è valida" #~ msgid "KiB" #~ msgstr "KiB" #~ msgid "" #~ "Last scanned state does not match repository state.\n" #~ "\n" #~ "Another Git program has modified this repository since the last scan. A rescan must be performed before a merge can be performed.\n" #~ "\n" #~ "The rescan will be automatically started now.\n" #~ msgstr "" #~ "L'ultimo stato analizzato non corrisponde allo stato dell'archivio.\n" #~ "\n" #~ "Un altro programma Git ha modificato questo archivio dall'ultima analisi.Bisogna effettuare una nuova analisi prima di poter effettuare una fusione.\n" #~ "\n" #~ "La nuova analisi comincerà ora.\n" #~ msgid "" #~ "Last scanned state does not match repository state.\n" #~ "\n" #~ "Another Git program has modified this repository since the last scan. A rescan must be performed before another commit can be created.\n" #~ "\n" #~ "The rescan will be automatically started now.\n" #~ msgstr "" #~ "L'ultimo stato analizzato non corrisponde allo stato dell'archivio.\n" #~ "\n" #~ "Un altro programma Git ha modificato questo archivio dall'ultima analisi. Bisogna effettuare una nuova analisi prima di poter creare una nuova revisione.\n" #~ "\n" #~ "La nuova analisi comincerà ora.\n" #~ msgid "" #~ "Last scanned state does not match repository state.\n" #~ "\n" #~ "Another Git program has modified this repository since the last scan. A rescan must be performed before the current branch can be changed.\n" #~ "\n" #~ "The rescan will be automatically started now.\n" #~ msgstr "" #~ "L'ultimo stato analizzato non corrisponde allo stato dell'archivio.\n" #~ "\n" #~ "Un altro programma Git ha modificato questo archivio dall'ultima analisi. Bisogna effettuare una nuova analisi prima di poter cambiare il ramo attuale.\n" #~ "\n" #~ "La nuova analisi comincerà ora.\n" #~ msgid "Linking objects" #~ msgstr "Collegamento oggetti" #~ msgid "Loading annotation..." #~ msgstr "Caricamento annotazioni..." #~ msgid "Loading copy/move tracking annotations..." #~ msgstr "Caricamento annotazioni per copie/spostamenti..." #~ msgid "Loading original location annotations..." #~ msgstr "Caricamento annotazioni per posizione originaria..." #~ msgid "Local Branches" #~ msgstr "Rami locali" #~ msgid "Local Merge..." #~ msgstr "Fusione locale..." #~ msgid "Location %s already exists." #~ msgstr "Il file/directory %s esiste già." #~ msgid "Main Font" #~ msgstr "Caratteri principali" #~ msgid "Match Tracking Branch Name" #~ msgstr "Appaia nome del duplicato locale di ramo remoto" #~ msgid "Match Tracking Branches" #~ msgstr "Appaia duplicati locali di rami remoti" #~ msgid "Merge completed successfully." #~ msgstr "Fusione completata con successo." #~ msgid "Merge strategy '%s' not supported." #~ msgstr "La strategia di fusione '%s' non è supportata." #~ msgid "Merged Into:" #~ msgstr "Fuso in:" #~ msgid "Merging %s and %s..." #~ msgstr "Fusione di %s e %s in corso..." #~ msgid "Modified, not staged" #~ msgstr "Modificato, non preparato per una nuova revisione" #~ msgid "New Branch Name Template" #~ msgstr "Modello per il nome di un nuovo ramo" #~ msgid "New Commit" #~ msgstr "Nuova revisione" #~ msgid "New Name:" #~ msgstr "Nuovo Nome:" #~ msgid "" #~ "No changes to commit.\n" #~ "\n" #~ "No files were modified by this commit and it was not a merge commit.\n" #~ "\n" #~ "A rescan will be automatically started now.\n" #~ msgstr "" #~ "Nessuna modifica per la nuova revisione.\n" #~ "\n" #~ "Questa revisione non modifica alcun file e non effettua alcuna fusione.\n" #~ "\n" #~ "Si procederà subito ad una nuova analisi.\n" #~ msgid "No default branch obtained." #~ msgstr "Non è stato trovato un ramo predefinito." #~ msgid "" #~ "No differences detected.\n" #~ "\n" #~ "%s has no changes.\n" #~ "\n" #~ "The modification date of this file was updated by another application, but the content within the file was not changed.\n" #~ "\n" #~ "A rescan will be automatically started to find other files which may have the same state." #~ msgstr "" #~ "Non sono state trovate differenze.\n" #~ "\n" #~ "%s non ha modifiche.\n" #~ "\n" #~ "La data di modifica di questo file è stata cambiata da un'altra applicazione, ma il contenuto del file è rimasto invariato.\n" #~ "\n" #~ "Si procederà automaticamente ad una nuova analisi per trovare altri file che potrebbero avere lo stesso stato." #~ msgid "No working directory" #~ msgstr "Nessuna directory di lavoro" #~ msgid "Number of loose objects" #~ msgstr "Numero di oggetti slegati" #~ msgid "Number of packed objects" #~ msgstr "Numero di oggetti impacchettati" #~ msgid "Number of packs" #~ msgstr "Numero di pacchetti" #~ msgid "One or more of the merge tests failed because you have not fetched the necessary commits. Try fetching from %s first." #~ msgstr "Impossibile verificare una o più fusioni: mancano le revisioni necessarie. Prova prima a recuperarle da %s." #~ msgid "Options" #~ msgstr "Opzioni" #~ msgid "Original File:" #~ msgstr "File originario:" #~ msgid "Originally By:" #~ msgstr "In origine da:" #~ msgid "Packed objects waiting for pruning" #~ msgstr "Oggetti impacchettati che attendono la potatura" #, fuzzy #~ msgid "Path to git repository" #~ msgstr "%s non è un archivio Git." #~ msgid "Please select one or more branches to delete." #~ msgstr "Scegliere uno o più rami da cancellare." #~ msgid "Please supply a branch name." #~ msgstr "Inserire un nome per il ramo." #~ msgid "Portions staged for commit" #~ msgstr "Parti preparate per una nuova revisione" #~ msgid "" #~ "Possible environment issues exist.\n" #~ "\n" #~ "The following environment variables are probably\n" #~ "going to be ignored by any Git subprocess run\n" #~ "by %s:\n" #~ "\n" #~ msgstr "" #~ "Possibili problemi con le variabili d'ambiente.\n" #~ "\n" #~ "Le seguenti variabili d'ambiente saranno probabilmente\n" #~ "ignorate da tutti i sottoprocessi di Git avviati\n" #~ "da %s:\n" #~ "\n" #~ msgid "Preferences..." #~ msgstr "Preferenze..." #~ msgid "Prune Tracking Branches During Fetch" #~ msgstr "Effettua potatura dei duplicati locali di rami remoti durante il recupero" #~ msgid "Pruning tracking branches deleted from %s" #~ msgstr "Effettua potatura dei duplicati locali di rami remoti cancellati da %s" #~ msgid "Push Branches" #~ msgstr "Propaga rami" #~ msgid "Push to" #~ msgstr "Propaga verso" #~ msgid "Pushing %s %s to %s" #~ msgstr "Propagazione %s %s a %s" #~ msgid "Reading %s..." #~ msgstr "Lettura di %s..." #~ msgid "Ready to commit." #~ msgstr "Pronto per creare una nuova revisione." #~ msgid "Ready." #~ msgstr "Pronto." #, fuzzy #~ msgid "Rebase Branch" #~ msgstr "Rinomina ramo" #, fuzzy #~ msgid "Rebase..." #~ msgstr "Ripristina..." #~ msgid "" #~ "Recovering deleted branches is difficult.\n" #~ "\n" #~ "Delete the selected branches?" #~ msgstr "" #~ "Ricomporre rami cancellati è difficile.\n" #~ "\n" #~ "Cancellare i rami selezionati?" #~ msgid "" #~ "Recovering deleted branches is difficult. \n" #~ "\n" #~ " Delete the selected branches?" #~ msgstr "" #~ "Ricomporre rami cancellati può essere complicato. \n" #~ "\n" #~ " Eliminare i rami selezionati?" #~ msgid "Refreshing file status..." #~ msgstr "Controllo dello stato dei file in corso..." #, fuzzy #~ msgid "Remote Branches" #~ msgstr "Rinomina ramo" #~ msgid "Remote:" #~ msgstr "Remoto:" #, fuzzy #~ msgid "Rename remote?" #~ msgstr "Remoto" #~ msgid "Repository" #~ msgstr "Archivio" #~ msgid "Requires merge resolution" #~ msgstr "Richiede risoluzione dei conflitti" #~ msgid "Rescan" #~ msgstr "Analizza nuovamente" #~ msgid "" #~ "Reset changes?\n" #~ "\n" #~ "Resetting the changes will cause *ALL* uncommitted changes to be lost.\n" #~ "\n" #~ "Continue with resetting the current changes?" #~ msgstr "" #~ "Ripristinare la revisione corrente e annullare le modifiche?\n" #~ "\n" #~ "L'annullamento delle modifiche causerà la perdita di *TUTTE* le modifiche non ancora presenti nell'archivio.\n" #~ "\n" #~ "Continuare con l'annullamento delle modifiche attuali?" #~ msgid "Revert changes in these %i files?" #~ msgstr "Annullare le modifiche in questi %i file?" #, fuzzy #~ msgid "Select File" #~ msgstr "Seleziona tutto" #, fuzzy #~ msgid "Select file from \"%s\"" #~ msgstr "Cancellazione rami da %s" #~ msgid "Shared (Fastest, Not Recommended, No Backup)" #~ msgstr "Shared (il più veloce, non raccomandato, nessun backup)" #~ msgid "Shared only available for local repository." #~ msgstr "Shared è disponibile solo per archivi locali." #~ msgid "Show Less Context" #~ msgstr "Mostra meno contesto" #~ msgid "Show More Context" #~ msgstr "Mostra più contesto" #~ msgid "Source Branches" #~ msgstr "Rami di origine" #~ msgid "Spell Checker Failed" #~ msgstr "Errore nel correttore ortografico" #~ msgid "Spell checker silently failed on startup" #~ msgstr "Il correttore ortografico ha riportato un errore all'avvio" #~ msgid "Spell checking is unavailable" #~ msgstr "Correzione ortografica indisponibile" #~ msgid "Spelling Dictionary:" #~ msgstr "Lingua dizionario:" #~ msgid "Stage Hunk For Commit" #~ msgstr "Prepara sezione per una nuova revisione" #~ msgid "Staged Changes (Will Commit)" #~ msgstr "Modifiche preparate (saranno nella nuova revisione)" #~ msgid "Staged for commit, missing" #~ msgstr "Preparato per una nuova revisione, mancante" #~ msgid "Staged for removal" #~ msgstr "Preparato per la rimozione" #~ msgid "Staged for removal, still present" #~ msgstr "Preparato alla rimozione, ancora presente" #, fuzzy #~ msgid "Staging Area" #~ msgstr "Analisi in corso %s..." #~ msgid "Staging area (index) is already locked." #~ msgstr "L'area di preparazione per una nuova revisione (indice) è già bloccata." #~ msgid "Standard (Fast, Semi-Redundant, Hardlinks)" #~ msgstr "Standard (veloce, semi-ridondante, con hardlink)" #~ msgid "Standard only available for local repository." #~ msgstr "Standard è disponibile solo per archivi locali." #~ msgid "Starting gitk... please wait..." #~ msgstr "Avvio di gitk... attendere..." #~ msgid "Staying on branch '%s'." #~ msgstr "Si rimarrà sul ramo '%s'." #~ msgid "Success" #~ msgstr "Successo" #~ msgid "The 'master' branch has not been initialized." #~ msgstr "Il ramo 'master' non è stato inizializzato." #~ msgid "The following branches are not completely merged into %s:" #~ msgstr "I rami seguenti non sono stati fusi completamente in %s:" #~ msgid "" #~ "The following branches are not completely merged into %s:\n" #~ "\n" #~ " - %s" #~ msgstr "" #~ "I rami seguenti non sono stati fusi completamente in %s:\n" #~ "\n" #~ " - %s" #~ msgid "" #~ "There is nothing to amend.\n" #~ "\n" #~ "You are about to create the initial commit. There is no commit before this to amend.\n" #~ msgstr "" #~ "Non c'è niente da correggere.\n" #~ "\n" #~ "Stai per creare la revisione iniziale. Non esiste una revisione precedente da correggere.\n" #~ msgid "This Detached Checkout" #~ msgstr "Questa revisione attiva staccata" #~ msgid "" #~ "This is example text.\n" #~ "If you like this text, it can be your font." #~ msgstr "" #~ "Questo è un testo d'esempio.\n" #~ "Se ti piace questo testo, scegli questo carattere." #~ msgid "" #~ "This repository currently has approximately %i loose objects.\n" #~ "\n" #~ "To maintain optimal performance it is strongly recommended that you compress the database when more than %i loose objects exist.\n" #~ "\n" #~ "Compress the database now?" #~ msgstr "" #~ "Questo archivio attualmente ha circa %i oggetti slegati.\n" #~ "\n" #~ "Per mantenere buone prestazioni si raccomanda di comprimere l'archivio quando sono presenti più di %i oggetti slegati.\n" #~ "\n" #~ "Comprimere l'archivio ora?" #~ msgid "Tracking branch %s is not a branch in the remote repository." #~ msgstr "Il duplicato locale del ramo remoto %s non è un ramo nell'archivio remoto." #~ msgid "Transfer Options" #~ msgstr "Opzioni di trasferimento" #~ msgid "Unable to copy object: %s" #~ msgstr "Impossibile copiare oggetto: %s" #~ msgid "Unable to copy objects/info/alternates: %s" #~ msgstr "Impossibile copiare oggetti/info/alternate: %s" #~ msgid "Unable to display %s" #~ msgstr "Impossibile visualizzare %s" #~ msgid "Unable to hardlink object: %s" #~ msgstr "Hardlink impossibile sull'oggetto: %s" #~ msgid "Unable to obtain your identity:" #~ msgstr "Impossibile ottenere la tua identità:" #~ msgid "" #~ "Unable to start gitk:\n" #~ "\n" #~ "%s does not exist" #~ msgstr "" #~ "Impossibile avviare gitk:\n" #~ "\n" #~ "%s non esiste" #~ msgid "Unable to unlock the index." #~ msgstr "Impossibile sbloccare l'accesso all'indice" #~ msgid "Unexpected EOF from spell checker" #~ msgstr "Il correttore ortografico ha mandato un EOF inaspettato" #~ msgid "" #~ "Unknown file state %s detected.\n" #~ "\n" #~ "File %s cannot be committed by this program.\n" #~ msgstr "" #~ "Stato di file %s sconosciuto.\n" #~ "\n" #~ "Questo programma non può creare una revisione contenente il file %s.\n" #~ msgid "Unlock Index" #~ msgstr "Sblocca l'accesso all'indice" #~ msgid "" #~ "Unmerged files cannot be committed.\n" #~ "\n" #~ "File %s has merge conflicts. You must resolve them and stage the file before committing.\n" #~ msgstr "" #~ "Non è possibile creare una revisione con file non sottoposti a fusione.\n" #~ "\n" #~ "Il file %s presenta dei conflitti. Devi risolverli e preparare il file per creare una nuova revisione prima di effettuare questa azione.\n" #~ msgid "Unrecognized spell checker" #~ msgstr "Correttore ortografico sconosciuto" #~ msgid "Unstage Hunk From Commit" #~ msgstr "Sezione non preparata per una nuova revisione" #~ msgid "Unsupported spell checker" #~ msgstr "Correttore ortografico non supportato" #~ msgid "Updating the Git index failed. A rescan will be automatically started to resynchronize git-gui." #~ msgstr "Impossibile aggiornare l'indice. Ora sarà avviata una nuova analisi che aggiornerà git-gui." #~ msgid "Updating working directory to '%s'..." #~ msgstr "Aggiornamento della directory di lavoro a '%s' in corso..." #, fuzzy #~ msgid "Updating..." #~ msgstr "Avvio in corso..." #~ msgid "Use thin pack (for slow network connections)" #~ msgstr "Utilizza 'thin pack' (per connessioni lente)" #~ msgid "Verify Database" #~ msgstr "Verifica l'archivio" #~ msgid "Verifying the object database with fsck-objects" #~ msgstr "Verifica dell'archivio con fsck-objects in corso" #~ msgid "Visualize %s's History" #~ msgstr "Visualizza la cronologia di %s" #~ msgid "Working... please wait..." #~ msgstr "Elaborazione in corso... attendere..." #~ msgid "" #~ "You are in the middle of a change.\n" #~ "\n" #~ "File %s is modified.\n" #~ "\n" #~ "You should complete the current commit before starting a merge. Doing so will help you abort a failed merge, should the need arise.\n" #~ msgstr "" #~ "Sei nel mezzo di una modifica.\n" #~ "\n" #~ "Il file %s è stato modificato.\n" #~ "\n" #~ "Bisogna completare la creazione della revisione attuale prima di iniziare una fusione. In questo modo sarà più facile interrompere una fusione non riuscita, nel caso ce ne fosse bisogno.\n" #~ msgid "" #~ "You are in the middle of a conflicted merge.\n" #~ "\n" #~ "File %s has merge conflicts.\n" #~ "\n" #~ "You must resolve them, stage the file, and commit to complete the current merge. Only then can you begin another merge.\n" #~ msgstr "" #~ "Sei nel mezzo di una fusione con conflitti.\n" #~ "\n" #~ "Il file %s ha dei conflitti.\n" #~ "\n" #~ "Bisogna risolvere i conflitti, preparare il file per una nuova revisione ed infine crearla per completare la fusione attuale. Solo a questo punto potrai iniziare un'altra fusione.\n" #~ msgid "" #~ "You are no longer on a local branch.\n" #~ "\n" #~ "If you wanted to be on a branch, create one now starting from 'This Detached Checkout'." #~ msgstr "" #~ "Non si è più su un ramo locale\n" #~ "\n" #~ "Se si vuole rimanere su un ramo, crearne uno ora a partire da 'Questa revisione attiva staccata'." #~ msgid "You must correct the above errors before committing." #~ msgstr "Bisogna correggere gli errori suddetti prima di creare una nuova revisione." #~ msgid "[Up To Parent]" #~ msgstr "[Directory superiore]" #~ msgid "commit-tree failed:" #~ msgstr "commit-tree non riuscito:" #~ msgid "fatal: Cannot resolve %s" #~ msgstr "errore grave: impossibile risolvere %s" #~ msgid "files" #~ msgstr "file" #~ msgid "files checked out" #~ msgstr "file presenti nella directory di lavoro" #~ msgid "files reset" #~ msgstr "ripristino file" #~ msgid "git-gui - a graphical user interface for Git." #~ msgstr "git-gui - un'interfaccia grafica per Git." #~ msgid "git-gui: fatal error" #~ msgstr "git-gui: errore grave" #~ msgid "lines annotated" #~ msgstr "linee annotate" #~ msgid "objects" #~ msgstr "oggetti" #~ msgid "pt." #~ msgstr "pt." #~ msgid "push %s" #~ msgstr "propaga verso %s" #~ msgid "remote prune %s" #~ msgstr "potatura remota di %s" #~ msgid "update-ref failed:" #~ msgstr "update-ref non riuscito:" #~ msgid "warning" #~ msgstr "attenzione" #~ msgid "warning: Tcl does not support encoding '%s'." #~ msgstr "attenzione: Tcl non supporta la codifica '%s'." #~ msgid "write-tree failed:" #~ msgstr "write-tree non riuscito:" git-cola-3.6/po/ja.po000066400000000000000000002713751356743264500144670ustar00rootroot00000000000000# Translation of git-cola to Japanese # Copyright (C) 2007 Shawn Pearce at el. # This file is distributed under the same license as the git-cola package. # しらいし ななこ , 2007. # fu7mu4 , 2018-2019. # Shun Sakai , 2019. # msgid "" msgstr "" "Project-Id-Version: git-cola VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-17 01:06-0700\n" "PO-Revision-Date: 2019-07-27 13:24+0900\n" "Last-Translator: Shun Sakai \n" "Language-Team: Japanese\n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "" "\n" "

\n" " Drag and drop or use the Add button to add\n" " patches to the list\n" "

\n" " " msgstr "" "\n" "

\n" " ドラッグ&ドロップまたは追加ボタンを押して追加します。\n" " リストにパッチを適用する\n" "

\n" " " #, python-format msgid "" "\n" "
\n" " Git Cola has been translated into different languages thanks\n" " to the help of the individuals listed below.\n" "\n" "
\n" "

\n" " Translation is approximate. If you find a mistake,\n" " please let us know by opening an issue on Github:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " We invite you to participate in translation by adding or updating\n" " a translation and opening a pull request.\n" "

\n" "\n" "
\n" "\n" " " msgstr "" "\n" "
\n" " Git Cola は様々な言語に翻訳されてきました。\n" " 以下のリストの皆さまに感謝します。\n" "\n" "
\n" "

\n" " 翻訳はおおよそです。もし間違いがあった場合、\n" " Githubに課題を作成して知らせてください。:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " 私たちはあなたに翻訳を追加したり翻訳を更新したりしていただきたいです。\n" " そしてプルリクエストを送っていただきたいです。\n" "

\n" "\n" "
\n" "\n" " " #, python-format msgid "" "\n" "
\n" " Git Cola version %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " msgstr "" "\n" "
\n" " Git Cola のバージョンは %(cola_version)s、 %(build_version)sの\n" "
    \n" "
  • %(platform_version)sです。\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " #, python-format msgid "" "\n" "
\n" " Please use %(bug_link)s to report issues.\n" "
\n" " " msgstr "" "\n" "
\n" " %(bug_link)s を使って課題を報告してください。\n" "
\n" " " #, python-format msgid "" "\n" " Format String Variables\n" " -----------------------\n" " %(path)s = relative file path\n" " %(abspath)s = absolute file path\n" " %(dirname)s = relative directory path\n" " %(absdirname)s = absolute directory path\n" " %(filename)s = file basename\n" " %(basename)s = file basename without extension\n" " %(ext)s = file extension\n" msgstr "" "\n" " フォーマットストリング変数\n" " -----------------------\n" " %(path)s = ファイルへの相対パス\n" " %(abspath)s = ファイルへの絶対パス\n" " %(dirname)s = ディレクトリへの相対パス\n" " %(absdirname)s = ディレクトリへの絶対パス\n" " %(filename)s = ファイルのベース名\n" " %(basename)s = ファイルのベース名(拡張子なし)\n" " %(ext)s = ファイルの拡張子\n" msgid "" "\n" "Commands\n" "--------\n" "pick = use commit\n" "reword = use commit, but edit the commit message\n" "edit = use commit, but stop for amending\n" "squash = use commit, but meld into previous commit\n" "fixup = like \"squash\", but discard this commit's log message\n" "exec = run command (the rest of the line) using shell\n" "\n" "These lines can be re-ordered; they are executed from top to bottom.\n" "\n" "If you disable a line here THAT COMMIT WILL BE LOST.\n" "\n" "However, if you disable everything, the rebase will be aborted.\n" "\n" "Keyboard Shortcuts\n" "------------------\n" "? = show help\n" "j = move down\n" "k = move up\n" "J = shift row down\n" "K = shift row up\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "spacebar = toggle enabled\n" "\n" "ctrl+enter = accept changes and rebase\n" "ctrl+q = cancel and abort the rebase\n" "ctrl+d = launch difftool\n" msgstr "" "\n" "コマンド\n" "--------\n" "pick = コミットを使う。\n" "reword = コミットを使う、がしかしコミットメッセージを編集する。\n" "edit = コミットを使う、が修正のために停止する。\n" "squash = コミットを使う、が以前のコミットと混ぜ合わせる。\n" "fixup = \"squash\"に似ているが、コミットログのメッセージを破棄する。\n" "exec = シェルを使って、(行の残り部分の)コマンドを実行する。\n" "\n" "これらの行は並べ直すことができます。これは上から下に実行します。\n" "\n" "もし1行を無効にした場合、そのコミットはなくなります。\n" "\n" "しかし、もし全てを無効にした場合、そのrebaseは中止になります。\n" "\n" "キーボードショートカット\n" "------------------\n" "?= ヘルプの表示\n" "j = 下に移動\n" "k = 上に移動\n" "J = shift row down\n" "K = shift row up\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "spacebar = 有効化の切り替え\n" "\n" "ctrl+enter = 変更を受け入れて、rebaseする\n" "ctrl+q = rebaseをキャンセルして、rebaseを中止する。\n" "ctrl+d = diffツールの起動\n" msgid "" "\n" "Keyboard Shortcuts\n" "------------------\n" "J, Down = Move Down\n" "K, Up = Move Up\n" "Enter = Edit Selected Files\n" "Spacebar = Open File Using Default Application\n" "Ctrl + L = Focus Text Entry Field\n" "? = Show Help\n" "\n" "The up and down arrows change focus between the text entry field\n" "and the results.\n" msgstr "" "\n" "キーボードショートカット\n" "------------------\n" "J, Down = 下に移動\n" "K, Up = 上に移動\n" "Enter = 選択ファイルの編集\n" "Spacebar = デフォルトのアプリケーションでファイルを開く\n" "Ctrl + L = テキスト項目にフォーカスを移動する\n" "?= ヘルプを表示する\n" "\n" "カーソルの上下でテキスト項目と結果の間でフォーカスを変更する。\n" msgid " - DAG" msgstr " - DAG" msgid " commits ago" msgstr " 前にコミット" #, python-format msgid "\"%(branch)s\" has been deleted from \"%(remote)s\"." msgstr "\"%(branch)s\" は \"%(remote)s\" から削除されています。" #, python-format msgid "\"%(command)s\" returned exit status \"%(status)d\"" msgstr "\"%(command)s\" は終了ステータスとして \"%(status)d\" を返しました。" #, python-format msgid "\"%(command)s\" returned exit status %(status)d" msgstr "\"%(command)s\" は終了ステータスとして %(status)d を返しました。" #, python-format msgid "\"%s\" already exists" msgstr "\"%s\" ブランチは既に存在します。" #, python-format msgid "\"%s\" already exists, cola will create a new directory" msgstr "\"%s\" は既に存在しています。git colaは新しいディレクトリを作成してします。" #, python-format msgid "\"%s\" requires a selected file." msgstr "\"%s\" は選択したファイルを要求します。" msgid "#" msgstr "#" #, python-format msgid "%(project)s: %(branch)s - Browse" msgstr "%(project)s: %(branch)s - ブラウズ" #, python-format msgid "%(project)s: %(ref)s - DAG" msgstr "%(project)s: %(ref)s - DAG" #, python-format msgid "%d days ago" msgstr "%d 日前" #, python-format msgid "%d hours ago" msgstr "%d 時間前" #, python-format msgid "%d minutes ago" msgstr "%d 分前" #, python-format msgid "%d patch(es) applied." msgstr "%d パッチを適用しました。" #, python-format msgid "%d skipped" msgstr "%d スキップしました。" #, python-format msgid "" "%s appears to contain merge conflicts.\n" "\n" "You should probably skip this file.\n" "Stage it anyways?" msgstr "" "%s マージに衝突があることがわかりました。\n" "\n" "このファイルはおそらくスキップすべきです。\n" "これをステージングしますか?" #, python-format msgid "%s is not a Git repository." msgstr "%s は Gitのリポジトリではありません。" #, python-format msgid "%s will be removed from your bookmarks." msgstr "%s をあなたのブックマークから削除します。" #, python-format msgid "%s will be removed from your recent repositories." msgstr "%s をあなたの最近のリポジトリリストから削除します。" #, python-format msgid "%s: No such file or directory." msgstr "%s: そのようなファイルやディレクトリはありません。" msgid "&Edit" msgstr "&E編集" msgid "&File" msgstr "&Fファイル" msgid "(Amending)" msgstr "(訂正)" msgid "*** Branch Point ***" msgstr "*** ブランチポイント ***" msgid "*** Sandbox ***" msgstr "*** サンドボックス ***" msgid "100%" msgstr "100%" msgid "200%" msgstr "200%" msgid "25%" msgstr "25%" msgid "400%" msgstr "400%" msgid "50%" msgstr "50%" msgid "800%" msgstr "800%" msgid " ..." msgstr "<パス> ..." msgid "" "A commit template has not been configured.\n" "Use \"git config\" to define \"commit.template\"\n" "so that it points to a commit template." msgstr "" "コミットテンプレートは変更できません。\n" "\"git config\" を使って、\"commit.template\"を定義してください。\n" "これはコミットテンプレートを指定します。" #, python-format msgid "A hook must be provided at \"%s\"" msgstr "フックが\"%s\"で提供されなければなりません。" #, python-format msgid "A stash named \"%s\" already exists" msgstr "\"%s\" という名前のstashは既に存在します。" msgid "Abort" msgstr "中止しています。" msgid "Abort Action" msgstr "アクションを中止しています。" msgid "Abort Merge" msgstr "マージを中止しています。" msgid "Abort Merge..." msgstr "マージ中止…" msgid "Abort the action?" msgstr "このアクションを中止しますか?" msgid "" "Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" "Recovering uncommitted changes is not possible." msgstr "" "現在のマージを中止すると、コミットしていない *全て* の変更を失います。\n" "コミットしていない変更を戻すことはできません。" msgid "Aborting the current merge?" msgstr "現在のマージを中止しますか?" msgid "About" msgstr "About" msgid "About git-cola" msgstr "git-colaについて" msgid "Accept" msgstr "受け入れ" msgid "" "Accept changes and rebase\n" "Shortcut: Ctrl+Enter" msgstr "" "変更を受け入れてrebaseします。\n" "ショートカット: Ctrl+Enter" msgid "Action Name" msgstr "アクション名" msgid "Actions" msgstr "アクション" msgid "Actions..." msgstr "アクション..." msgid "Add" msgstr "追加" msgid "Add Favorite" msgstr "お気に入りの追加" msgid "Add Remote" msgstr "リモートの追加" msgid "Add Separator" msgstr "セパレータの追加" msgid "Add Toolbar" msgstr "ツールバーの追加" msgid "" "Add and remove remote repositories using the \n" "Add(+) and Delete(-) buttons on the left-hand side.\n" "\n" "Remotes can be renamed by selecting one from the list\n" "and pressing \"enter\", or by double-clicking." msgstr "" "リモートリポジトリの追加や削除するには\n" "左側のAdd(+) または Delete(-) ボタンを使用します。\n" "\n" "リモートリポジトリの名前を変更するには、リストから選択して\n" "\"enter\"を入力する、またはダブルクリックします。" msgid "Add new remote git repository" msgstr "新しいgitのリモートリポジトリを追加します。" msgid "Add patches (+)" msgstr "パッチを追加 (+)" msgid "Add remote" msgstr "リモートを追加" msgid "Add to .gitignore" msgstr ".gitignoreに追加" msgid "Add to Git Annex" msgstr "Git Annexに追加" msgid "Add to Git LFS" msgstr "Git LFSに追加" msgid "Additions" msgstr "追加" msgid "Advanced" msgstr "拡張" msgid "Age" msgstr "年齢" msgid "All Repositories" msgstr "全てのリポジトリ" #, python-format msgid "" "All submodules will be updated using\n" "\"%s\"" msgstr "" msgid "Allow non-fast-forward updates. Using \"force\" can cause the remote repository to lose commits; use it with care" msgstr "ファストフォワードではない更新を許可します。\"force\" はリモートリポジトリでコミットを失う可能性があります。使用には注意してください。" msgid "Always create a merge commit when enabled, even when the merge is a fast-forward update" msgstr "可能な場合には常にマージコミットを作成するする、たとえそのマージがファーストフォワードアップデートだった場合でもでも作成する。" msgid "Amend" msgstr "訂正" msgid "Amend Commit" msgstr "コミットの訂正" msgid "Amend Last Commit" msgstr "最新コミットを訂正" msgid "Amend the published commit?" msgstr "発行済のコミットを訂正しますか?" msgid "Amending" msgstr "訂正中" msgid "" "An action is still running.\n" "Terminating it could result in data loss." msgstr "" "アクション継続中です。\n" "中断は結果としてデータを失うことがありえます。" msgid "" "An unsigned, lightweight tag will be created instead.\n" "Create an unsigned tag?" msgstr "" "署名のない、軽量のタグを代わりにに作成します。\n" "署名なしタグを作成しますか?" msgid "Appearance" msgstr "外観" msgid "Apply" msgstr "適用" msgid "Apply Patches" msgstr "パッチの適用" msgid "Apply Patches..." msgstr "パッチの適用..." msgid "Apply and drop the selected stash (git stash pop)" msgstr "選択したスタッシュを適用する(git stash pop)" msgid "Apply the selected stash" msgstr "選択したスタッシュを適用する" msgid "Arguments" msgstr "引数" msgid "Attach" msgstr "アタッチ" msgid "Author" msgstr "著者" msgid "Authors" msgstr "著者" msgid "Auto" msgstr "自動" msgid "Auto-Wrap Lines" msgstr "自動行折り返し" msgid "Basic Regexp" msgstr "基本正規表現" msgid "Blame Viewer" msgstr "責任者ビューアー" #, fuzzy msgid "Blame selected paths" msgstr "選択したパスの名前を変更" msgid "Blame..." msgstr "責任者..." msgid "Bold on dark headers instead of italic" msgstr "イタリックフォントからボールドフォントとダークヘッダに" msgid "Branch" msgstr "ブランチ" #, python-format msgid "" "Branch \"%(branch)s\" does not exist in \"%(remote)s\".\n" "A new remote branch will be published." msgstr "" "\"%(branch)s\" は \"%(remote)s\" に存在していません。\n" "新しいリモートブランチを作成し、公開します。" #, python-format msgid "Branch \"%s\" already exists." msgstr "\"%s\" ブランチは既に存在します。" msgid "Branch Diff Viewer" msgstr "ブランチ差分ビューアー" msgid "Branch Exists" msgstr "ブランチの存在" msgid "Branch Name" msgstr "ブランチ名" #, python-format msgid "Branch: %s" msgstr "ブランチ: %s" msgid "Branches" msgstr "ブランチ" msgid "Branches..." msgstr "ブランチ..." msgid "Brazilian translation" msgstr "ブラジル語翻訳" msgid "Browse" msgstr "ブラウズ" msgid "Browse Commits..." msgstr "コミットのブラウズ..." msgid "Browse Current Branch..." msgstr "現在ブランチのブラウズ..." msgid "Browse Other Branch..." msgstr "その他のブランチのブラウズ..." msgid "Browse..." msgstr "ブラウズ..." msgid "Browser" msgstr "ブラウザー" #, python-format msgid "Browsing %s" msgstr "%s のブラウズ" msgid "Bypass Commit Hooks" msgstr "コミットフックの回避" msgid "Cancel" msgstr "中止" msgid "" "Cancel rebase\n" "Shortcut: Ctrl+Q" msgstr "" "rebaseの中止\n" "ショートカット: Ctrl+Q: Ctrl+Q" msgid "Cannot Amend" msgstr "訂正不可" #, python-format msgid "Cannot exec \"%s\": please configure a blame viewer" msgstr "\"%s\"を実行できません。責任者ビューアーを設定してください。" #, python-format msgid "Cannot exec \"%s\": please configure a history browser" msgstr "\"%s\"を実行できません。履歴ビューアーを設定してください。" #, python-format msgid "Cannot exec \"%s\": please configure your editor" msgstr "\"%s\"を実行できません。エディタを設定してください。" msgid "Changed Upstream" msgstr "変更したアップストリーム" msgid "Check Spelling" msgstr "スペルチェック" msgid "Check spelling" msgstr "スペルチェック" msgid "Checkout" msgstr "チェックアウト" msgid "Checkout After Creation" msgstr "作成してすぐチェックアウト" msgid "Checkout Branch" msgstr "ブランチをチェックアウト" msgid "Checkout Detached HEAD" msgstr "デタッチしたHEADをチェックアウト" msgid "Checkout as new branch" msgstr "新しいブランチとしてチェックアウト" msgid "Checkout..." msgstr "チェックアウト..." msgid "Cherry Pick" msgstr "チェリーピック" msgid "Cherry-Pick Commit" msgstr "チェリーピックコミット" msgid "Cherry-Pick..." msgstr "チェリーピック..." msgid "Choose Paths" msgstr "パスの選択" msgid "Choose the \"git grep\" regular expression mode" msgstr "\"git grep\" 正規表現モードを選択する" msgid "Clear Default Repository" msgstr "デフォルトリポジトリをクリアする" msgid "Clear commit message" msgstr "コミットメッセージをクリアする" msgid "Clear commit message?" msgstr "コミットメッセージをクリアしますか?" msgid "Clear..." msgstr "クリア..." msgid "Clone" msgstr "Clone" msgid "Clone Repository" msgstr "リポジトリのClone" msgid "Clone..." msgstr "Clone…" #, python-format msgid "Cloning repository at %s" msgstr "リポジトリのClone中: %s" msgid "Close" msgstr "閉じる" msgid "Close..." msgstr "閉じ作業中..." msgid "Collapse all" msgstr "全てCollapse" msgid "Command" msgstr "コマンド" msgid "Commit" msgstr "コミット" msgid "Commit failed" msgstr "コミット失敗" msgid "Commit staged changes" msgstr "ステージした変更をコミット" msgid "" "Commit staged changes\n" "Shortcut: Ctrl+Enter" msgstr "" "ステージした変更をコミット\n" "ショートカット: Ctrl+Enter" msgid "Commit summary" msgstr "コミットサマリー" msgid "Commit the merge if there are no conflicts. Uncheck to leave the merge uncommitted" msgstr "衝突のない場合のみこのマージをコミットチェックなしで、コミットされていないマージを残す。" msgid "Commit@@verb" msgstr "コミット" msgid "Compare" msgstr "比較" msgid "Compare All" msgstr "全て比較" msgid "Configure the remote branch as the the new upstream" msgstr "新しいアップストリームとしてリモートブランチを設定する" msgid "Configure toolbar" msgstr "ツールバーの設定" msgid "Console" msgstr "コンソール" msgid "Continue" msgstr "続行" msgid "Copy" msgstr "コピー" msgid "Copy Basename to Clipboard" msgstr "ベースネームをクリップボードにコピー" msgid "Copy Leading Path to Clipboard" msgstr "リーディングパスをクリップボードにコピー" msgid "Copy Path to Clipboard" msgstr "パスをクリップボードにコピー" msgid "Copy Relative Path to Clipboard" msgstr "相対パスをクリップボードにコピー" msgid "Copy SHA-1" msgstr "SHA-1をコピー" msgid "Copy..." msgstr "コピー中..." #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "Git URL \"%s\"がパースできません。" msgid "Create Branch" msgstr "ブランチを作成" msgid "Create Patch" msgstr "パッチを作成" msgid "Create Remote Branch" msgstr "リモートブランチを作成" msgid "Create Signed Commit" msgstr "署名されたコミットの作成" msgid "Create Tag" msgstr "タグの作成" msgid "Create Tag..." msgstr "タグの作成中..." msgid "Create Unsigned Tag" msgstr "書名のないタグの作成" msgid "Create a merge commit even when the merge resolves as a fast-forward" msgstr "マージコミットを作成するそれがファーストフォワードとしてマージされる可能性がある" msgid "Create a new remote branch?" msgstr "リモートブランチを作成しますか?" msgid "Create..." msgstr "作成…" #, python-format msgid "Created a new tag named \"%s\"" msgstr "新しく作成したタグ \"%s\" " msgid "Current Repository" msgstr "現在のリポジトリ" msgid "Custom Copy Actions" msgstr "コピーアクションをカスタム" msgid "Customize..." msgstr "カスタマイズ中..." msgid "Cut" msgstr "切り取り" msgid "Czech translation" msgstr "チェコ語翻訳" msgid "DAG..." msgstr "DAG中..." msgid "Dark Theme" msgstr "ダークテーマ" msgid "Date, Time" msgstr "日時" #, fuzzy msgid "Default" msgstr "既定値に戻す" msgid "Delete" msgstr "削除" #, python-format msgid "Delete %d file(s)?" msgstr "%d のfileを削除しますか?" msgid "Delete Bookmark" msgstr "ブックマークの削除" msgid "Delete Bookmark?" msgstr "ブックマークを削除しますか?" msgid "Delete Branch" msgstr "ブランチ削除" msgid "Delete Files" msgstr "ファイルの削除" msgid "Delete Files..." msgstr "ファイルを削除中..." msgid "Delete Files?" msgstr "ファイルを削除しますか?" msgid "Delete Remote" msgstr "リモートの削除" msgid "Delete Remote Branch" msgstr "リモートブランチの削除" msgid "Delete Remote Branch..." msgstr "リモートブランチの削除中..." msgid "Delete remote" msgstr "リモートの削除" #, python-format msgid "Delete remote \"%s\"" msgstr "リモート \"%s\"の削除" msgid "Delete remote?" msgstr "リモートを削除しますか?" msgid "Delete selected branch?" msgstr "選択したブランチを削除しますか?" msgid "Delete toolbar" msgstr "ツールバーの削除" msgid "Delete..." msgstr "削除中…" #, python-format msgid "Deleting \"%s\" failed" msgstr "\"%s\"の削除に失敗しました。" msgid "Deletions" msgstr "削除" msgid "Detach" msgstr "デタッチ" msgid "Detect Conflict Markers" msgstr "衝突マーカーをデタッチ" msgid "Detect conflict markers in unmerged files" msgstr "マージされていない衝突マーカーの検出" msgid "Developer" msgstr "開発者" msgid "Diff" msgstr "差分" msgid "Diff Against Predecessor..." msgstr "前任者との差分..." msgid "Diff Options" msgstr "diffツールオプション" msgid "Diff Tool" msgstr "差分ツール" msgid "Diff selected -> this" msgstr "Diff 選択 -> this" msgid "Diff this -> selected" msgstr "Diff this -> 選択" msgid "Diffstat" msgstr "差分状態" msgid "Difftool" msgstr "差分ツール" msgid "Directory Exists" msgstr "ディレクトリの存在" msgid "Display Untracked Files" msgstr "未トラックファイルの表示" msgid "Documentation" msgstr "ドキュメント" msgid "Drop" msgstr "ドロップ" msgid "Drop Stash" msgstr "スタッシュのドロップ" msgid "Drop Stash?" msgstr "ドロップをスタッシュしますか?" #, python-format msgid "Drop the \"%s\" stash?" msgstr "\"%s\" スタッシュをドロップしますか?" msgid "Drop the selected stash" msgstr "選択したスタッシュをドロップします。" msgid "Edit" msgstr "編集" msgid "Edit Rebase" msgstr "リベースを編集" msgid "Edit Remotes" msgstr "リモートを編集" msgid "Edit Remotes..." msgstr "リモートを編集中..." msgid "Edit remotes by selecting them from the list" msgstr "リストから選択してリモートを編集する" msgid "Edit selected paths" msgstr "選択したパスを編集する" msgid "Edit..." msgstr "編集中..." msgid "Editor" msgstr "エディタ" msgid "Email Address" msgstr "メールアドレス" msgid "Email contributor" msgstr "メールコントリビュータ" msgid "Enabled" msgstr "有効" msgid "Enter New Branch Name" msgstr "新しいブランチ名を入力する" msgid "Enter a name for the new bare repo" msgstr "新しいbaraリポジトリの名前を入力する" msgid "Enter a name for the stash" msgstr "スタッシュの名前を入力する" msgid "Error" msgstr "エラー" msgid "Error Cloning" msgstr "クローン中のエラー" msgid "Error Creating Branch" msgstr "ブランチ作成エラー" msgid "Error Creating Repository" msgstr "リポジトリ作成エラー" msgid "Error Deleting Remote Branch" msgstr "リモートブランチ削除エラー" msgid "Error Editing File" msgstr "ファイル編集エラー" msgid "Error Launching Blame Viewer" msgstr "責任者ビューア起動エラー" msgid "Error Launching History Browser" msgstr "履歴ブラウザ起動エラー" #, python-format msgid "Error creating remote \"%s\"" msgstr "リモート \"%s\"作成エラー" msgid "Error creating stash" msgstr "スタッシュ作成エラー" #, python-format msgid "Error deleting remote \"%s\"" msgstr "リモート \"%s\" 削除エラー" #, python-format msgid "Error renaming \"%(name)s\" to \"%(new_name)s\"" msgstr "\"%(name)s\" から \"%(new_name)s\" の名前変更エラー" msgid "Error running prepare-commitmsg hook" msgstr "コミットメッセージ前フック実行エラー" #, fuzzy, python-format msgid "Error updating submodule %s" msgstr "リモート \"%s\"作成エラー" #, fuzzy msgid "Error updating submodules" msgstr "ファイル編集エラー" msgid "Error: Cannot find commit template" msgstr "エラー:コミットテンプレートが見つかりません。" msgid "Error: Stash exists" msgstr "エラー:スタッシュの存在" msgid "Error: Unconfigured commit template" msgstr "エラー:コミットテンプレートが設定されていない" #, python-format msgid "Error: could not clone \"%s\"" msgstr "エラー: \"%s\" が cloneできない" #, python-format msgid "Error: could not create tag \"%s\"" msgstr "エラー: tag \"%s\" が作成できない" #, python-format msgid "Executing action %s" msgstr "アクション %s の実行中" msgid "Expand all" msgstr "全て展開" msgid "Export Patches" msgstr "パッチのエクスポート" msgid "Export Patches..." msgstr "パッチのエクスポート中..." msgid "Expression..." msgstr "表現..." msgid "Extended Regexp" msgstr "拡張正規表現" msgid "Extended description..." msgstr "拡張記述..." msgid "Fast Forward Only" msgstr "ファーストフードのみ" msgid "Fast-forward only" msgstr "ファーストフードのみ" msgid "Favorite repositories" msgstr "よく使うリポジトリ" msgid "Favorites" msgstr "よく使う" msgid "Fetch" msgstr "取得" msgid "Fetch Tracking Branch" msgstr "トラッキング・ブランチを取得" msgid "Fetch..." msgstr "取得中..." msgid "File Browser..." msgstr "ファイルブラウザ..." msgid "File Differences" msgstr "ファイル差分" msgid "File Saved" msgstr "保存したファイル" #, python-format msgid "File saved to \"%s\"" msgstr "ファイルを \"%s\" へ保存" msgid "File system change monitoring: disabled because \"cola.inotify\" is false.\n" msgstr "ファイルシステム変更監視: \"cola.inotify\"がfalseであるため、無効です。\n" msgid "File system change monitoring: disabled because libc does not support the inotify system calls.\n" msgstr "ファイルシステム変更監視: libcがinotifyシステムコールをサポートしていないため、無効です。\n" msgid "File system change monitoring: disabled because pywin32 is not installed.\n" msgstr "ファイルシステム変更監視: pywin32がインストールされていないため、無効です。\n" msgid "" "File system change monitoring: disabled because the limit on the total number of inotify watches was reached. You may be able to increase the limit on the number of watches by running:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" msgstr "" "ファイルシステム変更監視: inotify 監視の総数が上限に到達したため無効です。inotifyの監視の総数の上限を増加させるには以下のように実行します。:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" msgid "File system change monitoring: enabled.\n" msgstr "ファイルシステム変更監視: 有効です。\n" msgid "Filename" msgstr "ファイル名" msgid "Files" msgstr "ファイル" msgid "Filter branches..." msgstr "ブランチのフィルタ..." msgid "Filter paths..." msgstr "パスのフィルタ..." msgid "Find Files" msgstr "ファイルの検索" msgid "Fixed String" msgstr "固定文字列" msgid "Fixed-Width Font" msgstr "固定幅フォント" msgid "Fixup" msgstr "修正" msgid "Fixup Previous Commit" msgstr "以前のコミットを修正" msgid "Flat dark blue" msgstr "" msgid "Flat dark green" msgstr "" msgid "Flat dark grey" msgstr "" msgid "Flat dark red" msgstr "" msgid "Flat light blue" msgstr "" msgid "Flat light green" msgstr "" msgid "Flat light grey" msgstr "" msgid "Flat light red" msgstr "" msgid "Font Size" msgstr "フォントサイズ" msgid "Force" msgstr "強制" msgid "Force Fetch" msgstr "強制フェッチ" msgid "Force Fetch?" msgstr "強制フェッチしますか?" msgid "Force Push" msgstr "強制プッシュ" msgid "Force Push?" msgstr "強制プッシュしますか?" #, python-format msgid "Force fetching from %s?" msgstr "%sから強制フェッチしますか?" #, python-format msgid "Force push to %s?" msgstr "%sへ強制プッシュしますか?" msgid "Format String" msgstr "フォーマットストリング" msgid "French translation" msgstr "フランス語翻訳" msgid "GPG-sign the merge commit" msgstr "マージコミットのGPG署名" msgid "GUI theme" msgstr "GUIテーマ" #, python-format msgid "Gathering info for \"%s\"..." msgstr "\"%s\"の情報を収集..." msgid "German translation" msgstr "ドイツ語翻訳" msgid "Get Commit Message Template" msgstr "コミットメッセージのテンプレートを取得" msgid "Go Down" msgstr "下に移動" msgid "Go Up" msgstr "上に移動" msgid "Grab File..." msgstr "ファイルのGrab..." msgid "Graph" msgstr "グラフ" msgid "Grep" msgstr "Grep" msgid "Have you rebased/pulled lately?" msgstr "最近rebaseまたはpullを実行しましたか?" msgid "Help" msgstr "ヘルプ" msgid "Help - Custom Copy Actions" msgstr "ヘルプ - カスタムコピーアクション" msgid "Help - Find Files" msgstr "ヘルプ - ファイルの捜索" msgid "Help - git-xbase" msgstr "ヘルプ - git-xbase" msgid "Hide Details.." msgstr "詳細を隠す。" msgid "High DPI" msgstr "高DPI" msgid "History Browser" msgstr "履歴ブラウザ" msgid "Hungarian translation" msgstr "ハンガリー語翻訳" msgid "Icon theme" msgstr "アイコンテーマ" msgid "Ignore all whitespace" msgstr "全ての空白文字を無視する" msgid "Ignore changes in amount of whitespace" msgstr "変更の空白文字を無視する" msgid "Ignore changes in whitespace at EOL" msgstr "変更の、改行などの行末空白文字を無視する" msgid "Ignore custom pattern" msgstr "カスタムパターンで無視を指定する" msgid "Ignore exact filename" msgstr "厳密に指定したファイル名で無視を指定する" msgid "Ignore filename or pattern" msgstr "ファイル名またはパターンで無視を指定する" msgid "Include tags " msgstr "タグを含める " msgid "Indent Status paths" msgstr "" msgid "Indonesian translation" msgstr "インドネシア語翻訳" msgid "Initialize Git Annex" msgstr "Git Annexを初期化する" msgid "Initialize Git LFS" msgstr "Git LFSを初期化する" msgid "Inititalize submodules" msgstr "サブモジュールを初期化する" msgid "Insert spaces instead of tabs" msgstr "タブではなく空白スペースを挿入する" msgid "Interactive Rebase" msgstr "インタラクティブリベース" msgid "Invalid Revision" msgstr "無効なリビジョン" msgid "Keep *.orig Merge Backups" msgstr "*.orig マージバックアップを保持" msgid "Keep Index" msgstr "インデックスを保持" msgid "Keyboard Shortcuts" msgstr "キーボードショートカット" msgid "Launch Diff Tool" msgstr "差分ツールを起動" msgid "Launch Directory Diff Tool" msgstr "ディレクトリ差分ツールを起動" msgid "Launch Editor" msgstr "エディタを起動" msgid "Launch Terminal" msgstr "ターミナルを起動" msgid "" "Launch external diff tool\n" "Shortcut: Ctrl+D" msgstr "" "外部差分ツールを起動\n" "ショートカット: Ctrl+D" msgid "Launch git-cola" msgstr "git-colaを起動" msgid "Launch git-difftool against previous versions" msgstr "git差分ツールを以前のバージョンに対して起動" msgid "Launch git-difftool on the current path" msgstr "git差分ツールを現在のパスに対して起動" msgid "Light Theme" msgstr "ライトテーマ" msgid "Load Commit Message" msgstr "コミットメッセージをロード" msgid "Load Commit Message..." msgstr "コミットメッセージをロード中" msgid "Load Previous Commit Message" msgstr "以前のコミットメッセージをロード" msgid "Loading..." msgstr "ロード中..." msgid "Local" msgstr "ローカル" msgid "Local Branch" msgstr "ローカルブランチ" msgid "Local branch" msgstr "ローカルブランチ" msgid "Lock Layout" msgstr "レイアウトのロック" msgid "Log" msgstr "ログ" msgid "Maintainer (since 2007) and developer" msgstr "2007年からのメンテナーと開発者" msgid "Merge" msgstr "マージ" #, python-format msgid "Merge \"%(revision)s\" into \"%(branch)s\"" msgstr "\"%(revision)s\" を \"%(branch)s\" にマージ" msgid "Merge Tool" msgstr "マージツール" msgid "Merge Verbosity" msgstr "マージの冗長度" msgid "Merge failed. Conflict resolution is required." msgstr "マージ失敗衝突の解明が必要です。" #, python-format msgid "Merge into \"%s\"" msgstr "\"%s\"へのマージ" msgid "Merge into current branch" msgstr "現在のブランチへマージ" msgid "Merge..." msgstr "マージ中..." msgid "Merging" msgstr "マージ中" msgid "Message" msgstr "メッセージ" msgid "Missing Commit Message" msgstr "コミットメッセージの喪失" msgid "Missing Data" msgstr "データの喪失" msgid "Missing Name" msgstr "名前の喪失" msgid "Missing Revision" msgstr "リビジョンの喪失" msgid "Missing Tag Message" msgstr "タグメッセージの喪失" msgid "Modified" msgstr "修正" msgid "More..." msgstr "以上..." msgid "Move Down" msgstr "下に移動" msgid "Move Up" msgstr "上に移動" msgid "Move files to trash" msgstr "ファイルをゴミ箱に移動" msgid "Name" msgstr "名前" msgid "Name for the new remote" msgstr "新しいリモートの名前" msgid "New Bare Repository..." msgstr "新しい Bare リポジトリ..." msgid "New Repository..." msgstr "新しいリポジトリ..." msgid "New..." msgstr "新規…" msgid "Next File" msgstr "次のファイル" msgid "No" msgstr "いいえ" msgid "No Revision Specified" msgstr "指定リビジョンがありません" msgid "" "No changes to commit.\n" "\n" "You must stage at least 1 file before you can commit." msgstr "" "コミットする変更がありません\n" "\n" "コミットする前に少なくとも1ファイルをステージしなければなりません。" msgid "No commits exist in this branch." msgstr "このブランチにコミットはありません。" msgid "No fast forward" msgstr "ファーストフォワードがありません" msgid "No fast-forward" msgstr "ファーストフォワードがありません" msgid "No repository selected." msgstr "リポジトリが選択されていません。" msgid "Non-fast-forward fetch overwrites local history!" msgstr "ファーストフォワードではないフェッチはローカルの履歴を上書きします!" msgid "" "Non-fast-forward push overwrites published history!\n" "(Did you pull first?)" msgstr "" "ファーストフォワードではないフェッチは発行した履歴を上書きします!\n" "(pullを先に行いますか?)" msgid "Nothing to commit" msgstr "コミットするものはありません。" msgid "Nothing to do" msgstr "すべきことはありません" msgid "Number of Diff Context Lines" msgstr "diff の文脈行数" msgid "Open" msgstr "開く" msgid "Open Git Repository..." msgstr "Git リポジトリを開く..." #, fuzzy msgid "Open Parent" msgstr "最近のものを開く" msgid "Open Parent Directory" msgstr "親ディレクトリを開く" msgid "Open Recent" msgstr "最近のものを開く" msgid "Open Using Default Application" msgstr "デフォルトのアプリケーションで開く" msgid "Open in New Window" msgstr "新しいウィンドウで開く" msgid "Open in New Window..." msgstr "新しいウィンドウで開いています..." msgid "Open..." msgstr "開く…" msgid "Other branches" msgstr "その他のブランチ" msgid "Overwrite" msgstr "上書き" #, python-format msgid "Overwrite \"%s\"?" msgstr "\"%s\"を上書きしますか?" msgid "Overwrite File?" msgstr "ファイルを上書きしますか?" msgid "" "Parse arguments using a shell.\n" "Queries with spaces will require \"double quotes\"." msgstr "" "シェルで引数をパースします。\n" "空白文字のあるクエリは二重引用符で囲む必要があります。" msgid "Partially Staged" msgstr "部分ステージ" msgid "Paste" msgstr "貼り付け" msgid "Patch(es) Applied" msgstr "パッチの適用" msgid "Path" msgstr "パス" msgid "Path or URL to clone (Env. $VARS okay)" msgstr "CloneのパスやURL(環境変数は解釈できる)" msgid "Pick" msgstr "ピック" msgid "Pixel XOR" msgstr "Pixel XOR" msgid "Please provide both a branch name and revision expression." msgstr "ブランチ名とリビジョン表現を両方を提供してください。" msgid "Please select a file" msgstr "ファイルを選択してください" msgid "Please specify a name for the new tag." msgstr "新しいタグの名前を指定してください。" msgid "Please specify a revision to tag." msgstr "タグをつけるためのリビジョンを指定してください。" msgid "" "Please supply a commit message.\n" "\n" "A good commit message has the following format:\n" "\n" "- First line: Describe in one sentence what you did.\n" "- Second line: Blank\n" "- Remaining lines: Describe why this change is good.\n" msgstr "" "コミットメッセージを提供してください。\n" "\n" "良いコミットメッセージは次のフォーマットを持ちます。:\n" "\n" "- 1行目: 1行であなたがしたことを説明します。\n" "- 2行目: 空行\n" "- 3行目以降: あなたがした変更の理由を説明します。\n" msgid "Point the current branch head to a new commit?" msgstr "現在のブランチのheadを新しいコミットに指定しますか?" msgid "Polish translation" msgstr "ポーランド語翻訳" msgid "Pop" msgstr "Pop" msgid "Preferences" msgstr "設定" msgid "Prefix" msgstr "prefix" msgid "Prepare Commit Message" msgstr "コミットメッセージの準備" msgid "Prevent \"Stage\" from staging all files when nothing is selected" msgstr "何も選択されていないとき、全てのファイルをステージングしないようにする" msgid "Previous File" msgstr "以前ののファイル" msgid "Prompt on creation" msgstr "生成時のプロンプト" msgid "Prompt when pushing creates new remote branches" msgstr "新規のリモートブランチを作成するプッシュ時のプロンプト" msgid "Prune " msgstr "Prune " msgid "Pull" msgstr "プル" msgid "Pull..." msgstr "プル..." msgid "Push" msgstr "プッシュ" msgid "Push..." msgstr "プッシュ…" msgid "Quit" msgstr "終了" msgid "Rebase" msgstr "Rebase" #, python-format msgid "Rebase onto %s" msgstr "%s にrebase" msgid "Rebase stopped" msgstr "停止したrebase" msgid "Rebase the current branch instead of merging" msgstr "マージの代わりに現在ブランチをrebase" msgid "Rebasing" msgstr "rebase中" msgid "Recent" msgstr "最近" msgid "Recent repositories" msgstr "最近のリポジトリ" msgid "Recent repository count" msgstr "最近のリポジトリ数" msgid "Recently Modified Files" msgstr "最近の修正ファイル" msgid "Recently Modified Files..." msgstr "最近の修正ファイル..." msgid "Recovering a dropped stash is not possible." msgstr "ドロップしたスタッシュの回復をはできません。" msgid "Recovering lost commits may not be easy." msgstr "失なわれたコミットを回復するのは簡単ではありません。" msgid "Redo" msgstr "やり直し" msgid "Reduce commit history to minimum" msgstr "コミット履歴を最小に減らす" msgid "Refresh" msgstr "再読み込み" msgid "Refuse to merge unless the current HEAD is already up-to-date or the merge can be resolved as a fast-forward" msgstr "現在のHEADが既に最新ではないまたはマージがファーストフォワードとして解決されない限りマージを拒否する。" msgid "Remote" msgstr "リモート" msgid "Remote Branch" msgstr "リモートブランチ" msgid "Remote Branch Deleted" msgstr "リモートブランチ削除" msgid "Remote git repositories - double-click to rename" msgstr "リモートgitリポジトリ - ダブルクリックして名前の変更" msgid "Remove" msgstr "削除" #, python-format msgid "Remove %s from the recent list?" msgstr "最近のリストから %s を削除しますか?" msgid "Remove Element" msgstr "要素の削除" msgid "Remove remote-tracking branches that no longer exist on the remote" msgstr "リモートリポジトリ上に今は存在するしないブランチのリモートトラッキングを削除する" msgid "Remove selected (Delete)" msgstr "選択したものを削除 (Delete)" msgid "Rename" msgstr "名前変更" #, python-format msgid "Rename \"%s\"" msgstr "\"%s\" の名前を変更" msgid "Rename Branch" msgstr "ブランチの名前変更" msgid "Rename Branch..." msgstr "ブランチの名前変更中..." msgid "Rename Existing Branch" msgstr "存在するブランチの名前変更" msgid "Rename Remote" msgstr "リモートの名前変更" msgid "Rename Repository" msgstr "リポジトリの名前変更" msgid "Rename branch" msgstr "ブランチの名前変更" #, python-format msgid "Rename remote \"%(current)s\" to \"%(new)s\"?" msgstr "リモートの\"%(current)s\" を \"%(new)s\" と名前を変更しますか?" msgid "Rename selected paths" msgstr "選択したパスの名前を変更" #, python-format msgid "Repository: %s" msgstr "リポジトリ: %s" msgid "Reset" msgstr "リセット" #, python-format msgid "Reset \"%(branch)s\" to \"%(revision)s\"?" msgstr "ブランチの \"%(branch)s\" を \"%(revision)s\" リビジョンにリセットしますか?" msgid "Reset Branch" msgstr "ブランチのリセット" msgid "Reset Branch Head" msgstr "ブランチをHeadにリセット" msgid "Reset Branch?" msgstr "ブランチをリセットしますか?" msgid "Reset Hard" msgstr "ハードリセット" msgid "Reset Merge" msgstr "マージリセット" msgid "Reset Soft" msgstr "ソフトリセット" msgid "Reset Worktree" msgstr "ワークツリーをリセット" msgid "Reset hard?" msgstr "ハードリセットをしますか?" msgid "Reset merge?" msgstr " マージリセットをしますか?" msgid "Reset soft?" msgstr "ソフトリセットをしますか?" msgid "Reset worktree?" msgstr "ワークツリーをリセットしますか?" #, python-format msgid "Resetting \"%(branch)s\" to \"%(revision)s\" will lose commits." msgstr "\"%(branch)s\" ブランチを \"%(revision)s\" リビジョンにリセットするとコミットが失われます。" msgid "Restart the application after changing appearance settings." msgstr "" msgid "Revert" msgstr "リバート" msgid "Revert Diff Hunk" msgstr "差分のリバート" msgid "Revert Diff Hunk..." msgstr "差分のリバート中" msgid "Revert Diff Hunk?" msgstr "差分をリバートしますか?" msgid "Revert Selected Lines" msgstr "選択行のリバート" msgid "Revert Selected Lines..." msgstr "選択行のリバート中" msgid "Revert Selected Lines?" msgstr "選択行をリバートしますか?" msgid "Revert Uncommitted Changes" msgstr "コミットしていない変更のリバート" msgid "Revert Uncommitted Changes?" msgstr "コミットしていない変更のリバート中" msgid "Revert Uncommitted Edits..." msgstr "コミットしていない編集のリバート中" msgid "Revert Unstaged Changes" msgstr "ステージングしていない変更のリバート" msgid "Revert Unstaged Changes?" msgstr "ステージングしていない変更をリバートしますか?" msgid "Revert Unstaged Edits..." msgstr "ステージングしていない編集のリバート中" msgid "Revert the uncommitted changes?" msgstr "コミットしていない変更をリバートしますか?" msgid "Revert the unstaged changes?" msgstr "ステージングしていない変更をリバートしますか?" msgid "Revert uncommitted changes to selected paths" msgstr "コミットしていない変更を選択パスへリバート" msgid "Revert unstaged changes to selected paths" msgstr "ステージングしていない変更を選択パスへリバート" msgid "Review" msgstr "レビュー" msgid "Review..." msgstr "レビュー..." msgid "Revision" msgstr "リビジョン" msgid "Revision Expression:" msgstr "リビジョン表現:" msgid "Revision to Merge" msgstr "マージするリビジョン" msgid "Reword" msgstr "書き直し" msgid "Rewrite Published Commit?" msgstr "発行済コミットを書き直しますか?" msgid "Run" msgstr "実行" #, python-format msgid "Run \"%s\"?" msgstr "\"%s\"を実行しますか?" #, python-format msgid "Run %s?" msgstr "%sを実行しますか?" #, python-format msgid "Run the \"%s\" command?" msgstr "\"%s\"コマンドを実行しますか?" #, python-format msgid "Running command: %s" msgstr "コマンド %s を実行中..." msgid "Russian translation" msgstr "ロシア語翻訳" msgid "SHA-1" msgstr "SHA-1" msgid "Safe Mode" msgstr "セーフモード" msgid "Save" msgstr "保存" msgid "Save Archive" msgstr "アーカイブ保存" msgid "Save As Tarball/Zip..." msgstr "Tarball/Zip形式で保存する" msgid "Save GUI Settings" msgstr "GUI設定を保存する" msgid "Save Stash" msgstr "スタッシュを保存する" msgid "Save modified state to new stash" msgstr "修正した状態を新しいスタッシュで保存する" #, python-format msgid "Saved \"%(filename)s\" from \"%(ref)s\" to \"%(destination)s\"" msgstr "\"%(ref)s\" から \"%(destination)s\" に \"%(filename)s\" を保存する" msgid "Search" msgstr "検索" msgid "Search Authors" msgstr "著者を検索" msgid "Search Commit Messages" msgstr "コミットメッセージを検索" msgid "Search Committers" msgstr "コミッターを検索" msgid "Search Date Range" msgstr "検索日時の範囲" msgid "Search Diffs" msgstr "差分検索" msgid "Search by Expression" msgstr "表現による検索" msgid "Search by Path" msgstr "パスによる検索" msgid "Search for a fixed string" msgstr "固定文字列検索" msgid "Search using a POSIX basic regular expression" msgstr "POSIX基本正規表現検索" msgid "Search using a POSIX extended regular expression" msgstr "POSIX拡張正規表現検索" msgid "Search..." msgstr "検索中..." msgid "Select" msgstr "選択" msgid "Select All" msgstr "全て選択" msgid "Select Branch to Review" msgstr "レビュー対象のブランチを選択" msgid "Select Child" msgstr "子を選択" msgid "Select Commit" msgstr "コミットを選択" msgid "Select Directory..." msgstr "ディレクトリを選択..." msgid "Select New Upstream" msgstr "新しいアップストリームを選択" msgid "Select Newest Child" msgstr "最新の子を選択" msgid "Select Oldest Parent" msgstr "最古の親を選択" msgid "Select Parent" msgstr "親を選択" msgid "Select Previous Version" msgstr "以前のバージョンを選択" msgid "Select Repository..." msgstr "リポジトリを選択..." msgid "Select a parent directory for the new clone" msgstr "新しいクローン用に親ディレクトリを選択" msgid "Select manually..." msgstr "マニュアルで選択..." msgid "Select output dir" msgstr "出力ディレクトリを選択" msgid "Select output directory" msgstr "出力ディレクトリを選択" msgid "Select patch file(s)..." msgstr "パッチファイルを選択..." msgid "Select repository" msgstr "リポジトリを選択" msgid "Set Default Repository" msgstr "デフォルトリポジトリを設定" msgid "Set Upstream Branch" msgstr "アップストリームブランチを設定" msgid "" "Set the sort order for branches and tags.\n" "Toggle between date-based and version-name-based sorting." msgstr "" msgid "Set upstream" msgstr "アップストリームを設定" msgid "Settings" msgstr "設定" msgid "Shell arguments" msgstr "シェル引数" msgid "Shift Down" msgstr "シフトダウン" msgid "Shift Up" msgstr "シフトアップ" msgid "Shortcuts" msgstr "ショートカット" msgid "Show Details..." msgstr "詳細の表示..." msgid "Show Diffstat After Merge" msgstr "マージ後に diffstat を表示" msgid "Show Full Paths in the Window Title" msgstr "ウィンドウタイトルにフルパスを表示" msgid "Show Help" msgstr "ヘルプの表示" msgid "Show History" msgstr "履歴の表示" msgid "Show file counts in Status titles" msgstr "" msgid "" "Show help\n" "Shortcut: ?" msgstr "" "ヘルプの表示\n" "ショートカット: ?" msgid "Show icon? (if available)" msgstr "アイコンを表示しますか?(可能な場合)" msgid "Show line numbers" msgstr "行数の表示" msgid "Show whole surrounding functions of changes" msgstr "変更を含む関数全体を表示" msgid "Showing changes since" msgstr "期日以降の変更の表示 :" msgid "Side by side" msgstr "サイドバイサイド表示" msgid "Sign Off" msgstr "署名" msgid "Sign Tag" msgstr "署名されたタグ" msgid "Sign off on this commit" msgstr "このコミットの署名をOFFにする" msgid "Simplified Chinese translation" msgstr "中国語翻訳(簡体字)" msgid "Skip" msgstr "スキップ" msgid "Skip Current Patch" msgstr "現在のパスをスキップ" msgid "Sort bookmarks alphabetically" msgstr "ブックマークをアルファベット順にソート" msgid "Spanish translation" msgstr "スペイン語翻訳" msgid "Specifies the SHA-1 to tag" msgstr "タグにSHA-1を指定する" msgid "Specifies the tag message" msgstr "タグメッセージを指定する" msgid "Specifies the tag name" msgstr "タグ名を指定する" msgid "Spelling Suggestions" msgstr "スペルの提案" msgid "Squash" msgstr "スカッシュ" msgid "Squash the merged commits into a single commit" msgstr "複数のマージコミットを一つのコミットにまとめる(スカッシュ)" msgid "Stage" msgstr "ステージ" msgid "Stage / Unstage" msgstr "ステージ / ステージ解除" msgid "Stage All Untracked" msgstr "全てのトラックしていないものをステージする" msgid "Stage Changed Files To Commit" msgstr "コミットするために変更されたファイルをステージする" msgid "Stage Diff Hunk" msgstr "差分のステージング" msgid "Stage Modified" msgstr "修正のステージング" msgid "Stage Selected" msgstr "選択分のステージング" msgid "Stage Selected Lines" msgstr "選択行のステージング" msgid "Stage Unmerged" msgstr "非マージ分のステージング" msgid "Stage Untracked" msgstr "非トラック分のステージング" msgid "Stage and Commit" msgstr "ステージングとコミット" msgid "Stage and commit?" msgstr "ステージングとコミットをしますか?" msgid "Stage conflicts" msgstr "コンフリクトのステージング" msgid "Stage conflicts?" msgstr "コンフリクトのステージングしますか?" msgid "Stage/unstage selected paths for commit" msgstr "選択したパスのステージングまたは登録解除" msgid "Staged" msgstr "ステージ済" #, python-format msgid "Staging: %s" msgstr "%s をステージしています…" msgid "Start Interactive Rebase..." msgstr "インタラクティブリベースを開始する..." msgid "Starting Revision" msgstr "初期リビジョン" msgid "Stash" msgstr "スタッシュ" msgid "Stash Index" msgstr "インデックスのスタッシュ" msgid "Stash staged changes only" msgstr "ステージされた変更のみをスタッシュ" msgid "Stash unstaged changes only, keeping staged changes" msgstr "ステージされていない変更のみをスタッシュ、ステージされた変更を維持" msgid "Stash..." msgstr "スタッシュ中..." msgid "Status" msgstr "ステータス" msgid "Stop tracking paths" msgstr "パスのトラッキングを中止する" msgid "Submodules" msgstr "サブモジュール" msgid "Summarize Merge Commits" msgstr "マージコミットの要約" msgid "Summary" msgstr "要約" msgid "Tab Width" msgstr "タグ幅" msgid "Tag" msgstr "タグ" msgid "Tag Created" msgstr "作成されたタグ" msgid "Tag message..." msgstr "タグメッセージ..." msgid "Tag-signing was requested but the tag message is empty." msgstr "タグの署名が要求されていますが、タグメッセージが空です。" msgid "Tags" msgstr "タグ" msgid "Text Width" msgstr "テキスト幅" msgid "The branch will be no longer available." msgstr "このブランチはもう利用できません。" #, python-format msgid "The branch will be reset using \"git reset --hard %s\"" msgstr "このブランチは\"git reset --hard %s\"でリセットする。" #, python-format msgid "The branch will be reset using \"git reset --merge %s\"" msgstr "このブランチは\"git reset --merge %s\"でリセットする。" #, python-format msgid "The branch will be reset using \"git reset --mixed %s\"" msgstr "このブランチは\"git reset --mixed %s\"でリセットする。" #, python-format msgid "The branch will be reset using \"git reset --soft %s\"" msgstr "このブランチは\"git reset --soft %s\"でリセットする。" msgid "The commit message will be cleared." msgstr "このコミットメッセージはクリアされました。" #, python-format msgid "The file \"%s\" exists and will be overwritten." msgstr "このファイル \"%s\"は存在します。そんため上書きされます。" msgid "The following files will be deleted:" msgstr "以下のファイルは削除されます。:" msgid "The revision expression cannot be empty." msgstr "このリビジョン表記を空にできません。" #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be reset using \"git reset --keep %s\"" msgstr "このワークツリーは\"git reset --keep %s\"でリセットする。" msgid "This cannot be undone. Clear commit message?" msgstr "ジレは元に戻せません。コミットメッセージをクリアしますか?" msgid "" "This commit has already been published.\n" "This operation will rewrite published history.\n" "You probably don't want to do this." msgstr "" "このコミットは既に発行済みです。\n" "この操作は、発行済履歴を上書きします。\n" "この操作は、あなたが望んだ操作ではない可能性が高いです。" msgid "" "This operation drops uncommitted changes.\n" "These changes cannot be recovered." msgstr "" "この操作は、コミットしていない変更をドロップします。\n" "これらの変更は回復できません。" msgid "" "This operation removes uncommitted edits from selected files.\n" "These changes cannot be recovered." msgstr "" "この操作は、選択されたファイルのコミットされていない編集を削除します。\n" "これらの変更は回復できません。" msgid "" "This operation removes unstaged edits from selected files.\n" "These changes cannot be recovered." msgstr "" "この操作は、選択されたファイルのステージされていない編集を削除します。\n" "これらの変更は回復できません。" msgid "" "This repository is currently being rebased.\n" "Resolve conflicts, commit changes, and run:\n" " Rebase > Continue" msgstr "" "このリポジトリは現在リベースされています。\n" "衝突を解決し、変更をコミットして実行します。:\n" " Rebase > Continue" msgid "" "This repository is in the middle of a merge.\n" "Resolve conflicts and commit changes." msgstr "" "このリポジトリはマージの中間です。\n" "衝突を解決し、変更をコミットします。:" msgid "Toggle Enabled" msgstr "有効に切り替えます。" msgid "Toggle the branches filter" msgstr "ブランチフィルタを切り替えます" msgid "Toggle the paths filter" msgstr "パスフィルタを切り替えます" msgid "Tracking Branch" msgstr "トラッキングブランチ" msgid "Tracking branch" msgstr "トラッキングブランチ" msgid "Traditional Chinese (Taiwan) translation" msgstr "伝統的中国語(台湾)翻訳" msgid "Translators" msgstr "翻訳者" msgid "Turkish translation" msgstr "トルコ語翻訳" msgid "URL" msgstr "URL" #, python-format msgid "URL: %s" msgstr "URL: %s" msgid "Ukranian translation" msgstr "ウクライナ語翻訳" msgid "Unable to rebase" msgstr "リベースできません" #, python-format msgid "Unable to set URL for \"%(name)s\" to \"%(url)s\"" msgstr "URLの\"%(name)s\" を \"%(url)s\" に設定できません。" msgid "Undo" msgstr "元に戻す" msgid "Unmerged" msgstr "マージされていない" msgid "Unstage" msgstr "ステージされていない" msgid "Unstage All" msgstr "全てのステージを解除" msgid "Unstage Diff Hunk" msgstr "差分のステージ解除" msgid "Unstage From Commit" msgstr "コミットからステージを解除する" msgid "Unstage Selected" msgstr "選択をステージ解除" msgid "Unstage Selected Lines" msgstr "選択行をステージ解除する" #, python-format msgid "Unstaging: %s" msgstr "ステージ解除: %s" msgid "Untrack Selected" msgstr "選択のトラック解除する" msgid "Untracked" msgstr "トラック解除済み" #, python-format msgid "Untracking: %s" msgstr "トラック解除中:%s" msgid "Update All Submodules..." msgstr "" msgid "Update Existing Branch:" msgstr "既存のブランチを更新:" #, fuzzy msgid "Update Submodule" msgstr "更新しました" msgid "Update Submodule..." msgstr "" #, fuzzy msgid "Update Submodules" msgstr "サブモジュールを初期化する" #, fuzzy msgid "Update all submodules?" msgstr "サブモジュールを初期化する" #, fuzzy msgid "Update submodules..." msgstr "サブモジュールを初期化する" #, fuzzy msgid "Update this submodule" msgstr "サブモジュールを初期化する" msgid "Update this submodule?" msgstr "" msgid "Updating" msgstr "更新" msgid "User Name" msgstr "ユーザ名" msgid "Version" msgstr "バージョン" msgid "View" msgstr "ビュー" msgid "View History..." msgstr "ビュー履歴..." msgid "View history for selected paths" msgstr "選択パスのビュー履歴" msgid "Visualize" msgstr "可視化" msgid "Visualize All Branches..." msgstr "全てのブランチを可視化" msgid "Visualize Current Branch..." msgstr "現在ブランチを可視化" msgid "Whether to sign the tag (git tag -s)" msgstr "タグで署名した場所 (git tag -s)" msgid "Would you like to stage and commit all modified files?" msgstr "全ての修正したファイルを、ステージしてコミットしますか?" msgid "XOR" msgstr "XOR" msgid "Yes" msgstr "はい" msgid "" "You are in the middle of a merge.\n" "Cannot amend while merging." msgstr "" "マージ中です。\n" "マージ中は訂正できません。" msgid "You cannot rebase with uncommitted changes." msgstr "コミットされていない変更をリベースできません。" msgid "You must specify a revision to merge." msgstr "マージするリビジョンを指定してください。" msgid "You must specify a revision to view." msgstr "表示するリビジョンを指定してください。" msgid "Zoom In" msgstr "ズームイン" msgid "Zoom Out" msgstr "ズームアウト" msgid "Zoom to Fit" msgstr "表示幅に合わせてズーム" msgid "command-line arguments" msgstr "コマンドライン引数" msgid "error: unable to execute git" msgstr "エラー: gitを実行できません。" #, python-format msgid "exit code %s" msgstr "終了コード %s" #, python-format msgid "fatal: \"%s\" is not a directory. Please specify a correct --repo ." msgstr "致命的: \"%s\" はディレクトリではありません。正しいパスを--repo で指定してください。" #, python-format msgid "git cola version %s" msgstr "git cola バージョン %s" msgid "git-cola" msgstr "git-cola" msgid "git-cola diff" msgstr "git-cola diff" msgid "grep result..." msgstr "grep 結果..." msgid "hotkeys.html" msgstr "hotkeys.html" msgid "unknown" msgstr "不明" msgid "vX.Y.Z" msgstr "vX.Y.Z" msgid "x 1" msgstr "" msgid "x 1.5" msgstr "" msgid "x 2" msgstr "" msgid "yyyy-MM-dd" msgstr "yyyy-MM-dd" #~ msgid "" #~ "\n" #~ "\n" #~ "A good replacement for %s\n" #~ "is placing values for the user.name and\n" #~ "user.email settings into your personal\n" #~ "~/.gitconfig file.\n" #~ msgstr "" #~ "\n" #~ "\n" #~ "個人的な ~/.gitconfig ファイル内で user.name と user.email の値を設定\n" #~ "するのが、%s の良い代用となります\n" #~ msgid "" #~ "\n" #~ "This is due to a known issue with the\n" #~ "Tcl binary distributed by Cygwin." #~ msgstr "" #~ "\n" #~ "これは Cygwin で配布されている Tcl バイナリに\n" #~ "関しての既知の問題によります" #~ msgid "%s ... %*i of %*i %s (%3i%%)" #~ msgstr "%1$s ... %4$*i %6$s 中の %2$*i (%7$3i%%)" #~ msgid "%s Repository" #~ msgstr "%s リポジトリ" #~ msgid "%s of %s" #~ msgstr "%s の %s ブランチ" #~ msgid "'%s' is not an acceptable branch name." #~ msgstr "'%s' はブランチ名に使えません。" #~ msgid "* Binary file (not showing content)." #~ msgstr "* バイナリファイル(内容は表示しません)" #~ msgid "A branch is required for 'Merged Into'." #~ msgstr "'マージ先' にはブランチが必要です。" #~ msgid "Abort completed. Ready." #~ msgstr "中断完了。" #~ msgid "Abort failed." #~ msgstr "中断に失敗しました。" #~ msgid "Aborted checkout of '%s' (file level merging is required)." #~ msgstr "'%s' のチェックアウトを中止しました(ファイル毎のマージが必要です)。" #~ msgid "Always (Do not perform merge checks)" #~ msgstr "無条件(マージ検査をしない)" #~ msgid "Always (Do not perform merge test.)" #~ msgstr "無条件(マージテストしない)" #~ msgid "Amended Commit Message:" #~ msgstr "訂正したコミットメッセージ:" #~ msgid "Amended Initial Commit Message:" #~ msgstr "訂正した最初のコミットメッセージ:" #~ msgid "Amended Merge Commit Message:" #~ msgstr "訂正したマージコミットメッセージ:" #~ msgid "Annotation complete." #~ msgstr "注釈完了しました" #~ msgid "Any unstaged changes will be permanently lost by the revert." #~ msgstr "変更を元に戻すとコミット予定していない変更は全て失われます。" #~ msgid "Apply/Reverse Hunk" #~ msgstr "パッチを適用/取り消す" #~ msgid "Arbitrary URL:" #~ msgstr "任意の URL:" #~ msgid "" #~ "Branch '%s' already exists.\n" #~ "\n" #~ "It cannot fast-forward to %s.\n" #~ "A merge is required." #~ msgstr "" #~ "ブランチ '%s' は既に存在します。\n" #~ "\n" #~ "%s に早送りできません。\n" #~ "マージが必要です。" #~ msgid "Branch '%s' does not exist." #~ msgstr "ブランチ'%s'は存在しません。" #~ msgid "Branch created" #~ msgstr "ブランチ名" #~ msgid "Browse %s's Files" #~ msgstr "ブランチ %s のファイルを見る" #~ msgid "Browse Branch Files" #~ msgstr "現在のブランチのファイルを見る" #~ msgid "Browse Revision..." #~ msgstr "リビジョン" #~ msgid "Calling commit-msg hook..." #~ msgstr "コミット・メッセージ・フックを実行中・・・" #~ msgid "" #~ "Cannot abort while amending.\n" #~ "\n" #~ "You must finish amending this commit.\n" #~ msgstr "" #~ "訂正中には中止できません。\n" #~ "\n" #~ "まず今のコミット訂正を完了させて下さい。\n" #~ msgid "" #~ "Cannot amend while merging.\n" #~ "\n" #~ "You are currently in the middle of a merge that has not been fully completed. You cannot amend the prior commit unless you first abort the current merge activity.\n" #~ msgstr "" #~ "マージ中にコミットの訂正はできません。\n" #~ "\n" #~ "現在はまだマージの途中です。先にこのマージを中止しないと、前のコミットの訂正はできません\n" #~ msgid "Cannot determine HEAD. See console output for details." #~ msgstr "HEAD を確定できません。コンソール出力を見て下さい" #~ msgid "Cannot fetch branches and objects. See console output for details." #~ msgstr "ブランチやオブジェクトを取得できません。コンソール出力を見て下さい" #~ msgid "Cannot fetch tags. See console output for details." #~ msgstr "タグを取得できません。コンソール出力を見て下さい" #~ msgid "Cannot find git in PATH." #~ msgstr "PATH 中に git が見つかりません" #~ msgid "" #~ "Cannot merge while amending.\n" #~ "\n" #~ "You must finish amending this commit before starting any type of merge.\n" #~ msgstr "" #~ "訂正中にはマージできません。\n" #~ "\n" #~ "訂正処理を完了するまでは新たにマージを開始できません。\n" #~ msgid "Cannot move to top of working directory:" #~ msgstr "作業ディレクトリの最上位に移動できません" #~ msgid "Cannot parse Git version string:" #~ msgstr "Git バージョン名が理解できません:" #~ msgid "Cannot resolve %s as a commit." #~ msgstr "%s をコミットとして解釈できません" #~ msgid "Cannot use funny .git directory:" #~ msgstr "変な .git ディレクトリは使えません" #~ msgid "Cannot write shortcut:" #~ msgstr "ショートカットが書けません:" #~ msgid "Change Font" #~ msgstr "フォントを変更" #~ msgid "Checked out '%s'." #~ msgstr "'%s' をチェックアウトしました" #~ msgid "Clone Type:" #~ msgstr "複製方式:" #~ msgid "Clone failed." #~ msgstr "複写に失敗しました。" #~ msgid "Cloning from %s" #~ msgstr "%s から複製しています" #~ msgid "Commit %s appears to be corrupt" #~ msgstr "コミット %s は壊れています" #~ msgid "Commit declined by commit-msg hook." #~ msgstr "コミット・メッセージ・フックがコミットを拒否しました" #~ msgid "Commit declined by pre-commit hook." #~ msgstr "コミット前フックがコミットを拒否しました" #~ msgid "Commit failed: %s" #~ msgstr "コミットに失敗しました。" #~ msgid "Commit@@noun" #~ msgstr "コミット" #~ msgid "Compress Database" #~ msgstr "データベース圧縮" #~ msgid "Compressing the object database" #~ msgstr "データベース圧縮" #~ msgid "Copied Or Moved Here By:" #~ msgstr "複写・移動者:" #~ msgid "Copying objects" #~ msgstr "オブジェクトを複写しています" #~ msgid "Counting objects" #~ msgstr "オブジェクトを数えています" #~ msgid "Create Desktop Icon" #~ msgstr "デスクトップ・アイコンを作る" #~ msgid "Created commit: %s" #~ msgstr "コミット %s を作成しました: %s" #~ msgid "Creating working directory" #~ msgstr "作業ディレクトリを作成しています" #~ msgid "Current Branch:" #~ msgstr "現在のブランチ" #~ msgid "Database Statistics" #~ msgstr "データベース統計" #~ msgid "Decrease Font Size" #~ msgstr "フォントを小さく" #~ msgid "Delete Local Branch" #~ msgstr "ローカル・ブランチを削除" #~ msgid "Delete Only If" #~ msgstr "条件付で削除" #~ msgid "Delete Only If Merged Into" #~ msgstr "マージ済みの時のみ削除" #~ msgid "Destination Repository" #~ msgstr "送り先リポジトリ" #~ msgid "Detach From Local Branch" #~ msgstr "ローカル・ブランチから削除" #~ msgid "Diff/Console Font" #~ msgstr "diff/コンソール・フォント" #~ msgid "Directory %s already exists." #~ msgstr "ディレクトリ '%s' は既に存在します。" #~ msgid "Disk space used by loose objects" #~ msgstr "ばらばらなオブジェクトの使用するディスク量" #~ msgid "Disk space used by packed objects" #~ msgstr "パックされたオブジェクトの使用するディスク量" #~ msgid "Do Nothing" #~ msgstr "何もしない" #~ msgid "Enter Git Repository" #~ msgstr "GIT リポジトリ" #~ msgid "Error %s" #~ msgstr "エラー" #~ msgid "Error loading commit data for amend:" #~ msgstr "訂正するコミットのデータを読めません:" #~ msgid "Error: Command Failed" #~ msgstr "エラー: コマンドが失敗しました" #~ msgid "Failed to completely save options:" #~ msgstr "完全にオプションを保存できません:" #~ msgid "Failed to configure origin" #~ msgstr "origin を設定できませんでした" #~ msgid "Failed to create repository %s:" #~ msgstr "リポジトリ %s を作製できません:" #~ msgid "" #~ "Failed to delete branches:\n" #~ "%s" #~ msgstr "" #~ "以下のブランチを削除できません:\n" #~ "%s" #~ msgid "Failed to open repository %s:" #~ msgstr "リポジトリ %s を開けません:" #~ msgid "Failed to rename '%s'." #~ msgstr "'%s'の名前変更に失敗しました。" #~ msgid "" #~ "Failed to set current branch.\n" #~ "\n" #~ "This working directory is only partially switched. We successfully updated your files, but failed to update an internal Git file.\n" #~ "\n" #~ "This should not have occurred. %s will now close and give up." #~ msgstr "" #~ "現在のブランチを設定できません。\n" #~ "\n" #~ "作業ディレクトリは部分的にしか切り替わっていません。ファイルの更新には成功しましたが、 Git の内部データを更新できませんでした。\n" #~ "起こるはずのないエラーです。あきらめて %s を終了します。" #~ msgid "Failed to stage selected hunk." #~ msgstr "選択されたパッチをコミット予定に加えられません。" #~ msgid "Failed to unstage selected hunk." #~ msgstr "選択されたパッチをコミット予定から外せません。" #~ msgid "Failed to update '%s'." #~ msgstr "'%s' の更新に失敗しました。" #~ msgid "Fast Forward Only " #~ msgstr "早送りのみ" #~ msgid "Fetch from" #~ msgstr "取得元" #~ msgid "Fetching new changes from %s" #~ msgstr "%s から新しい変更をフェッチしています" #~ msgid "File level merge required." #~ msgstr "ファイル毎のマージが必要です。" #~ msgid "Font Example" #~ msgstr "フォント・サンプル" #~ msgid "Font Family" #~ msgstr "フォント・ファミリー" #~ msgid "Force overwrite existing branch (may discard changes)" #~ msgstr "既存ブランチを上書き(変更を破棄する可能性があります)" #~ msgid "From Repository" #~ msgstr "元のリポジトリ" #~ msgid "Full Copy (Slower, Redundant Backup)" #~ msgstr "全複写(低速・冗長バックアップ)" #~ msgid "Garbage files" #~ msgstr "ゴミファイル" #~ msgid "Git Gui" #~ msgstr "Git GUI" #~ msgid "Git Repository (subproject)" #~ msgstr "Git リポジトリ(サブプロジェクト)" #~ msgid "Git directory not found:" #~ msgstr "Git ディレクトリが見つかりません:" #~ msgid "" #~ "Git version cannot be determined.\n" #~ "\n" #~ "%s claims it is version '%s'.\n" #~ "\n" #~ "%s requires at least Git 1.5.0 or later.\n" #~ "\n" #~ "Assume '%s' is version 1.5.0?\n" #~ msgstr "" #~ "Git のバージョンが確認できません。\n" #~ "\n" #~ "%s はバージョン '%s' とのことです。\n" #~ "\n" #~ "%s は最低でも 1.5.0 かそれ以降の Git が必要です\n" #~ "\n" #~ "'%s' はバージョン 1.5.0 と思って良いですか?\n" #~ msgid "Hardlinks are unavailable. Falling back to copying." #~ msgstr "ハードリンクが作れないので、コピーします" #~ msgid "In File:" #~ msgstr "ファイル:" #~ msgid "Increase Font Size" #~ msgstr "フォントを大きく" #~ msgid "Initial Commit Message:" #~ msgstr "最初のコミットメッセージ:" #~ msgid "Initial file checkout failed." #~ msgstr "初期チェックアウトに失敗しました" #~ msgid "Invalid GIT_COMMITTER_IDENT:" #~ msgstr "GIT_COMMITTER_IDENT が無効です:" #~ msgid "Invalid date from Git: %s" #~ msgstr "Git から出た無効な日付: %s" #~ msgid "Invalid font specified in %s:" #~ msgstr "%s に無効なフォントが指定されています:" #~ msgid "Invalid spell checking configuration" #~ msgstr "スペルチェックの設定が不正です" #~ msgid "KiB" #~ msgstr "KiB" #~ msgid "" #~ "Last scanned state does not match repository state.\n" #~ "\n" #~ "Another Git program has modified this repository since the last scan. A rescan must be performed before a merge can be performed.\n" #~ "\n" #~ "The rescan will be automatically started now.\n" #~ msgstr "" #~ "最後にスキャンした状態はリポジトリの状態と合致しません。\n" #~ "\n" #~ "最後にスキャンして以後、別の Git プログラムがリポジトリを変更しています。マージを開始する前に、再スキャンが必要です。\n" #~ "\n" #~ "自動的に再スキャンを開始します。\n" #~ msgid "" #~ "Last scanned state does not match repository state.\n" #~ "\n" #~ "Another Git program has modified this repository since the last scan. A rescan must be performed before another commit can be created.\n" #~ "\n" #~ "The rescan will be automatically started now.\n" #~ msgstr "" #~ "最後にスキャンした状態はリポジトリの状態と合致しません。\n" #~ "\n" #~ "最後にスキャンして以後、別の Git プログラムがリポジトリを変更しています。新しくコミットする前に、再スキャンが必要です。\n" #~ "\n" #~ "自動的に再スキャンを開始します。\n" #~ msgid "" #~ "Last scanned state does not match repository state.\n" #~ "\n" #~ "Another Git program has modified this repository since the last scan. A rescan must be performed before the current branch can be changed.\n" #~ "\n" #~ "The rescan will be automatically started now.\n" #~ msgstr "" #~ "最後にスキャンした状態はリポジトリの状態と合致しません。\n" #~ "\n" #~ "最後にスキャンして以後、別の Git プログラムがリポジトリを変更しています。現在のブランチを変更する前に、再スキャンが必要です。\n" #~ "\n" #~ "自動的に再スキャンを開始します。\n" #~ msgid "Linking objects" #~ msgstr "オブジェクトを連結しています" #~ msgid "Loading annotation..." #~ msgstr "注釈を読み込んでいます…" #~ msgid "Loading copy/move tracking annotations..." #~ msgstr "コピー・移動追跡データを読んでいます…" #~ msgid "Loading original location annotations..." #~ msgstr "元位置行の注釈データを読んでいます…" #~ msgid "Local Branches" #~ msgstr "ローカル・ブランチ" #~ msgid "Local Merge..." #~ msgstr "ローカル・マージ…" #~ msgid "Location %s already exists." #~ msgstr "'%s' は既に存在します。" #~ msgid "Main Font" #~ msgstr "主フォント" #~ msgid "Match Tracking Branch Name" #~ msgstr "トラッキング・ブランチ名を合わせる" #~ msgid "Match Tracking Branches" #~ msgstr "トラッキングブランチを合わせる" #~ msgid "Merge completed successfully." #~ msgstr "マージが完了しました" #~ msgid "Merge strategy '%s' not supported." #~ msgstr "'%s' マージ戦略はサポートされていません。" #~ msgid "Merged Into:" #~ msgstr "マージ先:" #~ msgid "Merging %s and %s..." #~ msgstr "%s と %s をマージ中・・・" #~ msgid "Modified, not staged" #~ msgstr "変更あり、コミット未予定" #~ msgid "New Branch Name Template" #~ msgstr "新しいブランチ名のテンプレート" #~ msgid "New Commit" #~ msgstr "新規コミット" #~ msgid "New Name:" #~ msgstr "新しい名前:" #~ msgid "" #~ "No changes to commit.\n" #~ "\n" #~ "No files were modified by this commit and it was not a merge commit.\n" #~ "\n" #~ "A rescan will be automatically started now.\n" #~ msgstr "" #~ "コミットする変更がありません。\n" #~ "\n" #~ "マージでなく、また、一つも変更点がありません。\n" #~ "\n" #~ "自動的に再スキャンを開始します。\n" #~ msgid "No default branch obtained." #~ msgstr "デフォールト・ブランチが取得されませんでした" #~ msgid "" #~ "No differences detected.\n" #~ "\n" #~ "%s has no changes.\n" #~ "\n" #~ "The modification date of this file was updated by another application, but the content within the file was not changed.\n" #~ "\n" #~ "A rescan will be automatically started to find other files which may have the same state." #~ msgstr "" #~ "変更がありません。\n" #~ "\n" #~ "%s には変更がありません。\n" #~ "\n" #~ "このファイルの変更時刻は他のアプリケーションによって更新されていますがファイル内容には変更がありません。\n" #~ "\n" #~ "同様な状態のファイルを探すために、自動的に再スキャンを開始します。" #~ msgid "No working directory" #~ msgstr "作業ディレクトリがありません" #~ msgid "Not connected to aspell" #~ msgstr "aspell に接続していません" #~ msgid "Number of loose objects" #~ msgstr "ばらばらなオブジェクトの数" #~ msgid "Number of packed objects" #~ msgstr "パックされたオブジェクトの数" #~ msgid "Number of packs" #~ msgstr "パックの数" #~ msgid "One or more of the merge tests failed because you have not fetched the necessary commits. Try fetching from %s first." #~ msgstr "必要なコミットが不足しているために、マージ検査が失敗しました。まず %s からフェッチして下さい。" #~ msgid "Options" #~ msgstr "オプション" #~ msgid "Original File:" #~ msgstr "元ファイル" #~ msgid "Originally By:" #~ msgstr "原作者:" #~ msgid "PATCH %(current)d/%(count)d" #~ msgstr "PATCH %(current)d/%(count)d" #~ msgid "Packed objects waiting for pruning" #~ msgstr "パックに存在するので捨てて良いオブジェクトの数" #~ msgid "Path to git repository" #~ msgstr "Git リポジトリではありません: %s" #~ msgid "Please select one or more branches to delete." #~ msgstr "削除するブランチを選択して下さい。" #~ msgid "Please supply a branch name." #~ msgstr "ブランチ名を指定して下さい。" #~ msgid "Portions staged for commit" #~ msgstr "部分的にコミット予定済" #~ msgid "" #~ "Possible environment issues exist.\n" #~ "\n" #~ "The following environment variables are probably\n" #~ "going to be ignored by any Git subprocess run\n" #~ "by %s:\n" #~ "\n" #~ msgstr "" #~ "環境に問題がある可能性があります\n" #~ "\n" #~ "以下の環境変数は %s が起動する Git サブプロセスによって無視されるでしょう:\n" #~ "\n" #~ msgid "Preferences..." #~ msgstr "設定…" #~ msgid "Prune Tracking Branches During Fetch" #~ msgstr "フェッチ中にトラッキングブランチを刈る" #~ msgid "Pruning tracking branches deleted from %s" #~ msgstr "%s から削除されたトラッキング・ブランチを刈っています" #~ msgid "Push Branches" #~ msgstr "ブランチをプッシュ" #~ msgid "Push to" #~ msgstr "プッシュ先" #~ msgid "Pushing %s %s to %s" #~ msgstr "%3$s へ %1$s %2$s をプッシュしています" #~ msgid "Reading %s..." #~ msgstr "%s を読んでいます…" #~ msgid "Ready to commit." #~ msgstr "コミット準備完了" #~ msgid "Ready." #~ msgstr "準備完了" #~ msgid "Rebase Branch" #~ msgstr "ブランチの名前変更" #~ msgid "Rebase..." #~ msgstr "リセット…" #~ msgid "" #~ "Recovering deleted branches is difficult.\n" #~ "\n" #~ "Delete the selected branches?" #~ msgstr "" #~ "削除したブランチを回復するのは困難です。\n" #~ "\n" #~ "選択したブランチを削除して良いですか?" #~ msgid "" #~ "Recovering deleted branches is difficult. \n" #~ "\n" #~ " Delete the selected branches?" #~ msgstr "" #~ "ブランチを削除すると元に戻すのは困難です。 \n" #~ "\n" #~ " 選択したブランチを削除しますか?" #~ msgid "Refreshing file status..." #~ msgstr "ファイル状態を更新しています…" #~ msgid "Remote Branches" #~ msgstr "ブランチの名前変更" #~ msgid "Remote:" #~ msgstr "リモート:" #~ msgid "Rename remote?" #~ msgstr "リモート" #~ msgid "Repository" #~ msgstr "リポジトリ" #~ msgid "Requires merge resolution" #~ msgstr "要マージ解決" #~ msgid "Rescan" #~ msgstr "再スキャン" #~ msgid "" #~ "Reset changes?\n" #~ "\n" #~ "Resetting the changes will cause *ALL* uncommitted changes to be lost.\n" #~ "\n" #~ "Continue with resetting the current changes?" #~ msgstr "" #~ "変更点をリセットしますか?\n" #~ "\n" #~ "変更点をリセットすると、コミットしていない全ての変更が失われます。\n" #~ "\n" #~ "リセットしてよろしいですか?" #~ msgid "Revert changes in these %i files?" #~ msgstr "これら %i 個のファイルにした変更を元に戻しますか?" #~ msgid "Select File" #~ msgstr "全て選択" #~ msgid "Select file from \"%s\"" #~ msgstr "%s からブランチを削除しています。" #~ msgid "Shared (Fastest, Not Recommended, No Backup)" #~ msgstr "共有(最高速・非推奨・バックアップ無し)" #~ msgid "Shared only available for local repository." #~ msgstr "共有方式は同一計算機上のリポジトリにのみ使えます。" #~ msgid "Show Less Context" #~ msgstr "文脈を少なく" #~ msgid "Show More Context" #~ msgstr "文脈を多く" #~ msgid "Source Branches" #~ msgstr "元のブランチ" #~ msgid "Spell Checker Failed" #~ msgstr "スペルチェック失敗" #~ msgid "Spell checker silently failed on startup" #~ msgstr "スペルチェッカーの起動に失敗しました" #~ msgid "Spell checking is unavailable" #~ msgstr "スペルチェック機能は使えません" #~ msgid "Spelling Dictionary:" #~ msgstr "スペルチェック辞書" #~ msgid "Stage Hunk For Commit" #~ msgstr "パッチをコミット予定に加える" #~ msgid "Staged Changes (Will Commit)" #~ msgstr "ステージングされた(コミット予定済の)変更" #~ msgid "Staged for commit, missing" #~ msgstr "コミット予定済、ファイル無し" #~ msgid "Staged for removal" #~ msgstr "削除予定済" #~ msgid "Staged for removal, still present" #~ msgstr "削除予定済、ファイル未削除" #~ msgid "Staging Area" #~ msgstr "%s をスキャンしています…" #~ msgid "Staging area (index) is already locked." #~ msgstr "インデックスは既にロックされています。" #~ msgid "Standard (Fast, Semi-Redundant, Hardlinks)" #~ msgstr "標準(高速・中冗長度・ハードリンク)" #~ msgid "Standard only available for local repository." #~ msgstr "標準方式は同一計算機上のリポジトリにのみ使えます。" #~ msgid "Starting gitk... please wait..." #~ msgstr "gitk を起動中…お待ち下さい…" #~ msgid "Staying on branch '%s'." #~ msgstr "ブランチ '%s' に滞まります。" #~ msgid "Success" #~ msgstr "成功" #~ msgid "Summary:" #~ msgstr "要約:" #~ msgid "The 'master' branch has not been initialized." #~ msgstr "'master' ブランチが初期化されていません" #~ msgid "The following branches are not completely merged into %s:" #~ msgstr "以下のブランチは %s に完全にマージされていません:" #~ msgid "" #~ "The following branches are not completely merged into %s:\n" #~ "\n" #~ " - %s" #~ msgstr "" #~ "以下のブランチは %s に完全にマージされていません:\n" #~ "\n" #~ " - %s" #~ msgid "" #~ "There is nothing to amend.\n" #~ "\n" #~ "You are about to create the initial commit. There is no commit before this to amend.\n" #~ msgstr "" #~ "訂正するコミットがそもそもありません。\n" #~ "\n" #~ "これから作るのは最初のコミットです。その前にはまだ訂正するようなコミットはありません。\n" #~ msgid "This Detached Checkout" #~ msgstr "分離されたチェックアウト" #~ msgid "" #~ "This is example text.\n" #~ "If you like this text, it can be your font." #~ msgstr "" #~ "これはサンプル文です。\n" #~ "このフォントが気に入ればお使いになれます。" #~ msgid "" #~ "This repository currently has approximately %i loose objects.\n" #~ "\n" #~ "To maintain optimal performance it is strongly recommended that you compress the database when more than %i loose objects exist.\n" #~ "\n" #~ "Compress the database now?" #~ msgstr "" #~ "このリポジトリにはおおよそ %i 個の個別オブジェクトがあります\n" #~ "\n" #~ "最適な性能を保つために、%i 個以上の個別オブジェクトを作る毎にデータベースを圧縮することを推奨します\n" #~ "\n" #~ "データベースを圧縮しますか?" #~ msgid "Tracking branch %s is not a branch in the remote repository." #~ msgstr "トラッキング・ブランチ %s は遠隔リポジトリのブランチではありません。" #~ msgid "Transfer Options" #~ msgstr "通信オプション" #~ msgid "Unable to copy object: %s" #~ msgstr "オブジェクトを複写できません: %s" #~ msgid "Unable to copy objects/info/alternates: %s" #~ msgstr "objects/info/alternates を複写できません: %s" #~ msgid "Unable to display %s" #~ msgstr "%s を表示できません" #~ msgid "Unable to hardlink object: %s" #~ msgstr "オブジェクトをハードリンクできません: %s" #~ msgid "Unable to obtain your identity:" #~ msgstr "ユーザの正体を確認できません:" #~ msgid "" #~ "Unable to start gitk:\n" #~ "\n" #~ "%s does not exist" #~ msgstr "" #~ "gitk を起動できません:\n" #~ "\n" #~ "%s がありません" #~ msgid "Unable to unlock the index." #~ msgstr "インデックスをロックできません" #~ msgid "Unexpected EOF from spell checker" #~ msgstr "スペルチェッカーが予想外の EOF を返しました" #~ msgid "" #~ "Unknown file state %s detected.\n" #~ "\n" #~ "File %s cannot be committed by this program.\n" #~ msgstr "" #~ "不明なファイル状態 %s です。\n" #~ "\n" #~ "ファイル %s は本プログラムではコミットできません。\n" #~ msgid "Unlock Index" #~ msgstr "インデックスのロック解除" #~ msgid "" #~ "Unmerged files cannot be committed.\n" #~ "\n" #~ "File %s has merge conflicts. You must resolve them and stage the file before committing.\n" #~ msgstr "" #~ "マージしていないファイルはコミットできません。\n" #~ "\n" #~ "ファイル %s にはマージ衝突が残っています。まず解決してコミット予定に加える必要があります。\n" #~ msgid "Unrecognized spell checker" #~ msgstr "スペルチェッカーが判別できません" #~ msgid "Unstage Hunk From Commit" #~ msgstr "パッチをコミット予定から外す" #~ msgid "Unsupported spell checker" #~ msgstr "サポートされていないスペルチェッカーです" #~ msgid "Updating the Git index failed. A rescan will be automatically started to resynchronize git-gui." #~ msgstr "GIT インデックスの更新が失敗しました。git-gui と同期をとるために再スキャンします。" #~ msgid "Updating working directory to '%s'..." #~ msgstr "作業ディレクトリを '%s' に更新しています…" #~ msgid "Updating..." #~ msgstr "起動中…" #~ msgid "Use thin pack (for slow network connections)" #~ msgstr "Thin Pack を使う(遅いネットワーク接続)" #~ msgid "Verify Database" #~ msgstr "データベース検証" #~ msgid "Verifying the object database with fsck-objects" #~ msgstr "fsck-objects でオブジェクト・データベースを検証しています" #~ msgid "Visualize %s's History" #~ msgstr "ブランチ %s の履歴を見る" #~ msgid "Working... please wait..." #~ msgstr "実行中…お待ち下さい…" #~ msgid "" #~ "You are in the middle of a change.\n" #~ "\n" #~ "File %s is modified.\n" #~ "\n" #~ "You should complete the current commit before starting a merge. Doing so will help you abort a failed merge, should the need arise.\n" #~ msgstr "" #~ "変更の途中です。\n" #~ "\n" #~ "ファイル %s は変更中です。\n" #~ "\n" #~ "現在のコミットを完了してからマージを開始して下さい。そうする方がマージに失敗したときの回復が楽です。\n" #~ msgid "" #~ "You are in the middle of a conflicted merge.\n" #~ "\n" #~ "File %s has merge conflicts.\n" #~ "\n" #~ "You must resolve them, stage the file, and commit to complete the current merge. Only then can you begin another merge.\n" #~ msgstr "" #~ "衝突のあったマージの途中です。\n" #~ "\n" #~ "ファイル %s にはマージ中の衝突が残っています。\n" #~ "\n" #~ "このファイルの衝突を解決し、コミット予定に加えて、コミットすることでマージを完了します。そうやって始めて、新たなマージを開始できるようになります。\n" #~ msgid "" #~ "You are no longer on a local branch.\n" #~ "\n" #~ "If you wanted to be on a branch, create one now starting from 'This Detached Checkout'." #~ msgstr "" #~ "ローカル・ブランチから離れます。\n" #~ "\n" #~ "ブランチ上に滞まりたいときは、この「分離されたチェックアウト」から新規ブランチを開始してください。" #~ msgid "You must correct the above errors before committing." #~ msgstr "コミットする前に、以上のエラーを修正して下さい" #~ msgid "[Up To Parent]" #~ msgstr "[上位フォルダへ]" #~ msgid "buckets" #~ msgstr "バケツ" #~ msgid "commit-tree failed:" #~ msgstr "commit-tree が失敗しました:" #~ msgid "fatal: Cannot resolve %s" #~ msgstr "致命的エラー: %s を解決できません" #~ msgid "files" #~ msgstr "ファイル" #~ msgid "files checked out" #~ msgstr "チェックアウトされたファイル" #~ msgid "files reset" #~ msgstr "リセットしたファイル" #~ msgid "git-gui - a graphical user interface for Git." #~ msgstr "Git のグラフィカルUI git-gui" #~ msgid "git-gui: fatal error" #~ msgstr "git-gui: 致命的なエラー" #~ msgid "lines annotated" #~ msgstr "行を注釈しました" #~ msgid "objects" #~ msgstr "オブジェクト" #~ msgid "pt." #~ msgstr "ポイント" #~ msgid "push %s" #~ msgstr "%s をプッシュ" #~ msgid "remote prune %s" #~ msgstr "遠隔刈込 %s" #~ msgid "update-ref failed:" #~ msgstr "update-ref が失敗しました:" #~ msgid "warning" #~ msgstr "警告" #~ msgid "warning: Tcl does not support encoding '%s'." #~ msgstr "警告: Tcl はエンコーディング '%s' をサポートしていません" #~ msgid "write-tree failed:" #~ msgstr "write-tree が失敗しました:" git-cola-3.6/po/pl.po000066400000000000000000001545551356743264500145100ustar00rootroot00000000000000# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Łukasz Wojniłowicz , 2016. msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-17 01:06-0700\n" "PO-Revision-Date: 2016-09-10 17:28+0100\n" "Last-Translator: Łukasz Wojniłowicz \n" "Language-Team: Polish \n" "Language: pl_PL\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Lokalize 2.0\n" msgid "" "\n" "

\n" " Drag and drop or use the Add button to add\n" " patches to the list\n" "

\n" " " msgstr "" "\n" "

\n" " Przeciągnij i upuść lub naciśnij Dodaj, aby dodać\n" " łaty do listy\n" "

\n" " " #, python-format msgid "" "\n" "
\n" " Git Cola has been translated into different languages thanks\n" " to the help of the individuals listed below.\n" "\n" "
\n" "

\n" " Translation is approximate. If you find a mistake,\n" " please let us know by opening an issue on Github:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " We invite you to participate in translation by adding or updating\n" " a translation and opening a pull request.\n" "

\n" "\n" "
\n" "\n" " " msgstr "" #, python-format msgid "" "\n" "
\n" " Git Cola version %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " msgstr "" #, python-format msgid "" "\n" "
\n" " Please use %(bug_link)s to report issues.\n" "
\n" " " msgstr "" #, python-format msgid "" "\n" " Format String Variables\n" " -----------------------\n" " %(path)s = relative file path\n" " %(abspath)s = absolute file path\n" " %(dirname)s = relative directory path\n" " %(absdirname)s = absolute directory path\n" " %(filename)s = file basename\n" " %(basename)s = file basename without extension\n" " %(ext)s = file extension\n" msgstr "" msgid "" "\n" "Commands\n" "--------\n" "pick = use commit\n" "reword = use commit, but edit the commit message\n" "edit = use commit, but stop for amending\n" "squash = use commit, but meld into previous commit\n" "fixup = like \"squash\", but discard this commit's log message\n" "exec = run command (the rest of the line) using shell\n" "\n" "These lines can be re-ordered; they are executed from top to bottom.\n" "\n" "If you disable a line here THAT COMMIT WILL BE LOST.\n" "\n" "However, if you disable everything, the rebase will be aborted.\n" "\n" "Keyboard Shortcuts\n" "------------------\n" "? = show help\n" "j = move down\n" "k = move up\n" "J = shift row down\n" "K = shift row up\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "spacebar = toggle enabled\n" "\n" "ctrl+enter = accept changes and rebase\n" "ctrl+q = cancel and abort the rebase\n" "ctrl+d = launch difftool\n" msgstr "" msgid "" "\n" "Keyboard Shortcuts\n" "------------------\n" "J, Down = Move Down\n" "K, Up = Move Up\n" "Enter = Edit Selected Files\n" "Spacebar = Open File Using Default Application\n" "Ctrl + L = Focus Text Entry Field\n" "? = Show Help\n" "\n" "The up and down arrows change focus between the text entry field\n" "and the results.\n" msgstr "" "\n" "Skróty klawiszowe\n" "------------------\n" "J, Strzałka w dół = Przejdź w dół\n" "K, Strzałka w górę = Przejdź w górę\n" "Enter = Edytuj wybrany plik\n" "Spacja = Otwórz plik przy użyciu domyślnej aplikacji\n" "Ctrl + L = Uaktywnij pole wprowadzania tekstu\n" "? = Pokaż pomoc\n" "\n" "Strzałki w górę i dół zmieniają uaktywnienie pomiędzy polem tekstowym\n" "i wynikami.\n" msgid " - DAG" msgstr " - DAG" msgid " commits ago" msgstr " wdrożeń temu" #, python-format msgid "\"%(branch)s\" has been deleted from \"%(remote)s\"." msgstr "\"%(branch)s\" została usunięta z \"%(remote)s\"." #, python-format msgid "\"%(command)s\" returned exit status \"%(status)d\"" msgstr "\"%(command)s\" zwróciło kod wyjścia \"%(status)d\"" #, python-format msgid "\"%(command)s\" returned exit status %(status)d" msgstr "\"%(command)s\" zwróciło kod wyjścia %(status)d" #, fuzzy, python-format msgid "\"%s\" already exists" msgstr "Gałąź \"%s\" już istnieje." #, python-format msgid "\"%s\" already exists, cola will create a new directory" msgstr "\"%s\" już istnieje, cola utworzy nowy katalog" #, python-format msgid "\"%s\" requires a selected file." msgstr "\"%s\" wymaga wybrania pliku." msgid "#" msgstr "" #, python-format msgid "%(project)s: %(branch)s - Browse" msgstr "%(project)s: %(branch)s - Przeglądaj" #, python-format msgid "%(project)s: %(ref)s - DAG" msgstr "%(project)s: %(ref)s - DAG" #, python-format msgid "%d days ago" msgstr "%d dni temu" #, python-format msgid "%d hours ago" msgstr "%d godzin temu" #, python-format msgid "%d minutes ago" msgstr "%d minut temu" #, python-format msgid "%d patch(es) applied." msgstr "Zastosowano %d łat" #, python-format msgid "%d skipped" msgstr "Pominięto %d" #, python-format msgid "" "%s appears to contain merge conflicts.\n" "\n" "You should probably skip this file.\n" "Stage it anyways?" msgstr "" "Wygląda na to, że %s zawiera sprzeczności po scalaniu.\n" "\n" "Powinieneś pominąć ten plik.\n" "Czy dobrać go mimo tego?" #, python-format msgid "%s is not a Git repository." msgstr "%s nie jest repozytorium Git." #, python-format msgid "%s will be removed from your bookmarks." msgstr "%s zostanie usunięta z twoich zakładek." #, python-format msgid "%s will be removed from your recent repositories." msgstr "%s zostanie usunięte z listy ostatnich repozytoriów." #, python-format msgid "%s: No such file or directory." msgstr "%s: Nie ma takiego pliku lub katalogu." msgid "&Edit" msgstr "&Edycja" msgid "&File" msgstr "Plik" msgid "(Amending)" msgstr "(Uzupełnianie)" msgid "*** Branch Point ***" msgstr "*** Punkt gałęzi ***" msgid "*** Sandbox ***" msgstr "*** Piaskownica ***" msgid "100%" msgstr "" msgid "200%" msgstr "" msgid "25%" msgstr "" msgid "400%" msgstr "" msgid "50%" msgstr "" msgid "800%" msgstr "" msgid " ..." msgstr "<ścieżka> ..." msgid "" "A commit template has not been configured.\n" "Use \"git config\" to define \"commit.template\"\n" "so that it points to a commit template." msgstr "" "Szablon wdrożenia nie został ustawiony.\n" "Wykonaj \"git config\", aby określić \"commit.template\"\n" "tak aby wskazywał na szablon wdrożenia." #, python-format msgid "A hook must be provided at \"%s\"" msgstr "" #, python-format msgid "A stash named \"%s\" already exists" msgstr "Przechowalnia o nazwie \"%s\" już istnieje" msgid "Abort" msgstr "Przerwij" msgid "Abort Action" msgstr "Przerwij działanie" msgid "Abort Merge" msgstr "Przerwij scalanie" msgid "Abort Merge..." msgstr "Przerwij scalanie..." msgid "Abort the action?" msgstr "Przerwać działanie?" msgid "" "Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" "Recovering uncommitted changes is not possible." msgstr "" "Przerwanie obecnego scalania spowoduje utratę *WSZYSTKICH* niewdrożonych zmian.\n" "Przywrócenie niewdrożonych zmian będzie niemożliwe." msgid "Aborting the current merge?" msgstr "Przerwać bieżące scalanie?" msgid "About" msgstr "O" msgid "About git-cola" msgstr "O git-cola" msgid "Accept" msgstr "" #, fuzzy msgid "" "Accept changes and rebase\n" "Shortcut: Ctrl+Enter" msgstr "" "Wdroż zebrane zmiany\n" "Skrót: Ctrl+Enter" #, fuzzy msgid "Action Name" msgstr "Działania" msgid "Actions" msgstr "Działania" msgid "Actions..." msgstr "Działania..." msgid "Add" msgstr "Dodaj" #, fuzzy msgid "Add Favorite" msgstr "Ulubione" msgid "Add Remote" msgstr "Dodaj zdalne repozytorium" msgid "Add Separator" msgstr "" msgid "Add Toolbar" msgstr "" msgid "" "Add and remove remote repositories using the \n" "Add(+) and Delete(-) buttons on the left-hand side.\n" "\n" "Remotes can be renamed by selecting one from the list\n" "and pressing \"enter\", or by double-clicking." msgstr "" "Dodawaj i usuwaj zdalne repozytoria przy użyciu \n" "przycisków Dodaj(+) i Usuń(-) po lewej stronie.\n" "\n" "Nazwy repozytoriów zdalnych można zmienić zaznaczając je na wykazie\n" "i naciskając \"enter\" lub klikając dwukrotnie." msgid "Add new remote git repository" msgstr "Dodaj nowe zdalne repozytorium git" msgid "Add patches (+)" msgstr "Dodaj łaty (+)" msgid "Add remote" msgstr "Dodaj zdalne repozytorium" msgid "Add to .gitignore" msgstr "Dodaj do .gitignore" #, fuzzy msgid "Add to Git Annex" msgstr "Dodaj do .gitignore" msgid "Add to Git LFS" msgstr "" msgid "Additions" msgstr "Dodano" msgid "Advanced" msgstr "Zaawansowane" msgid "Age" msgstr "Wiek" msgid "All Repositories" msgstr "Wszystkie repozytoria" #, python-format msgid "" "All submodules will be updated using\n" "\"%s\"" msgstr "" msgid "Allow non-fast-forward updates. Using \"force\" can cause the remote repository to lose commits; use it with care" msgstr "" msgid "Always create a merge commit when enabled, even when the merge is a fast-forward update" msgstr "Zawsze twórz wdrożenie scalania, gdy włączone, nawet gdy scalanie polega na przewinięciu do przodu" msgid "Amend" msgstr "Uzupełnij" msgid "Amend Commit" msgstr "Uzupełnij wdrożenie" msgid "Amend Last Commit" msgstr "Uzupełnij ostatnie wdrożenie" msgid "Amend the published commit?" msgstr "Uzupełnić opublikowane wdrożenie?" msgid "Amending" msgstr "Uzupełnianie" msgid "" "An action is still running.\n" "Terminating it could result in data loss." msgstr "" "Działanie nadal jest wykonywane.\n" "Jego zakończenie może skutkować utratą danych." msgid "" "An unsigned, lightweight tag will be created instead.\n" "Create an unsigned tag?" msgstr "" "Zamiast tego zostanie utworzony niepodpisany, lekki znacznik.\n" "Czy utworzyć niepodpisany znacznik?" msgid "Appearance" msgstr "" msgid "Apply" msgstr "Zastosuj" msgid "Apply Patches" msgstr "Stosowanie łat" msgid "Apply Patches..." msgstr "Zastosuj łaty..." #, fuzzy msgid "Apply and drop the selected stash (git stash pop)" msgstr "Zastosuj wybraną przechowalnię" msgid "Apply the selected stash" msgstr "Zastosuj wybraną przechowalnię" msgid "Arguments" msgstr "Argumenty" msgid "Attach" msgstr "Dołącz" msgid "Author" msgstr "Autor" #, fuzzy msgid "Authors" msgstr "Autor" msgid "Auto" msgstr "" msgid "Auto-Wrap Lines" msgstr "Zawijaj wiersze" msgid "Basic Regexp" msgstr "Podstawowe wyrażenie regularne" msgid "Blame Viewer" msgstr "Przeglądarka autorów" #, fuzzy msgid "Blame selected paths" msgstr "Edytuj wybraną ścieżkę/ścieżki" msgid "Blame..." msgstr "Przejrzyj autorów..." msgid "Bold on dark headers instead of italic" msgstr "Czcionka pogrubiona z ciemnym tłem zamiast pochylonych nagłówków" msgid "Branch" msgstr "Gałąź" #, python-format msgid "" "Branch \"%(branch)s\" does not exist in \"%(remote)s\".\n" "A new remote branch will be published." msgstr "" "Gałąź \"%(branch)s\" nie istnieje w \"%(remote)s\".\n" "Zostanie opublikowana nowa zdalna gałąź." #, python-format msgid "Branch \"%s\" already exists." msgstr "Gałąź \"%s\" już istnieje." msgid "Branch Diff Viewer" msgstr "Przeglądarka różnic w gałęziach" msgid "Branch Exists" msgstr "Gałąź istnieje" msgid "Branch Name" msgstr "Nazwa gałęzi" #, python-format msgid "Branch: %s" msgstr "Gałąź: %s" #, fuzzy msgid "Branches" msgstr "Gałąź" msgid "Branches..." msgstr "Pomiędzy gałęziami..." msgid "Brazilian translation" msgstr "" msgid "Browse" msgstr "Przeglądaj" msgid "Browse Commits..." msgstr "Przeglądaj wdrożenia..." msgid "Browse Current Branch..." msgstr "Przeglądaj bieżącą gałąź..." msgid "Browse Other Branch..." msgstr "Przeglądaj inną gałąź..." msgid "Browse..." msgstr "Przeglądaj..." msgid "Browser" msgstr "Przeglądarka" #, python-format msgid "Browsing %s" msgstr "Przeglądanie %s" msgid "Bypass Commit Hooks" msgstr "Pomiń sprawdzanie wdrożenia" msgid "Cancel" msgstr "" #, fuzzy msgid "" "Cancel rebase\n" "Shortcut: Ctrl+Q" msgstr "" "Wdroż zebrane zmiany\n" "Skrót: Ctrl+Enter" msgid "Cannot Amend" msgstr "Nie można uzupełnić" #, python-format msgid "Cannot exec \"%s\": please configure a blame viewer" msgstr "Nie można wykonać \"%s\": ustaw przeglądarkę autorów" #, python-format msgid "Cannot exec \"%s\": please configure a history browser" msgstr "Nie można wykonać \"%s\": ustaw przeglądarkę historii" #, python-format msgid "Cannot exec \"%s\": please configure your editor" msgstr "Nie można wykonać \"%s\": ustaw swój edytor" msgid "Changed Upstream" msgstr "Zmienione w źródle odgórnym" msgid "Check Spelling" msgstr "Sprawdzanie pisowni" #, fuzzy msgid "Check spelling" msgstr "Sprawdzanie pisowni" msgid "Checkout" msgstr "Przełącz" msgid "Checkout After Creation" msgstr "Przełącz po utworzeniu" msgid "Checkout Branch" msgstr "Przełącz na gałąź" #, fuzzy msgid "Checkout Detached HEAD" msgstr "Przełącz na gałąź" #, fuzzy msgid "Checkout as new branch" msgstr "Przełącz na gałąź" msgid "Checkout..." msgstr "Przełącz..." msgid "Cherry Pick" msgstr "Zaciągnij wybiórczo" msgid "Cherry-Pick Commit" msgstr "Wybiórczo zaciągnij wdrożenie" msgid "Cherry-Pick..." msgstr "Zaciągnij wybiórczo..." msgid "Choose Paths" msgstr "Wybierz ścieżkę/ścieżki" msgid "Choose the \"git grep\" regular expression mode" msgstr "Wybierz tryb wyrażenia regularnego \"git grep\"" msgid "Clear Default Repository" msgstr "Wyczyść domyślne repozytorium" msgid "Clear commit message" msgstr "Wyczyść opis wdrożenia" msgid "Clear commit message?" msgstr "Wyczyścić opis wdrożenia?" msgid "Clear..." msgstr "Wyczyść..." #, fuzzy msgid "Clone" msgstr "Sklonuj..." msgid "Clone Repository" msgstr "Sklonuj repozytorium" msgid "Clone..." msgstr "Sklonuj..." #, python-format msgid "Cloning repository at %s" msgstr "Klonowanie repozytorium o adresie %s" msgid "Close" msgstr "Zamknij" msgid "Close..." msgstr "Zamknij..." msgid "Collapse all" msgstr "Zwiń wszystko" #, fuzzy msgid "Command" msgstr "Wdrożenie" msgid "Commit" msgstr "Wdrożenie" msgid "Commit failed" msgstr "Nieudane wdrażanie" msgid "Commit staged changes" msgstr "Wdroż dobrane zmiany" msgid "" "Commit staged changes\n" "Shortcut: Ctrl+Enter" msgstr "" "Wdroż zebrane zmiany\n" "Skrót: Ctrl+Enter" msgid "Commit summary" msgstr "Nazwa wdrożenia" msgid "Commit the merge if there are no conflicts. Uncheck to leave the merge uncommitted" msgstr "Wdroż scalenie, jeśli brak sprzeczności. Odznacz pole, aby pozostawić scalenie niewdrożonym" msgid "Commit@@verb" msgstr "Wdroż@@verb" msgid "Compare" msgstr "Porównaj" #, fuzzy msgid "Compare All" msgstr "Porównaj" msgid "Configure the remote branch as the the new upstream" msgstr "Ustaw zdalną gałąź jako nowe źródło odgórne" msgid "Configure toolbar" msgstr "" msgid "Console" msgstr "Konsola" msgid "Continue" msgstr "Kontynuuj" msgid "Copy" msgstr "Kopiuj" #, fuzzy msgid "Copy Basename to Clipboard" msgstr "Kopiuj ścieżkę do schowka" #, fuzzy msgid "Copy Leading Path to Clipboard" msgstr "Kopiuj względną ścieżkę do schowka" msgid "Copy Path to Clipboard" msgstr "Kopiuj ścieżkę do schowka" msgid "Copy Relative Path to Clipboard" msgstr "Kopiuj względną ścieżkę do schowka" msgid "Copy SHA-1" msgstr "Kopiuj SHA-1" #, fuzzy msgid "Copy..." msgstr "Kopiuj" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "Nie można przetworzyć adresu URL Gita: \"%s\"" msgid "Create Branch" msgstr "Utwórz gałąź" msgid "Create Patch" msgstr "Utwórz łatę" msgid "Create Remote Branch" msgstr "Utwórz zdalną gałąź" msgid "Create Signed Commit" msgstr "Podpisz wdrożenie" msgid "Create Tag" msgstr "Utwórz znacznik" msgid "Create Tag..." msgstr "Utwórz znacznik..." msgid "Create Unsigned Tag" msgstr "Utwórz niepodpisany znacznik" #, fuzzy msgid "Create a merge commit even when the merge resolves as a fast-forward" msgstr "Zawsze twórz wdrożenie scalania, gdy włączone, nawet gdy scalanie polega na przewinięciu do przodu" msgid "Create a new remote branch?" msgstr "Czy utworzyć nową zdalną gałąź?" msgid "Create..." msgstr "Utwórz..." #, python-format msgid "Created a new tag named \"%s\"" msgstr "Utworzono nowy znacznik o nazwie \"%s\"" msgid "Current Repository" msgstr "Bieżące repozytorium" msgid "Custom Copy Actions" msgstr "" #, fuzzy msgid "Customize..." msgstr "Zamknij..." msgid "Cut" msgstr "" msgid "Czech translation" msgstr "" msgid "DAG..." msgstr "DAG..." msgid "Dark Theme" msgstr "" msgid "Date, Time" msgstr "Data, czas" msgid "Default" msgstr "" msgid "Delete" msgstr "Usuń" #, python-format msgid "Delete %d file(s)?" msgstr "Usunąć %d plik(ów)?" msgid "Delete Bookmark" msgstr "Usuń zakładkę" msgid "Delete Bookmark?" msgstr "Usunąć zakładkę?" msgid "Delete Branch" msgstr "Usuń gałąź" msgid "Delete Files" msgstr "Usuń pliki" msgid "Delete Files..." msgstr "Usuń plik(i)..." msgid "Delete Files?" msgstr "Usunąć pliki?" msgid "Delete Remote" msgstr "Usuń zdalne repozytorium" msgid "Delete Remote Branch" msgstr "Usuń zdalną gałąź" msgid "Delete Remote Branch..." msgstr "Usuń zdalne repozytorium..." msgid "Delete remote" msgstr "Usuń zdalne repozytorium" #, python-format msgid "Delete remote \"%s\"" msgstr "Usuń zdalne repozytorium \"%s\"" msgid "Delete remote?" msgstr "Usunąć zdalne repozytorium?" #, fuzzy msgid "Delete selected branch?" msgstr "Usuń zdalną gałąź" #, fuzzy msgid "Delete toolbar" msgstr "Usuń zakładkę" msgid "Delete..." msgstr "Usuń..." #, python-format msgid "Deleting \"%s\" failed" msgstr "Nie udało się usunąć \"%s\"" msgid "Deletions" msgstr "Usunięto" msgid "Detach" msgstr "Odłącz" msgid "Detect Conflict Markers" msgstr "Wykryj znaczniki sprzeczności" msgid "Detect conflict markers in unmerged files" msgstr "Wykryj znaczniki sprzeczności w niescalonych plikach" msgid "Developer" msgstr "" msgid "Diff" msgstr "Różnica" msgid "Diff Against Predecessor..." msgstr "Różnica wzgl. poprzednika..." msgid "Diff Options" msgstr "Opcje różnicy" msgid "Diff Tool" msgstr "Narzędzie różnicy" msgid "Diff selected -> this" msgstr "Różnica zaznaczenia wzgl. tego" msgid "Diff this -> selected" msgstr "Różnica tego wzgl. zaznaczenia" msgid "Diffstat" msgstr "Statystyka różnicy" #, fuzzy msgid "Difftool" msgstr "Narzędzie różnicy" msgid "Directory Exists" msgstr "Katalog istnieje" msgid "Display Untracked Files" msgstr "Wyświetl niezarządzane pliki" msgid "Documentation" msgstr "Dokumentacja" msgid "Drop" msgstr "Porzuć" msgid "Drop Stash" msgstr "Porzuć przechowalnię" msgid "Drop Stash?" msgstr "Porzucić przechowalnię?" #, python-format msgid "Drop the \"%s\" stash?" msgstr "Porzucić przechowalnię \"%s\"?" msgid "Drop the selected stash" msgstr "Porzuć wybraną przechowalnię" #, fuzzy msgid "Edit" msgstr "&Edycja" msgid "Edit Rebase" msgstr "Edytuj przebazowanie" msgid "Edit Remotes" msgstr "Edytuj zdalne repozytoria" msgid "Edit Remotes..." msgstr "Edytuj zdalne repozytoria..." msgid "Edit remotes by selecting them from the list" msgstr "" msgid "Edit selected paths" msgstr "Edytuj wybraną ścieżkę/ścieżki" msgid "Edit..." msgstr "Edytuj..." msgid "Editor" msgstr "Edytor" msgid "Email Address" msgstr "Adres email" msgid "Email contributor" msgstr "" msgid "Enabled" msgstr "" msgid "Enter New Branch Name" msgstr "Podaj nazwę nowej gałęzi" #, fuzzy msgid "Enter a name for the new bare repo" msgstr "Podaj nazwę dla przechowalni" msgid "Enter a name for the stash" msgstr "Podaj nazwę dla przechowalni" msgid "Error" msgstr "Błąd" msgid "Error Cloning" msgstr "Błąd klonowania" msgid "Error Creating Branch" msgstr "Błąd tworzenia gałęzi" msgid "Error Creating Repository" msgstr "Błąd tworzenia repozytorium" msgid "Error Deleting Remote Branch" msgstr "Błąd usuwania zdalnej gałęzi" msgid "Error Editing File" msgstr "Błąd edytowania pliku" msgid "Error Launching Blame Viewer" msgstr "Błąd uruchamiania przeglądarki autorów" msgid "Error Launching History Browser" msgstr "Błąd uruchamiania przeglądarki historii" #, python-format msgid "Error creating remote \"%s\"" msgstr "Błąd podczas tworzenia zdalnego repozytorium \"%s\"" #, fuzzy msgid "Error creating stash" msgstr "Błąd tworzenia gałęzi" #, python-format msgid "Error deleting remote \"%s\"" msgstr "Błąd usuwania zdalnego repozytorium \"%s\"" #, fuzzy, python-format msgid "Error renaming \"%(name)s\" to \"%(new_name)s\"" msgstr "Znaczenie \"%(revision)s\" jako \"%(name)s\"" msgid "Error running prepare-commitmsg hook" msgstr "" #, fuzzy, python-format msgid "Error updating submodule %s" msgstr "Błąd podczas tworzenia zdalnego repozytorium \"%s\"" #, fuzzy msgid "Error updating submodules" msgstr "Błąd edytowania pliku" msgid "Error: Cannot find commit template" msgstr "Błąd: Nie można znaleźć szablonu wdrożenia" msgid "Error: Stash exists" msgstr "Błąd: Przechowalnia istnieje" msgid "Error: Unconfigured commit template" msgstr "Błąd: Nieustawiony szablon wdrożenia" #, python-format msgid "Error: could not clone \"%s\"" msgstr "Błąd: nie można sklonować \"%s\"" #, python-format msgid "Error: could not create tag \"%s\"" msgstr "Błąd: nie można utworzyć znacznika \"%s\"" #, python-format msgid "Executing action %s" msgstr "" msgid "Expand all" msgstr "Rozwiń wszystko" msgid "Export Patches" msgstr "Eksportowanie łat" msgid "Export Patches..." msgstr "Eksportuj łaty..." msgid "Expression..." msgstr "Jako wyrażenie..." msgid "Extended Regexp" msgstr "Rozszerzone wyrażenie regularne" msgid "Extended description..." msgstr "Rozszerzony opis..." msgid "Fast Forward Only" msgstr "Tylko przewinięcie do przodu" #, fuzzy msgid "Fast-forward only" msgstr "Tylko przewinięcie do przodu" msgid "Favorite repositories" msgstr "Ulubione repozytoria" msgid "Favorites" msgstr "Ulubione" msgid "Fetch" msgstr "Pobierz" msgid "Fetch Tracking Branch" msgstr "Pobierz odgórną gałąź" msgid "Fetch..." msgstr "Pobierz..." msgid "File Browser..." msgstr "Przeglądarka plików..." msgid "File Differences" msgstr "Różniące się pliki" msgid "File Saved" msgstr "Zapisano plik" #, python-format msgid "File saved to \"%s\"" msgstr "Plik zapisano w \"%s\"" msgid "File system change monitoring: disabled because \"cola.inotify\" is false.\n" msgstr "Monitorowanie zmiany systemu plików: wyłączone, bo \"cola.inotify\" jest false.\n" msgid "File system change monitoring: disabled because libc does not support the inotify system calls.\n" msgstr "Monitorowanie zmiany systemu plików: wyłączone, bo libc nie obsługuje wywołań systemowych inotify.\n" msgid "File system change monitoring: disabled because pywin32 is not installed.\n" msgstr "Monitorowanie zmiany systemu plików: wyłączone, bo nie wgrano pywin32.\n" msgid "" "File system change monitoring: disabled because the limit on the total number of inotify watches was reached. You may be able to increase the limit on the number of watches by running:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" msgstr "" "Monitorowanie zmiany systemu plików: wyłączone, bo osiągnięto górną granicę całkowitej liczby obserwowanych inotify. Możesz zwiększyć tę granicę wykonując:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" msgid "File system change monitoring: enabled.\n" msgstr "Monitorowanie zmiany systemu plików: włączone.\n" msgid "Filename" msgstr "Nazwa pliku" msgid "Files" msgstr "Pliki" #, fuzzy msgid "Filter branches..." msgstr "Odfiltruj ścieżki..." msgid "Filter paths..." msgstr "Odfiltruj ścieżki..." msgid "Find Files" msgstr "Znajdź pliki" msgid "Fixed String" msgstr "Stały ciąg znaków" msgid "Fixed-Width Font" msgstr "Czcionka o stałej szerokości" msgid "Fixup" msgstr "" msgid "Fixup Previous Commit" msgstr "Poprawka do wcześniejszego wdrożenia" msgid "Flat dark blue" msgstr "" msgid "Flat dark green" msgstr "" msgid "Flat dark grey" msgstr "" msgid "Flat dark red" msgstr "" msgid "Flat light blue" msgstr "" msgid "Flat light green" msgstr "" msgid "Flat light grey" msgstr "" msgid "Flat light red" msgstr "" msgid "Font Size" msgstr "Rozmiar czcionki" #, fuzzy msgid "Force" msgstr "Wymuś wypchnięcie" msgid "Force Fetch" msgstr "Wymuś pobranie" msgid "Force Fetch?" msgstr "Wymusić pobranie?" msgid "Force Push" msgstr "Wymuś wypchnięcie" msgid "Force Push?" msgstr "Wymusić wypchnięcie?" #, python-format msgid "Force fetching from %s?" msgstr "Wymusić pobranie z %s?" #, python-format msgid "Force push to %s?" msgstr "Wymusić wypchnięcie do %s?" #, fuzzy msgid "Format String" msgstr "Stały ciąg znaków" msgid "French translation" msgstr "" msgid "GPG-sign the merge commit" msgstr "Podpisz-GPG scalane wdrożenie" msgid "GUI theme" msgstr "" #, python-format msgid "Gathering info for \"%s\"..." msgstr "Zbieranie informacji dla \"%s\"..." msgid "German translation" msgstr "" msgid "Get Commit Message Template" msgstr "Pobierz szablon opisu wdrożenia" msgid "Go Down" msgstr "Przejdź w dół" msgid "Go Up" msgstr "Przejdź w górę" msgid "Grab File..." msgstr "Pobierz plik..." msgid "Graph" msgstr "Graf" msgid "Grep" msgstr "Wyszukaj (grep)" msgid "Have you rebased/pulled lately?" msgstr "Czy ostatnio przebazowałeś/zaciągnąłeś?" msgid "Help" msgstr "Pomoc" msgid "Help - Custom Copy Actions" msgstr "" msgid "Help - Find Files" msgstr "Pomoc - Znajdź pliki" msgid "Help - git-xbase" msgstr "" msgid "Hide Details.." msgstr "" msgid "High DPI" msgstr "" msgid "History Browser" msgstr "Przeglądarka historii" msgid "Hungarian translation" msgstr "" msgid "Icon theme" msgstr "" msgid "Ignore all whitespace" msgstr "Pomiń wszystkie białe znaki" msgid "Ignore changes in amount of whitespace" msgstr "Pomiń zmiany w liczbie białych znaków" msgid "Ignore changes in whitespace at EOL" msgstr "Pomiń zmiany w białych znakach na końcu wiersza" msgid "Ignore custom pattern" msgstr "" #, fuzzy msgid "Ignore exact filename" msgstr "Pomiń wszystkie białe znaki" msgid "Ignore filename or pattern" msgstr "" msgid "Include tags " msgstr "Uwzględnij znaczniki" msgid "Indent Status paths" msgstr "" msgid "Indonesian translation" msgstr "" msgid "Initialize Git Annex" msgstr "" msgid "Initialize Git LFS" msgstr "" msgid "Inititalize submodules" msgstr "" msgid "Insert spaces instead of tabs" msgstr "" msgid "Interactive Rebase" msgstr "Interaktywne przebazowanie" msgid "Invalid Revision" msgstr "Nieprawidłowe wydanie" msgid "Keep *.orig Merge Backups" msgstr "Zachowaj kopie zapasowe *.orig po scalaniu" msgid "Keep Index" msgstr "Zachowaj indeks" msgid "Keyboard Shortcuts" msgstr "Skróty klawiszowe" msgid "Launch Diff Tool" msgstr "Wywołaj narzędzie różnicy" #, fuzzy msgid "Launch Directory Diff Tool" msgstr "Wywołaj narzędzie różnicy" msgid "Launch Editor" msgstr "Otwórz w edytorze" msgid "Launch Terminal" msgstr "Uruchom terminal" msgid "" "Launch external diff tool\n" "Shortcut: Ctrl+D" msgstr "" msgid "Launch git-cola" msgstr "Uruchom git-cola" #, fuzzy msgid "Launch git-difftool against previous versions" msgstr "Uruchom git-difftool względem poprzednich wersji." #, fuzzy msgid "Launch git-difftool on the current path" msgstr "Uruchom git-difftool dla bieżącej ścieżki." msgid "Light Theme" msgstr "" msgid "Load Commit Message" msgstr "Wczytaj opis wdrożenia" msgid "Load Commit Message..." msgstr "Wczytaj opis wdrożenia..." msgid "Load Previous Commit Message" msgstr "Wczytaj opis wcześniejszego wdrożenia" msgid "Loading..." msgstr "Wczytywanie..." msgid "Local" msgstr "Lokalna" msgid "Local Branch" msgstr "Lokalna gałąź" msgid "Local branch" msgstr "Lokalna gałąź" msgid "Lock Layout" msgstr "Zablokuj układ" msgid "Log" msgstr "Dziennik" msgid "Maintainer (since 2007) and developer" msgstr "" msgid "Merge" msgstr "Scal" #, python-format msgid "Merge \"%(revision)s\" into \"%(branch)s\"" msgstr "Scal \"%(revision)s\" z \"%(branch)s\"" msgid "Merge Tool" msgstr "Narzędzie scalania" msgid "Merge Verbosity" msgstr "Szczegółowość scalania" msgid "Merge failed. Conflict resolution is required." msgstr "" #, python-format msgid "Merge into \"%s\"" msgstr "Scal z \"%s\"" #, fuzzy msgid "Merge into current branch" msgstr "Przeglądaj bieżącą gałąź..." msgid "Merge..." msgstr "Scal..." msgid "Merging" msgstr "Scalanie" msgid "Message" msgstr "Opis" msgid "Missing Commit Message" msgstr "Brak opisu wdrożenia" msgid "Missing Data" msgstr "Brakuje danych" msgid "Missing Name" msgstr "Brak nazwy" msgid "Missing Revision" msgstr "Brak wydania" msgid "Missing Tag Message" msgstr "Brak opisu znacznika" msgid "Modified" msgstr "Zmienione" msgid "More..." msgstr "Więcej..." msgid "Move Down" msgstr "Przesuń w dół" msgid "Move Up" msgstr "Przesuń w górę" msgid "Move files to trash" msgstr "Przenieś plik(i) do kosza" msgid "Name" msgstr "Nazwa" msgid "Name for the new remote" msgstr "Nazwa nowego zdalnego repozytorium" #, fuzzy msgid "New Bare Repository..." msgstr "Nowe repozytorium..." msgid "New Repository..." msgstr "Nowe repozytorium..." msgid "New..." msgstr "Nowe..." msgid "Next File" msgstr "Następny plik" msgid "No" msgstr "Nie" msgid "No Revision Specified" msgstr "Nie podano wydania" msgid "" "No changes to commit.\n" "\n" "You must stage at least 1 file before you can commit." msgstr "" "Brak zmian do wdrożenia.\n" "\n" "Musisz dobrać co najmniej 1 plik zanim będziesz mógł cokolwiek wdrożyć." msgid "No commits exist in this branch." msgstr "Brak wdrożeń w tej gałęzi." msgid "No fast forward" msgstr "Bez przewijania do przodu" #, fuzzy msgid "No fast-forward" msgstr "Bez przewijania do przodu" msgid "No repository selected." msgstr "Nie wybrano repozytorium." msgid "Non-fast-forward fetch overwrites local history!" msgstr "Pobranie bez przewinięcia do przodu zastępuje lokalną historię!" msgid "" "Non-fast-forward push overwrites published history!\n" "(Did you pull first?)" msgstr "Wypchnięcie bez przewinięcia do przodu zastępuje opublikowaną historię!" msgid "Nothing to commit" msgstr "Nie ma nic do wdrożenia" msgid "Nothing to do" msgstr "Nie ma nic do zrobienia" msgid "Number of Diff Context Lines" msgstr "Liczba wierszy kontekstu różnicy" msgid "Open" msgstr "Otwórz" msgid "Open Git Repository..." msgstr "Otwórz repozytorium Git..." #, fuzzy msgid "Open Parent" msgstr "Otwórz z ostatnich" msgid "Open Parent Directory" msgstr "Otwórz katalog nadrzędny" msgid "Open Recent" msgstr "Otwórz z ostatnich" msgid "Open Using Default Application" msgstr "Otwórz w domyślnej aplikacji" msgid "Open in New Window" msgstr "Otwórz w nowym oknie" msgid "Open in New Window..." msgstr "Otwórz w nowym oknie..." msgid "Open..." msgstr "Otwórz..." #, fuzzy msgid "Other branches" msgstr "Odfiltruj ścieżki..." msgid "Overwrite" msgstr "Zastąp" #, python-format msgid "Overwrite \"%s\"?" msgstr "Zastąpić \"%s\"?" msgid "Overwrite File?" msgstr "Zastąpić plik?" msgid "" "Parse arguments using a shell.\n" "Queries with spaces will require \"double quotes\"." msgstr "" "Przetwórz argumenty przy użyciu powłoki.\n" "Zapytania z odstępami będą wymagać cudzysłowów." msgid "Partially Staged" msgstr "Częściowo zebrany" msgid "Paste" msgstr "" msgid "Patch(es) Applied" msgstr "Zastosowano łatę/łaty" msgid "Path" msgstr "" msgid "Path or URL to clone (Env. $VARS okay)" msgstr "Ścieżka lub adres URL do sklonowania (Zm. środowiskowe $VARS są OK)" msgid "Pick" msgstr "" msgid "Pixel XOR" msgstr "" msgid "Please provide both a branch name and revision expression." msgstr "Podaj zarówno nazwę gałęzi jak i wyrażenie wydania." msgid "Please select a file" msgstr "Wybierz plik" msgid "Please specify a name for the new tag." msgstr "Podać nazwę dla nowego znacznika." msgid "Please specify a revision to tag." msgstr "Podaj wydanie do oznaczenia." msgid "" "Please supply a commit message.\n" "\n" "A good commit message has the following format:\n" "\n" "- First line: Describe in one sentence what you did.\n" "- Second line: Blank\n" "- Remaining lines: Describe why this change is good.\n" msgstr "" "Podaj opis wdrożenia.\n" "\n" "Dobry opis wdrożenia ma następującą postać:\n" "\n" "- Pierwszy wiersz: Opisz w jednym zdaniu co zrobiłeś.\n" "- Drugi wiersz: Pusty\n" "- Pozostałe wiersze: Opisz dlaczego ta zmiana jest dobra.\n" msgid "Point the current branch head to a new commit?" msgstr "Ustawić HEAD bieżącej gałęzi na nowe wdrożenie?" msgid "Polish translation" msgstr "" msgid "Pop" msgstr "" msgid "Preferences" msgstr "Ustawienia" msgid "Prefix" msgstr "Przedrostek" #, fuzzy msgid "Prepare Commit Message" msgstr "Wyszukaj opisu wdrożenia" msgid "Prevent \"Stage\" from staging all files when nothing is selected" msgstr "" msgid "Previous File" msgstr "Poprzedni plik" msgid "Prompt on creation" msgstr "" #, fuzzy msgid "Prompt when pushing creates new remote branches" msgstr "Czy utworzyć nową zdalną gałąź?" msgid "Prune " msgstr "" msgid "Pull" msgstr "Zaciągnij" msgid "Pull..." msgstr "Zaciągnij..." msgid "Push" msgstr "Wypchnij" msgid "Push..." msgstr "Wypchnij..." msgid "Quit" msgstr "Wyjdź" msgid "Rebase" msgstr "Przebazuj" #, python-format msgid "Rebase onto %s" msgstr "Przebazowanie na %s" #, fuzzy msgid "Rebase stopped" msgstr "Przebazowanie" #, fuzzy msgid "Rebase the current branch instead of merging" msgstr "Ustawić HEAD bieżącej gałęzi na nowe wdrożenie?" msgid "Rebasing" msgstr "Zmienianie bazy" msgid "Recent" msgstr "Ostatnie" msgid "Recent repositories" msgstr "Ostatnie repozytoria" #, fuzzy msgid "Recent repository count" msgstr "Ostatnie repozytoria" msgid "Recently Modified Files" msgstr "Ostatnio zmienone pliki" msgid "Recently Modified Files..." msgstr "Ostatnio zmienone pliki..." msgid "Recovering a dropped stash is not possible." msgstr "Odzyskanie porzuconej przechowalni będzie niemożliwe." msgid "Recovering lost commits may not be easy." msgstr "Przywrócenie utraconych wdrożeń może nie być łatwe." msgid "Redo" msgstr "" msgid "Reduce commit history to minimum" msgstr "" msgid "Refresh" msgstr "Odśwież" msgid "Refuse to merge unless the current HEAD is already up-to-date or the merge can be resolved as a fast-forward" msgstr "" msgid "Remote" msgstr "Zdalne repozytorium" msgid "Remote Branch" msgstr "Zdalna gałąź" msgid "Remote Branch Deleted" msgstr "Usunięto zdalną gałąź" msgid "Remote git repositories - double-click to rename" msgstr "Zdalne repozytoria git - kliknij dwukrotnie, aby zmienić nazwę" msgid "Remove" msgstr "Usuń" #, python-format msgid "Remove %s from the recent list?" msgstr "Usunąć %s z listy ostatnich?" #, fuzzy msgid "Remove Element" msgstr "Usuń" msgid "Remove remote-tracking branches that no longer exist on the remote" msgstr "" msgid "Remove selected (Delete)" msgstr "Usuń wybrane (Usuń)" msgid "Rename" msgstr "Zmień nazwę" #, fuzzy, python-format msgid "Rename \"%s\"" msgstr "Zmień nazwę" #, fuzzy msgid "Rename Branch" msgstr "Zmień nazwę gałęzi..." msgid "Rename Branch..." msgstr "Zmień nazwę gałęzi..." msgid "Rename Existing Branch" msgstr "Zmień nazwę istniejącej gałęzi" msgid "Rename Remote" msgstr "Zmień nazwę zdalnego repozytorium" #, fuzzy msgid "Rename Repository" msgstr "Sklonuj repozytorium" #, fuzzy msgid "Rename branch" msgstr "Zmień nazwę gałęzi..." #, python-format msgid "Rename remote \"%(current)s\" to \"%(new)s\"?" msgstr "Zmień nazwę zdalnego repozytorium z \"%(current)s\" na \"%(new)s\"?" #, fuzzy msgid "Rename selected paths" msgstr "Edytuj wybraną ścieżkę/ścieżki" #, python-format msgid "Repository: %s" msgstr "Repozytorium: %s" msgid "Reset" msgstr "Wyzeruj" #, python-format msgid "Reset \"%(branch)s\" to \"%(revision)s\"?" msgstr "Wyzerować \"%(branch)s\" do \"%(revision)s\"?" msgid "Reset Branch" msgstr "Wyzeruj gałąź" msgid "Reset Branch Head" msgstr "Wyzeruj HEAD gałęzi" msgid "Reset Branch?" msgstr "Wyzerować gałąź?" #, fuzzy msgid "Reset Hard" msgstr "Wyzeruj HEAD gałęzi" #, fuzzy msgid "Reset Merge" msgstr "Wydanie do scalenia" #, fuzzy msgid "Reset Soft" msgstr "Wyzeruj drzewo robocze" msgid "Reset Worktree" msgstr "Wyzeruj drzewo robocze" #, fuzzy msgid "Reset hard?" msgstr "Wyzerować gałąź?" #, fuzzy msgid "Reset merge?" msgstr "Wyzerować drzewo robocze?" #, fuzzy msgid "Reset soft?" msgstr "Wyzerować drzewo robocze?" msgid "Reset worktree?" msgstr "Wyzerować drzewo robocze?" #, python-format msgid "Resetting \"%(branch)s\" to \"%(revision)s\" will lose commits." msgstr "Wyzerowanie \"%(branch)s\" do \"%(revision)s\" spowoduje utratę wdrożeń." msgid "Restart the application after changing appearance settings." msgstr "" msgid "Revert" msgstr "" msgid "Revert Diff Hunk" msgstr "Wycofaj kawałek różnicy" msgid "Revert Diff Hunk..." msgstr "Wycofaj kawałek różnicy..." msgid "Revert Diff Hunk?" msgstr "Wycofać kawałek różnicy?" msgid "Revert Selected Lines" msgstr "Wycofaj zaznaczone wiersze" msgid "Revert Selected Lines..." msgstr "Wycofaj zaznaczone wiersze..." msgid "Revert Selected Lines?" msgstr "Wycofać zaznaczone wiersze?" msgid "Revert Uncommitted Changes" msgstr "Wycofaj niewdrożone zmiany" msgid "Revert Uncommitted Changes?" msgstr "Wycofać niewdrożone zmiany?" msgid "Revert Uncommitted Edits..." msgstr "Wycofaj niewdrożone zmiany..." msgid "Revert Unstaged Changes" msgstr "Wycofaj odłożone zmiany" msgid "Revert Unstaged Changes?" msgstr "Wycofać odłożone zmiany?" msgid "Revert Unstaged Edits..." msgstr "Wycofaj odłożone zmiany..." msgid "Revert the uncommitted changes?" msgstr "Wycofać niewdrożone zmiany?" msgid "Revert the unstaged changes?" msgstr "Wycofać odłożone zmiany?" #, fuzzy msgid "Revert uncommitted changes to selected paths" msgstr "Wycofaj niewdrożone zmiany w wybranych ścieżkach." #, fuzzy msgid "Revert unstaged changes to selected paths" msgstr "Wycofaj niezebrane zmiany w wybranych ścieżkach." msgid "Review" msgstr "Przegląd" msgid "Review..." msgstr "Przejrzyj..." msgid "Revision" msgstr "Wydanie" msgid "Revision Expression:" msgstr "Wyrażenie wydania:" msgid "Revision to Merge" msgstr "Wydanie do scalenia" msgid "Reword" msgstr "" msgid "Rewrite Published Commit?" msgstr "Zmienić opublikowane wdrożenie?" msgid "Run" msgstr "Wykonaj" #, python-format msgid "Run \"%s\"?" msgstr "Uruchom \"%s\"?" #, python-format msgid "Run %s?" msgstr "Wykonać %s?" #, python-format msgid "Run the \"%s\" command?" msgstr "Wykonać polecenie \"%s\"?" #, python-format msgid "Running command: %s" msgstr "Wykonywanie polecenia: %s" msgid "Russian translation" msgstr "" #, fuzzy msgid "SHA-1" msgstr "Kopiuj SHA-1" #, fuzzy msgid "Safe Mode" msgstr "Dobierz zmienone" msgid "Save" msgstr "Zachowaj" msgid "Save Archive" msgstr "Zapisz archiwum" msgid "Save As Tarball/Zip..." msgstr "Zapisz jako Tarball/Zip..." msgid "Save GUI Settings" msgstr "Zapisz ustawienia GUI" msgid "Save Stash" msgstr "Zachowaj przechowalnię" msgid "Save modified state to new stash" msgstr "Zachowaj zmieniony stan w nowej przechowalni" #, python-format msgid "Saved \"%(filename)s\" from \"%(ref)s\" to \"%(destination)s\"" msgstr "Zapisano \"%(filename)s\" z \"%(ref)s\" do \"%(destination)s\"" msgid "Search" msgstr "Wyszukaj" msgid "Search Authors" msgstr "Wyszukaj autorów" msgid "Search Commit Messages" msgstr "Wyszukaj opisu wdrożenia" msgid "Search Committers" msgstr "Wyszukaj wdrożeniowców" msgid "Search Date Range" msgstr "Wyszukaj zakresu dat" msgid "Search Diffs" msgstr "Wyszukaj różnicy" msgid "Search by Expression" msgstr "Wyszukaj po wyrażeniu" msgid "Search by Path" msgstr "Wyszukaj po ścieżce" msgid "Search for a fixed string" msgstr "Wyszukaj stały ciąg znaków" msgid "Search using a POSIX basic regular expression" msgstr "Wyszukaj przy użyciu podstawowego wyrażenia regularnego POSIX" msgid "Search using a POSIX extended regular expression" msgstr "Wyszukaj przy użyciu rozszerzonego wyrażenia regularnego POSIX" msgid "Search..." msgstr "Wyszukaj..." msgid "Select" msgstr "Wybierz" msgid "Select All" msgstr "Zaznacz wszystko" msgid "Select Branch to Review" msgstr "Wybierz gałąź do przeglądnięcia" msgid "Select Child" msgstr "Wybierz potomnego" msgid "Select Commit" msgstr "Wybierz wdrożenie" #, fuzzy msgid "Select Directory..." msgstr "Wybierz repozytorium..." msgid "Select New Upstream" msgstr "Wybierz nowe źródło odgórne" msgid "Select Newest Child" msgstr "Wybierz najnowszego potomnego" msgid "Select Oldest Parent" msgstr "Wybierz najstarszego przodka" msgid "Select Parent" msgstr "Wybierz przodka" msgid "Select Previous Version" msgstr "Wybierz poprzednią wersję" msgid "Select Repository..." msgstr "Wybierz repozytorium..." msgid "Select a parent directory for the new clone" msgstr "Wybierz katalog nadrzędny do sklonowania" msgid "Select manually..." msgstr "Wybierz ręcznie..." #, fuzzy msgid "Select output dir" msgstr "Wybierz wdrożenie" #, fuzzy msgid "Select output directory" msgstr "Wybierz repozytorium..." #, fuzzy msgid "Select patch file(s)..." msgstr "Wybierz plik(i) łat(y)..." #, fuzzy msgid "Select repository" msgstr "Wybierz repozytorium..." msgid "Set Default Repository" msgstr "Ustaw domyślne repozytorium" #, fuzzy msgid "Set Upstream Branch" msgstr "Ustaw źródło odgórne" msgid "" "Set the sort order for branches and tags.\n" "Toggle between date-based and version-name-based sorting." msgstr "" msgid "Set upstream" msgstr "Ustaw źródło odgórne" msgid "Settings" msgstr "Ustawienia" msgid "Shell arguments" msgstr "Argumenty powłoki" msgid "Shift Down" msgstr "" msgid "Shift Up" msgstr "" msgid "Shortcuts" msgstr "Skróty" #, fuzzy msgid "Show Details..." msgstr "Usuń plik(i)..." msgid "Show Diffstat After Merge" msgstr "Pokaż statystykę różnicy po scaleniu" msgid "Show Full Paths in the Window Title" msgstr "" msgid "Show Help" msgstr "Pokaż pomoc" msgid "Show History" msgstr "Pokaż historię" msgid "Show file counts in Status titles" msgstr "" msgid "" "Show help\n" "Shortcut: ?" msgstr "" "Pokaż pomoc\n" "Skrót: ?" msgid "Show icon? (if available)" msgstr "" msgid "Show line numbers" msgstr "" msgid "Show whole surrounding functions of changes" msgstr "Pokaż całe funkcje otaczające przy zmianach" msgid "Showing changes since" msgstr "Wyświetlanie zmian od" msgid "Side by side" msgstr "" msgid "Sign Off" msgstr "Podpisz się" msgid "Sign Tag" msgstr "Podpisz znacznik" msgid "Sign off on this commit" msgstr "Podpisz się na tym wdrożeniu" msgid "Simplified Chinese translation" msgstr "" msgid "Skip" msgstr "Pomiń" msgid "Skip Current Patch" msgstr "Pomiń obecną łatę" msgid "Sort bookmarks alphabetically" msgstr "Uszereguj zakładki alfabetycznie" msgid "Spanish translation" msgstr "" msgid "Specifies the SHA-1 to tag" msgstr "Jest SHA-1 znacznika" msgid "Specifies the tag message" msgstr "Jest opisem znacznika" msgid "Specifies the tag name" msgstr "Jest nazwą znacznika" msgid "Spelling Suggestions" msgstr "Sprawdzanie pisowni" msgid "Squash" msgstr "Złącz" msgid "Squash the merged commits into a single commit" msgstr "Złącz scalone wdrożenie/wdrożenia w pojedyncze wdrożenie" msgid "Stage" msgstr "Dobierz" msgid "Stage / Unstage" msgstr "Dobierz / odłóż" msgid "Stage All Untracked" msgstr "Dobierz wszystkie niezarządzane" msgid "Stage Changed Files To Commit" msgstr "Dobierz zmienione pliki do wdrożenia" msgid "Stage Diff Hunk" msgstr "Dobierz kawałek różnicy" msgid "Stage Modified" msgstr "Dobierz zmienone" msgid "Stage Selected" msgstr "Dobierz zaznaczone" msgid "Stage Selected Lines" msgstr "Dobierz zaznaczone wiersze" msgid "Stage Unmerged" msgstr "Dobierz niescalone" msgid "Stage Untracked" msgstr "Dobierz niezarządzane" msgid "Stage and Commit" msgstr "Zbierz i wdroż" msgid "Stage and commit?" msgstr "Zebrać i wdrożyć?" msgid "Stage conflicts" msgstr "Dobrać sprzeczności" msgid "Stage conflicts?" msgstr "Dobrać sprzeczności?" msgid "Stage/unstage selected paths for commit" msgstr "Dobierz/odłóż wybraną ścieżkę/ścieżki dla wdrożenia" msgid "Staged" msgstr "Dobrane" #, python-format msgid "Staging: %s" msgstr "Dobieranie: %s" msgid "Start Interactive Rebase..." msgstr "Interaktywne przebazowanie..." msgid "Starting Revision" msgstr "Rozpoczynanie wydania" msgid "Stash" msgstr "Przechowalnia" #, fuzzy msgid "Stash Index" msgstr "Przechowalnia" #, fuzzy msgid "Stash staged changes only" msgstr "Wdroż dobrane zmiany" #, fuzzy msgid "Stash unstaged changes only, keeping staged changes" msgstr "Wycofaj niezebrane zmiany w wybranych ścieżkach." msgid "Stash..." msgstr "Przechowaj..." msgid "Status" msgstr "Stan" msgid "Stop tracking paths" msgstr "Zaprzestań zarządzanie ścieżką/ścieżkami" msgid "Submodules" msgstr "" msgid "Summarize Merge Commits" msgstr "Podsumuj wdrożenia scalające" msgid "Summary" msgstr "Nazwa" msgid "Tab Width" msgstr "Szerokość tabulacji" msgid "Tag" msgstr "Znacznik" msgid "Tag Created" msgstr "Utworzono znacznik" msgid "Tag message..." msgstr "Opis znacznika..." msgid "Tag-signing was requested but the tag message is empty." msgstr "Zażądano podpisania znacznika, lecz opis znacznika jest pusty." msgid "Tags" msgstr "" msgid "Text Width" msgstr "Szerokość tekstu" msgid "The branch will be no longer available." msgstr "" #, fuzzy, python-format msgid "The branch will be reset using \"git reset --hard %s\"" msgstr "Gałąź zostanie wyzerowana przy użyciu \"git reset --mixed %s\"" #, fuzzy, python-format msgid "The branch will be reset using \"git reset --merge %s\"" msgstr "Gałąź zostanie wyzerowana przy użyciu \"git reset --mixed %s\"" #, python-format msgid "The branch will be reset using \"git reset --mixed %s\"" msgstr "Gałąź zostanie wyzerowana przy użyciu \"git reset --mixed %s\"" #, fuzzy, python-format msgid "The branch will be reset using \"git reset --soft %s\"" msgstr "Gałąź zostanie wyzerowana przy użyciu \"git reset --mixed %s\"" msgid "The commit message will be cleared." msgstr "Opis wdrożenia zostanie wyczyszczony." #, python-format msgid "The file \"%s\" exists and will be overwritten." msgstr "Plik %s już istnieje i zostanie zastąpiony." msgid "The following files will be deleted:" msgstr "Zostaną usunięte następujące pliki:" msgid "The revision expression cannot be empty." msgstr "Wyrażenie wydania nie może być puste." #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, fuzzy, python-format msgid "The worktree will be reset using \"git reset --keep %s\"" msgstr "Drzewo robocze zostanie wyzerowane przy użyciu \"git reset --merge %s\"" msgid "This cannot be undone. Clear commit message?" msgstr "Nie będzie można tego wycofać. Czy wyczyścić opis wdrożenia?" msgid "" "This commit has already been published.\n" "This operation will rewrite published history.\n" "You probably don't want to do this." msgstr "" "To wdrożenie już jest opublikowane.\n" "Działanie to zmieni opublikowaną historię.\n" "Prawdopodobnie nie chcesz tego." #, fuzzy msgid "" "This operation drops uncommitted changes.\n" "These changes cannot be recovered." msgstr "" "To działanie porzuci niewdrożone zmiany.\n" "Zmian tych nie będzie można przywrócić." msgid "" "This operation removes uncommitted edits from selected files.\n" "These changes cannot be recovered." msgstr "" "To działanie porzuci niewdrożone zmiany.\n" "Zmian tych nie będzie można przywrócić." msgid "" "This operation removes unstaged edits from selected files.\n" "These changes cannot be recovered." msgstr "" "To działanie porzuci odłożone zmiany.\n" "Tych zmian nie będzie można odzyskać." msgid "" "This repository is currently being rebased.\n" "Resolve conflicts, commit changes, and run:\n" " Rebase > Continue" msgstr "" "Repozytorium jest przebazowywane.\n" "Wyjaśnij sprzeczności, wdroż zmiany i wykonaj:\n" " Zmiana bazy > Kontynuuj" msgid "" "This repository is in the middle of a merge.\n" "Resolve conflicts and commit changes." msgstr "" "To repozytorium jest w środku scalania.\n" "Wyjaśnij sprzeczności i wdroż zmiany." msgid "Toggle Enabled" msgstr "" #, fuzzy msgid "Toggle the branches filter" msgstr "Przełącz filtr ścieżek" msgid "Toggle the paths filter" msgstr "Przełącz filtr ścieżek" msgid "Tracking Branch" msgstr "Odgórna gałąź" msgid "Tracking branch" msgstr "Odgórna gałąź" msgid "Traditional Chinese (Taiwan) translation" msgstr "" msgid "Translators" msgstr "" msgid "Turkish translation" msgstr "" msgid "URL" msgstr "Adres URL" #, python-format msgid "URL: %s" msgstr "Adres URL: %s" msgid "Ukranian translation" msgstr "" msgid "Unable to rebase" msgstr "Nie można przebazować" #, python-format msgid "Unable to set URL for \"%(name)s\" to \"%(url)s\"" msgstr "" msgid "Undo" msgstr "" msgid "Unmerged" msgstr "Niescalone" msgid "Unstage" msgstr "Odłóż" msgid "Unstage All" msgstr "Odłóż wszystkie" msgid "Unstage Diff Hunk" msgstr "Odłóż kawałek różnicy" msgid "Unstage From Commit" msgstr "Odłóż" msgid "Unstage Selected" msgstr "Odłóż zaznaczone" msgid "Unstage Selected Lines" msgstr "Odłóż zaznaczone wiersze" #, python-format msgid "Unstaging: %s" msgstr "Odkładanie: %s" msgid "Untrack Selected" msgstr "Nie zarządzaj wybranymi" msgid "Untracked" msgstr "Niezarządzane" #, python-format msgid "Untracking: %s" msgstr "Nie zarządzaj: %s" msgid "Update All Submodules..." msgstr "" msgid "Update Existing Branch:" msgstr "Uaktualnij bieżącą gałąź:" msgid "Update Submodule" msgstr "" msgid "Update Submodule..." msgstr "" msgid "Update Submodules" msgstr "" msgid "Update all submodules?" msgstr "" msgid "Update submodules..." msgstr "" msgid "Update this submodule" msgstr "" msgid "Update this submodule?" msgstr "" msgid "Updating" msgstr "Uaktualnianie" msgid "User Name" msgstr "Nazwa użytkownika" #, fuzzy msgid "Version" msgstr "Wydanie" msgid "View" msgstr "Widok" msgid "View History..." msgstr "Przejrzyj historię..." msgid "View history for selected paths" msgstr "Przejrzyj historię dla wybranej ścieżki/ścieżek" msgid "Visualize" msgstr "Zobrazuj" msgid "Visualize All Branches..." msgstr "Zobrazuj wszystkie gałęzie..." msgid "Visualize Current Branch..." msgstr "Zobrazuj bieżącą gałąź..." msgid "Whether to sign the tag (git tag -s)" msgstr "Określa czy podpisać znacznik (git tag -s)" msgid "Would you like to stage and commit all modified files?" msgstr "Czy chcesz zebrać i wdrożyć wszystkie zmienione pliki?" msgid "XOR" msgstr "" msgid "Yes" msgstr "" msgid "" "You are in the middle of a merge.\n" "Cannot amend while merging." msgstr "" "Jesteś w środku scalania.\n" "Nie można uzupełniać w trakcie scalania." msgid "You cannot rebase with uncommitted changes." msgstr "Nie można przebazować, gdy masz niewdrożone zmiany." msgid "You must specify a revision to merge." msgstr "Musisz podać wydanie do scalenia." msgid "You must specify a revision to view." msgstr "Musisz podać wydanie do obejrzenia." msgid "Zoom In" msgstr "Zbliż" msgid "Zoom Out" msgstr "Oddal" msgid "Zoom to Fit" msgstr "Dopasuj" msgid "command-line arguments" msgstr "argumenty wiersza poleceń" msgid "error: unable to execute git" msgstr "" #, python-format msgid "exit code %s" msgstr "kod wyjścia %s" #, python-format msgid "fatal: \"%s\" is not a directory. Please specify a correct --repo ." msgstr "krytyczny: \"%s\" nie jest katalogiem. Podaj poprawne --repo <ścieżka>." #, python-format msgid "git cola version %s" msgstr "wersja git coli %s" msgid "git-cola" msgstr "git-cola" msgid "git-cola diff" msgstr "różnica git-cola" msgid "grep result..." msgstr "wyszukaj w wynikach..." msgid "hotkeys.html" msgstr "hotkeys.html" msgid "unknown" msgstr "nieznany" msgid "vX.Y.Z" msgstr "vX.Y.Z" msgid "x 1" msgstr "" msgid "x 1.5" msgstr "" msgid "x 2" msgstr "" msgid "yyyy-MM-dd" msgstr "yyyy-MM-dd" #, fuzzy #~ msgid "\"%s\" returned exit status %d" #~ msgstr "\"%(command)s\" zwróciło kod wyjścia %(status)d" #~ msgid "\"git commit\" returned exit code %s" #~ msgstr "\"git commit\" zwróciło kod wyjścia %s" #~ msgid "Already up-to-date." #~ msgstr "Nic nowego." #~ msgid "Commit failed: %s" #~ msgstr "Nieudane wdrażanie: %s" #~ msgid "Created commit: %s" #~ msgstr "Utworzono wdrożenie: %s" #~ msgid "Enter Git Repository" #~ msgstr "Podaj repozytorium git" #, fuzzy #~ msgid "Error %s" #~ msgstr "Błędy: %s" #~ msgid "Errors: %s" #~ msgstr "Błędy: %s" #~ msgid "Exit code: %s" #~ msgstr "Kod wyjścia: %s" #~ msgid "Fast Forward Only " #~ msgstr "Tylko przewinięcie do przodu" #~ msgid "GPG-signed" #~ msgstr "Podpisane GPG" #, fuzzy #~ msgid "Local Branches" #~ msgstr "Lokalna gałąź" #~ msgid "" #~ "Output:\n" #~ "%s" #~ msgstr "" #~ "Wynik:\n" #~ "%s" #~ msgid "Output: %s" #~ msgstr "Wynik: %s" #~ msgid "PATCH %(current)d/%(count)d" #~ msgstr "ŁATA %(current)d/%(count)d" #~ msgid "Path to git repository" #~ msgstr "Ścieżka do repozytorium git" #, fuzzy #~ msgid "Remote Branches" #~ msgstr "Zdalna gałąź" #~ msgid "Rename remote?" #~ msgstr "Zmienić nazwę zdalnego repozytorium?" #~ msgid "Select File" #~ msgstr "Wybierz plik" #~ msgid "Select file from \"%s\"" #~ msgstr "Wybierz plik z \"%s\"" #~ msgid "Staging Area" #~ msgstr "Punkt zbiorczy" #~ msgid "Summary:" #~ msgstr "Nazwa:" #~ msgid "" #~ "This PyQt4 does not include QtWebKit.\n" #~ "The keyboard shortcuts feature is unavailable." #~ msgstr "" #~ "Ten PyQt4 nie zawiera QtWebKit.\n" #~ "Skróty klawiszowe są niedostępne." #~ msgid "git clone returned exit code %s" #~ msgstr "klonowanie git zwróciło kod wyjścia %s" #~ msgid "git tag returned exit code %s" #~ msgstr "git tag zwrócił kod wyjścia %s" git-cola-3.6/po/pt_BR.po000066400000000000000000001616631356743264500151010ustar00rootroot00000000000000# Copyright (C) 2007, 2008 Shawn Pearce, et al. # This file is distributed under the same license as the git-cola package. # Vitor Lobo , 2013-2014. msgid "" msgstr "" "Project-Id-Version: git-cola VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-17 01:06-0700\n" "PO-Revision-Date: 2018-06-25 12:37-0300\n" "Last-Translator: Rafael Nascimento \n" "Language-Team: Brazillian \n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.0.8\n" msgid "" "\n" "

\n" " Drag and drop or use the Add button to add\n" " patches to the list\n" "

\n" " " msgstr "" "\n" "

\n" " Arraste e solte ou use o botão Adicionar para adicionar\n" " patches à lista\n" "

\n" " " #, python-format msgid "" "\n" "
\n" " Git Cola has been translated into different languages thanks\n" " to the help of the individuals listed below.\n" "\n" "
\n" "

\n" " Translation is approximate. If you find a mistake,\n" " please let us know by opening an issue on Github:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " We invite you to participate in translation by adding or updating\n" " a translation and opening a pull request.\n" "

\n" "\n" "
\n" "\n" " " msgstr "" "\n" "
\n" " Git Cola foi traduzido em diferentes linguagens graças\n" " à ajuda dos indivíduos listados abaixo.\n" "\n" "
\n" "

\n" " A tradução é aproximada. Se você achar um erro,\n" " por favor nos avise abrindo um issue no Github:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " Nós convidamos você a participar da tradução adicionando\n" " ou atualizando a tradução e abrindo um pull request.\n" "

\n" "\n" "
\n" "\n" " " #, python-format msgid "" "\n" "
\n" " Git Cola version %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " msgstr "" "\n" "
\n" " Git Cola version %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " #, python-format msgid "" "\n" "
\n" " Please use %(bug_link)s to report issues.\n" "
\n" " " msgstr "" "\n" "
\n" " Por favor use %(bug_link)s para reportar problemas.\n" "
\n" " " #, python-format msgid "" "\n" " Format String Variables\n" " -----------------------\n" " %(path)s = relative file path\n" " %(abspath)s = absolute file path\n" " %(dirname)s = relative directory path\n" " %(absdirname)s = absolute directory path\n" " %(filename)s = file basename\n" " %(basename)s = file basename without extension\n" " %(ext)s = file extension\n" msgstr "" "\n" " String para formatação de Variáveis\n" " -----------------------\n" " %(path)s = caminho relativo do arquivo\n" " %(abspath)s = caminho absoluto do arquivo\n" " %(dirname)s = caminho relativo do diretório\n" " %(absdirname)s = caminho absoluto do diretório\n" " %(filename)s = nome base do arquivo\n" " %(basename)s = nome base do arquivo sem extensão\n" " %(ext)s = extensão do arquivo\n" msgid "" "\n" "Commands\n" "--------\n" "pick = use commit\n" "reword = use commit, but edit the commit message\n" "edit = use commit, but stop for amending\n" "squash = use commit, but meld into previous commit\n" "fixup = like \"squash\", but discard this commit's log message\n" "exec = run command (the rest of the line) using shell\n" "\n" "These lines can be re-ordered; they are executed from top to bottom.\n" "\n" "If you disable a line here THAT COMMIT WILL BE LOST.\n" "\n" "However, if you disable everything, the rebase will be aborted.\n" "\n" "Keyboard Shortcuts\n" "------------------\n" "? = show help\n" "j = move down\n" "k = move up\n" "J = shift row down\n" "K = shift row up\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "spacebar = toggle enabled\n" "\n" "ctrl+enter = accept changes and rebase\n" "ctrl+q = cancel and abort the rebase\n" "ctrl+d = launch difftool\n" msgstr "" "\n" "Commands\n" "--------\n" "pick = usar commit\n" "reword = usar commit, mas editar a mensagem do commit\n" "edit = usar commit, mas parar para edita-ló\n" "squash = usar commit, mas fundir com commit anterior\n" "fixup = como \"squash\", mas descarta o log desse commit\n" "exec = executa um comando (no resto da linha) usando shell\n" "\n" "Essas linhas podem ser reordenadas; Elas são executadas de cima para baixo.\n" "\n" "Se você desabilitar uma linha aqui O COMMIT SERÁ PERDIDO.\n" "\n" "Porem, se você desabilitar tudo, o rebase será abortado .\n" "\n" "Atalhos do Teclado\n" "------------------\n" "? = mostrar ajuda\n" "j = mover para baixo\n" "k = mover para cima\n" "J = deslocar fila para baixo\n" "K = deslocar fila para cima\n" "\n" "1, p = escolher\n" "2, r = reescrever \n" "3, e = editar\n" "4, f = corrigir\n" "5, s = squash\n" "spacebar = alternar ativado\n" "\n" "ctrl+enter = aceitar mudanças e usar rebase\n" "ctrl+q = cancelar e abortar o rebase\n" "ctrl+d = lançar ferramenta de comparação\n" msgid "" "\n" "Keyboard Shortcuts\n" "------------------\n" "J, Down = Move Down\n" "K, Up = Move Up\n" "Enter = Edit Selected Files\n" "Spacebar = Open File Using Default Application\n" "Ctrl + L = Focus Text Entry Field\n" "? = Show Help\n" "\n" "The up and down arrows change focus between the text entry field\n" "and the results.\n" msgstr "" "\n" "Keyboard Shortcuts\n" "------------------\n" "J, Down = Mover para Cima\n" "K, Up = Mover para baixo\n" "Enter = Editar arquivos selecionados \n" "Spacebar = Abrir arquivo usando a aplicação padrão\n" "Ctrl + L = Focar campo de entrada de texto\n" "? = Mostrar ajuda\n" "\n" "As setas para cima e para baixo mudam o foco entre a caixa de entrada\n" "e os resultados.\n" msgid " - DAG" msgstr "Visualizar o Histórico" msgid " commits ago" msgstr "commits anteriores" #, python-format msgid "\"%(branch)s\" has been deleted from \"%(remote)s\"." msgstr "\"%(branch)s\" foi removida do \"%(remote)s\"." #, python-format msgid "\"%(command)s\" returned exit status \"%(status)d\"" msgstr "\"%(command)s\" retornou estado de saída \"%(status)d\"" #, python-format msgid "\"%(command)s\" returned exit status %(status)d" msgstr "\"%(command)s\" retornou estado de saída %(status)d" #, fuzzy, python-format msgid "\"%s\" already exists" msgstr "Branch \"%s\" já existe." #, python-format msgid "\"%s\" already exists, cola will create a new directory" msgstr "\"%s\" já existe, o cola já criou um novo diretório" #, python-format msgid "\"%s\" requires a selected file." msgstr "\"%s\" requer um arquivo selecionado" msgid "#" msgstr "#" #, python-format msgid "%(project)s: %(branch)s - Browse" msgstr "%(project)s: %(branch)s - Navegar" #, python-format msgid "%(project)s: %(ref)s - DAG" msgstr "%(project)s: %(ref)s - DAG" #, python-format msgid "%d days ago" msgstr "%d dias atrás" #, python-format msgid "%d hours ago" msgstr "%d horas atrás" #, python-format msgid "%d minutes ago" msgstr "%d minutos atrás" #, python-format msgid "%d patch(es) applied." msgstr "%d patch(es) foram aplicados." #, python-format msgid "%d skipped" msgstr "%d ignorado" #, python-format msgid "" "%s appears to contain merge conflicts.\n" "\n" "You should probably skip this file.\n" "Stage it anyways?" msgstr "" "parece que %s contém conflitos de merge.\n" "\n" "Você provavelmente deveria pular este arquivo.\n" "Selecionar o arquivo de qualquer forma?" #, fuzzy, python-format msgid "%s is not a Git repository." msgstr "Entrar no Repositório Git" #, python-format msgid "%s will be removed from your bookmarks." msgstr "%s será removido dos favoritos." #, python-format msgid "%s will be removed from your recent repositories." msgstr "%s será removido dos seu repositórios recentes." #, python-format msgid "%s: No such file or directory." msgstr "%s: Não existe o arquivo ou diretório" msgid "&Edit" msgstr "&Editar" msgid "&File" msgstr "&Arquivo" msgid "(Amending)" msgstr "(Modificando)" msgid "*** Branch Point ***" msgstr "*** Ponto do Branch ***" msgid "*** Sandbox ***" msgstr "*** Sandbox ***" msgid "100%" msgstr "100%" msgid "200%" msgstr "" msgid "25%" msgstr "" msgid "400%" msgstr "" msgid "50%" msgstr "" msgid "800%" msgstr "" msgid " ..." msgstr " ..." msgid "" "A commit template has not been configured.\n" "Use \"git config\" to define \"commit.template\"\n" "so that it points to a commit template." msgstr "" "Nenhum template de commit foi configurado.\n" "Use \"git config\"para definir \"commit.template\"\n" "para que aponte para um template de commit." #, python-format msgid "A hook must be provided at \"%s\"" msgstr "Um hook precisa ser fornecido em \"%s\"" #, python-format msgid "A stash named \"%s\" already exists" msgstr "Um nome de stash \"%s\" já existe" msgid "Abort" msgstr "Abortar" msgid "Abort Action" msgstr "Abortar Ação" msgid "Abort Merge" msgstr "Abortar Mesclagem" msgid "Abort Merge..." msgstr "Abortar Mesclagem..." msgid "Abort the action?" msgstr "Abortar a ação?" msgid "" "Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" "Recovering uncommitted changes is not possible." msgstr "" "Abortando o merge atual irá causar a perda de *TODOS* as mudanças sem um commit. \n" "Não é possível recuperar mudanças sem commit." msgid "Aborting the current merge?" msgstr "Abordar o merge atual?" msgid "About" msgstr "Sobre" msgid "About git-cola" msgstr "Sobre o git-cola" msgid "Accept" msgstr "Aceitar" msgid "" "Accept changes and rebase\n" "Shortcut: Ctrl+Enter" msgstr "" "Aceitar as mudanças e usar rebase\n" "Atalho: Ctrl+Enter" msgid "Action Name" msgstr "Nome da Ação" msgid "Actions" msgstr "Ações" msgid "Actions..." msgstr "Ações..." msgid "Add" msgstr "Adicionar" msgid "Add Favorite" msgstr "Adicionar Favorito" msgid "Add Remote" msgstr "Adicionar Remoto" msgid "Add Separator" msgstr "Adicionar Separador" msgid "Add Toolbar" msgstr "Adicionar Barra de Ferramentas" msgid "" "Add and remove remote repositories using the \n" "Add(+) and Delete(-) buttons on the left-hand side.\n" "\n" "Remotes can be renamed by selecting one from the list\n" "and pressing \"enter\", or by double-clicking." msgstr "" "Adicionar e remover repositórios remotos usando os \n" "botões Adicionar(+) e Deletar(-) no lado esquerdo.\n" "\n" "Repositórios remotos podem ser renomeados, selecionando uma opção da lista\n" "e pressionando a \"enter\", ou clicando duas vezes." msgid "Add new remote git repository" msgstr "Adicionar novo repositório git" msgid "Add patches (+)" msgstr "Adicionar patches (+)" msgid "Add remote" msgstr "Adicionar remoto" msgid "Add to .gitignore" msgstr "Adicionar ao .gitignore" msgid "Add to Git Annex" msgstr "Adicionar ao Git Annex" msgid "Add to Git LFS" msgstr "Adicionar ao Git LFS" msgid "Additions" msgstr "Adições" msgid "Advanced" msgstr "Avançado" msgid "Age" msgstr "Idade" msgid "All Repositories" msgstr "Todos os Repositórios" #, python-format msgid "" "All submodules will be updated using\n" "\"%s\"" msgstr "" msgid "Allow non-fast-forward updates. Using \"force\" can cause the remote repository to lose commits; use it with care" msgstr "Permitir atualizações non-fast-forward. Usando \"force\" pode fazer com que o repositório perca commits; use com cuidado." msgid "Always create a merge commit when enabled, even when the merge is a fast-forward update" msgstr "Sempre crie um commit de merge quando habilitado, mesmo quando o merge é uma atualização de fast-forward" msgid "Amend" msgstr "Alterar" msgid "Amend Commit" msgstr "Alterar Commit" msgid "Amend Last Commit" msgstr "Alterar o Último Commit" msgid "Amend the published commit?" msgstr "Alterar o commit publicado ?" msgid "Amending" msgstr "Alterando" msgid "" "An action is still running.\n" "Terminating it could result in data loss." msgstr "" "Uma ação ainda está sendo executada.\n" "Finaliza-la pode resultar em perda de dados." msgid "" "An unsigned, lightweight tag will be created instead.\n" "Create an unsigned tag?" msgstr "" "Uma tag leve e não assinada será criada.\n" "Criar uma tag não assinada?" msgid "Appearance" msgstr "Aparência" msgid "Apply" msgstr "Aplicar" msgid "Apply Patches" msgstr "Aplicar Patches" msgid "Apply Patches..." msgstr "Aplicar Patches..." msgid "Apply and drop the selected stash (git stash pop)" msgstr "Aplicar e cancelar o stash selecionado (git stash pop)" msgid "Apply the selected stash" msgstr "Aplicar o stash selecionar" msgid "Arguments" msgstr "Argumentos" msgid "Attach" msgstr "Anexar" msgid "Author" msgstr "Autor" msgid "Authors" msgstr "Autores" msgid "Auto" msgstr "" msgid "Auto-Wrap Lines" msgstr "Auto-Quebra de Linhas" msgid "Basic Regexp" msgstr "Regexp Básico" msgid "Blame Viewer" msgstr "Visualizador de Blame" #, fuzzy msgid "Blame selected paths" msgstr "Renomear caminhos selecionados" msgid "Blame..." msgstr "Blame..." msgid "Bold on dark headers instead of italic" msgstr "Fonte em negrito com o fundo escuro em vez de cabeçalhos em itálico" msgid "Branch" msgstr "Branch" #, python-format msgid "" "Branch \"%(branch)s\" does not exist in \"%(remote)s\".\n" "A new remote branch will be published." msgstr "" "Branch \"%(branch)s\" não existe em \"%(remote)s\".\n" "Um novo branch remoto será publicado." #, python-format msgid "Branch \"%s\" already exists." msgstr "Branch \"%s\" já existe." msgid "Branch Diff Viewer" msgstr "Visualizador de Diff do Branch" msgid "Branch Exists" msgstr "Branch Existe" msgid "Branch Name" msgstr "Nome do Branch" #, python-format msgid "Branch: %s" msgstr "Branch: %s" msgid "Branches" msgstr "Branches" msgid "Branches..." msgstr "Branches..." msgid "Brazilian translation" msgstr "Tradução Brasileira" msgid "Browse" msgstr "Navegar" msgid "Browse Commits..." msgstr "Navegar nos Commits..." msgid "Browse Current Branch..." msgstr "Navegar no Branch Atual..." msgid "Browse Other Branch..." msgstr "Navegar em Outro Branch..." msgid "Browse..." msgstr "Navegar..." msgid "Browser" msgstr "Navegar" #, python-format msgid "Browsing %s" msgstr "Navegando %s" msgid "Bypass Commit Hooks" msgstr "Ignorar Commit Hooks" msgid "Cancel" msgstr "Cancelar" msgid "" "Cancel rebase\n" "Shortcut: Ctrl+Q" msgstr "" "Cancelar rebase\n" "Atalho: Ctrl+Q" msgid "Cannot Amend" msgstr "Não pode alterar" #, python-format msgid "Cannot exec \"%s\": please configure a blame viewer" msgstr "Não é possível executar \"%s\": por favor configure o visualizador de blame" #, python-format msgid "Cannot exec \"%s\": please configure a history browser" msgstr "Não é possível executar \"%s\": por favor configure o navegador de histórico" #, python-format msgid "Cannot exec \"%s\": please configure your editor" msgstr "Não é possível executar \"%s\": por favor configure seu editor" msgid "Changed Upstream" msgstr "Upstream Modificado" msgid "Check Spelling" msgstr "Verificar Ortografia" msgid "Check spelling" msgstr "Verificar ortografia" msgid "Checkout" msgstr "Checkout" msgid "Checkout After Creation" msgstr "Checkout depois da criação" msgid "Checkout Branch" msgstr "Checkout Branch" msgid "Checkout Detached HEAD" msgstr "Checkout HEAD desanexado" msgid "Checkout as new branch" msgstr "Checkout como um novo branch" msgid "Checkout..." msgstr "Checkout..." msgid "Cherry Pick" msgstr "" msgid "Cherry-Pick Commit" msgstr "" msgid "Cherry-Pick..." msgstr "" msgid "Choose Paths" msgstr "Escolha os caminhos" msgid "Choose the \"git grep\" regular expression mode" msgstr "Escolha o modo de expressão regular do \"git grep\"" msgid "Clear Default Repository" msgstr "Limpar Repositório Atual" msgid "Clear commit message" msgstr "Limpar mensagem do commit" msgid "Clear commit message?" msgstr "Limpar mensagem do Commit?" msgid "Clear..." msgstr "Limpar..." msgid "Clone" msgstr "Clonar..." #, fuzzy msgid "Clone Repository" msgstr "Clonar Repositório" msgid "Clone..." msgstr "Clonar..." #, python-format msgid "Cloning repository at %s" msgstr "Clonando repositório em %s" msgid "Close" msgstr "Fechar" msgid "Close..." msgstr "Fechar" msgid "Collapse all" msgstr "Recolher todos" msgid "Command" msgstr "Comando" msgid "Commit" msgstr "Commit" msgid "Commit failed" msgstr "Falha no Commit" msgid "Commit staged changes" msgstr "Commit as mudanças selecionadas" msgid "" "Commit staged changes\n" "Shortcut: Ctrl+Enter" msgstr "" "Commit as mudanças selecionadas\n" "Atalho: Ctrl+Enter" msgid "Commit summary" msgstr "Descreva resumidamente o que modificou..." msgid "Commit the merge if there are no conflicts. Uncheck to leave the merge uncommitted" msgstr "Commit o merge se não houver conflitos. Desmarque para deixar o merge sem commit." msgid "Commit@@verb" msgstr "" msgid "Compare" msgstr "Comparar" msgid "Compare All" msgstr "Comparar Todos" msgid "Configure the remote branch as the the new upstream" msgstr "Configurar o branch remoto como novo upstream" msgid "Configure toolbar" msgstr "Configurar Barra de Ferramentas" msgid "Console" msgstr "" msgid "Continue" msgstr "Continuar" msgid "Copy" msgstr "Copiar" msgid "Copy Basename to Clipboard" msgstr "Copiar Nome Base para o clipboard" msgid "Copy Leading Path to Clipboard" msgstr "Copiar o Caminho Principal para o Clipboard" msgid "Copy Path to Clipboard" msgstr "Copiar o Caminho para o Clipboard" msgid "Copy Relative Path to Clipboard" msgstr "Copiar Caminho Relativo para o Clipboard" msgid "Copy SHA-1" msgstr "Copiar SHA-1" msgid "Copy..." msgstr "Copiar..." #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "Não foi possível analisar o URL do Git \"%s\"" msgid "Create Branch" msgstr "Criar Branch" msgid "Create Patch" msgstr "Criar Patch" msgid "Create Remote Branch" msgstr "Criar Branch Remoto" msgid "Create Signed Commit" msgstr "Criar Commit Assinado" msgid "Create Tag" msgstr "Criar Tag" msgid "Create Tag..." msgstr "Criar Tag..." msgid "Create Unsigned Tag" msgstr "Criar Tag Não Assinada." msgid "Create a merge commit even when the merge resolves as a fast-forward" msgstr "Criar um commit de merge mesmo se o merge resultar em fast-foward" msgid "Create a new remote branch?" msgstr "Criar um novo branch remoto?" msgid "Create..." msgstr "Criar..." #, python-format msgid "Created a new tag named \"%s\"" msgstr "Criar uma nova tag chamada \"%s\"" msgid "Current Repository" msgstr "Repositório Atual" msgid "Custom Copy Actions" msgstr "Ações customizadas de copiar" msgid "Customize..." msgstr "Customizar..." msgid "Cut" msgstr "Cortar" msgid "Czech translation" msgstr "" msgid "DAG..." msgstr "Visualizar o histórico..." msgid "Dark Theme" msgstr "" msgid "Date, Time" msgstr "Data, Tempo" msgid "Default" msgstr "Padrão" msgid "Delete" msgstr "Deletar" #, python-format msgid "Delete %d file(s)?" msgstr "Excluir %d arquiv(o)s?" msgid "Delete Bookmark" msgstr "Remover Favorito" msgid "Delete Bookmark?" msgstr "Remover Favorito?" msgid "Delete Branch" msgstr "Deletar Branch" msgid "Delete Files" msgstr "Excluir Arquivos" msgid "Delete Files..." msgstr "Excluir Arquiv(o)s..." msgid "Delete Files?" msgstr "Excluir Arquivos?" msgid "Delete Remote" msgstr "Deletar Remoto ?" msgid "Delete Remote Branch" msgstr "Remover Branch Remoto" msgid "Delete Remote Branch..." msgstr "Remover Branch Remoto..." msgid "Delete remote" msgstr "Deletar Repositórios Remotos" #, python-format msgid "Delete remote \"%s\"" msgstr "Remover remoto \"%s\"" msgid "Delete remote?" msgstr "Remover remoto?" msgid "Delete selected branch?" msgstr "Remover branch selecionada?" msgid "Delete toolbar" msgstr "Remover barra de ferramentas" msgid "Delete..." msgstr "Deletar..." #, python-format msgid "Deleting \"%s\" failed" msgstr "A deleção de \"%s\" falhou" msgid "Deletions" msgstr "Deleções" msgid "Detach" msgstr "Desanexar" msgid "Detect Conflict Markers" msgstr "Detectar Marcadores de Conflitos" msgid "Detect conflict markers in unmerged files" msgstr "Detectar marcadores de conflitos em arquivos que não entraram no merge" msgid "Developer" msgstr "Desenvolvedor" msgid "Diff" msgstr "Compare" msgid "Diff Against Predecessor..." msgstr "Comparar com o antecessor" msgid "Diff Options" msgstr "Opções de Comparação" msgid "Diff Tool" msgstr "Ferramenta de Comparação" msgid "Diff selected -> this" msgstr "Comparar selecionado -> esse" msgid "Diff this -> selected" msgstr "Comparar esse -> selecionado" msgid "Diffstat" msgstr "Compare Modificações (Antes/Depois)" #, fuzzy msgid "Difftool" msgstr "Ferramenta de Comparação" msgid "Directory Exists" msgstr "Diretório Existe" msgid "Display Untracked Files" msgstr "Exibir Arquivos não Controlados" msgid "Documentation" msgstr "Documentação" msgid "Drop" msgstr "Cancelar" msgid "Drop Stash" msgstr "Cancelar o Stash" msgid "Drop Stash?" msgstr "Cancelar o Stash?" #, python-format msgid "Drop the \"%s\" stash?" msgstr "Cancelar o \"%s\" stash?" msgid "Drop the selected stash" msgstr "Cancelar o stash selecionado" #, fuzzy msgid "Edit" msgstr "&Editar" msgid "Edit Rebase" msgstr "Editar Rebase" msgid "Edit Remotes" msgstr "Editar Repositórios Remotos" msgid "Edit Remotes..." msgstr "Editar Repositórios Remotos..." msgid "Edit remotes by selecting them from the list" msgstr "Editar os remotos os selecionando na lista" msgid "Edit selected paths" msgstr "Editar caminhos selecionados" msgid "Edit..." msgstr "Editar..." msgid "Editor" msgstr "" msgid "Email Address" msgstr "Endereço de Email" msgid "Email contributor" msgstr "Email do Contribuidor" msgid "Enabled" msgstr "Habilitado" msgid "Enter New Branch Name" msgstr "Digite o nome do novo Branch" msgid "Enter a name for the new bare repo" msgstr "Digite o nome para o novo repo vazio" msgid "Enter a name for the stash" msgstr "Digite o nome para o stash" msgid "Error" msgstr "Erro" msgid "Error Cloning" msgstr "Erro ao Clonar" msgid "Error Creating Branch" msgstr "Erro ao Criar Branch" msgid "Error Creating Repository" msgstr "Erro ao Criar Repositório" msgid "Error Deleting Remote Branch" msgstr "Erro Removendo Branch Remoto" msgid "Error Editing File" msgstr "Erro Editando Arquivo" msgid "Error Launching Blame Viewer" msgstr "Erro Lançando o Visualizador de Blame" msgid "Error Launching History Browser" msgstr "Erro Lançando o Visualizador de Histórico" #, python-format msgid "Error creating remote \"%s\"" msgstr "Erro criando o remoto \"%s\"" msgid "Error creating stash" msgstr "Erro ao criar o stash" #, python-format msgid "Error deleting remote \"%s\"" msgstr "Erro removendo o remoto \"%s\"" #, python-format msgid "Error renaming \"%(name)s\" to \"%(new_name)s\"" msgstr "Erro renomeando \"%(name)s\" para \"%(new_name)s\"" msgid "Error running prepare-commitmsg hook" msgstr "Erro executando prepare-commitmsg hook" #, fuzzy, python-format msgid "Error updating submodule %s" msgstr "Erro criando o remoto \"%s\"" #, fuzzy msgid "Error updating submodules" msgstr "Erro Editando Arquivo" msgid "Error: Cannot find commit template" msgstr "Erro: Não foi possível encontrar o template do commit" msgid "Error: Stash exists" msgstr "Erro: Stash já existe" msgid "Error: Unconfigured commit template" msgstr "Erro: Template do Commit não foi configurado" #, python-format msgid "Error: could not clone \"%s\"" msgstr "Erro: não é possível clonar \"%s\"" #, python-format msgid "Error: could not create tag \"%s\"" msgstr "Erro: não foi possível criar tag \"%s\"" #, python-format msgid "Executing action %s" msgstr "Executando ação \"%s\"" msgid "Expand all" msgstr "Expandir tudo" msgid "Export Patches" msgstr "Exportar Patches" msgid "Export Patches..." msgstr "Exportar Patches..." msgid "Expression..." msgstr "Expressão" msgid "Extended Regexp" msgstr "Regexp Extendido" msgid "Extended description..." msgstr "Descreva em detalhes o que modificou..." msgid "Fast Forward Only" msgstr "Somente Fast Forward" msgid "Fast-forward only" msgstr "Somente Fast Forward" msgid "Favorite repositories" msgstr "Repositórios Favoritos" msgid "Favorites" msgstr "Favoritos" msgid "Fetch" msgstr "Fetch" msgid "Fetch Tracking Branch" msgstr "" msgid "Fetch..." msgstr "" msgid "File Browser..." msgstr "Navegador de Arquivos..." msgid "File Differences" msgstr "Diferença de Arquivos" msgid "File Saved" msgstr "Arquivo Salvo" #, python-format msgid "File saved to \"%s\"" msgstr "Arquivo salvo em \"%s\"" #, fuzzy msgid "File system change monitoring: disabled because \"cola.inotify\" is false.\n" msgstr "inotify está desativado por causa \"cola.inotift\" is false\n" msgid "File system change monitoring: disabled because libc does not support the inotify system calls.\n" msgstr "Monitoramento de alterações do sistema de arquivos: desabilitado porque libc não suporta chamadas do sistema inotify.\n" msgid "File system change monitoring: disabled because pywin32 is not installed.\n" msgstr "Monitoramento de alterações do sistema de arquivos: desabilitado porque pywin32 não foi instalado.\n" msgid "" "File system change monitoring: disabled because the limit on the total number of inotify watches was reached. You may be able to increase the limit on the number of watches by running:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" msgstr "" "Monitoramento de alterações do sistema de arquivos: desabilitado porque o numero total de observadores inotify chegou ao limite. Você pode mudar o limite da quantidade de observadores executando:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" msgid "File system change monitoring: enabled.\n" msgstr "Monitoramento de alterações do sistema de arquivos: habilitado.\n" msgid "Filename" msgstr "Nome do Arquivo" msgid "Files" msgstr "Arquivos" msgid "Filter branches..." msgstr "Filtrar branches..." msgid "Filter paths..." msgstr "Filtrar caminhos..." msgid "Find Files" msgstr "Procurar Arquivos" msgid "Fixed String" msgstr "String Fixa" msgid "Fixed-Width Font" msgstr "Fonte de Largura Fixa" msgid "Fixup" msgstr "" msgid "Fixup Previous Commit" msgstr "Fixup Commit Anterior" msgid "Flat dark blue" msgstr "" msgid "Flat dark green" msgstr "" msgid "Flat dark grey" msgstr "" msgid "Flat dark red" msgstr "" msgid "Flat light blue" msgstr "" msgid "Flat light green" msgstr "" msgid "Flat light grey" msgstr "" msgid "Flat light red" msgstr "" msgid "Font Size" msgstr "Tamanho de Fonte" msgid "Force" msgstr "Forçar" msgid "Force Fetch" msgstr "Forçar Fetch" msgid "Force Fetch?" msgstr "Forçar Fetch?" msgid "Force Push" msgstr "Forçar Push" msgid "Force Push?" msgstr "Forçar Push?" #, python-format msgid "Force fetching from %s?" msgstr "Forçar fetch de %s?" #, python-format msgid "Force push to %s?" msgstr "Forçar push para %s?" msgid "Format String" msgstr "Formatar String" msgid "French translation" msgstr "" msgid "GPG-sign the merge commit" msgstr "Assinar com GPG o Commit de Merge" msgid "GUI theme" msgstr "" #, python-format msgid "Gathering info for \"%s\"..." msgstr "Reunindo Informação de \"%s\"..." msgid "German translation" msgstr "" msgid "Get Commit Message Template" msgstr "Obter Template da Mensagem do Commit" msgid "Go Down" msgstr "Descer" msgid "Go Up" msgstr "Subir" msgid "Grab File..." msgstr "Arquivo Grab" msgid "Graph" msgstr "Gráfico" msgid "Grep" msgstr "" msgid "Have you rebased/pulled lately?" msgstr "Você tem usado rebase/pull recentemente?" msgid "Help" msgstr "Ajuda" msgid "Help - Custom Copy Actions" msgstr "Ajuda - Ações de Copia Customizadas" msgid "Help - Find Files" msgstr "Ajuda - Procurar Arquivos" msgid "Help - git-xbase" msgstr "Ajuda - git-xbase" msgid "Hide Details.." msgstr "Esconder Detalhes..." msgid "High DPI" msgstr "" msgid "History Browser" msgstr "Navegador de Histórico" msgid "Hungarian translation" msgstr "" msgid "Icon theme" msgstr "" msgid "Ignore all whitespace" msgstr "Ignorar todos espaços em branco." msgid "Ignore changes in amount of whitespace" msgstr "Ignorar alterações na quantidade de espaço em branco" msgid "Ignore changes in whitespace at EOL" msgstr "Ignorar alterações no espaço em branco no EOL (Fim da Linha)" msgid "Ignore custom pattern" msgstr "Ignorar padrão customizado" msgid "Ignore exact filename" msgstr "Ignorar nome exato do arquivo" msgid "Ignore filename or pattern" msgstr "Ignorar nome do arquivo ou padrão" msgid "Include tags " msgstr "Incluir tags" msgid "Indent Status paths" msgstr "" msgid "Indonesian translation" msgstr "" msgid "Initialize Git Annex" msgstr "Inicializar Git Annex" msgid "Initialize Git LFS" msgstr "Inicializar Git LFS" msgid "Inititalize submodules" msgstr "Inicializar submódulos" msgid "Insert spaces instead of tabs" msgstr "Inserir espaços em vez de tabs" msgid "Interactive Rebase" msgstr "Rebase Interativo" msgid "Invalid Revision" msgstr "Revisão Inválida" msgid "Keep *.orig Merge Backups" msgstr "Manter *.orig na Mesclagem de Backups" msgid "Keep Index" msgstr "Manter Índice" msgid "Keyboard Shortcuts" msgstr "Teclas de Atalho" msgid "Launch Diff Tool" msgstr "Iniciar a Ferramenta de Comparação" msgid "Launch Directory Diff Tool" msgstr "Iniciar a Ferramenta de Comparação na Pasta" msgid "Launch Editor" msgstr "Iniciar Editor" msgid "Launch Terminal" msgstr "Iniciar Terminal" msgid "" "Launch external diff tool\n" "Shortcut: Ctrl+D" msgstr "" "Atalho para lançar a ferramenta de comparação externa:\n" "Ctrl+D" msgid "Launch git-cola" msgstr "Iniciar git-cola" msgid "Launch git-difftool against previous versions" msgstr "Iniciar git-difftool contra as versões anteriores" msgid "Launch git-difftool on the current path" msgstr "Iniciar git-difftool no caminho atual" msgid "Light Theme" msgstr "" msgid "Load Commit Message" msgstr "Carregar a Mensagem do Commit" msgid "Load Commit Message..." msgstr "Carregar a Mensagem do Commit..." msgid "Load Previous Commit Message" msgstr "Carregar Mensagem Anterior do Commit..." msgid "Loading..." msgstr "Carregando..." msgid "Local" msgstr "" msgid "Local Branch" msgstr "Branch Local" msgid "Local branch" msgstr "Branch local" msgid "Lock Layout" msgstr "Trancar Layout" msgid "Log" msgstr "" msgid "Maintainer (since 2007) and developer" msgstr "Mantenedor (desde 2007) e desenvolvedor" msgid "Merge" msgstr "Merge" #, python-format msgid "Merge \"%(revision)s\" into \"%(branch)s\"" msgstr "Merge \"%(revision)s\" em \"%(branch)s\"" msgid "Merge Tool" msgstr "Ferramenta de Merge" msgid "Merge Verbosity" msgstr "Verbosidade do Merge" msgid "Merge failed. Conflict resolution is required." msgstr "Falha no Merge. Necessário resolução de Conflitos." #, python-format msgid "Merge into \"%s\"" msgstr "Merge em \"%s\"" #, fuzzy msgid "Merge into current branch" msgstr "Procurar Branch Atual..." msgid "Merge..." msgstr "Merge..." msgid "Merging" msgstr "" msgid "Message" msgstr "Mensagem" msgid "Missing Commit Message" msgstr "Mensagem do Commit em Falta" msgid "Missing Data" msgstr "Data em Falta" msgid "Missing Name" msgstr "Nome em falta" msgid "Missing Revision" msgstr "Falta a Revisão" msgid "Missing Tag Message" msgstr "Falta a mensagem da tag" msgid "Modified" msgstr "Modificado" msgid "More..." msgstr "Mais..." msgid "Move Down" msgstr "Mover para Baixo" msgid "Move Up" msgstr "Mover para cima" msgid "Move files to trash" msgstr "Mover arquivos para lixeira" msgid "Name" msgstr "Nome" msgid "Name for the new remote" msgstr "Nome do novo remoto" #, fuzzy msgid "New Bare Repository..." msgstr "Novo Repositório" msgid "New Repository..." msgstr "Novo Repositório" msgid "New..." msgstr "Novo" msgid "Next File" msgstr "Próximo Arquivo" msgid "No" msgstr "Não" msgid "No Revision Specified" msgstr "Nenhuma revisão foi especificada" msgid "" "No changes to commit.\n" "\n" "You must stage at least 1 file before you can commit." msgstr "" "Commit não possui mudanças.\n" "\n" "Você precisa selecionar pelo menos 1 arquivo antes de realizar um Commit." msgid "No commits exist in this branch." msgstr "Não existe confirmações no branch" msgid "No fast forward" msgstr "Sem Fast Forward" msgid "No fast-forward" msgstr "Sem Fast Forward" msgid "No repository selected." msgstr "Nenhum repositório selecionado" msgid "Non-fast-forward fetch overwrites local history!" msgstr "Fetch sem Fast Forward reescreve o histórico local !" msgid "" "Non-fast-forward push overwrites published history!\n" "(Did you pull first?)" msgstr "" "Push sem Fast-Forward reescreve o histórico publicado !\n" "(Você deu pull primeiro ?)" msgid "Nothing to commit" msgstr "Nada para comitar" msgid "Nothing to do" msgstr "Nada a fazer" msgid "Number of Diff Context Lines" msgstr "Número de Comparações no Contexto de Linhas" msgid "Open" msgstr "Abrir" msgid "Open Git Repository..." msgstr "Abrir o Repositório Git" #, fuzzy msgid "Open Parent" msgstr "Aberto Recentemente" msgid "Open Parent Directory" msgstr "Abrir Pasta Pai" msgid "Open Recent" msgstr "Aberto Recentemente" msgid "Open Using Default Application" msgstr "Abrir usando aplicação padrão" msgid "Open in New Window" msgstr "Abrir em uma Nova Janela" msgid "Open in New Window..." msgstr "Abrir em uma Nova Janela" msgid "Open..." msgstr "Abrir" #, fuzzy msgid "Other branches" msgstr "Redefinir..." msgid "Overwrite" msgstr "Sobrescrever" #, python-format msgid "Overwrite \"%s\"?" msgstr "Sobrescrever \"%s\"?" msgid "Overwrite File?" msgstr "Sobrescrever Arquivo?" msgid "" "Parse arguments using a shell.\n" "Queries with spaces will require \"double quotes\"." msgstr "" "Analisar argumento usando um shell.\n" "Consultas com espaços precisam de \"aspas duplas\"." msgid "Partially Staged" msgstr "Stage Parcial" msgid "Paste" msgstr "Colar" msgid "Patch(es) Applied" msgstr "Patch(s) Aplicados" msgid "Path" msgstr "Caminho" msgid "Path or URL to clone (Env. $VARS okay)" msgstr "Caminho ou URL para clonar (Env. $VARS okay)" msgid "Pick" msgstr "Usar Commit" msgid "Pixel XOR" msgstr "" msgid "Please provide both a branch name and revision expression." msgstr "Por favor, forneça um nome ao branch e expressão revisão" msgid "Please select a file" msgstr "Por favor selecione um arquivo" msgid "Please specify a name for the new tag." msgstr "Por favor especifique um nome para a nova tag." msgid "Please specify a revision to tag." msgstr "Por favor especifique a revisão da tag." msgid "" "Please supply a commit message.\n" "\n" "A good commit message has the following format:\n" "\n" "- First line: Describe in one sentence what you did.\n" "- Second line: Blank\n" "- Remaining lines: Describe why this change is good.\n" msgstr "" "Por favor forneça uma mensagem de commit.\n" "\n" "Uma boa mensagem de commit contem o seguinte formato:\n" "\n" "- Primeira Linha: Descreva em uma sentença o que você fez.\n" "- Segunda linha: Branco\n" "- Linhas Remanescentes: Descreva porque esta mudança é boa.\n" msgid "Point the current branch head to a new commit?" msgstr "Apontar o HEAD do branch atual para um novo commit?" msgid "Polish translation" msgstr "" msgid "Pop" msgstr "" msgid "Preferences" msgstr "Preferências" msgid "Prefix" msgstr "Prefixo" msgid "Prepare Commit Message" msgstr "Preparar Mensagem do Commit" msgid "Prevent \"Stage\" from staging all files when nothing is selected" msgstr "Previnir \"Stage\" de selecionar todos arquivos quando nada é selecionado" msgid "Previous File" msgstr "Arquivo Anterior" msgid "Prompt on creation" msgstr "Perguntar ao Criar" msgid "Prompt when pushing creates new remote branches" msgstr "Perguntar quando push criar novo branch" msgid "Prune " msgstr "" #, fuzzy msgid "Pull" msgstr "Puxar..." msgid "Pull..." msgstr "Pull..." msgid "Push" msgstr "Push" msgid "Push..." msgstr "Push..." msgid "Quit" msgstr "Sair" msgid "Rebase" msgstr "" #, python-format msgid "Rebase onto %s" msgstr "Rebase em %s" msgid "Rebase stopped" msgstr "Rebase parou" msgid "Rebase the current branch instead of merging" msgstr "Rebase o branch atual em vez de merge" msgid "Rebasing" msgstr "" msgid "Recent" msgstr "Recente" msgid "Recent repositories" msgstr "Repositórios Recentes" msgid "Recent repository count" msgstr "Contagem de Repositórios Recentes" msgid "Recently Modified Files" msgstr "Arquivos Modificados Recentemente" msgid "Recently Modified Files..." msgstr "Arquivos Modificados Recentemente" msgid "Recovering a dropped stash is not possible." msgstr "Recuperação de uma stash derrubada não é possível" msgid "Recovering lost commits may not be easy." msgstr "Recuperar commits perdidos pode não ser fácil." msgid "Redo" msgstr "Refazer" msgid "Reduce commit history to minimum" msgstr "Reduzir histórico de commits para o minimo" msgid "Refresh" msgstr "Recarregar" msgid "Refuse to merge unless the current HEAD is already up-to-date or the merge can be resolved as a fast-forward" msgstr "Recusar merge a menos que o HEAD atual já esteja atualizado ou o merge pode ser resolvido como fast-forward" msgid "Remote" msgstr "Remoto" msgid "Remote Branch" msgstr "Branch Remoto" msgid "Remote Branch Deleted" msgstr "Branch Remoto Removido" msgid "Remote git repositories - double-click to rename" msgstr "Repositórios Remotos - duplo click para renomear" msgid "Remove" msgstr "Remover" #, python-format msgid "Remove %s from the recent list?" msgstr "Remover %s da lista de recentes ?" msgid "Remove Element" msgstr "Remover Elemento" msgid "Remove remote-tracking branches that no longer exist on the remote" msgstr "Remover rastreamento remoto de branchs que não existem mais no remoto " msgid "Remove selected (Delete)" msgstr "Remover selecionado" msgid "Rename" msgstr "Renomear" #, python-format msgid "Rename \"%s\"" msgstr "Renomear \"%s\"" msgid "Rename Branch" msgstr "Renomear Branch" #, fuzzy msgid "Rename Branch..." msgstr "Branch Remoto" msgid "Rename Existing Branch" msgstr "Renomear Branch Existente" msgid "Rename Remote" msgstr "Renomear Remoto" msgid "Rename Repository" msgstr "Renomear Repositório" msgid "Rename branch" msgstr "Renomear branch" #, python-format msgid "Rename remote \"%(current)s\" to \"%(new)s\"?" msgstr "Renomear remoto de \"%(current)s\" para \"%(new)s\"?" msgid "Rename selected paths" msgstr "Renomear caminhos selecionados" #, python-format msgid "Repository: %s" msgstr "Repositório: %s" msgid "Reset" msgstr "Resetar" #, python-format msgid "Reset \"%(branch)s\" to \"%(revision)s\"?" msgstr "Resetar \"%(branch)s\" to \"%(revision)s\"?" msgid "Reset Branch" msgstr "Resetar Branch" msgid "Reset Branch Head" msgstr "Resetar Head do Branch" msgid "Reset Branch?" msgstr "Resetar Branch?" msgid "Reset Hard" msgstr "Resetar Hard" msgid "Reset Merge" msgstr "Resetar Merge" msgid "Reset Soft" msgstr "Resetar Soft" msgid "Reset Worktree" msgstr "Resetar Worktree" msgid "Reset hard?" msgstr "Resetar hard?" msgid "Reset merge?" msgstr "Resetar merge?" msgid "Reset soft?" msgstr "Resetar soft?" msgid "Reset worktree?" msgstr "Resetar Worktree?" #, python-format msgid "Resetting \"%(branch)s\" to \"%(revision)s\" will lose commits." msgstr "Resetar \"%(branch)s\" para \"%(revision)s\" irá perder commits." msgid "Restart the application after changing appearance settings." msgstr "A alteração de aparência necessita reiniciar a aplicação." msgid "Revert" msgstr "Reverter" msgid "Revert Diff Hunk" msgstr "Reverter pedaço do Diff" msgid "Revert Diff Hunk..." msgstr "Reverter pedaço do Diff..." msgid "Revert Diff Hunk?" msgstr "Reverter pedaço do Diff ?" msgid "Revert Selected Lines" msgstr "Reverter Linhas Selecionadas" msgid "Revert Selected Lines..." msgstr "Reverter Linhas Selecionadas..." msgid "Revert Selected Lines?" msgstr "Reverter Linhas Selecionadas?" msgid "Revert Uncommitted Changes" msgstr "Reverter Mudanças sem Commit" msgid "Revert Uncommitted Changes?" msgstr "Reverter Mudanças sem Commit?" #, fuzzy msgid "Revert Uncommitted Edits..." msgstr "Reverter edições Uncommitted" msgid "Revert Unstaged Changes" msgstr "Reverter Mudanças sem Stage" msgid "Revert Unstaged Changes?" msgstr "Reverter Mudanças sem Stage?" msgid "Revert Unstaged Edits..." msgstr "Reverter Edições Unstaged" msgid "Revert the uncommitted changes?" msgstr "Reverter as mudanças sem Commit?" msgid "Revert the unstaged changes?" msgstr "Reverter as mudanças sem stage?" msgid "Revert uncommitted changes to selected paths" msgstr "Reverter as mudanças sem Commit nos caminhos selecionados" msgid "Revert unstaged changes to selected paths" msgstr "Reverter as mudanças sem Stage nos caminhos selecionados" msgid "Review" msgstr "Revisar" msgid "Review..." msgstr "Revisar..." msgid "Revision" msgstr "Revisão" msgid "Revision Expression:" msgstr "Revisar Expressões" msgid "Revision to Merge" msgstr "Revisão para Merge" msgid "Reword" msgstr "Reescrever" msgid "Rewrite Published Commit?" msgstr "Reescrever Commit Publicado?" msgid "Run" msgstr "Executar" #, python-format msgid "Run \"%s\"?" msgstr "Executar \"%s\"?" #, python-format msgid "Run %s?" msgstr "Executar %s?" #, python-format msgid "Run the \"%s\" command?" msgstr "Executar o comando \"%s\"?" #, python-format msgid "Running command: %s" msgstr "Executando o comando: %s" msgid "Russian translation" msgstr "" msgid "SHA-1" msgstr "SHA-1" msgid "Safe Mode" msgstr "Modo Seguro" msgid "Save" msgstr "Salvar" msgid "Save Archive" msgstr "Salvar Arquivo" msgid "Save As Tarball/Zip..." msgstr "Salvar Como Tarball/Zip..." msgid "Save GUI Settings" msgstr "Salvar Configuração da GUI" msgid "Save Stash" msgstr "Salvar o Stash" msgid "Save modified state to new stash" msgstr "Salvar o estágio modificado do novo stash" #, python-format msgid "Saved \"%(filename)s\" from \"%(ref)s\" to \"%(destination)s\"" msgstr "\"%(filename)s\" salvo de \"%(ref)s\" para \"%(destination)s\"" msgid "Search" msgstr "Pesquisar" msgid "Search Authors" msgstr "Pesquisar por Autores" msgid "Search Commit Messages" msgstr "Pesquisar por Mensagens de Commit" msgid "Search Committers" msgstr "Pesquisar por responsáveis do Commit" msgid "Search Date Range" msgstr "Pesquisar por Intervalo de Data" msgid "Search Diffs" msgstr "Pesquisar por Diffs" msgid "Search by Expression" msgstr "Pesquisar pela Expressão" msgid "Search by Path" msgstr "Pesquisar pelo Caminho" msgid "Search for a fixed string" msgstr "Pesquisar por uma String Fixa" msgid "Search using a POSIX basic regular expression" msgstr "Procurar usando expressão regular básica POSIX" msgid "Search using a POSIX extended regular expression" msgstr "Procurar usando expressão regular extendida POSIX" msgid "Search..." msgstr "Pesquisar..." msgid "Select" msgstr "Selecionar" msgid "Select All" msgstr "Selecionar Tudo" msgid "Select Branch to Review" msgstr "Selecionar Branch para Revisar" msgid "Select Child" msgstr "Selecionar Filho" msgid "Select Commit" msgstr "Selecionar Commit" #, fuzzy msgid "Select Directory..." msgstr "Selecionar Repositório" msgid "Select New Upstream" msgstr "Selecionar Novo Upstream" msgid "Select Newest Child" msgstr "Selecionar Filho mais novo" msgid "Select Oldest Parent" msgstr "Selecionar Pai mais velho" msgid "Select Parent" msgstr "Selecionar Pai" msgid "Select Previous Version" msgstr "Selecionar Versão Anterior" msgid "Select Repository..." msgstr "Selecionar Repositório" msgid "Select a parent directory for the new clone" msgstr "Selecionar um diretório pai para o novo clone" msgid "Select manually..." msgstr "Selecione manualmente" msgid "Select output dir" msgstr "Selecionar pasta de saída" msgid "Select output directory" msgstr "Selecionar pasta de saída" #, fuzzy msgid "Select patch file(s)..." msgstr "Excluir %d arquiv(o)s?" #, fuzzy msgid "Select repository" msgstr "Selecionar Repositório" msgid "Set Default Repository" msgstr "Definir Repositório Padrão" msgid "Set Upstream Branch" msgstr "Definir Branch Upstream" msgid "" "Set the sort order for branches and tags.\n" "Toggle between date-based and version-name-based sorting." msgstr "" msgid "Set upstream" msgstr "Definir Upstream" msgid "Settings" msgstr "Configurações" msgid "Shell arguments" msgstr "Argumentos do Shell" msgid "Shift Down" msgstr "Shift Para Baixo" msgid "Shift Up" msgstr "Shift Para Cima" msgid "Shortcuts" msgstr "Atalhos" msgid "Show Details..." msgstr "Mostrar Detalhes..." msgid "Show Diffstat After Merge" msgstr "Mostrar o Status de Comparação após Mesclagem" msgid "Show Full Paths in the Window Title" msgstr "Mostrar Caminhos Completos no Titulo da Janela" #, fuzzy msgid "Show Help" msgstr "Ajuda" #, fuzzy msgid "Show History" msgstr "Ver Histórico..." msgid "Show file counts in Status titles" msgstr "" msgid "" "Show help\n" "Shortcut: ?" msgstr "" "Mostrar Ajuda\n" "Atalho: ?" msgid "Show icon? (if available)" msgstr "Mostrar Ícone? (Se disponível)" msgid "Show line numbers" msgstr "Mostrar numero das linhas" msgid "Show whole surrounding functions of changes" msgstr "Mostrar função pai inteira" msgid "Showing changes since" msgstr "Mostrar mudanças desde" msgid "Side by side" msgstr "Lado a Lado" msgid "Sign Off" msgstr "Não Assinar" msgid "Sign Tag" msgstr "Assinar a Tag" msgid "Sign off on this commit" msgstr "Cancelar Assinatura desse Commit" msgid "Simplified Chinese translation" msgstr "" msgid "Skip" msgstr "Pular" msgid "Skip Current Patch" msgstr "Pular Path Atual" msgid "Sort bookmarks alphabetically" msgstr "Ordenar favoritos alfabeticamente" msgid "Spanish translation" msgstr "" msgid "Specifies the SHA-1 to tag" msgstr "Especificar o SHA-1 para a Tag" msgid "Specifies the tag message" msgstr "Especifique a mensagem da tag" msgid "Specifies the tag name" msgstr "Especifique o nome da tag" msgid "Spelling Suggestions" msgstr "Sugestões de Ortografia" msgid "Squash" msgstr "" msgid "Squash the merged commits into a single commit" msgstr "Unir os commits mesclados em um commit único" msgid "Stage" msgstr "" msgid "Stage / Unstage" msgstr "Estágio / Sem estágio " msgid "Stage All Untracked" msgstr "Stage todos Untracked" msgid "Stage Changed Files To Commit" msgstr "Stage Arquivos Modificados para o Commit" msgid "Stage Diff Hunk" msgstr "Reverter pedaço do Diff" msgid "Stage Modified" msgstr "Stage Modificado" msgid "Stage Selected" msgstr "Stage Selecionado" msgid "Stage Selected Lines" msgstr "Stage Linhas Selecionadas" msgid "Stage Unmerged" msgstr "" msgid "Stage Untracked" msgstr "" msgid "Stage and Commit" msgstr "Stage e Commit" msgid "Stage and commit?" msgstr "Stage e Commit?" msgid "Stage conflicts" msgstr "Conflitos no Stage" #, fuzzy msgid "Stage conflicts?" msgstr "Stage Modificado" msgid "Stage/unstage selected paths for commit" msgstr "Stage/unstage os caminhos selecionados para o Commit" msgid "Staged" msgstr "" #, python-format msgid "Staging: %s" msgstr "" msgid "Start Interactive Rebase..." msgstr "Iniciar Rebase Interativo..." msgid "Starting Revision" msgstr "Iniciar Revisão" msgid "Stash" msgstr "" msgid "Stash Index" msgstr "Stash Índice" msgid "Stash staged changes only" msgstr "Stage somente mudanças selecionadas" msgid "Stash unstaged changes only, keeping staged changes" msgstr "Stash somente em mudanças não selecionadas, mantendo mudanças selecionadas" msgid "Stash..." msgstr "" msgid "Status" msgstr "" msgid "Stop tracking paths" msgstr "Parar rastreamento de caminhos" msgid "Submodules" msgstr "Submódulos" msgid "Summarize Merge Commits" msgstr "Resumir os Commits de Merge" msgid "Summary" msgstr "Sumário" msgid "Tab Width" msgstr "Largura da Aba" msgid "Tag" msgstr "" msgid "Tag Created" msgstr "Tag Criada" msgid "Tag message..." msgstr "Mensagem da Tag..." msgid "Tag-signing was requested but the tag message is empty." msgstr "A assinatura de tags foi solicitada, mas a mensagem da tag está vazia." msgid "Tags" msgstr "" msgid "Text Width" msgstr "Largura do Texto" msgid "The branch will be no longer available." msgstr "O branch não ficará mais disponível" #, python-format msgid "The branch will be reset using \"git reset --hard %s\"" msgstr "O branch será resetado usando \"git reset --hard %s\"" #, python-format msgid "The branch will be reset using \"git reset --merge %s\"" msgstr "O branch será resetado usando \"git reset --merge %s\"" #, python-format msgid "The branch will be reset using \"git reset --mixed %s\"" msgstr "O branch será resetado usando \"git reset --mixed %s\"" #, python-format msgid "The branch will be reset using \"git reset --soft %s\"" msgstr "O branch será resetado usando \"git reset --soft %s\"" #, fuzzy msgid "The commit message will be cleared." msgstr "Os arquivos a seguir serão apagados:" #, python-format msgid "The file \"%s\" exists and will be overwritten." msgstr "O arquivo \"%s\" existe e será sobrescrito." msgid "The following files will be deleted:" msgstr "Os arquivos a seguir serão apagados:" msgid "The revision expression cannot be empty." msgstr "A revisão da expressão não pode ser vazia" #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be reset using \"git reset --keep %s\"" msgstr "O worktree será resetado usando \"git reset --keep %s\"" msgid "This cannot be undone. Clear commit message?" msgstr "Isso não pode ser feito. Limpar mensagem do commit ?" msgid "" "This commit has already been published.\n" "This operation will rewrite published history.\n" "You probably don't want to do this." msgstr "" "Este commit já foi publicado.\n" "Essa operação irá sobrescrever a história publicada.\n" "Você provavelmente não deseja fazer isso." msgid "" "This operation drops uncommitted changes.\n" "These changes cannot be recovered." msgstr "" "Essa operação cancela mudanças sem commit.\n" "Essas mudanças não podem ser recuperadas." msgid "" "This operation removes uncommitted edits from selected files.\n" "These changes cannot be recovered." msgstr "" "Essa operação remove edições sem commit dos arquivos selecionados.\n" "Essas mudanças não podem ser recuperadas." msgid "" "This operation removes unstaged edits from selected files.\n" "These changes cannot be recovered." msgstr "" "Essa operação remove edições sem stage dos arquivos selecionados.\n" "Essas mudanças não podem ser recuperadas." msgid "" "This repository is currently being rebased.\n" "Resolve conflicts, commit changes, and run:\n" " Rebase > Continue" msgstr "" "Esse repositório está em Rebase.\n" "Resolva os conflitos, comite as mudanças, e execute:\n" " Rebase > Continuar" msgid "" "This repository is in the middle of a merge.\n" "Resolve conflicts and commit changes." msgstr "" "Esse repositório está no meio de um merge.\n" "Resolva os conflitos e comite as mudanças." msgid "Toggle Enabled" msgstr "Alternar Habilitado" msgid "Toggle the branches filter" msgstr "Alternar os filtros dos branches" msgid "Toggle the paths filter" msgstr "Alterar os caminhos do filtro" msgid "Tracking Branch" msgstr "Rastreando Branch" msgid "Tracking branch" msgstr "Rastreando branch" msgid "Traditional Chinese (Taiwan) translation" msgstr "" msgid "Translators" msgstr "Tradutores" msgid "Turkish translation" msgstr "" msgid "URL" msgstr "" #, python-format msgid "URL: %s" msgstr "" msgid "Ukranian translation" msgstr "" msgid "Unable to rebase" msgstr "Incapaz de realizar Rebase" #, python-format msgid "Unable to set URL for \"%(name)s\" to \"%(url)s\"" msgstr "Incapaz de modificar a URL de \"%(name)s\" para \"%(url)s\"" msgid "Undo" msgstr "Desfazer" msgid "Unmerged" msgstr "" msgid "Unstage" msgstr "Unstage" msgid "Unstage All" msgstr "Unstage em Todos" msgid "Unstage Diff Hunk" msgstr "Unstage pedaço do Diff" msgid "Unstage From Commit" msgstr "Unstage do Commit" msgid "Unstage Selected" msgstr "Unstage Selecionados" msgid "Unstage Selected Lines" msgstr "Unstage Linhas Selecionadas" #, python-format msgid "Unstaging: %s" msgstr "" msgid "Untrack Selected" msgstr "Remover rastreio do selecionado" msgid "Untracked" msgstr "Não rastreado" #, python-format msgid "Untracking: %s" msgstr "Removendo rastreio: %s" msgid "Update All Submodules..." msgstr "" msgid "Update Existing Branch:" msgstr "Atualizar Branch Existente:" msgid "Update Submodule" msgstr "" msgid "Update Submodule..." msgstr "" #, fuzzy msgid "Update Submodules" msgstr "Inicializar Submódulos" #, fuzzy msgid "Update all submodules?" msgstr "Inicializar submódulos" #, fuzzy msgid "Update submodules..." msgstr "Inicializar submódulos" #, fuzzy msgid "Update this submodule" msgstr "Inicializar submódulos" msgid "Update this submodule?" msgstr "Atualizar este submódulo?" msgid "Updating" msgstr "Atualizando" msgid "User Name" msgstr "Nome do Usuário" msgid "Version" msgstr "Versão" msgid "View" msgstr "Ver" msgid "View History..." msgstr "Ver Histórico..." msgid "View history for selected paths" msgstr "Ver histórico dos caminhos selecionados" msgid "Visualize" msgstr "Visualizar" msgid "Visualize All Branches..." msgstr "Visualizar todos os Branches..." msgid "Visualize Current Branch..." msgstr "Visualizar Branch Atual..." msgid "Whether to sign the tag (git tag -s)" msgstr "Se assinar a tag (git tag -s)" msgid "Would you like to stage and commit all modified files?" msgstr "Gostaria de stage e commit todos os arquivos modificados ?" msgid "XOR" msgstr "" msgid "Yes" msgstr "Sim" msgid "" "You are in the middle of a merge.\n" "Cannot amend while merging." msgstr "" "Você está no meio de um merge.\n" "Você não pode modificar durante o merge." msgid "You cannot rebase with uncommitted changes." msgstr "Você não pode usar rebase com mudanças sem commit." msgid "You must specify a revision to merge." msgstr "Você precisa especificar uma revisão para o merge." msgid "You must specify a revision to view." msgstr "Você precisa especificar uma revisão para visualizar." msgid "Zoom In" msgstr "Aumentar o Zoom" msgid "Zoom Out" msgstr "Reduzir o Zoom" msgid "Zoom to Fit" msgstr "Zoom para Ajustar" msgid "command-line arguments" msgstr "Argumentos da linha de comando" msgid "error: unable to execute git" msgstr "erro: incapaz de executar git" #, python-format msgid "exit code %s" msgstr "Código de Saída %s" #, python-format msgid "fatal: \"%s\" is not a directory. Please specify a correct --repo ." msgstr "fatal: \"%s\" não é um diretório. Por favor especifique um caminho correto --repo ." #, python-format msgid "git cola version %s" msgstr "Versão do Git Cola %s" msgid "git-cola" msgstr "" msgid "git-cola diff" msgstr "" msgid "grep result..." msgstr "resultados do grep..." msgid "hotkeys.html" msgstr "" msgid "unknown" msgstr "desconhecido" msgid "vX.Y.Z" msgstr "" msgid "x 1" msgstr "" msgid "x 1.5" msgstr "" msgid "x 2" msgstr "" msgid "yyyy-MM-dd" msgstr "" #~ msgid "Already up-to-date." #~ msgstr "Até a data" #~ msgid "Bookmarks" #~ msgstr "Marcadores" #~ msgid "Bookmarks..." #~ msgstr "Marcadores..." #~ msgid "Commit failed: %s" #~ msgstr "Confirmação Falhou: %s" #~ msgid "Created commit: %s" #~ msgstr "Confirmação Criada: %s" #~ msgid "Enter Git Repository" #~ msgstr "Entrar no Repositório Git" #, fuzzy #~ msgid "Error %s" #~ msgstr "Erros: %s" #~ msgid "Errors: %s" #~ msgstr "Erros: %s" #~ msgid "Exit code: %s" #~ msgstr "Código de saída" #~ msgid "Fast Forward Only " #~ msgstr "Avançar Rapidamente" #, fuzzy #~ msgid "Local Branches" #~ msgstr "Branch Local" #~ msgid "No files selected for checkout from HEAD." #~ msgstr "Arquivos não selecionados para checkout do cabeçalho" #~ msgid "Options" #~ msgstr "Opções" #~ msgid "" #~ "Output:\n" #~ "%s" #~ msgstr "" #~ "Saída:\n" #~ "%s" #~ msgid "Output: %s" #~ msgstr "Saída: %s" #~ msgid "Path to git repository" #~ msgstr "Caminho do repositório git" #~ msgid "Process Selection" #~ msgstr "Selecionar Processo" #, fuzzy #~ msgid "Remote Branches" #~ msgstr "Branch Remoto" #~ msgid "Rename remote?" #~ msgstr "Renomear Remoto?" #~ msgid "Select File" #~ msgstr "Selecionar Arquivo" #~ msgid "Select file from \"%s\"" #~ msgstr "Selecione um arquivo de \"%s\"" #~ msgid "Summary:" #~ msgstr "Sumário:" #~ msgid "Updating..." #~ msgstr "Atualização..." git-cola-3.6/po/ru.po000066400000000000000000003075061356743264500145170ustar00rootroot00000000000000# Translation of git-cola to russian # Copyright (C) 2007 Shawn Pearce at el. # This file is distributed under the same license as the git-cola package. # Irina Riesen , 2007. # Alex Riesen , 2007. # Vaiz , 2015 # msgid "" msgstr "" "Project-Id-Version: git-cola VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-17 01:06-0700\n" "PO-Revision-Date: 2015-10-24 12:00-0200\n" "Last-Translator: Vaiz \n" "Language-Team: Russian\n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "" "\n" "

\n" " Drag and drop or use the Add button to add\n" " patches to the list\n" "

\n" " " msgstr "" "\n" "

\n" " Перетащите или используйте кнопку Добавить, чтобы добавить\n" " патчи в список\n" "

\n" " " #, python-format msgid "" "\n" "
\n" " Git Cola has been translated into different languages thanks\n" " to the help of the individuals listed below.\n" "\n" "
\n" "

\n" " Translation is approximate. If you find a mistake,\n" " please let us know by opening an issue on Github:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " We invite you to participate in translation by adding or updating\n" " a translation and opening a pull request.\n" "

\n" "\n" "
\n" "\n" " " msgstr "" #, python-format msgid "" "\n" "
\n" " Git Cola version %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " msgstr "" #, python-format msgid "" "\n" "
\n" " Please use %(bug_link)s to report issues.\n" "
\n" " " msgstr "" #, python-format msgid "" "\n" " Format String Variables\n" " -----------------------\n" " %(path)s = relative file path\n" " %(abspath)s = absolute file path\n" " %(dirname)s = relative directory path\n" " %(absdirname)s = absolute directory path\n" " %(filename)s = file basename\n" " %(basename)s = file basename without extension\n" " %(ext)s = file extension\n" msgstr "" msgid "" "\n" "Commands\n" "--------\n" "pick = use commit\n" "reword = use commit, but edit the commit message\n" "edit = use commit, but stop for amending\n" "squash = use commit, but meld into previous commit\n" "fixup = like \"squash\", but discard this commit's log message\n" "exec = run command (the rest of the line) using shell\n" "\n" "These lines can be re-ordered; they are executed from top to bottom.\n" "\n" "If you disable a line here THAT COMMIT WILL BE LOST.\n" "\n" "However, if you disable everything, the rebase will be aborted.\n" "\n" "Keyboard Shortcuts\n" "------------------\n" "? = show help\n" "j = move down\n" "k = move up\n" "J = shift row down\n" "K = shift row up\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "spacebar = toggle enabled\n" "\n" "ctrl+enter = accept changes and rebase\n" "ctrl+q = cancel and abort the rebase\n" "ctrl+d = launch difftool\n" msgstr "" #, fuzzy msgid "" "\n" "Keyboard Shortcuts\n" "------------------\n" "J, Down = Move Down\n" "K, Up = Move Up\n" "Enter = Edit Selected Files\n" "Spacebar = Open File Using Default Application\n" "Ctrl + L = Focus Text Entry Field\n" "? = Show Help\n" "\n" "The up and down arrows change focus between the text entry field\n" "and the results.\n" msgstr "" "\n" "Горячие клавиши\n" "------------------\n" "J, Down = Опуститься вниз\n" "K, Up = Подняться вверх\n" "Enter = Редактировать выбранные файлы\n" "Spacebar = Открыть файл используя приложенние по умолчанию\n" "Ctrl+L = Фокус на полее для ввода текста\n" "? = Показать справку\n" "\n" "Стрелки вверх и вниз переключают фокус между полем для ввода текста\n" "и результатом.\n" msgid " - DAG" msgstr "" msgid " commits ago" msgstr " коммитов назад" #, python-format msgid "\"%(branch)s\" has been deleted from \"%(remote)s\"." msgstr "\"%(branch)s\" была удалена из \"%(remote)s\"." #, python-format msgid "\"%(command)s\" returned exit status \"%(status)d\"" msgstr "\"%(command)s\" завершилась с кодом \"%(status)d\"" #, python-format msgid "\"%(command)s\" returned exit status %(status)d" msgstr "\"%(command)s\" завершилась с кодом %(status)d" #, fuzzy, python-format msgid "\"%s\" already exists" msgstr "Ветвь \"%s\" уже существует." #, python-format msgid "\"%s\" already exists, cola will create a new directory" msgstr "\"%s\" уже существует, cole создаст новый каталог" #, python-format msgid "\"%s\" requires a selected file." msgstr "Для \"%s\" требуется выбрать файл." msgid "#" msgstr "" #, python-format msgid "%(project)s: %(branch)s - Browse" msgstr "" #, python-format msgid "%(project)s: %(ref)s - DAG" msgstr "" #, python-format msgid "%d days ago" msgstr "%d дней назад" #, python-format msgid "%d hours ago" msgstr "%d часов назад" #, python-format msgid "%d minutes ago" msgstr "%d минут назад" #, python-format msgid "%d patch(es) applied." msgstr "%d патч(ей) применено." #, python-format msgid "%d skipped" msgstr "%d пропущенно" #, python-format msgid "" "%s appears to contain merge conflicts.\n" "\n" "You should probably skip this file.\n" "Stage it anyways?" msgstr "" "%s содержит конфликты слияния.\n" "\n" "Скорее всего вы должны пропустить этот файл.\n" "Зафиксировать в любом случае?" #, python-format msgid "%s is not a Git repository." msgstr "%s не является git репозиторием." #, python-format msgid "%s will be removed from your bookmarks." msgstr "%s будет удален из ваших закладок" #, python-format msgid "%s will be removed from your recent repositories." msgstr "%s будет удален из вашего последнего репозитория." #, python-format msgid "%s: No such file or directory." msgstr "%s: нет такого файла или каталога" msgid "&Edit" msgstr "Редактировать" msgid "&File" msgstr "Файл" msgid "(Amending)" msgstr "(Отмена коммита)" msgid "*** Branch Point ***" msgstr "" msgid "*** Sandbox ***" msgstr "" msgid "100%" msgstr "" msgid "200%" msgstr "" msgid "25%" msgstr "" msgid "400%" msgstr "" msgid "50%" msgstr "" msgid "800%" msgstr "" msgid " ..." msgstr "" msgid "" "A commit template has not been configured.\n" "Use \"git config\" to define \"commit.template\"\n" "so that it points to a commit template." msgstr "" "Шаблон коммита не настроен.\n" "Используйте \"git config\" для определения \"commit.template\"\n" "так, чтобы он указывал на шаблон коммита." #, python-format msgid "A hook must be provided at \"%s\"" msgstr "" #, python-format msgid "A stash named \"%s\" already exists" msgstr "Заначка (stash) с именем '%s' уже существует." msgid "Abort" msgstr "Отменить" msgid "Abort Action" msgstr "Отмена действия" msgid "Abort Merge" msgstr "Прервать слияние" msgid "Abort Merge..." msgstr "Прервать слияние..." msgid "Abort the action?" msgstr "Отменить действие?" msgid "" "Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" "Recovering uncommitted changes is not possible." msgstr "" "Прерывание объединения приведет к потере *ВСЕХ* незакомиченных изменений.\n" "Восстановить незакомиченные изменения будет невозможно." msgid "Aborting the current merge?" msgstr "Отменить текущее слияние?" msgid "About" msgstr "О программе" msgid "About git-cola" msgstr "О git-cola" msgid "Accept" msgstr "" #, fuzzy msgid "" "Accept changes and rebase\n" "Shortcut: Ctrl+Enter" msgstr "" "Закоммитить подготовленные изменения\n" "Ctrl+Enter" #, fuzzy msgid "Action Name" msgstr "Настройки" msgid "Actions" msgstr "Действия" msgid "Actions..." msgstr "Действия..." msgid "Add" msgstr "Добавить" #, fuzzy msgid "Add Favorite" msgstr "Избранное" msgid "Add Remote" msgstr "Добавить внешний репозиторий" msgid "Add Separator" msgstr "" msgid "Add Toolbar" msgstr "" msgid "" "Add and remove remote repositories using the \n" "Add(+) and Delete(-) buttons on the left-hand side.\n" "\n" "Remotes can be renamed by selecting one from the list\n" "and pressing \"enter\", or by double-clicking." msgstr "" "Добавляйте и удаляйте внешние репозитории используя \n" "кнопки Добавить(+) и Удалить(-) на левой стороне.\n" "\n" "Можно переименовать репозиторий выбрав его из списка\n" "и нажав \"enter\", или с помощью двойного клика." msgid "Add new remote git repository" msgstr "Добавить внешний репозиторий" msgid "Add patches (+)" msgstr "Добавить патчи (+)" msgid "Add remote" msgstr "Добавить внешний репозиторий" msgid "Add to .gitignore" msgstr "Добавить в .gitignore" #, fuzzy msgid "Add to Git Annex" msgstr "Добавить в .gitignore" msgid "Add to Git LFS" msgstr "" msgid "Additions" msgstr "Добавлено строк" msgid "Advanced" msgstr "Дополнительно" msgid "Age" msgstr "Возраст" msgid "All Repositories" msgstr "Все репозитории" #, python-format msgid "" "All submodules will be updated using\n" "\"%s\"" msgstr "" msgid "Allow non-fast-forward updates. Using \"force\" can cause the remote repository to lose commits; use it with care" msgstr "" msgid "Always create a merge commit when enabled, even when the merge is a fast-forward update" msgstr "Если эта опция активна, то даже при слиянии в режиме fast-forward update будет создан отдельный (merge) коммит" msgid "Amend" msgstr "Отмена коммита" msgid "Amend Commit" msgstr "Отменить коммит" msgid "Amend Last Commit" msgstr "Отменить последний коммит" msgid "Amend the published commit?" msgstr "Отменить опубликованный коммит?" msgid "Amending" msgstr "Отмена коммита" msgid "" "An action is still running.\n" "Terminating it could result in data loss." msgstr "" "Команда до сих пор выполняется.\n" "Отмена приведет к потере данных." msgid "" "An unsigned, lightweight tag will be created instead.\n" "Create an unsigned tag?" msgstr "" "Будет создан неподписанный, легкий тег.\n" "Создать неподписанный тег??" msgid "Appearance" msgstr "" msgid "Apply" msgstr "Применить" msgid "Apply Patches" msgstr "Применить патчи" msgid "Apply Patches..." msgstr "Применить патчи..." #, fuzzy msgid "Apply and drop the selected stash (git stash pop)" msgstr "Применить выбранные заначки (stash)" msgid "Apply the selected stash" msgstr "Применить выбранные заначки (stash)" msgid "Arguments" msgstr "Аргументы" msgid "Attach" msgstr "Прикрепить" msgid "Author" msgstr "Автор" #, fuzzy msgid "Authors" msgstr "Автор" msgid "Auto" msgstr "" msgid "Auto-Wrap Lines" msgstr "Авто перенос строчек" msgid "Basic Regexp" msgstr "Базовый синтаксис" #, fuzzy msgid "Blame Viewer" msgstr "Просмотр файла" #, fuzzy msgid "Blame selected paths" msgstr "Редактировать выбранный путь(и)" #, fuzzy msgid "Blame..." msgstr "Переименовать..." msgid "Bold on dark headers instead of italic" msgstr "" msgid "Branch" msgstr "Ветвь" #, python-format msgid "" "Branch \"%(branch)s\" does not exist in \"%(remote)s\".\n" "A new remote branch will be published." msgstr "" "Ветвь \"%(branch)s\" не существует в \"%(remote)s\".\n" "Будет добавлена новая внешняя ветвь." #, python-format msgid "Branch \"%s\" already exists." msgstr "Ветвь \"%s\" уже существует." msgid "Branch Diff Viewer" msgstr "" msgid "Branch Exists" msgstr "Ветвь существует" msgid "Branch Name" msgstr "Название ветви" #, python-format msgid "Branch: %s" msgstr "Ветвь: %s" #, fuzzy msgid "Branches" msgstr "Ветвь" msgid "Branches..." msgstr "Ветви..." msgid "Brazilian translation" msgstr "" msgid "Browse" msgstr "Показать" msgid "Browse Commits..." msgstr "Показать коммиты..." msgid "Browse Current Branch..." msgstr "Просмотреть текущую ветвь..." msgid "Browse Other Branch..." msgstr "Просмотреть другие ветви..." msgid "Browse..." msgstr "Показать..." msgid "Browser" msgstr "Просомтрщик" #, python-format msgid "Browsing %s" msgstr "Просмотр %s" msgid "Bypass Commit Hooks" msgstr "" msgid "Cancel" msgstr "Отменить" #, fuzzy msgid "" "Cancel rebase\n" "Shortcut: Ctrl+Q" msgstr "" "Закоммитить подготовленные изменения\n" "Ctrl+Enter" msgid "Cannot Amend" msgstr "Нельзя отменить коммит" #, fuzzy, python-format msgid "Cannot exec \"%s\": please configure a blame viewer" msgstr "Не удалось запустить \"%s\": пожалуйста, настройте ваш редактор" #, python-format msgid "Cannot exec \"%s\": please configure a history browser" msgstr "Неполучилось выполнить \"%s\": пожалуйста, настройте просмотрщик истории" #, python-format msgid "Cannot exec \"%s\": please configure your editor" msgstr "Не удалось запустить \"%s\": пожалуйста, настройте ваш редактор" msgid "Changed Upstream" msgstr "" msgid "Check Spelling" msgstr "Проверить правописание" #, fuzzy msgid "Check spelling" msgstr "Проверить правописание" msgid "Checkout" msgstr "Перейти" msgid "Checkout After Creation" msgstr "После создания сделать текущей ветвью" msgid "Checkout Branch" msgstr "Перейти на ветвь" #, fuzzy msgid "Checkout Detached HEAD" msgstr "Перейти на ветвь" #, fuzzy msgid "Checkout as new branch" msgstr "Перейти на ветвь" msgid "Checkout..." msgstr "Перейти..." msgid "Cherry Pick" msgstr "" #, fuzzy msgid "Cherry-Pick Commit" msgstr "Cherry-Pick коммит" #, fuzzy msgid "Cherry-Pick..." msgstr "Перейти..." msgid "Choose Paths" msgstr "Выберите путь" msgid "Choose the \"git grep\" regular expression mode" msgstr "Выберите тип синтаксиса для \"git grep\"" #, fuzzy msgid "Clear Default Repository" msgstr "Текущий репозиторий" msgid "Clear commit message" msgstr "Очистить комментарий к коммиту" msgid "Clear commit message?" msgstr "Очистить комментарий к коммиту?" msgid "Clear..." msgstr "Очистить..." msgid "Clone" msgstr "Склонировать" msgid "Clone Repository" msgstr "Клонировать репозиторий" msgid "Clone..." msgstr "Клонировать..." #, python-format msgid "Cloning repository at %s" msgstr "Клонировать существующий репозиторий в %s" msgid "Close" msgstr "Закрыть" msgid "Close..." msgstr "Закрыть..." msgid "Collapse all" msgstr "Свернуть все" #, fuzzy msgid "Command" msgstr "Описание коммита" msgid "Commit" msgstr "Описание коммита" msgid "Commit failed" msgstr "Не удалось закоммитить" msgid "Commit staged changes" msgstr "Закоммитить подготовленные изменения" msgid "" "Commit staged changes\n" "Shortcut: Ctrl+Enter" msgstr "" "Закоммитить подготовленные изменения\n" "Ctrl+Enter" msgid "Commit summary" msgstr "Краткое описание коммита" msgid "Commit the merge if there are no conflicts. Uncheck to leave the merge uncommitted" msgstr "Закоммитить слияние, если нет конфликтов. Снимите отметку, чтобы оставить слияние незакомиченным" msgid "Commit@@verb" msgstr "" msgid "Compare" msgstr "Сравнить" #, fuzzy msgid "Compare All" msgstr "Сравнить" msgid "Configure the remote branch as the the new upstream" msgstr "" msgid "Configure toolbar" msgstr "" msgid "Console" msgstr "Консоль" msgid "Continue" msgstr "Продолжить" msgid "Copy" msgstr "Копировать" #, fuzzy msgid "Copy Basename to Clipboard" msgstr "Копировать путь в буфер" #, fuzzy msgid "Copy Leading Path to Clipboard" msgstr "Копировать относительный путь в буфер" msgid "Copy Path to Clipboard" msgstr "Копировать путь в буфер" msgid "Copy Relative Path to Clipboard" msgstr "Копировать относительный путь в буфер" msgid "Copy SHA-1" msgstr "Копировать SHA-1" #, fuzzy msgid "Copy..." msgstr "Копировать" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "Неполучилось разобрать Git URL: \"%s\"" msgid "Create Branch" msgstr "Создать ветвь" msgid "Create Patch" msgstr "Создать патч" msgid "Create Remote Branch" msgstr "Создать внешнюю ветвь" msgid "Create Signed Commit" msgstr "Создать подписанный коммит" msgid "Create Tag" msgstr "Создать тег" msgid "Create Tag..." msgstr "Создать тег..." msgid "Create Unsigned Tag" msgstr "Создать неподписанный тег" #, fuzzy msgid "Create a merge commit even when the merge resolves as a fast-forward" msgstr "Если эта опция активна, то даже при слиянии в режиме fast-forward update будет создан отдельный (merge) коммит" msgid "Create a new remote branch?" msgstr "Создать новую внешнюю ветвь?" msgid "Create..." msgstr "Создать..." #, python-format msgid "Created a new tag named \"%s\"" msgstr "Создан новый тег с именем \"%s\"" msgid "Current Repository" msgstr "Текущий репозиторий" msgid "Custom Copy Actions" msgstr "" #, fuzzy msgid "Customize..." msgstr "Закрыть..." msgid "Cut" msgstr "Вырезать" msgid "Czech translation" msgstr "" msgid "DAG..." msgstr "" msgid "Dark Theme" msgstr "" msgid "Date, Time" msgstr "Дата, Время" #, fuzzy msgid "Default" msgstr "Восстановить настройки по умолчанию" msgid "Delete" msgstr "Удалить" #, python-format msgid "Delete %d file(s)?" msgstr "Удалить %d файл(ы)?" msgid "Delete Bookmark" msgstr "Удалить закладку" msgid "Delete Bookmark?" msgstr "Удалить закладку?" msgid "Delete Branch" msgstr "Удалить ветвь" msgid "Delete Files" msgstr "Удалить файлы" msgid "Delete Files..." msgstr "Удалить файл(ы)..." msgid "Delete Files?" msgstr "Удалить файлы?" msgid "Delete Remote" msgstr "Удалить внешнюю ветвь" msgid "Delete Remote Branch" msgstr "Удалить внешнюю ветвь" msgid "Delete Remote Branch..." msgstr "Удалить внешнюю ветвь..." msgid "Delete remote" msgstr "Удалить внешний репозиторий" #, python-format msgid "Delete remote \"%s\"" msgstr "Удалить внешнюю ветвь \"%s\"" msgid "Delete remote?" msgstr "Удалить внешнюю ветвь?" #, fuzzy msgid "Delete selected branch?" msgstr "Удалить внешнюю ветвь" #, fuzzy msgid "Delete toolbar" msgstr "Удалить закладку" msgid "Delete..." msgstr "Удалить..." #, python-format msgid "Deleting \"%s\" failed" msgstr "Не удалось удалить \"%s\"" msgid "Deletions" msgstr "Удалено строк" msgid "Detach" msgstr "Открепить" msgid "Detect Conflict Markers" msgstr "Обнаруживать отметки о конфликтах" msgid "Detect conflict markers in unmerged files" msgstr "Обнаруживать отметки о конфликтах в неслитых файлах" msgid "Developer" msgstr "" msgid "Diff" msgstr "Сравнение" msgid "Diff Against Predecessor..." msgstr "" msgid "Diff Options" msgstr "Настройки сравнения" msgid "Diff Tool" msgstr "Программа сравнения" msgid "Diff selected -> this" msgstr "Сравнить выделенное состояние с текущим" msgid "Diff this -> selected" msgstr "Сравнить текущее состояние с выделенным" msgid "Diffstat" msgstr "Список различий" #, fuzzy msgid "Difftool" msgstr "Программа сравнения" msgid "Directory Exists" msgstr "Каталог существует" msgid "Display Untracked Files" msgstr "Показывать не добавленные в контроль версий файлы" msgid "Documentation" msgstr "Документация" msgid "Drop" msgstr "Удалить" msgid "Drop Stash" msgstr "Удалить заначку (stash)" msgid "Drop Stash?" msgstr "Удалить заначку (stash)?" #, python-format msgid "Drop the \"%s\" stash?" msgstr "Удалить заначку (stash) \"%s\"" msgid "Drop the selected stash" msgstr "Удалить выбранную заначку (stash)" #, fuzzy msgid "Edit" msgstr "Редактировать" msgid "Edit Rebase" msgstr "Редактировать перемещение (rebase)" msgid "Edit Remotes" msgstr "Редактировать внешние репозитории" msgid "Edit Remotes..." msgstr "Редактировать внешние репозитории..." msgid "Edit remotes by selecting them from the list" msgstr "" msgid "Edit selected paths" msgstr "Редактировать выбранный путь(и)" msgid "Edit..." msgstr "Редактировать..." msgid "Editor" msgstr "Редактор" msgid "Email Address" msgstr "Адрес электронной почты" msgid "Email contributor" msgstr "" msgid "Enabled" msgstr "" #, fuzzy msgid "Enter New Branch Name" msgstr "Введите новое имя ветви" #, fuzzy msgid "Enter a name for the new bare repo" msgstr "Введите имя для заначки (stash)" msgid "Enter a name for the stash" msgstr "Введите имя для заначки (stash)" msgid "Error" msgstr "Ошибка" msgid "Error Cloning" msgstr "Ошибка клонирования" msgid "Error Creating Branch" msgstr "При создании ветви возникла ошибка" msgid "Error Creating Repository" msgstr "Не удалось создать репозиторий" msgid "Error Deleting Remote Branch" msgstr "Не удалось удалить внешную ветвь" msgid "Error Editing File" msgstr "Ошибка редактирования файла" #, fuzzy msgid "Error Launching Blame Viewer" msgstr "Ошибка запуска Просмотрщика истории" msgid "Error Launching History Browser" msgstr "Ошибка запуска Просмотрщика истории" #, python-format msgid "Error creating remote \"%s\"" msgstr "Не удалось создать внешную ветвь \"%s\"" #, fuzzy msgid "Error creating stash" msgstr "При создании ветви возникла ошибка" #, python-format msgid "Error deleting remote \"%s\"" msgstr "Не удалось удалить внешнюю ветвь \"%s\"" #, fuzzy, python-format msgid "Error renaming \"%(name)s\" to \"%(new_name)s\"" msgstr "Добавить тег \"%(revision)s\" к \"%(name)s\"" #, fuzzy msgid "Error running prepare-commitmsg hook" msgstr "Вызов программы поддержки репозитория pre-commit..." #, fuzzy, python-format msgid "Error updating submodule %s" msgstr "Не удалось создать внешную ветвь \"%s\"" #, fuzzy msgid "Error updating submodules" msgstr "Ошибка редактирования файла" msgid "Error: Cannot find commit template" msgstr "Ошибка: Не получается найти шаблон коммита" msgid "Error: Stash exists" msgstr "Ошибка: заначка (stash) уже существует" msgid "Error: Unconfigured commit template" msgstr "Ошибка: шаблон коммита не настроен" #, python-format msgid "Error: could not clone \"%s\"" msgstr "Ошибка: не получилось клонировать \"%s\"" #, python-format msgid "Error: could not create tag \"%s\"" msgstr "Ошибка: не получилось создать тег \"%s\"" #, fuzzy, python-format msgid "Executing action %s" msgstr "Словарь вернут к %s." msgid "Expand all" msgstr "Развернуть все" msgid "Export Patches" msgstr "Экспортировать патчи" msgid "Export Patches..." msgstr "Экспортировать патчи..." msgid "Expression..." msgstr "Выражения..." msgid "Extended Regexp" msgstr "Расширенный синтаксис" msgid "Extended description..." msgstr "Расширенное описание..." msgid "Fast Forward Only" msgstr "Только Fast Forward" #, fuzzy msgid "Fast-forward only" msgstr "Только Fast Forward" msgid "Favorite repositories" msgstr "Избранные репозитории" msgid "Favorites" msgstr "Избранное" msgid "Fetch" msgstr "Получить все (fetch)" msgid "Fetch Tracking Branch" msgstr "Получить отслеживаемую ветвь" msgid "Fetch..." msgstr "Скачать все ветки (fetch)..." msgid "File Browser..." msgstr "Файловый менеджер..." msgid "File Differences" msgstr "Сравнение файлов" msgid "File Saved" msgstr "Файл сохранен" #, python-format msgid "File saved to \"%s\"" msgstr "Файл сохранен в \"%s\"" #, fuzzy msgid "File system change monitoring: disabled because \"cola.inotify\" is false.\n" msgstr "inotify отключены, потому что \"cola.inotify\" имеет значение \"false\"\n" msgid "File system change monitoring: disabled because libc does not support the inotify system calls.\n" msgstr "" msgid "File system change monitoring: disabled because pywin32 is not installed.\n" msgstr "" msgid "" "File system change monitoring: disabled because the limit on the total number of inotify watches was reached. You may be able to increase the limit on the number of watches by running:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" msgstr "" msgid "File system change monitoring: enabled.\n" msgstr "" msgid "Filename" msgstr "Имя файла" msgid "Files" msgstr "Файлы" #, fuzzy msgid "Filter branches..." msgstr "Фильтр путей..." msgid "Filter paths..." msgstr "Фильтр путей..." msgid "Find Files" msgstr "Поиск файлов" msgid "Fixed String" msgstr "Фиксированная строка" msgid "Fixed-Width Font" msgstr "Шрифт с фиксированной шириной" msgid "Fixup" msgstr "" msgid "Fixup Previous Commit" msgstr "Исправить предыдущий коммит" msgid "Flat dark blue" msgstr "" msgid "Flat dark green" msgstr "" msgid "Flat dark grey" msgstr "" msgid "Flat dark red" msgstr "" msgid "Flat light blue" msgstr "" msgid "Flat light green" msgstr "" msgid "Flat light grey" msgstr "" msgid "Flat light red" msgstr "" msgid "Font Size" msgstr "Размер шрифта" #, fuzzy msgid "Force" msgstr "Перезаписать все (push)" msgid "Force Fetch" msgstr "Перезаписать все (fetch)" msgid "Force Fetch?" msgstr "Перезаписать все (fetch)?" msgid "Force Push" msgstr "Перезаписать все (push)" msgid "Force Push?" msgstr "Перезаписать все (push)?" #, python-format msgid "Force fetching from %s?" msgstr "Перезаписать (fetch) все из %s " #, python-format msgid "Force push to %s?" msgstr "Перезаписать все (push) в %s?" #, fuzzy msgid "Format String" msgstr "Фиксированная строка" msgid "French translation" msgstr "" msgid "GPG-sign the merge commit" msgstr "" msgid "GUI theme" msgstr "" #, python-format msgid "Gathering info for \"%s\"..." msgstr "Получение информации о \"%s\"..." msgid "German translation" msgstr "" msgid "Get Commit Message Template" msgstr "Получить шаблон комментария к коммиту" msgid "Go Down" msgstr "Вниз" msgid "Go Up" msgstr "Вверх" msgid "Grab File..." msgstr "Захватить файл..." msgid "Graph" msgstr "График" msgid "Grep" msgstr "Поиск подстроки (git grep)" msgid "Have you rebased/pulled lately?" msgstr "Вы недавно выполняли rebase/pull?" msgid "Help" msgstr "Помощь" msgid "Help - Custom Copy Actions" msgstr "" msgid "Help - Find Files" msgstr "Помощь - Поиск файлов" msgid "Help - git-xbase" msgstr "" msgid "Hide Details.." msgstr "" msgid "High DPI" msgstr "" msgid "History Browser" msgstr "Просмотрщик истории" msgid "Hungarian translation" msgstr "" msgid "Icon theme" msgstr "" msgid "Ignore all whitespace" msgstr "Игнорировать все пробелы" msgid "Ignore changes in amount of whitespace" msgstr "" msgid "Ignore changes in whitespace at EOL" msgstr "" msgid "Ignore custom pattern" msgstr "" #, fuzzy msgid "Ignore exact filename" msgstr "Игнорировать все пробелы" msgid "Ignore filename or pattern" msgstr "" msgid "Include tags " msgstr "Включая теги" msgid "Indent Status paths" msgstr "" msgid "Indonesian translation" msgstr "" #, fuzzy msgid "Initialize Git Annex" msgstr "Инициализация..." #, fuzzy msgid "Initialize Git LFS" msgstr "Инициализация..." msgid "Inititalize submodules" msgstr "" msgid "Insert spaces instead of tabs" msgstr "" msgid "Interactive Rebase" msgstr "Интерактивное перемещение (rebase)" msgid "Invalid Revision" msgstr "Неверная версия" msgid "Keep *.orig Merge Backups" msgstr "" msgid "Keep Index" msgstr "Сохранить индекс" msgid "Keyboard Shortcuts" msgstr "Горячие клавиши" msgid "Launch Diff Tool" msgstr "Запустить средство сравнения" #, fuzzy msgid "Launch Directory Diff Tool" msgstr "Запустить средство сравнения" msgid "Launch Editor" msgstr "Запустить редактор" msgid "Launch Terminal" msgstr "Запустить терминал" msgid "" "Launch external diff tool\n" "Shortcut: Ctrl+D" msgstr "" msgid "Launch git-cola" msgstr "Запустить git-cola" #, fuzzy msgid "Launch git-difftool against previous versions" msgstr "Сравнить c помощью git-difftool с предыдущей версией." #, fuzzy msgid "Launch git-difftool on the current path" msgstr "Запустить git-difftool по выбранному пути" msgid "Light Theme" msgstr "" msgid "Load Commit Message" msgstr "Загрузить комментарий к коммиту" msgid "Load Commit Message..." msgstr "Загрузить комментарий к коммиту..." msgid "Load Previous Commit Message" msgstr "Загрузить комментарий к предыдущему коммиту" msgid "Loading..." msgstr "Загрузка..." msgid "Local" msgstr "" msgid "Local Branch" msgstr "Локальная ветвь:" msgid "Local branch" msgstr "Локальная ветвь:" msgid "Lock Layout" msgstr "Зафиксировать панели" msgid "Log" msgstr "Лог" msgid "Maintainer (since 2007) and developer" msgstr "" msgid "Merge" msgstr "Слияние (merge)" #, python-format msgid "Merge \"%(revision)s\" into \"%(branch)s\"" msgstr "Объединить (merge) \"%(revision)s\" в \"%(branch)s\"" msgid "Merge Tool" msgstr "Программа слияния (merge)" msgid "Merge Verbosity" msgstr "Уровень детальности сообщений при объединении" msgid "Merge failed. Conflict resolution is required." msgstr "Не удалось завершить объединение. Требуется разрешение конфликта." #, python-format msgid "Merge into \"%s\"" msgstr "Объединить (merge) с \"%s\"" #, fuzzy msgid "Merge into current branch" msgstr "Просмотреть текущую ветвь..." msgid "Merge..." msgstr "Слияние (merge)..." msgid "Merging" msgstr "Слияние" msgid "Message" msgstr "Сообщение" msgid "Missing Commit Message" msgstr "Отсутсвует комментарий к коммиту" msgid "Missing Data" msgstr "Отсутствуют данные" msgid "Missing Name" msgstr "Отсутствует имя" msgid "Missing Revision" msgstr "Версия не найдена" msgid "Missing Tag Message" msgstr "Отсутсвует описание тега" msgid "Modified" msgstr "Изменено" msgid "More..." msgstr "Далее..." msgid "Move Down" msgstr "Опуститься вниз" msgid "Move Up" msgstr "Подняться вверх" msgid "Move files to trash" msgstr "Удалить файл(ы) в корзину" msgid "Name" msgstr "Имя:" msgid "Name for the new remote" msgstr "Имя нового внешнего репозитория" #, fuzzy msgid "New Bare Repository..." msgstr "Новый репозиторий..." msgid "New Repository..." msgstr "Новый репозиторий..." msgid "New..." msgstr "Новый..." msgid "Next File" msgstr "Следующий файл" msgid "No" msgstr "Нет" msgid "No Revision Specified" msgstr "Версия не указана" msgid "" "No changes to commit.\n" "\n" "You must stage at least 1 file before you can commit." msgstr "" "Отсутствуют изменения для коммита.\n" "\n" "Добавить к коммиту хотя бы один файл перед созданием коммита." msgid "No commits exist in this branch." msgstr "В данной ветке не существует коммитов" msgid "No fast forward" msgstr "" msgid "No fast-forward" msgstr "" msgid "No repository selected." msgstr "Не указан репозиторий." msgid "Non-fast-forward fetch overwrites local history!" msgstr "Non-fast-forward fetch перепишет локальную историю!" msgid "" "Non-fast-forward push overwrites published history!\n" "(Did you pull first?)" msgstr "" "Non-fast-forward push перепишет историю на сервере!\n" "(Вы выполнили pull?)" msgid "Nothing to commit" msgstr "Отсуствуют измения для коммита" msgid "Nothing to do" msgstr "Нечего делать" msgid "Number of Diff Context Lines" msgstr "Число строк в контексте сравнения" msgid "Open" msgstr "Открыть" msgid "Open Git Repository..." msgstr "Открыть Git репозиторий..." #, fuzzy msgid "Open Parent" msgstr "Открыть последний" msgid "Open Parent Directory" msgstr "Открыть родительский каталог" msgid "Open Recent" msgstr "Открыть последний" msgid "Open Using Default Application" msgstr "Открыть, используя приложение по умолчанию" msgid "Open in New Window" msgstr "Открыть в новом окне" msgid "Open in New Window..." msgstr "Открыть в новом окне..." msgid "Open..." msgstr "Открыть..." #, fuzzy msgid "Other branches" msgstr "Фильтр путей..." msgid "Overwrite" msgstr "Перезаписать" #, python-format msgid "Overwrite \"%s\"?" msgstr "Перезаписать \"%s\"?" msgid "Overwrite File?" msgstr "Перезаписать файл?" msgid "" "Parse arguments using a shell.\n" "Queries with spaces will require \"double quotes\"." msgstr "" "Разбор аргументов с помощью шелла.\n" "Запросы с пробелами должны быть в \"двойных кавычках\"." msgid "Partially Staged" msgstr "Частично добавлено к коммиту" msgid "Paste" msgstr "Вставить" msgid "Patch(es) Applied" msgstr "Патчи применены" msgid "Path" msgstr "" msgid "Path or URL to clone (Env. $VARS okay)" msgstr "Путь или URL для клонирования (Env. $VARS okay)" msgid "Pick" msgstr "" msgid "Pixel XOR" msgstr "" msgid "Please provide both a branch name and revision expression." msgstr "Пожалуйста, предоставьте имя ветви и версию" msgid "Please select a file" msgstr "Пожалуйста, выберите файл" msgid "Please specify a name for the new tag." msgstr "Укажите имя для нового тега" msgid "Please specify a revision to tag." msgstr "Пожалуйста, укажите версию для тега." msgid "" "Please supply a commit message.\n" "\n" "A good commit message has the following format:\n" "\n" "- First line: Describe in one sentence what you did.\n" "- Second line: Blank\n" "- Remaining lines: Describe why this change is good.\n" msgstr "" "Напишите комментарий к коммиту.\n" "\n" "Рекомендуется следующий формат комментария:\n" "\n" "- Первая строка: краткое описание сделанных изменений.\n" "- Вторая строка пустая\n" "- Оставшиеся строки: опишите, что дают ваши изменения.\n" msgid "Point the current branch head to a new commit?" msgstr "" msgid "Polish translation" msgstr "" msgid "Pop" msgstr "" msgid "Preferences" msgstr "Настройки" msgid "Prefix" msgstr "Префикс" #, fuzzy msgid "Prepare Commit Message" msgstr "Поиск комментария к коммиту" msgid "Prevent \"Stage\" from staging all files when nothing is selected" msgstr "" msgid "Previous File" msgstr "Предыдущий файл" msgid "Prompt on creation" msgstr "" #, fuzzy msgid "Prompt when pushing creates new remote branches" msgstr "Создать новую внешнюю ветвь?" #, fuzzy msgid "Prune " msgstr "Чистка" msgid "Pull" msgstr "Получить (pull)" msgid "Pull..." msgstr "Получить (pull)..." msgid "Push" msgstr "Отправить (push)" msgid "Push..." msgstr "Отправить (push)..." msgid "Quit" msgstr "Выход" msgid "Rebase" msgstr "Переместить (rebase)" #, python-format msgid "Rebase onto %s" msgstr "Переместить (rebase) в %s" #, fuzzy msgid "Rebase stopped" msgstr "Переместить (rebase) " msgid "Rebase the current branch instead of merging" msgstr "" msgid "Rebasing" msgstr "Перемещение" msgid "Recent" msgstr "Недавнее" msgid "Recent repositories" msgstr "Недавние репозитории" #, fuzzy msgid "Recent repository count" msgstr "Недавние репозитории" msgid "Recently Modified Files" msgstr "Недавно измененные файлы" msgid "Recently Modified Files..." msgstr "Недавно измененные файлы..." msgid "Recovering a dropped stash is not possible." msgstr "Восстановить удаленные заначки (stash) будет невозможно" msgid "Recovering lost commits may not be easy." msgstr "Восстановить потерянные коммиты будет сложно." msgid "Redo" msgstr "Повторить" msgid "Reduce commit history to minimum" msgstr "" msgid "Refresh" msgstr "Обновить" msgid "Refuse to merge unless the current HEAD is already up-to-date or the merge can be resolved as a fast-forward" msgstr "" msgid "Remote" msgstr "Внешние репозитории" msgid "Remote Branch" msgstr "Внешняя ветвь" msgid "Remote Branch Deleted" msgstr "Внешняя ветвь удалена" msgid "Remote git repositories - double-click to rename" msgstr "Внешний репозиторий git - двойной клик для переименования" msgid "Remove" msgstr "Удалить" #, python-format msgid "Remove %s from the recent list?" msgstr "Удалить %s из списка последних изменений?" #, fuzzy msgid "Remove Element" msgstr "Удалить" msgid "Remove remote-tracking branches that no longer exist on the remote" msgstr "" msgid "Remove selected (Delete)" msgstr "Удалить выбранное (Delete)" msgid "Rename" msgstr "Переименовать" #, fuzzy, python-format msgid "Rename \"%s\"" msgstr "Переименовать" #, fuzzy msgid "Rename Branch" msgstr "Переименовать ветвь..." msgid "Rename Branch..." msgstr "Переименовать ветвь..." msgid "Rename Existing Branch" msgstr "Переименовать существующую ветвь:" msgid "Rename Remote" msgstr "Переименовать внешнюю ветвь" #, fuzzy msgid "Rename Repository" msgstr "Клонировать репозиторий" #, fuzzy msgid "Rename branch" msgstr "Переименовать ветвь..." #, python-format msgid "Rename remote \"%(current)s\" to \"%(new)s\"?" msgstr "Переименовать внешнюю ветвь \"%(current)s\" на \"%(new)s\"?" #, fuzzy msgid "Rename selected paths" msgstr "Редактировать выбранный путь(и)" #, python-format msgid "Repository: %s" msgstr "Репозиторий: %s" msgid "Reset" msgstr "Сброс" #, python-format msgid "Reset \"%(branch)s\" to \"%(revision)s\"?" msgstr "Сбросить (reset) \"%(branch)s\" к \"%(revision)s\"?" msgid "Reset Branch" msgstr "Сбросить (reset) ветвь" #, fuzzy msgid "Reset Branch Head" msgstr "Сбросить (reset) ветвь" msgid "Reset Branch?" msgstr "Сбросить (reset) ветвь?" #, fuzzy msgid "Reset Hard" msgstr "Сбросить (reset) ветвь" #, fuzzy msgid "Reset Merge" msgstr "Версия для объединения" #, fuzzy msgid "Reset Soft" msgstr "Сброс" msgid "Reset Worktree" msgstr "" #, fuzzy msgid "Reset hard?" msgstr "Сбросить (reset) ветвь?" #, fuzzy msgid "Reset merge?" msgstr "Сбросить (reset) ветвь?" #, fuzzy msgid "Reset soft?" msgstr "Сбросить '%s'?" msgid "Reset worktree?" msgstr "" #, python-format msgid "Resetting \"%(branch)s\" to \"%(revision)s\" will lose commits." msgstr "Сброс \"%(branch)s\" в \"%(revision)s\" приведет к потере коммитов." msgid "Restart the application after changing appearance settings." msgstr "" msgid "Revert" msgstr "" msgid "Revert Diff Hunk" msgstr "Откатить изменения в этой части" msgid "Revert Diff Hunk..." msgstr "Откатить изменения в этой части" msgid "Revert Diff Hunk?" msgstr "Откатить изменения в этой части?" msgid "Revert Selected Lines" msgstr "Отменить изменения в выбранных линиях" msgid "Revert Selected Lines..." msgstr "Откатить выделенные линии..." msgid "Revert Selected Lines?" msgstr "Отменить изменения в выбранных линиях?" msgid "Revert Uncommitted Changes" msgstr "Отменить незакомиченные изменения" msgid "Revert Uncommitted Changes?" msgstr "Отменить незакомиченные изменения?" msgid "Revert Uncommitted Edits..." msgstr "Отменить незакомиченные изменения..." msgid "Revert Unstaged Changes" msgstr "Откатить изменения" msgid "Revert Unstaged Changes?" msgstr "Откатить изменения?" msgid "Revert Unstaged Edits..." msgstr "Откатить изменения..." msgid "Revert the uncommitted changes?" msgstr "Отменить незакомиченные изменения?" msgid "Revert the unstaged changes?" msgstr "Откатить изменения?" #, fuzzy msgid "Revert uncommitted changes to selected paths" msgstr "Отменить незакомиченные изменения по выбранным путям." #, fuzzy msgid "Revert unstaged changes to selected paths" msgstr "Отменить незафиксированные изменения по выбранным путям." msgid "Review" msgstr "Просмотр" msgid "Review..." msgstr "Просмотр..." msgid "Revision" msgstr "Версия" msgid "Revision Expression:" msgstr "Выражение для определения версии:" msgid "Revision to Merge" msgstr "Версия для объединения" msgid "Reword" msgstr "" msgid "Rewrite Published Commit?" msgstr "Переписать опубликованный коммит?" msgid "Run" msgstr "Запустить" #, python-format msgid "Run \"%s\"?" msgstr "Запустить \"%s\"?" #, python-format msgid "Run %s?" msgstr "Запустить %s?" #, python-format msgid "Run the \"%s\" command?" msgstr "Выполнить комманду \"%s\"?" #, python-format msgid "Running command: %s" msgstr "Запуск комманды: %s" msgid "Russian translation" msgstr "" #, fuzzy msgid "SHA-1" msgstr "Копировать SHA-1" #, fuzzy msgid "Safe Mode" msgstr "Добавить к коммиту измененые файлы" msgid "Save" msgstr "Сохранить" msgid "Save Archive" msgstr "Сохранить архив" msgid "Save As Tarball/Zip..." msgstr "Сохранить как архив..." msgid "Save GUI Settings" msgstr "Сохранить настройки интерфейса" msgid "Save Stash" msgstr "Сохранить заначку (stash)" msgid "Save modified state to new stash" msgstr "Сохранить измененное состояние в новую заначку (stash)" #, python-format msgid "Saved \"%(filename)s\" from \"%(ref)s\" to \"%(destination)s\"" msgstr "Сохранен \"%(filename)s\" из \"%(ref)s\" в \"%(destination)s\"" msgid "Search" msgstr "Поиск" msgid "Search Authors" msgstr "Поиск авторов" msgid "Search Commit Messages" msgstr "Поиск комментария к коммиту" msgid "Search Committers" msgstr "Поиск авторов коммитов" msgid "Search Date Range" msgstr "Поиск по диапазону дат" msgid "Search Diffs" msgstr "Поиск различий" msgid "Search by Expression" msgstr "Поиск по выражению" msgid "Search by Path" msgstr "Поиск по пути" msgid "Search for a fixed string" msgstr "Искать фиксированную строку" msgid "Search using a POSIX basic regular expression" msgstr "" msgid "Search using a POSIX extended regular expression" msgstr "" msgid "Search..." msgstr "Поиск..." msgid "Select" msgstr "Выбрать" msgid "Select All" msgstr "Выделить все" msgid "Select Branch to Review" msgstr "Выбрать ветвь для просмотра" msgid "Select Child" msgstr "Выбрать наследника" msgid "Select Commit" msgstr "Выбрать коммит" #, fuzzy msgid "Select Directory..." msgstr "Выбрать репозиторий..." #, fuzzy msgid "Select New Upstream" msgstr "Выбрать" msgid "Select Newest Child" msgstr "Выбрать нового наследника" msgid "Select Oldest Parent" msgstr "Выбрать самого старшего родителя" msgid "Select Parent" msgstr "Выбрать родителя" msgid "Select Previous Version" msgstr "Выбрать предыдущую версию" msgid "Select Repository..." msgstr "Выбрать репозиторий..." msgid "Select a parent directory for the new clone" msgstr "Выберите родительский каталог для новой копии" msgid "Select manually..." msgstr "Выбрать вручную..." #, fuzzy msgid "Select output dir" msgstr "Выбрать коммит" #, fuzzy msgid "Select output directory" msgstr "Выбрать репозиторий..." #, fuzzy msgid "Select patch file(s)..." msgstr "Выбрать файл(ы) патча..." #, fuzzy msgid "Select repository" msgstr "Выбрать репозиторий..." #, fuzzy msgid "Set Default Repository" msgstr "Выбрать репозиторий..." #, fuzzy msgid "Set Upstream Branch" msgstr "Выбрать" msgid "" "Set the sort order for branches and tags.\n" "Toggle between date-based and version-name-based sorting." msgstr "" #, fuzzy msgid "Set upstream" msgstr "Выбрать" msgid "Settings" msgstr "Настройки" msgid "Shell arguments" msgstr "Ручной ввод аргументов \"git grep\"" msgid "Shift Down" msgstr "" msgid "Shift Up" msgstr "" msgid "Shortcuts" msgstr "Горячие клавиши" #, fuzzy msgid "Show Details..." msgstr "Удалить файл(ы)..." msgid "Show Diffstat After Merge" msgstr "Показать отчет об изменениях после объединения" msgid "Show Full Paths in the Window Title" msgstr "" msgid "Show Help" msgstr "Показать справку" #, fuzzy msgid "Show History" msgstr "Показать историю" msgid "Show file counts in Status titles" msgstr "" msgid "" "Show help\n" "Shortcut: ?" msgstr "" "Показать помощь\n" "Горячая клавиша: ?" msgid "Show icon? (if available)" msgstr "" msgid "Show line numbers" msgstr "" msgid "Show whole surrounding functions of changes" msgstr "" msgid "Showing changes since" msgstr "Показать изменения с" msgid "Side by side" msgstr "" msgid "Sign Off" msgstr "Подписать" msgid "Sign Tag" msgstr "Подписать тег" msgid "Sign off on this commit" msgstr "Подписаться под этим коммитом" msgid "Simplified Chinese translation" msgstr "" msgid "Skip" msgstr "Пропустить" msgid "Skip Current Patch" msgstr "Пропустить текущий патч" msgid "Sort bookmarks alphabetically" msgstr "Сортировать закладки по алфавиту" msgid "Spanish translation" msgstr "" msgid "Specifies the SHA-1 to tag" msgstr "Укажите SHA-1 для тега" msgid "Specifies the tag message" msgstr "Укажите описание тега" msgid "Specifies the tag name" msgstr "Укажите имя тега" #, fuzzy msgid "Spelling Suggestions" msgstr "Советы по правописанию" msgid "Squash" msgstr "Объединить (squash)" msgid "Squash the merged commits into a single commit" msgstr "Объединить слитые коммиты в один коммит" msgid "Stage" msgstr "Добавить к коммиту" msgid "Stage / Unstage" msgstr "Добавить / Убрать" msgid "Stage All Untracked" msgstr "Добавить к коммиту все неотслеживемые файлы" msgid "Stage Changed Files To Commit" msgstr "Добавить к коммиту измененные файлы" msgid "Stage Diff Hunk" msgstr "Добавить эту часть к коммиту" msgid "Stage Modified" msgstr "Добавить к коммиту измененые файлы" msgid "Stage Selected" msgstr "Добавить к коммиту" msgid "Stage Selected Lines" msgstr "Добавить к коммиту выделенные линии" msgid "Stage Unmerged" msgstr "Подготовить не слитые" msgid "Stage Untracked" msgstr "Добавить к коммиту не отслеживаемые файлы" msgid "Stage and Commit" msgstr "Добавить к коммиту и закоммитить" msgid "Stage and commit?" msgstr "Добавить к коммиту и закоммитить?" msgid "Stage conflicts" msgstr "Конфликты добавления к коммиту" msgid "Stage conflicts?" msgstr "Добавить к коммиту конфликтующие файлы?" msgid "Stage/unstage selected paths for commit" msgstr "Добавить/убрать выбранные пути к/из коммита" msgid "Staged" msgstr "Подготовленно к коммиту" #, python-format msgid "Staging: %s" msgstr "Добавление к коммиту: %s" msgid "Start Interactive Rebase..." msgstr "Начать интерактивное перемещение (rebase)..." msgid "Starting Revision" msgstr "Начальная версия" msgid "Stash" msgstr "Спрятать (stash)" #, fuzzy msgid "Stash Index" msgstr "Спрятать (stash)" #, fuzzy msgid "Stash staged changes only" msgstr "Закоммитить подготовленные изменения" #, fuzzy msgid "Stash unstaged changes only, keeping staged changes" msgstr "Отменить незафиксированные изменения по выбранным путям." msgid "Stash..." msgstr "Спрятать (stash)..." msgid "Status" msgstr "Статус" msgid "Stop tracking paths" msgstr "" msgid "Submodules" msgstr "" msgid "Summarize Merge Commits" msgstr "" msgid "Summary" msgstr "Описание" msgid "Tab Width" msgstr "Ширина табов" msgid "Tag" msgstr "Тег" msgid "Tag Created" msgstr "Тег создан" msgid "Tag message..." msgstr "Описание тега..." msgid "Tag-signing was requested but the tag message is empty." msgstr "Требуется подписать тег, но описание тега пустое." msgid "Tags" msgstr "" msgid "Text Width" msgstr "Ширина текста" msgid "The branch will be no longer available." msgstr "" #, python-format msgid "The branch will be reset using \"git reset --hard %s\"" msgstr "" #, python-format msgid "The branch will be reset using \"git reset --merge %s\"" msgstr "" #, python-format msgid "The branch will be reset using \"git reset --mixed %s\"" msgstr "" #, python-format msgid "The branch will be reset using \"git reset --soft %s\"" msgstr "" msgid "The commit message will be cleared." msgstr "Комментарий к коммиту был очищен." #, python-format msgid "The file \"%s\" exists and will be overwritten." msgstr "Файл \"%s\" существует и будет перезаписан." msgid "The following files will be deleted:" msgstr "Следующие файлы будут удалены:" msgid "The revision expression cannot be empty." msgstr "Поле версии не может быть пустым." #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be reset using \"git reset --keep %s\"" msgstr "" msgid "This cannot be undone. Clear commit message?" msgstr "Это не может быть отменено. Очистить комментарий к коммиту?" msgid "" "This commit has already been published.\n" "This operation will rewrite published history.\n" "You probably don't want to do this." msgstr "" "Этот коммит уже опубликован.\n" "Данная операция перепишет историю на сервере.\n" "Возможно лучше этого не делать." #, fuzzy msgid "" "This operation drops uncommitted changes.\n" "These changes cannot be recovered." msgstr "" "Эта операция отменит незакомиченные изменения.\n" "Эти изменения нельзя будет восстановить" msgid "" "This operation removes uncommitted edits from selected files.\n" "These changes cannot be recovered." msgstr "" "Эта операция отменит незакомиченные изменения.\n" "Эти изменения нельзя будет восстановить" msgid "" "This operation removes unstaged edits from selected files.\n" "These changes cannot be recovered." msgstr "" "Эта операция отменит незакомиченные изменения.\n" "Эти изменения нельзя будет восстановить" msgid "" "This repository is currently being rebased.\n" "Resolve conflicts, commit changes, and run:\n" " Rebase > Continue" msgstr "" "Этот репозиторий сейчас будет перемещен (rebase).\n" "Исправьте конфликты, закоммитьте изменения, и запустите:\n" " Переместить (rebase) > Продолжить" msgid "" "This repository is in the middle of a merge.\n" "Resolve conflicts and commit changes." msgstr "" "Этот репозиторий в процессе слияния (merge).\n" "Исправьте конфликты и закоммитьте изменения." msgid "Toggle Enabled" msgstr "" #, fuzzy msgid "Toggle the branches filter" msgstr "Включить фильтр путей" msgid "Toggle the paths filter" msgstr "Включить фильтр путей" msgid "Tracking Branch" msgstr "Ветвь слежения" msgid "Tracking branch" msgstr "Отслеживаемая ветвь" msgid "Traditional Chinese (Taiwan) translation" msgstr "" msgid "Translators" msgstr "" msgid "Turkish translation" msgstr "" msgid "URL" msgstr "" #, python-format msgid "URL: %s" msgstr "" msgid "Ukranian translation" msgstr "" msgid "Unable to rebase" msgstr "Не могу переместить (rebase)" #, python-format msgid "Unable to set URL for \"%(name)s\" to \"%(url)s\"" msgstr "" msgid "Undo" msgstr "Отменить" msgid "Unmerged" msgstr "Не объединено" msgid "Unstage" msgstr "Убрать из коммита" msgid "Unstage All" msgstr "Убрать все из коммита" msgid "Unstage Diff Hunk" msgstr "Убрать эту часть из коммита" msgid "Unstage From Commit" msgstr "Убрать из коммита" msgid "Unstage Selected" msgstr "Убрать из коммита" msgid "Unstage Selected Lines" msgstr "Убрать из коммита выбранные линии" #, python-format msgid "Unstaging: %s" msgstr "Удаление из коммита: %s" msgid "Untrack Selected" msgstr "Убрать выбранные файлы из контроля версий" msgid "Untracked" msgstr "Не добавлены в контроль версий" #, python-format msgid "Untracking: %s" msgstr "Не добавлено в контроль версий: %s" msgid "Update All Submodules..." msgstr "" msgid "Update Existing Branch:" msgstr "Обновить имеющуюся ветвь:" #, fuzzy msgid "Update Submodule" msgstr "Обновлено" msgid "Update Submodule..." msgstr "" msgid "Update Submodules" msgstr "" msgid "Update all submodules?" msgstr "" msgid "Update submodules..." msgstr "" msgid "Update this submodule" msgstr "" msgid "Update this submodule?" msgstr "" msgid "Updating" msgstr "Обновление" msgid "User Name" msgstr "Имя пользователя" #, fuzzy msgid "Version" msgstr "Версия" msgid "View" msgstr "Вид" msgid "View History..." msgstr "Показать историю..." msgid "View history for selected paths" msgstr "Показать историю для выбранного пути" msgid "Visualize" msgstr "Визуализировать" msgid "Visualize All Branches..." msgstr "Отобразить все ветви" msgid "Visualize Current Branch..." msgstr "Отобразить текущую ветвь..." msgid "Whether to sign the tag (git tag -s)" msgstr "Подписать тег (git tag -s)" msgid "Would you like to stage and commit all modified files?" msgstr "Вы хотить добавить к коммиту и закоммитить все измененные файлы?" msgid "XOR" msgstr "" msgid "Yes" msgstr "" msgid "" "You are in the middle of a merge.\n" "Cannot amend while merging." msgstr "" "Вы находитесь в процессе слияния (merge).\n" "Нельзя отменить коммит во время слияния." msgid "You cannot rebase with uncommitted changes." msgstr "Вы не можете выполнить перемещение (rebase) с незакомиченными изменениями." msgid "You must specify a revision to merge." msgstr "Вы должны выбрать версию для слияния (merge)." msgid "You must specify a revision to view." msgstr "Вы должны выбрать версию для просмотра." msgid "Zoom In" msgstr "Приблизить" msgid "Zoom Out" msgstr "Отдалить" msgid "Zoom to Fit" msgstr "Подогнать по размеру" msgid "command-line arguments" msgstr "фраза для поиска / аргументы командной строки" msgid "error: unable to execute git" msgstr "" #, python-format msgid "exit code %s" msgstr "код завершения %s" #, python-format msgid "fatal: \"%s\" is not a directory. Please specify a correct --repo ." msgstr "fatal: \"%s\" не является каталогом. Пожалуйста, укажите корректный --repo ." #, python-format msgid "git cola version %s" msgstr "" msgid "git-cola" msgstr "" msgid "git-cola diff" msgstr "" msgid "grep result..." msgstr "результаты поиска..." msgid "hotkeys.html" msgstr "" msgid "unknown" msgstr "неизвестно" msgid "vX.Y.Z" msgstr "" msgid "x 1" msgstr "" msgid "x 1.5" msgstr "" msgid "x 2" msgstr "" msgid "yyyy-MM-dd" msgstr "" #~ msgid "" #~ "\n" #~ "\n" #~ "A good replacement for %s\n" #~ "is placing values for the user.name and\n" #~ "user.email settings into your personal\n" #~ "~/.gitconfig file.\n" #~ msgstr "" #~ "\n" #~ "\n" #~ "Вместо использования %s можно\n" #~ "сохранить значения user.name и\n" #~ "user.email в Вашем персональном\n" #~ "файле ~/.gitconfig.\n" #~ msgid "" #~ "\n" #~ "This is due to a known issue with the\n" #~ "Tcl binary distributed by Cygwin." #~ msgstr "" #~ "\n" #~ "Это известная проблема с Tcl,\n" #~ "распространяемым Cygwin." #, fuzzy #~ msgid "\"%s\" returned exit status %d" #~ msgstr "\"%(command)s\" завершилась с кодом %(status)d" #~ msgid "\"git commit\" returned exit code %s" #~ msgstr "\"git commit\" вернул код %s" #~ msgid "%s ... %*i of %*i %s (%3i%%)" #~ msgstr "%s ... %*i из %*i %s (%3i%%)" #~ msgid "%s Repository" #~ msgstr "для репозитория %s" #~ msgid "%s of %s" #~ msgstr "%s из %s" #~ msgid "'%s' is not an acceptable branch name." #~ msgstr "Недопустимое название ветви '%s'." #~ msgid "* Binary file (not showing content)." #~ msgstr "* Двоичный файл (содержимое не показано)" #~ msgid "A branch is required for 'Merged Into'." #~ msgstr "Для опции 'Объединено с' требуется указать ветвь." #~ msgid "Abort completed. Ready." #~ msgstr "Прервано." #~ msgid "Abort failed." #~ msgstr "Прервать не удалось." #~ msgid "Aborted checkout of '%s' (file level merging is required)." #~ msgstr "Прерван переход на '%s' (требуется объединение на уровне файлов)" #~ msgid "Already up-to-date." #~ msgstr "И так последняя версия" #~ msgid "Always (Do not perform merge checks)" #~ msgstr "Всегда (не выполнять проверку объединений)" #~ msgid "Always (Do not perform merge test.)" #~ msgstr "Всегда (не выполнять проверку на объединение)" #~ msgid "Amended Commit Message:" #~ msgstr "Комментарий к исправленному состоянию:" #~ msgid "Amended Initial Commit Message:" #~ msgstr "Комментарий к исправленному первоначальному состоянию:" #~ msgid "Amended Merge Commit Message:" #~ msgstr "Комментарий к исправленному объединению:" #~ msgid "Annotation complete." #~ msgstr "Аннотация завершена." #~ msgid "Any unstaged changes will be permanently lost by the revert." #~ msgstr "Любые изменения, не подготовленные к сохранению, будут потеряны при данной операции." #~ msgid "Apply/Reverse Hunk" #~ msgstr "Применить/Убрать изменение" #~ msgid "Arbitrary URL:" #~ msgstr "по указанному URL:" #~ msgid "" #~ "Branch '%s' already exists.\n" #~ "\n" #~ "It cannot fast-forward to %s.\n" #~ "A merge is required." #~ msgstr "" #~ "Ветвь '%s' уже существует.\n" #~ "\n" #~ "Она не может быть прокручена(fast-forward) к %s.\n" #~ "Требуется объединение." #~ msgid "Branch '%s' does not exist." #~ msgstr "Ветвь '%s' не существует " #, fuzzy #~ msgid "Branch created" #~ msgstr "Название ветви" #~ msgid "Browse %s's Files" #~ msgstr "Показать файлы ветви %s" #~ msgid "Browse Branch Files" #~ msgstr "Показать файлы ветви" #, fuzzy #~ msgid "Browse Revision..." #~ msgstr "Версия" #~ msgid "Calling commit-msg hook..." #~ msgstr "Вызов программы поддержки репозитория commit-msg..." #~ msgid "" #~ "Cannot abort while amending.\n" #~ "\n" #~ "You must finish amending this commit.\n" #~ msgstr "" #~ "Невозможно прервать исправление.\n" #~ "\n" #~ "Завершите текущее исправление сохраненного состояния.\n" #~ msgid "" #~ "Cannot amend while merging.\n" #~ "\n" #~ "You are currently in the middle of a merge that has not been fully completed. You cannot amend the prior commit unless you first abort the current merge activity.\n" #~ msgstr "" #~ "Невозможно исправить состояние во время объединения.\n" #~ "\n" #~ "Текущее объединение не завершено. Невозможно исправить предыдущее сохраненное состояние не прерывая текущее объединение.\n" #~ msgid "Cannot determine HEAD. See console output for details." #~ msgstr "Не могу определить HEAD. Дополнительная информация на консоли." #~ msgid "Cannot fetch branches and objects. See console output for details." #~ msgstr "Не могу получить ветви и объекты. Дополнительная информация на консоли." #~ msgid "Cannot fetch tags. See console output for details." #~ msgstr "Не могу получить метки. Дополнительная информация на консоли." #~ msgid "Cannot find git in PATH." #~ msgstr "git не найден в PATH." #~ msgid "" #~ "Cannot merge while amending.\n" #~ "\n" #~ "You must finish amending this commit before starting any type of merge.\n" #~ msgstr "" #~ "Невозможно выполнить объединение во время исправления.\n" #~ "\n" #~ "Завершите исправление данного состояния перед выполнением операции объединения.\n" #~ msgid "Cannot move to top of working directory:" #~ msgstr "Невозможно перейти к корню рабочего каталога репозитория: " #~ msgid "Cannot parse Git version string:" #~ msgstr "Невозможно распознать строку версии Git: " #~ msgid "Cannot resolve %s as a commit." #~ msgstr "Не могу распознать %s как состояние." #~ msgid "Cannot use funny .git directory:" #~ msgstr "Каталог.git испорчен: " #~ msgid "Cannot write shortcut:" #~ msgstr "Невозможно записать ссылку:" #~ msgid "Change Font" #~ msgstr "Изменить шрифт" #~ msgid "Checked out '%s'." #~ msgstr "Ветвь '%s' сделана текущей." #~ msgid "Clone Type:" #~ msgstr "Тип клона:" #~ msgid "Clone failed." #~ msgstr "Клонирование не удалось." #~ msgid "Cloning from %s" #~ msgstr "Клонирование %s" #~ msgid "Commit %s appears to be corrupt" #~ msgstr "Состояние %s выглядит поврежденным" #~ msgid "Commit declined by commit-msg hook." #~ msgstr "Сохранение прервано программой поддержки репозитория commit-msg" #~ msgid "Commit declined by pre-commit hook." #~ msgstr "Сохранение прервано программой поддержки репозитория pre-commit" #~ msgid "Commit failed: %s" #~ msgstr "Не удалось создать коммит: %s" #~ msgid "Commit@@noun" #~ msgstr "Состояние" #~ msgid "Compress Database" #~ msgstr "Сжать базу данных" #~ msgid "Compressing the object database" #~ msgstr "Сжатие базы объектов" #~ msgid "Copied Or Moved Here By:" #~ msgstr "Скопировано/перемещено в:" #~ msgid "Copying objects" #~ msgstr "Копирование objects" #~ msgid "Counting objects" #~ msgstr "Считаю объекты" #~ msgid "Create Desktop Icon" #~ msgstr "Создать ярлык на рабочем столе" #~ msgid "Created commit: %s" #~ msgstr "Создан коммит: %s" #~ msgid "Creating working directory" #~ msgstr "Создаю рабочий каталог" #~ msgid "Current Branch:" #~ msgstr "Текущая ветвь:" #~ msgid "Database Statistics" #~ msgstr "Статистика базы данных" #~ msgid "Decrease Font Size" #~ msgstr "Уменьшить размер шрифта" #~ msgid "Delete Local Branch" #~ msgstr "Удалить локальную ветвь" #~ msgid "Delete Only If" #~ msgstr "Удалить только в случае, если" #~ msgid "Delete Only If Merged Into" #~ msgstr "Удалить только в случае, если было объединение с" #~ msgid "Destination Repository" #~ msgstr "Репозиторий назначения" #~ msgid "Detach From Local Branch" #~ msgstr "Отсоединить от локальной ветви" #~ msgid "Diff/Console Font" #~ msgstr "Шрифт консоли и изменений (diff)" #~ msgid "Directory %s already exists." #~ msgstr "Каталог '%s' уже существует." #~ msgid "Disk space used by loose objects" #~ msgstr "Объем дискового пространства, занятый несвязанными объектами" #~ msgid "Disk space used by packed objects" #~ msgstr "Объем дискового пространства, занятый упакованными объектами" #~ msgid "Do Nothing" #~ msgstr "Ничего не делать" #~ msgid "Enter Git Repository" #~ msgstr "Введите git репозиторий" #, fuzzy #~ msgid "Error %s" #~ msgstr "Ошибки: %s" #~ msgid "Error loading commit data for amend:" #~ msgstr "Ошибка при загрузке данных для исправления сохраненного состояния:" #~ msgid "Error: Command Failed" #~ msgstr "Ошибка: не удалось выполнить команду" #~ msgid "Errors: %s" #~ msgstr "Ошибки: %s" #~ msgid "Exit code: %s" #~ msgstr "Код завершения: %s" #~ msgid "Failed to completely save options:" #~ msgstr "Не удалось полностью сохранить настройки:" #~ msgid "Failed to configure origin" #~ msgstr "Не могу сконфигурировать исходный репозиторий." #~ msgid "Failed to create repository %s:" #~ msgstr "Не удалось создать репозиторий %s:" #~ msgid "" #~ "Failed to delete branches:\n" #~ "%s" #~ msgstr "" #~ "Не удалось удалить ветви:\n" #~ "%s" #~ msgid "Failed to open repository %s:" #~ msgstr "Не удалось открыть репозиторий %s:" #~ msgid "Failed to rename '%s'." #~ msgstr "Не удалось переименовать '%s'. " #~ msgid "" #~ "Failed to set current branch.\n" #~ "\n" #~ "This working directory is only partially switched. We successfully updated your files, but failed to update an internal Git file.\n" #~ "\n" #~ "This should not have occurred. %s will now close and give up." #~ msgstr "" #~ "Не удалось установить текущую ветвь.\n" #~ "\n" #~ "Ваш рабочий каталог обновлен только частично. Были обновлены все файлы кроме служебных файлов Git. \n" #~ "\n" #~ "Этого не должно было произойти. %s завершается." #~ msgid "Failed to stage selected hunk." #~ msgstr "Не удалось подготовить к сохранению выбранную часть." #~ msgid "Failed to unstage selected hunk." #~ msgstr "Не удалось исключить выбранную часть." #~ msgid "Failed to update '%s'." #~ msgstr "Не удалось обновить '%s'." #~ msgid "Fast Forward Only " #~ msgstr "Только Fast Forward" #~ msgid "Fetch from" #~ msgstr "Получение из" #~ msgid "Fetching new changes from %s" #~ msgstr "Получение изменений из %s " #~ msgid "File level merge required." #~ msgstr "Требуется объединение на уровне файлов." #~ msgid "Font Example" #~ msgstr "Пример текста" #~ msgid "Font Family" #~ msgstr "Шрифт" #~ msgid "Force overwrite existing branch (may discard changes)" #~ msgstr "Намеренно переписать существующую ветвь (возможна потеря изменений)" #~ msgid "From Repository" #~ msgstr "Из репозитория" #~ msgid "Full Copy (Slower, Redundant Backup)" #~ msgstr "Полная копия (Медленный, создает резервную копию)" #~ msgid "GPG-signed" #~ msgstr "Подписан GPG" #~ msgid "Garbage files" #~ msgstr "Мусор" #~ msgid "Git Repository (subproject)" #~ msgstr "Репозиторий Git (подпроект)" #~ msgid "Git directory not found:" #~ msgstr "Каталог Git не найден:" #~ msgid "" #~ "Git version cannot be determined.\n" #~ "\n" #~ "%s claims it is version '%s'.\n" #~ "\n" #~ "%s requires at least Git 1.5.0 or later.\n" #~ "\n" #~ "Assume '%s' is version 1.5.0?\n" #~ msgstr "" #~ "Невозможно определить версию Git\n" #~ "%s указывает на версию '%s'.\n" #~ "\n" #~ "для %s требуется версия Git, начиная с 1.5.0\n" #~ "\n" #~ "Принять '%s' как версию 1.5.0?\n" #~ msgid "Hardlinks are unavailable. Falling back to copying." #~ msgstr "\"Жесткие ссылки\" не доступны. Буду использовать копирование." #~ msgid "In File:" #~ msgstr "Файл:" #~ msgid "Increase Font Size" #~ msgstr "Увеличить размер шрифта" #, fuzzy #~ msgid "Index" #~ msgstr "Ошибка индекса" #~ msgid "Initial Commit Message:" #~ msgstr "Комментарий к первому состоянию:" #~ msgid "Initial file checkout failed." #~ msgstr "Не удалось получить начальное состояние файлов репозитория." #~ msgid "Invalid GIT_COMMITTER_IDENT:" #~ msgstr "Неверный GIT_COMMITTER_IDENT:" #~ msgid "Invalid date from Git: %s" #~ msgstr "Неправильная дата в репозитории: %s" #~ msgid "Invalid font specified in %s:" #~ msgstr "В %s установлен неверный шрифт:" #~ msgid "Invalid spell checking configuration" #~ msgstr "Неправильная конфигурация программы проверки правописания" #~ msgid "KiB" #~ msgstr "КБ" #~ msgid "" #~ "Last scanned state does not match repository state.\n" #~ "\n" #~ "Another Git program has modified this repository since the last scan. A rescan must be performed before a merge can be performed.\n" #~ "\n" #~ "The rescan will be automatically started now.\n" #~ msgstr "" #~ "Последнее прочитанное состояние репозитория не соответствует текущему.\n" #~ "\n" #~ "С момента последней проверки репозиторий был изменен другой программой Git. Необходимо перечитать репозиторий, прежде чем изменять текущую ветвь.\n" #~ "\n" #~ "Это будет сделано сейчас автоматически.\n" #~ msgid "" #~ "Last scanned state does not match repository state.\n" #~ "\n" #~ "Another Git program has modified this repository since the last scan. A rescan must be performed before another commit can be created.\n" #~ "\n" #~ "The rescan will be automatically started now.\n" #~ msgstr "" #~ "Последнее прочитанное состояние репозитория не соответствует текущему.\n" #~ "\n" #~ "С момента последней проверки репозиторий был изменен другой программой Git. Необходимо перечитать репозиторий, прежде чем изменять текущую ветвь. \n" #~ "\n" #~ "Это будет сделано сейчас автоматически.\n" #~ msgid "" #~ "Last scanned state does not match repository state.\n" #~ "\n" #~ "Another Git program has modified this repository since the last scan. A rescan must be performed before the current branch can be changed.\n" #~ "\n" #~ "The rescan will be automatically started now.\n" #~ msgstr "" #~ "Последнее прочитанное состояние репозитория не соответствует текущему.\n" #~ "\n" #~ "С момента последней проверки репозиторий был изменен другой программой Git. Необходимо перечитать репозиторий, прежде чем изменять текущую ветвь.\n" #~ "\n" #~ "Это будет сделано сейчас автоматически.\n" #~ msgid "Linking objects" #~ msgstr "Создание ссылок на objects" #~ msgid "Loading annotation..." #~ msgstr "Загрузка аннотации..." #~ msgid "Loading copy/move tracking annotations..." #~ msgstr "Загрузка аннотации копирований/переименований..." #~ msgid "Loading original location annotations..." #~ msgstr "Загрузка аннотаций первоначального положения объекта..." #~ msgid "Local Branches" #~ msgstr "Локальные ветви" #~ msgid "Local Merge..." #~ msgstr "Локальное объединение..." #~ msgid "Location %s already exists." #~ msgstr "Путь '%s' уже существует." #~ msgid "Main Font" #~ msgstr "Шрифт интерфейса" #~ msgid "Match Tracking Branch Name" #~ msgstr "Взять из имен ветвей слежения" #~ msgid "Match Tracking Branches" #~ msgstr "Имя новой ветви взять из имен ветвей слежения" #~ msgid "Merge completed successfully." #~ msgstr "Объединение успешно завершено." #~ msgid "Merge strategy '%s' not supported." #~ msgstr "Стратегия объединения '%s' не поддерживается." #~ msgid "Merged Into:" #~ msgstr "Объединено с:" #~ msgid "Merging %s and %s..." #~ msgstr "Объединение %s и %s..." #~ msgid "Modified, not staged" #~ msgstr "Изменено, не подготовлено" #~ msgid "New Branch Name Template" #~ msgstr "Шаблон для имени новой ветви" #~ msgid "New Commit" #~ msgstr "Новое состояние" #~ msgid "New Name:" #~ msgstr "Новое название:" #~ msgid "Next >" #~ msgstr "Дальше >" #~ msgid "" #~ "No changes to commit.\n" #~ "\n" #~ "No files were modified by this commit and it was not a merge commit.\n" #~ "\n" #~ "A rescan will be automatically started now.\n" #~ msgstr "" #~ "Отсутствуют изменения для сохранения.\n" #~ "\n" #~ "Ни один файл не был изменен и не было объединения.\n" #~ "\n" #~ "Сейчас автоматически запустится перечитывание репозитория.\n" #~ msgid "No default branch obtained." #~ msgstr "Не было получено ветви по умолчанию." #~ msgid "" #~ "No differences detected.\n" #~ "\n" #~ "%s has no changes.\n" #~ "\n" #~ "The modification date of this file was updated by another application, but the content within the file was not changed.\n" #~ "\n" #~ "A rescan will be automatically started to find other files which may have the same state." #~ msgstr "" #~ "Изменений не обнаружено.\n" #~ "\n" #~ "в %s отутствуют изменения.\n" #~ "\n" #~ "Дата изменения файла была обновлена другой программой, но содержимое файла осталось прежним.\n" #~ "\n" #~ "Сейчас будет запущено перечитывание репозитория, чтобы найти подобные файлы." #~ msgid "No working directory" #~ msgstr "Отсутствует рабочий каталог" #~ msgid "Number of loose objects" #~ msgstr "Количество несвязанных объектов" #~ msgid "Number of packed objects" #~ msgstr "Количество упакованных объектов" #~ msgid "Number of packs" #~ msgstr "Количество pack-файлов" #~ msgid "On Debian-based systems try: sudo apt-get install python-pyinotify" #~ msgstr "Если система основана на Debian попробуйте: sudo apt-get install python-pyinotify" #~ msgid "One or more of the merge tests failed because you have not fetched the necessary commits. Try fetching from %s first." #~ msgstr "Один или несколько тестов на объединение не прошли, потому что Вы не получили необходимые состояния. Попытайтесь получить их из %s." #~ msgid "Options" #~ msgstr "Настройки" #~ msgid "Original File:" #~ msgstr "Исходный файл:" #~ msgid "Originally By:" #~ msgstr "Источник:" #~ msgid "" #~ "Output:\n" #~ "%s" #~ msgstr "" #~ "Вывод:\n" #~ "%s" #~ msgid "Output: %s" #~ msgstr "Вывод: %s" #~ msgid "Packed objects waiting for pruning" #~ msgstr "Несвязанные объекты, которые можно удалить" #~ msgid "Path to git repository" #~ msgstr "Путь к git репозиторию" #~ msgid "Please select one or more branches to delete." #~ msgstr "Укажите одну или несколько ветвей для удаления." #~ msgid "Please supply a branch name." #~ msgstr "Укажите название ветви." #~ msgid "Portions staged for commit" #~ msgstr "Части, подготовленные для сохранения" #~ msgid "" #~ "Possible environment issues exist.\n" #~ "\n" #~ "The following environment variables are probably\n" #~ "going to be ignored by any Git subprocess run\n" #~ "by %s:\n" #~ "\n" #~ msgstr "" #~ "Возможны ошибки в переменных окружения.\n" #~ "\n" #~ "Переменные окружения, которые возможно\n" #~ "будут проигнорированы командами Git,\n" #~ "запущенными из %s\n" #~ "\n" #~ msgid "Preferences..." #~ msgstr "Настройки..." #~ msgid "Prune Tracking Branches During Fetch" #~ msgstr "Чистка ветвей слежения при получении изменений" #~ msgid "Pruning tracking branches deleted from %s" #~ msgstr "Чистка ветвей слежения, удаленных из %s" #~ msgid "Push Branches" #~ msgstr "Отправить изменения в ветвях" #~ msgid "Push to" #~ msgstr "Отправить" #~ msgid "Pushing %s %s to %s" #~ msgstr "Отправка %s %s в %s" #~ msgid "Reading %s..." #~ msgstr "Чтение %s..." #~ msgid "Ready to commit." #~ msgstr "Подготовлено для сохранения" #~ msgid "Ready." #~ msgstr "Готово." #, fuzzy #~ msgid "Rebase Branch" #~ msgstr "Переименование ветви" #, fuzzy #~ msgid "Rebase..." #~ msgstr "Сбросить..." #~ msgid "" #~ "Recovering deleted branches is difficult.\n" #~ "\n" #~ "Delete the selected branches?" #~ msgstr "" #~ "Восстановить удаленные ветви сложно.\n" #~ "\n" #~ "Продолжить?" #~ msgid "" #~ "Recovering deleted branches is difficult. \n" #~ "\n" #~ " Delete the selected branches?" #~ msgstr "" #~ "Восстанавливать удаленные ветви сложно. \n" #~ "\n" #~ " Удалить выбранные ветви?" #~ msgid "Refreshing file status..." #~ msgstr "Обновление информации о состоянии файлов..." #, fuzzy #~ msgid "Remote Branches" #~ msgstr "Внешняя ветвь" #~ msgid "Remote:" #~ msgstr "внешний:" #~ msgid "Rename remote?" #~ msgstr "Переименовать внешнюю ветвь?" #~ msgid "Repository" #~ msgstr "Репозиторий" #~ msgid "Requires merge resolution" #~ msgstr "Требуется разрешение конфликта при объединении" #~ msgid "Rescan" #~ msgstr "Перечитать" #~ msgid "" #~ "Reset changes?\n" #~ "\n" #~ "Resetting the changes will cause *ALL* uncommitted changes to be lost.\n" #~ "\n" #~ "Continue with resetting the current changes?" #~ msgstr "" #~ "Прервать объединение?\n" #~ "\n" #~ "Прерывание объединения приведет к потере *ВСЕХ* несохраненных изменений.\n" #~ "\n" #~ "Продолжить?" #~ msgid "Revert changes in these %i files?" #~ msgstr "Отменить изменения в %i файле(-ах)?" #~ msgid "Select File" #~ msgstr "Выбрать файл" #~ msgid "Select file from \"%s\"" #~ msgstr "Выбрать файл из \"%s\"" #~ msgid "Shared (Fastest, Not Recommended, No Backup)" #~ msgstr "Общий (Самый быстрый, не рекомендуется, без резервной копии)" #~ msgid "Shared only available for local repository." #~ msgstr "Общий клон возможен только для локального репозитория." #~ msgid "Show Less Context" #~ msgstr "Меньше контекста" #~ msgid "Show More Context" #~ msgstr "Больше контекста" #~ msgid "Source Branches" #~ msgstr "Исходные ветви" #~ msgid "Spell Checker Failed" #~ msgstr "Ошибка проверки правописания" #~ msgid "Spell checker silently failed on startup" #~ msgstr "Программа проверки правописания не смогла запустится" #~ msgid "Spell checking is unavailable" #~ msgstr "Проверка правописания не доступна" #~ msgid "Spelling Dictionary:" #~ msgstr "Словарь для проверки правописания:" #~ msgid "Stage Hunk For Commit" #~ msgstr "Подготовить часть для сохранения" #~ msgid "Staged Changes (Will Commit)" #~ msgstr "Подготовлено (будет сохранено)" #~ msgid "Staged for commit, missing" #~ msgstr "Подготовлено для сохранения, отсутствует" #~ msgid "Staged for removal" #~ msgstr "Подготовлено для удаления" #~ msgid "Staged for removal, still present" #~ msgstr "Подготовлено для удаления, еще не удалено" #~ msgid "Staging Area" #~ msgstr "Управление коммитом" #~ msgid "Staging area (index) is already locked." #~ msgstr "Рабочая область заблокирована другим процессом." #~ msgid "Standard (Fast, Semi-Redundant, Hardlinks)" #~ msgstr "Стандартный (Быстрый, полуизбыточный, \"жесткие\" ссылки)" #~ msgid "Standard only available for local repository." #~ msgstr "Стандартный клон возможен только для локального репозитория." #~ msgid "Starting gitk... please wait..." #~ msgstr "Запускается gitk... пожалуйста, ждите..." #~ msgid "Staying on branch '%s'." #~ msgstr "Ветвь '%s' остается текущей." #~ msgid "Success" #~ msgstr "Процесс успешно завершен" #~ msgid "Summary:" #~ msgstr "Описание:" #~ msgid "The 'master' branch has not been initialized." #~ msgstr "Не инициализирована ветвь 'master'." #~ msgid "The following branches are not completely merged into %s:" #~ msgstr "Следующие ветви объединены с %s не полностью:" #~ msgid "" #~ "The following branches are not completely merged into %s:\n" #~ "\n" #~ " - %s" #~ msgstr "" #~ "Следующие ветви объединены с %s не полностью:\n" #~ " - %s" #~ msgid "" #~ "There is nothing to amend.\n" #~ "\n" #~ "You are about to create the initial commit. There is no commit before this to amend.\n" #~ msgstr "" #~ "Отсутствует состояние для исправления.\n" #~ "\n" #~ "Вы создаете первое состояние в репозитории, здесь еще нечего исправлять.\n" #~ msgid "This Detached Checkout" #~ msgstr "Текущее отсоединенное состояние" #~ msgid "" #~ "This PyQt4 does not include QtWebKit.\n" #~ "The keyboard shortcuts feature is unavailable." #~ msgstr "" #~ "PyQt4 не включен в QtWebKit.\n" #~ "Горячие клавиши не доступны." #~ msgid "" #~ "This is example text.\n" #~ "If you like this text, it can be your font." #~ msgstr "" #~ "Это пример текста.\n" #~ "Если Вам нравится этот текст, это может быть Ваш шрифт." #~ msgid "" #~ "This repository currently has approximately %i loose objects.\n" #~ "\n" #~ "To maintain optimal performance it is strongly recommended that you compress the database when more than %i loose objects exist.\n" #~ "\n" #~ "Compress the database now?" #~ msgstr "" #~ "Этот репозиторий сейчас содержит примерно %i свободных объектов\n" #~ "\n" #~ "Для лучшей производительности рекомендуется сжать базу данных, когда есть более %i несвязанных объектов.\n" #~ "\n" #~ "Сжать базу данных сейчас?" #~ msgid "Tracking branch %s is not a branch in the remote repository." #~ msgstr "Ветвь слежения %s не является ветвью во внешнем репозитории." #~ msgid "Transfer Options" #~ msgstr "Настройки отправки" #~ msgid "Unable to copy object: %s" #~ msgstr "Не могу скопировать объект: %s" #~ msgid "Unable to copy objects/info/alternates: %s" #~ msgstr "Не могу скопировать objects/info/alternates: %s" #~ msgid "Unable to display %s" #~ msgstr "Не могу показать %s" #~ msgid "Unable to hardlink object: %s" #~ msgstr "Не могу \"жестко связать\" объект: %s" #~ msgid "Unable to obtain your identity:" #~ msgstr "Невозможно получить информацию об авторстве:" #~ msgid "" #~ "Unable to start gitk:\n" #~ "\n" #~ "%s does not exist" #~ msgstr "" #~ "Не удалось запустить gitk:\n" #~ "\n" #~ "%s не существует" #~ msgid "Unable to unlock the index." #~ msgstr "Не удалось разблокировать индекс" #~ msgid "Unexpected EOF from spell checker" #~ msgstr "Программа проверки правописания прервала передачу данных" #~ msgid "" #~ "Unknown file state %s detected.\n" #~ "\n" #~ "File %s cannot be committed by this program.\n" #~ msgstr "" #~ "Обнаружено неизвестное состояние файла %s.\n" #~ "\n" #~ "Файл %s не может быть сохранен данной программой.\n" #~ msgid "Unlock Index" #~ msgstr "Разблокировать индекс" #~ msgid "" #~ "Unmerged files cannot be committed.\n" #~ "\n" #~ "File %s has merge conflicts. You must resolve them and stage the file before committing.\n" #~ msgstr "" #~ "Нельзя сохранить необъединенные файлы.\n" #~ "\n" #~ "Для файла %s возник конфликт объединения. Разрешите конфликт и добавьте к подготовленным файлам перед сохранением.\n" #~ msgid "Unrecognized spell checker" #~ msgstr "Нераспознаная программа проверки правописания" #~ msgid "Unstage Hunk From Commit" #~ msgstr "Не сохранять часть" #~ msgid "Unsupported spell checker" #~ msgstr "Неподдерживаемая программа проверки правописания" #~ msgid "Updating the Git index failed. A rescan will be automatically started to resynchronize git-gui." #~ msgstr "Не удалось обновить индекс Git. Состояние репозитория будетперечитано автоматически." #~ msgid "Updating working directory to '%s'..." #~ msgstr "Обновление рабочего каталога из '%s'..." #~ msgid "Updating..." #~ msgstr "Обновление..." #~ msgid "Use thin pack (for slow network connections)" #~ msgstr "Использовать thin pack (для медленных сетевых подключений)" #~ msgid "Verify Database" #~ msgstr "Проверить базу данных" #~ msgid "Verifying the object database with fsck-objects" #~ msgstr "Проверка базы объектов при помощи fsck" #~ msgid "Visualize %s's History" #~ msgstr "История ветви %s наглядно" #~ msgid "Working... please wait..." #~ msgstr "В процессе... пожалуйста, ждите..." #~ msgid "" #~ "You are in the middle of a change.\n" #~ "\n" #~ "File %s is modified.\n" #~ "\n" #~ "You should complete the current commit before starting a merge. Doing so will help you abort a failed merge, should the need arise.\n" #~ msgstr "" #~ "Изменения не сохранены.\n" #~ "\n" #~ "Файл %s изменен.\n" #~ "\n" #~ "Подготовьте и сохраните измения перед началом объединения. В случае необходимости это позволит прервать операцию объединения.\n" #~ msgid "" #~ "You are in the middle of a conflicted merge.\n" #~ "\n" #~ "File %s has merge conflicts.\n" #~ "\n" #~ "You must resolve them, stage the file, and commit to complete the current merge. Only then can you begin another merge.\n" #~ msgstr "" #~ "Предыдущее объединение не завершено из-за конфликта.\n" #~ "\n" #~ "Для файла %s возник конфликт объединения.\n" #~ "\n" #~ "Разрешите конфликт, подготовьте файл и сохраните. Только после этого можно начать следующее объединение.\n" #~ msgid "" #~ "You are no longer on a local branch.\n" #~ "\n" #~ "If you wanted to be on a branch, create one now starting from 'This Detached Checkout'." #~ msgstr "" #~ "Вы находитесь не в локальной ветви.\n" #~ "\n" #~ "Если вы хотите снова вернуться к какой-нибудь ветви, создайте ее сейчас, начиная с 'Текущего отсоединенного состояния'." #~ msgid "You must correct the above errors before committing." #~ msgstr "Прежде чем сохранить, исправьте вышеуказанные ошибки." #~ msgid "[Up To Parent]" #~ msgstr "[На уровень выше]" #~ msgid "commit-tree failed:" #~ msgstr "Программа commit-tree завершилась с ошибкой:" #~ msgid "fatal: Cannot resolve %s" #~ msgstr "критическая ошибка: невозможно разрешить %s" #~ msgid "" #~ "file notification: disabled\n" #~ "Note: install pywin32 to enable.\n" #~ msgstr "" #~ "оповещения файлов: отключено\n" #~ "Примечание: требуется установить pywin32 для включения.\n" #~ msgid "files" #~ msgstr "файлов" #~ msgid "files checked out" #~ msgstr "файлы извлечены" #~ msgid "files reset" #~ msgstr "изменения в файлах отменены" #~ msgid "git clone returned exit code %s" #~ msgstr "git clone завершился со статусом %s" #~ msgid "git tag returned exit code %s" #~ msgstr "Комманда git tag завершилась с кодом %s" #~ msgid "git-gui - a graphical user interface for Git." #~ msgstr "git-gui - графический пользовательский интерфейс к Git." #~ msgid "git-gui: fatal error" #~ msgstr "git-gui: критическая ошибка" #~ msgid "inotify enabled." #~ msgstr "inotify включено" #~ msgid "lines annotated" #~ msgstr "строк прокомментировано" #~ msgid "objects" #~ msgstr "объекты" #~ msgid "push %s" #~ msgstr "отправить %s" # carbon copy #~ msgid "remote prune %s" #~ msgstr "чистка внешнего %s" #~ msgid "update-ref failed:" #~ msgstr "Программа update-ref завершилась с ошибкой:" #~ msgid "warning" #~ msgstr "предупреждение" #~ msgid "warning: Tcl does not support encoding '%s'." #~ msgstr "предупреждение: Tcl не поддерживает кодировку '%s'." #~ msgid "write-tree failed:" #~ msgstr "Программа write-tree завершилась с ошибкой:" git-cola-3.6/po/sv.po000066400000000000000000002143311356743264500145120ustar00rootroot00000000000000# Swedish translation of git-cola. # Copyright (C) 2007, 2008 Shawn Pearce, et al. # This file is distributed under the same license as the git-cola package. # # Peter Karlsson , 2007-2008. msgid "" msgstr "" "Project-Id-Version: git-cola VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-17 01:06-0700\n" "PO-Revision-Date: 2008-03-14 07:23+0100\n" "Last-Translator: Peter Karlsson \n" "Language-Team: Swedish\n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "" "\n" "

\n" " Drag and drop or use the Add button to add\n" " patches to the list\n" "

\n" " " msgstr "" #, python-format msgid "" "\n" "
\n" " Git Cola has been translated into different languages thanks\n" " to the help of the individuals listed below.\n" "\n" "
\n" "

\n" " Translation is approximate. If you find a mistake,\n" " please let us know by opening an issue on Github:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " We invite you to participate in translation by adding or updating\n" " a translation and opening a pull request.\n" "

\n" "\n" "
\n" "\n" " " msgstr "" #, python-format msgid "" "\n" "
\n" " Git Cola version %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " msgstr "" #, python-format msgid "" "\n" "
\n" " Please use %(bug_link)s to report issues.\n" "
\n" " " msgstr "" #, python-format msgid "" "\n" " Format String Variables\n" " -----------------------\n" " %(path)s = relative file path\n" " %(abspath)s = absolute file path\n" " %(dirname)s = relative directory path\n" " %(absdirname)s = absolute directory path\n" " %(filename)s = file basename\n" " %(basename)s = file basename without extension\n" " %(ext)s = file extension\n" msgstr "" msgid "" "\n" "Commands\n" "--------\n" "pick = use commit\n" "reword = use commit, but edit the commit message\n" "edit = use commit, but stop for amending\n" "squash = use commit, but meld into previous commit\n" "fixup = like \"squash\", but discard this commit's log message\n" "exec = run command (the rest of the line) using shell\n" "\n" "These lines can be re-ordered; they are executed from top to bottom.\n" "\n" "If you disable a line here THAT COMMIT WILL BE LOST.\n" "\n" "However, if you disable everything, the rebase will be aborted.\n" "\n" "Keyboard Shortcuts\n" "------------------\n" "? = show help\n" "j = move down\n" "k = move up\n" "J = shift row down\n" "K = shift row up\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "spacebar = toggle enabled\n" "\n" "ctrl+enter = accept changes and rebase\n" "ctrl+q = cancel and abort the rebase\n" "ctrl+d = launch difftool\n" msgstr "" msgid "" "\n" "Keyboard Shortcuts\n" "------------------\n" "J, Down = Move Down\n" "K, Up = Move Up\n" "Enter = Edit Selected Files\n" "Spacebar = Open File Using Default Application\n" "Ctrl + L = Focus Text Entry Field\n" "? = Show Help\n" "\n" "The up and down arrows change focus between the text entry field\n" "and the results.\n" msgstr "" msgid " - DAG" msgstr "" #, fuzzy msgid " commits ago" msgstr "Incheckningsmeddelande för sammanslagning:" #, python-format msgid "\"%(branch)s\" has been deleted from \"%(remote)s\"." msgstr "" #, python-format msgid "\"%(command)s\" returned exit status \"%(status)d\"" msgstr "" #, python-format msgid "\"%(command)s\" returned exit status %(status)d" msgstr "" #, fuzzy, python-format msgid "\"%s\" already exists" msgstr "Grenen \"%s\" finns redan." #, python-format msgid "\"%s\" already exists, cola will create a new directory" msgstr "" #, python-format msgid "\"%s\" requires a selected file." msgstr "" msgid "#" msgstr "" #, python-format msgid "%(project)s: %(branch)s - Browse" msgstr "" #, python-format msgid "%(project)s: %(ref)s - DAG" msgstr "" #, python-format msgid "%d days ago" msgstr "" #, python-format msgid "%d hours ago" msgstr "" #, python-format msgid "%d minutes ago" msgstr "" #, python-format msgid "%d patch(es) applied." msgstr "" #, python-format msgid "%d skipped" msgstr "" #, python-format msgid "" "%s appears to contain merge conflicts.\n" "\n" "You should probably skip this file.\n" "Stage it anyways?" msgstr "" #, fuzzy, python-format msgid "%s is not a Git repository." msgstr "Gitarkiv" #, python-format msgid "%s will be removed from your bookmarks." msgstr "" #, python-format msgid "%s will be removed from your recent repositories." msgstr "" #, fuzzy, python-format msgid "%s: No such file or directory." msgstr "ödesdigert: kunde inte ta status på sökvägen %s: Fil eller katalog saknas" msgid "&Edit" msgstr "Redigera" #, fuzzy msgid "&File" msgstr "&Fil" msgid "(Amending)" msgstr "" msgid "*** Branch Point ***" msgstr "" msgid "*** Sandbox ***" msgstr "" msgid "100%" msgstr "" msgid "200%" msgstr "" msgid "25%" msgstr "" msgid "400%" msgstr "" msgid "50%" msgstr "" msgid "800%" msgstr "" msgid " ..." msgstr "" msgid "" "A commit template has not been configured.\n" "Use \"git config\" to define \"commit.template\"\n" "so that it points to a commit template." msgstr "" #, python-format msgid "A hook must be provided at \"%s\"" msgstr "" #, fuzzy, python-format msgid "A stash named \"%s\" already exists" msgstr "Filen %s finns redan." #, fuzzy msgid "Abort" msgstr "Avbryter" #, fuzzy msgid "Abort Action" msgstr "Avbryter" #, fuzzy msgid "Abort Merge" msgstr "Avbryt sammanslagning..." msgid "Abort Merge..." msgstr "Avbryt sammanslagning..." msgid "Abort the action?" msgstr "" #, fuzzy msgid "" "Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" "Recovering uncommitted changes is not possible." msgstr "" "Avbryt sammanslagning?\n" "\n" "Om du avbryter sammanslagningen kommer *ALLA* ej incheckade ändringar att gå förlorade.\n" "\n" "Gå vidare med att avbryta den aktuella sammanslagningen?" msgid "Aborting the current merge?" msgstr "" #, fuzzy msgid "About" msgstr "Om %s" msgid "About git-cola" msgstr "" msgid "Accept" msgstr "" msgid "" "Accept changes and rebase\n" "Shortcut: Ctrl+Enter" msgstr "" #, fuzzy msgid "Action Name" msgstr "Alternativ" #, fuzzy msgid "Actions" msgstr "Alternativ" #, fuzzy msgid "Actions..." msgstr "Alternativ..." msgid "Add" msgstr "" #, fuzzy msgid "Add Favorite" msgstr "Fjärr" #, fuzzy msgid "Add Remote" msgstr "Fjärr" msgid "Add Separator" msgstr "" msgid "Add Toolbar" msgstr "" msgid "" "Add and remove remote repositories using the \n" "Add(+) and Delete(-) buttons on the left-hand side.\n" "\n" "Remotes can be renamed by selecting one from the list\n" "and pressing \"enter\", or by double-clicking." msgstr "" #, fuzzy msgid "Add new remote git repository" msgstr "Inte ett Gitarkiv: %s" msgid "Add patches (+)" msgstr "" #, fuzzy msgid "Add remote" msgstr "Fjärr" msgid "Add to .gitignore" msgstr "" msgid "Add to Git Annex" msgstr "" msgid "Add to Git LFS" msgstr "" #, fuzzy msgid "Additions" msgstr "Alternativ" msgid "Advanced" msgstr "" msgid "Age" msgstr "" #, fuzzy msgid "All Repositories" msgstr "Globalt (alla arkiv)" #, python-format msgid "" "All submodules will be updated using\n" "\"%s\"" msgstr "" msgid "Allow non-fast-forward updates. Using \"force\" can cause the remote repository to lose commits; use it with care" msgstr "" msgid "Always create a merge commit when enabled, even when the merge is a fast-forward update" msgstr "" msgid "Amend" msgstr "" #, fuzzy msgid "Amend Commit" msgstr "Lägg till föregående incheckning" msgid "Amend Last Commit" msgstr "Lägg till föregående incheckning" msgid "Amend the published commit?" msgstr "" msgid "Amending" msgstr "" msgid "" "An action is still running.\n" "Terminating it could result in data loss." msgstr "" msgid "" "An unsigned, lightweight tag will be created instead.\n" "Create an unsigned tag?" msgstr "" msgid "Appearance" msgstr "" #, fuzzy msgid "Apply" msgstr "Äpple" msgid "Apply Patches" msgstr "" msgid "Apply Patches..." msgstr "" msgid "Apply and drop the selected stash (git stash pop)" msgstr "" msgid "Apply the selected stash" msgstr "" msgid "Arguments" msgstr "" msgid "Attach" msgstr "" #, fuzzy msgid "Author" msgstr "Författare:" #, fuzzy msgid "Authors" msgstr "Författare:" msgid "Auto" msgstr "" msgid "Auto-Wrap Lines" msgstr "" msgid "Basic Regexp" msgstr "" #, fuzzy msgid "Blame Viewer" msgstr "Filvisare" #, fuzzy msgid "Blame selected paths" msgstr "Byt namn på gren" #, fuzzy msgid "Blame..." msgstr "Byt namn..." msgid "Bold on dark headers instead of italic" msgstr "" msgid "Branch" msgstr "Gren" #, python-format msgid "" "Branch \"%(branch)s\" does not exist in \"%(remote)s\".\n" "A new remote branch will be published." msgstr "" #, fuzzy, python-format msgid "Branch \"%s\" already exists." msgstr "Grenen \"%s\" finns redan." msgid "Branch Diff Viewer" msgstr "" #, fuzzy msgid "Branch Exists" msgstr "Grenar" msgid "Branch Name" msgstr "Namn på gren" #, fuzzy, python-format msgid "Branch: %s" msgstr "Gren:" #, fuzzy msgid "Branches" msgstr "Gren" #, fuzzy msgid "Branches..." msgstr "Grenar" msgid "Brazilian translation" msgstr "" #, fuzzy msgid "Browse" msgstr "Bläddra" #, fuzzy msgid "Browse Commits..." msgstr "Bläddra" #, fuzzy msgid "Browse Current Branch..." msgstr "Bläddra i grenens filer" #, fuzzy msgid "Browse Other Branch..." msgstr "Bläddra filer på gren..." #, fuzzy msgid "Browse..." msgstr "Bläddra" #, fuzzy msgid "Browser" msgstr "Bläddra" #, fuzzy, python-format msgid "Browsing %s" msgstr "Lägger till %s" msgid "Bypass Commit Hooks" msgstr "" msgid "Cancel" msgstr "Avbryt" msgid "" "Cancel rebase\n" "Shortcut: Ctrl+Q" msgstr "" #, fuzzy msgid "Cannot Amend" msgstr "Kan inte skriva ikon:" #, python-format msgid "Cannot exec \"%s\": please configure a blame viewer" msgstr "" #, python-format msgid "Cannot exec \"%s\": please configure a history browser" msgstr "" #, python-format msgid "Cannot exec \"%s\": please configure your editor" msgstr "" msgid "Changed Upstream" msgstr "" msgid "Check Spelling" msgstr "" msgid "Check spelling" msgstr "" msgid "Checkout" msgstr "Checka ut" msgid "Checkout After Creation" msgstr "Checka ut när skapad" msgid "Checkout Branch" msgstr "Checka ut gren" #, fuzzy msgid "Checkout Detached HEAD" msgstr "Checka ut gren" #, fuzzy msgid "Checkout as new branch" msgstr "Checka ut gren" msgid "Checkout..." msgstr "Checka ut..." msgid "Cherry Pick" msgstr "" #, fuzzy msgid "Cherry-Pick Commit" msgstr "Kopiera incheckning" #, fuzzy msgid "Cherry-Pick..." msgstr "Checka ut..." #, fuzzy msgid "Choose Paths" msgstr "Välj %s" msgid "Choose the \"git grep\" regular expression mode" msgstr "" #, fuzzy msgid "Clear Default Repository" msgstr "Skapa nytt arkiv" #, fuzzy msgid "Clear commit message" msgstr "Incheckningsmeddelande för sammanslagning:" #, fuzzy msgid "Clear commit message?" msgstr "Incheckningsmeddelande för sammanslagning:" #, fuzzy msgid "Clear..." msgstr "Klona..." msgid "Clone" msgstr "Klona" #, fuzzy msgid "Clone Repository" msgstr "Klona befintligt arkiv" msgid "Clone..." msgstr "Klona..." #, fuzzy, python-format msgid "Cloning repository at %s" msgstr "Klona befintligt arkiv" msgid "Close" msgstr "Stäng" #, fuzzy msgid "Close..." msgstr "Klona..." #, fuzzy msgid "Collapse all" msgstr "Stäng" #, fuzzy msgid "Command" msgstr "Incheckning:" #, fuzzy msgid "Commit" msgstr "Incheckning:" #, fuzzy msgid "Commit failed" msgstr "Incheckningen misslyckades." #, fuzzy msgid "Commit staged changes" msgstr "Checkar in ändringar..." msgid "" "Commit staged changes\n" "Shortcut: Ctrl+Enter" msgstr "" #, fuzzy msgid "Commit summary" msgstr "Incheckningsmeddelande:" msgid "Commit the merge if there are no conflicts. Uncheck to leave the merge uncommitted" msgstr "" msgid "Commit@@verb" msgstr "Checka in" msgid "Compare" msgstr "" msgid "Compare All" msgstr "" msgid "Configure the remote branch as the the new upstream" msgstr "" msgid "Configure toolbar" msgstr "" #, fuzzy msgid "Console" msgstr "Stäng" msgid "Continue" msgstr "Forstätt" msgid "Copy" msgstr "Kopiera" msgid "Copy Basename to Clipboard" msgstr "" msgid "Copy Leading Path to Clipboard" msgstr "" msgid "Copy Path to Clipboard" msgstr "" msgid "Copy Relative Path to Clipboard" msgstr "" #, fuzzy msgid "Copy SHA-1" msgstr "Kopiera alla" #, fuzzy msgid "Copy..." msgstr "Kopiera" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "" msgid "Create Branch" msgstr "Skapa gren" #, fuzzy msgid "Create Patch" msgstr "Skapa gren" #, fuzzy msgid "Create Remote Branch" msgstr "Ta bort fjärrgren" #, fuzzy msgid "Create Signed Commit" msgstr "Skapade incheckningen %s: %s" #, fuzzy msgid "Create Tag" msgstr "Skapa" #, fuzzy msgid "Create Tag..." msgstr "Skapa..." msgid "Create Unsigned Tag" msgstr "" msgid "Create a merge commit even when the merge resolves as a fast-forward" msgstr "" #, fuzzy msgid "Create a new remote branch?" msgstr "Skapa ny gren" msgid "Create..." msgstr "Skapa..." #, python-format msgid "Created a new tag named \"%s\"" msgstr "" #, fuzzy msgid "Current Repository" msgstr "Skapa nytt arkiv" msgid "Custom Copy Actions" msgstr "" #, fuzzy msgid "Customize..." msgstr "Klona..." msgid "Cut" msgstr "Klipp ut" msgid "Czech translation" msgstr "" msgid "DAG..." msgstr "" msgid "Dark Theme" msgstr "" msgid "Date, Time" msgstr "" #, fuzzy msgid "Default" msgstr "Återställ standardvärden" msgid "Delete" msgstr "Ta bort" #, python-format msgid "Delete %d file(s)?" msgstr "" #, fuzzy msgid "Delete Bookmark" msgstr "Ta bort gren" #, fuzzy msgid "Delete Bookmark?" msgstr "Ta bort gren" msgid "Delete Branch" msgstr "Ta bort gren" #, fuzzy msgid "Delete Files" msgstr "Ta bort" #, fuzzy msgid "Delete Files..." msgstr "Ta bort..." #, fuzzy msgid "Delete Files?" msgstr "Ta bort" #, fuzzy msgid "Delete Remote" msgstr "Ta bort fjärrgren" #, fuzzy msgid "Delete Remote Branch" msgstr "Ta bort fjärrgren" #, fuzzy msgid "Delete Remote Branch..." msgstr "Ta bort fjärrgren" #, fuzzy msgid "Delete remote" msgstr "Ta bort fjärrgren" #, fuzzy, python-format msgid "Delete remote \"%s\"" msgstr "Ta bort fjärrgren" #, fuzzy msgid "Delete remote?" msgstr "Ta bort fjärrgren" #, fuzzy msgid "Delete selected branch?" msgstr "Ta bort fjärrgren" #, fuzzy msgid "Delete toolbar" msgstr "Ta bort gren" msgid "Delete..." msgstr "Ta bort..." #, python-format msgid "Deleting \"%s\" failed" msgstr "" #, fuzzy msgid "Deletions" msgstr "Ta bort" #, fuzzy msgid "Detach" msgstr "Ta bort gren" msgid "Detect Conflict Markers" msgstr "" msgid "Detect conflict markers in unmerged files" msgstr "" msgid "Developer" msgstr "" msgid "Diff" msgstr "" msgid "Diff Against Predecessor..." msgstr "" #, fuzzy msgid "Diff Options" msgstr "Alternativ" msgid "Diff Tool" msgstr "" msgid "Diff selected -> this" msgstr "" msgid "Diff this -> selected" msgstr "" msgid "Diffstat" msgstr "" #, fuzzy msgid "Difftool" msgstr "Alternativ" #, fuzzy msgid "Directory Exists" msgstr "Katalog:" msgid "Display Untracked Files" msgstr "" #, fuzzy msgid "Documentation" msgstr "Webbdokumentation" msgid "Drop" msgstr "" msgid "Drop Stash" msgstr "" msgid "Drop Stash?" msgstr "" #, python-format msgid "Drop the \"%s\" stash?" msgstr "" msgid "Drop the selected stash" msgstr "" #, fuzzy msgid "Edit" msgstr "Redigera" #, fuzzy msgid "Edit Rebase" msgstr "Återställ" #, fuzzy msgid "Edit Remotes" msgstr "Fjärr" msgid "Edit Remotes..." msgstr "" msgid "Edit remotes by selecting them from the list" msgstr "" msgid "Edit selected paths" msgstr "" #, fuzzy msgid "Edit..." msgstr "Redigera" #, fuzzy msgid "Editor" msgstr "Redigera" msgid "Email Address" msgstr "E-postadress" msgid "Email contributor" msgstr "" msgid "Enabled" msgstr "" #, fuzzy msgid "Enter New Branch Name" msgstr "Namn på gren" msgid "Enter a name for the new bare repo" msgstr "" msgid "Enter a name for the stash" msgstr "" #, fuzzy msgid "Error" msgstr "fel" #, fuzzy msgid "Error Cloning" msgstr "Fel vid läsning av fil:" #, fuzzy msgid "Error Creating Branch" msgstr "Skapa gren" #, fuzzy msgid "Error Creating Repository" msgstr "Skapa nytt arkiv" #, fuzzy msgid "Error Deleting Remote Branch" msgstr "Skapa gren" #, fuzzy msgid "Error Editing File" msgstr "Fel vid inläsning av differens:" #, fuzzy msgid "Error Launching Blame Viewer" msgstr "Filbläddrare" #, fuzzy msgid "Error Launching History Browser" msgstr "Filbläddrare" #, python-format msgid "Error creating remote \"%s\"" msgstr "" #, fuzzy msgid "Error creating stash" msgstr "Skapa gren" #, python-format msgid "Error deleting remote \"%s\"" msgstr "" #, python-format msgid "Error renaming \"%(name)s\" to \"%(new_name)s\"" msgstr "" #, fuzzy msgid "Error running prepare-commitmsg hook" msgstr "Anropar krok före incheckning..." #, fuzzy, python-format msgid "Error updating submodule %s" msgstr "Fel vid inläsning av differens:" #, fuzzy msgid "Error updating submodules" msgstr "Fel vid inläsning av differens:" msgid "Error: Cannot find commit template" msgstr "" msgid "Error: Stash exists" msgstr "" msgid "Error: Unconfigured commit template" msgstr "" #, python-format msgid "Error: could not clone \"%s\"" msgstr "" #, python-format msgid "Error: could not create tag \"%s\"" msgstr "" #, fuzzy, python-format msgid "Executing action %s" msgstr "Återställer ordlistan till %s." msgid "Expand all" msgstr "" msgid "Export Patches" msgstr "" msgid "Export Patches..." msgstr "" #, fuzzy msgid "Expression..." msgstr "Alternativ..." msgid "Extended Regexp" msgstr "" msgid "Extended description..." msgstr "" msgid "Fast Forward Only" msgstr "Endast snabbspolning" #, fuzzy msgid "Fast-forward only" msgstr "Endast snabbspolning" #, fuzzy msgid "Favorite repositories" msgstr "Senaste arkiven" msgid "Favorites" msgstr "" #, fuzzy msgid "Fetch" msgstr "Återställ..." msgid "Fetch Tracking Branch" msgstr "Hämta spårande gren" #, fuzzy msgid "Fetch..." msgstr "Återställ..." #, fuzzy msgid "File Browser..." msgstr "Bläddra" #, fuzzy msgid "File Differences" msgstr "Inställningar" msgid "File Saved" msgstr "" #, python-format msgid "File saved to \"%s\"" msgstr "" msgid "File system change monitoring: disabled because \"cola.inotify\" is false.\n" msgstr "" msgid "File system change monitoring: disabled because libc does not support the inotify system calls.\n" msgstr "" msgid "File system change monitoring: disabled because pywin32 is not installed.\n" msgstr "" msgid "" "File system change monitoring: disabled because the limit on the total number of inotify watches was reached. You may be able to increase the limit on the number of watches by running:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" msgstr "" #, fuzzy msgid "File system change monitoring: enabled.\n" msgstr "Lita på filändringstidsstämplar\n" #, fuzzy msgid "Filename" msgstr "Byt namn" #, fuzzy msgid "Files" msgstr "Fil:" #, fuzzy msgid "Filter branches..." msgstr "Återställ..." #, fuzzy msgid "Filter paths..." msgstr "Återställ..." #, fuzzy msgid "Find Files" msgstr "Fil:" msgid "Fixed String" msgstr "" msgid "Fixed-Width Font" msgstr "" msgid "Fixup" msgstr "" #, fuzzy msgid "Fixup Previous Commit" msgstr "Incheckningsmeddelande för sammanslagning:" msgid "Flat dark blue" msgstr "" msgid "Flat dark green" msgstr "" msgid "Flat dark grey" msgstr "" msgid "Flat dark red" msgstr "" msgid "Flat light blue" msgstr "" msgid "Flat light green" msgstr "" msgid "Flat light grey" msgstr "" msgid "Flat light red" msgstr "" msgid "Font Size" msgstr "Storlek" msgid "Force" msgstr "" msgid "Force Fetch" msgstr "" msgid "Force Fetch?" msgstr "" msgid "Force Push" msgstr "" msgid "Force Push?" msgstr "" #, fuzzy, python-format msgid "Force fetching from %s?" msgstr "Hämtar %s från %s" #, python-format msgid "Force push to %s?" msgstr "" msgid "Format String" msgstr "" msgid "French translation" msgstr "" msgid "GPG-sign the merge commit" msgstr "" msgid "GUI theme" msgstr "" #, fuzzy, python-format msgid "Gathering info for \"%s\"..." msgstr "Läser differens för %s..." msgid "German translation" msgstr "" #, fuzzy msgid "Get Commit Message Template" msgstr "Textbredd för incheckningsmeddelande" msgid "Go Down" msgstr "" msgid "Go Up" msgstr "" msgid "Grab File..." msgstr "" msgid "Graph" msgstr "" msgid "Grep" msgstr "" msgid "Have you rebased/pulled lately?" msgstr "" msgid "Help" msgstr "Hjälp" msgid "Help - Custom Copy Actions" msgstr "" msgid "Help - Find Files" msgstr "" msgid "Help - git-xbase" msgstr "" msgid "Hide Details.." msgstr "" msgid "High DPI" msgstr "" #, fuzzy msgid "History Browser" msgstr "Filbläddrare" msgid "Hungarian translation" msgstr "" msgid "Icon theme" msgstr "" msgid "Ignore all whitespace" msgstr "" msgid "Ignore changes in amount of whitespace" msgstr "" msgid "Ignore changes in whitespace at EOL" msgstr "" msgid "Ignore custom pattern" msgstr "" msgid "Ignore exact filename" msgstr "" msgid "Ignore filename or pattern" msgstr "" #, fuzzy msgid "Include tags " msgstr "Ta med taggar" msgid "Indent Status paths" msgstr "" msgid "Indonesian translation" msgstr "" #, fuzzy msgid "Initialize Git Annex" msgstr "Initierar..." #, fuzzy msgid "Initialize Git LFS" msgstr "Initierar..." msgid "Inititalize submodules" msgstr "" msgid "Insert spaces instead of tabs" msgstr "" msgid "Interactive Rebase" msgstr "" #, fuzzy msgid "Invalid Revision" msgstr "Ogiltig revision: %s" msgid "Keep *.orig Merge Backups" msgstr "" msgid "Keep Index" msgstr "" msgid "Keyboard Shortcuts" msgstr "" msgid "Launch Diff Tool" msgstr "" msgid "Launch Directory Diff Tool" msgstr "" msgid "Launch Editor" msgstr "" msgid "Launch Terminal" msgstr "" msgid "" "Launch external diff tool\n" "Shortcut: Ctrl+D" msgstr "" msgid "Launch git-cola" msgstr "" msgid "Launch git-difftool against previous versions" msgstr "" msgid "Launch git-difftool on the current path" msgstr "" msgid "Light Theme" msgstr "" #, fuzzy msgid "Load Commit Message" msgstr "Incheckningsmeddelande:" #, fuzzy msgid "Load Commit Message..." msgstr "Incheckningsmeddelande:" #, fuzzy msgid "Load Previous Commit Message" msgstr "Incheckningsmeddelande för sammanslagning:" #, fuzzy msgid "Loading..." msgstr "Läser %s..." msgid "Local" msgstr "" msgid "Local Branch" msgstr "Lokal gren" #, fuzzy msgid "Local branch" msgstr "Lokal gren" msgid "Lock Layout" msgstr "" msgid "Log" msgstr "" msgid "Maintainer (since 2007) and developer" msgstr "" msgid "Merge" msgstr "Slå ihop" #, python-format msgid "Merge \"%(revision)s\" into \"%(branch)s\"" msgstr "" #, fuzzy msgid "Merge Tool" msgstr "Slå ihop" msgid "Merge Verbosity" msgstr "Pratsamhet för sammanslagningar" msgid "Merge failed. Conflict resolution is required." msgstr "Sammanslagningen misslyckades. Du måste lösa konflikterna." #, fuzzy, python-format msgid "Merge into \"%s\"" msgstr "Slå ihop i %s" #, fuzzy msgid "Merge into current branch" msgstr "Bläddra i grenens filer" #, fuzzy msgid "Merge..." msgstr "Slå ihop" #, fuzzy msgid "Merging" msgstr "Slå ihop" #, fuzzy msgid "Message" msgstr "Slå ihop" #, fuzzy msgid "Missing Commit Message" msgstr "Incheckningsmeddelande för sammanslagning:" #, fuzzy msgid "Missing Data" msgstr "Saknade" #, fuzzy msgid "Missing Name" msgstr "Saknade" #, fuzzy msgid "Missing Revision" msgstr "Inledande revision" #, fuzzy msgid "Missing Tag Message" msgstr "Revisioner att slå ihop" #, fuzzy msgid "Modified" msgstr "Oförändrade" #, fuzzy msgid "More..." msgstr "Klona..." msgid "Move Down" msgstr "" msgid "Move Up" msgstr "" msgid "Move files to trash" msgstr "" #, fuzzy msgid "Name" msgstr "Namn:" msgid "Name for the new remote" msgstr "" #, fuzzy msgid "New Bare Repository..." msgstr "Gitarkiv" #, fuzzy msgid "New Repository..." msgstr "Gitarkiv" msgid "New..." msgstr "Nytt..." #, fuzzy msgid "Next File" msgstr "Markera alla" msgid "No" msgstr "Nej" #, fuzzy msgid "No Revision Specified" msgstr "Ingen revision vald." #, fuzzy msgid "" "No changes to commit.\n" "\n" "You must stage at least 1 file before you can commit." msgstr "" "Inga ändringar att checka in.\n" "\n" "Du måste köa åtminstone en fil innan du kan checka in." msgid "No commits exist in this branch." msgstr "" #, fuzzy msgid "No fast forward" msgstr "Endast snabbspolning" #, fuzzy msgid "No fast-forward" msgstr "Endast snabbspolning" msgid "No repository selected." msgstr "Inget arkiv markerat." msgid "Non-fast-forward fetch overwrites local history!" msgstr "" msgid "" "Non-fast-forward push overwrites published history!\n" "(Did you pull first?)" msgstr "" #, fuzzy msgid "Nothing to commit" msgstr "Inga ändringar att checka in." #, fuzzy msgid "Nothing to do" msgstr "Ingenting att klona från %s." msgid "Number of Diff Context Lines" msgstr "Antal rader sammanhang i differenser" msgid "Open" msgstr "Öppna" #, fuzzy msgid "Open Git Repository..." msgstr "Öppna befintligt arkiv" #, fuzzy msgid "Open Parent" msgstr "Öppna tidigare arkiv:" #, fuzzy msgid "Open Parent Directory" msgstr "Öppna tidigare arkiv:" #, fuzzy msgid "Open Recent" msgstr "Öppna tidigare arkiv:" msgid "Open Using Default Application" msgstr "" msgid "Open in New Window" msgstr "" #, fuzzy msgid "Open in New Window..." msgstr "Öppna befintligt arkiv" msgid "Open..." msgstr "Öppna..." #, fuzzy msgid "Other branches" msgstr "Återställ..." msgid "Overwrite" msgstr "" #, python-format msgid "Overwrite \"%s\"?" msgstr "" msgid "Overwrite File?" msgstr "" msgid "" "Parse arguments using a shell.\n" "Queries with spaces will require \"double quotes\"." msgstr "" msgid "Partially Staged" msgstr "" msgid "Paste" msgstr "Klistra in" msgid "Patch(es) Applied" msgstr "" msgid "Path" msgstr "" msgid "Path or URL to clone (Env. $VARS okay)" msgstr "" msgid "Pick" msgstr "" msgid "Pixel XOR" msgstr "" msgid "Please provide both a branch name and revision expression." msgstr "" #, fuzzy msgid "Please select a file" msgstr "Välj en gren att spåra." msgid "Please specify a name for the new tag." msgstr "" #, fuzzy msgid "Please specify a revision to tag." msgstr "Välj en gren att byta namn på." msgid "" "Please supply a commit message.\n" "\n" "A good commit message has the following format:\n" "\n" "- First line: Describe in one sentence what you did.\n" "- Second line: Blank\n" "- Remaining lines: Describe why this change is good.\n" msgstr "" "Ange ett incheckningsmeddelande.\n" "\n" "Ett bra incheckningsmeddelande har följande format:\n" "\n" "- Första raden: Beskriv i en mening vad du gjorde.\n" "- Andra raden: Tom\n" "- Följande rader: Beskriv varför det här är en bra ändring.\n" msgid "Point the current branch head to a new commit?" msgstr "" msgid "Polish translation" msgstr "" msgid "Pop" msgstr "" msgid "Preferences" msgstr "Inställningar" msgid "Prefix" msgstr "" #, fuzzy msgid "Prepare Commit Message" msgstr "Incheckningsmeddelande för sammanslagning:" msgid "Prevent \"Stage\" from staging all files when nothing is selected" msgstr "" msgid "Previous File" msgstr "" msgid "Prompt on creation" msgstr "" #, fuzzy msgid "Prompt when pushing creates new remote branches" msgstr "Skapa ny gren" #, fuzzy msgid "Prune " msgstr "Ta bort från" #, fuzzy msgid "Pull" msgstr "Sänd..." #, fuzzy msgid "Pull..." msgstr "Sänd..." msgid "Push" msgstr "Sänd" msgid "Push..." msgstr "Sänd..." msgid "Quit" msgstr "Avsluta" #, fuzzy msgid "Rebase" msgstr "Återställ" #, fuzzy, python-format msgid "Rebase onto %s" msgstr "Återställ" #, fuzzy msgid "Rebase stopped" msgstr "Återställ" msgid "Rebase the current branch instead of merging" msgstr "" #, fuzzy msgid "Rebasing" msgstr "Återställ" #, fuzzy msgid "Recent" msgstr "Återställ" #, fuzzy msgid "Recent repositories" msgstr "Senaste arkiven" #, fuzzy msgid "Recent repository count" msgstr "Senaste arkiven" msgid "Recently Modified Files" msgstr "" #, fuzzy msgid "Recently Modified Files..." msgstr "Söker efter ändrade filer..." #, fuzzy msgid "Recovering a dropped stash is not possible." msgstr "Det kanske inte är så enkelt att återskapa förlorade incheckningar." msgid "Recovering lost commits may not be easy." msgstr "Det kanske inte är så enkelt att återskapa förlorade incheckningar." msgid "Redo" msgstr "Gör om" msgid "Reduce commit history to minimum" msgstr "" msgid "Refresh" msgstr "Uppdatera" msgid "Refuse to merge unless the current HEAD is already up-to-date or the merge can be resolved as a fast-forward" msgstr "" msgid "Remote" msgstr "Fjärr" #, fuzzy msgid "Remote Branch" msgstr "Byt namn på gren" #, fuzzy msgid "Remote Branch Deleted" msgstr "Byt namn på gren" msgid "Remote git repositories - double-click to rename" msgstr "" #, fuzzy msgid "Remove" msgstr "Fjärr" #, python-format msgid "Remove %s from the recent list?" msgstr "" #, fuzzy msgid "Remove Element" msgstr "Fjärr" msgid "Remove remote-tracking branches that no longer exist on the remote" msgstr "" #, fuzzy msgid "Remove selected (Delete)" msgstr "Byt namn på gren" msgid "Rename" msgstr "Byt namn" #, fuzzy, python-format msgid "Rename \"%s\"" msgstr "Byt namn" #, fuzzy msgid "Rename Branch" msgstr "Byt namn på gren" #, fuzzy msgid "Rename Branch..." msgstr "Byt namn på gren" #, fuzzy msgid "Rename Existing Branch" msgstr "Uppdatera befintlig gren:" #, fuzzy msgid "Rename Remote" msgstr "Fjärr" #, fuzzy msgid "Rename Repository" msgstr "Klona befintligt arkiv" #, fuzzy msgid "Rename branch" msgstr "Byt namn på gren" #, python-format msgid "Rename remote \"%(current)s\" to \"%(new)s\"?" msgstr "" #, fuzzy msgid "Rename selected paths" msgstr "Byt namn på gren" #, fuzzy, python-format msgid "Repository: %s" msgstr "Arkiv:" msgid "Reset" msgstr "Återställ" #, python-format msgid "Reset \"%(branch)s\" to \"%(revision)s\"?" msgstr "" #, fuzzy msgid "Reset Branch" msgstr "Ta bort gren" #, fuzzy msgid "Reset Branch Head" msgstr "Ta bort gren" #, fuzzy msgid "Reset Branch?" msgstr "Ta bort gren" #, fuzzy msgid "Reset Hard" msgstr "Ta bort gren" #, fuzzy msgid "Reset Merge" msgstr "Revisioner att slå ihop" #, fuzzy msgid "Reset Soft" msgstr "Återställ" msgid "Reset Worktree" msgstr "" #, fuzzy msgid "Reset hard?" msgstr "Ta bort gren" #, fuzzy msgid "Reset merge?" msgstr "Ta bort gren" #, fuzzy msgid "Reset soft?" msgstr "Återställa \"%s\"?" msgid "Reset worktree?" msgstr "" #, fuzzy, python-format msgid "Resetting \"%(branch)s\" to \"%(revision)s\" will lose commits." msgstr "Om du återställer \"%s\" till \"%s\" går följande incheckningar förlorade:" msgid "Restart the application after changing appearance settings." msgstr "" msgid "Revert" msgstr "" msgid "Revert Diff Hunk" msgstr "" msgid "Revert Diff Hunk..." msgstr "" msgid "Revert Diff Hunk?" msgstr "" msgid "Revert Selected Lines" msgstr "" msgid "Revert Selected Lines..." msgstr "" #, fuzzy msgid "Revert Selected Lines?" msgstr "Återställ ändringarna i filen %s?" #, fuzzy msgid "Revert Uncommitted Changes" msgstr "Återställ ändringar" #, fuzzy msgid "Revert Uncommitted Changes?" msgstr "Återställ ändringar" #, fuzzy msgid "Revert Uncommitted Edits..." msgstr "Återställ ändringar" #, fuzzy msgid "Revert Unstaged Changes" msgstr "Oköade ändringar" #, fuzzy msgid "Revert Unstaged Changes?" msgstr "Oköade ändringar" msgid "Revert Unstaged Edits..." msgstr "" msgid "Revert the uncommitted changes?" msgstr "" #, fuzzy msgid "Revert the unstaged changes?" msgstr "Oköade ändringar" #, fuzzy msgid "Revert uncommitted changes to selected paths" msgstr "Återställ ändringarna i filen %s?" #, fuzzy msgid "Revert unstaged changes to selected paths" msgstr "Återställ ändringarna i filen %s?" msgid "Review" msgstr "" #, fuzzy msgid "Review..." msgstr "Återställ..." msgid "Revision" msgstr "Revision" msgid "Revision Expression:" msgstr "Revisionsuttryck:" msgid "Revision to Merge" msgstr "Revisioner att slå ihop" msgid "Reword" msgstr "" msgid "Rewrite Published Commit?" msgstr "" msgid "Run" msgstr "" #, python-format msgid "Run \"%s\"?" msgstr "" #, python-format msgid "Run %s?" msgstr "" #, python-format msgid "Run the \"%s\" command?" msgstr "" #, python-format msgid "Running command: %s" msgstr "" msgid "Russian translation" msgstr "" #, fuzzy msgid "SHA-1" msgstr "Kopiera alla" msgid "Safe Mode" msgstr "" msgid "Save" msgstr "Spara" msgid "Save Archive" msgstr "" msgid "Save As Tarball/Zip..." msgstr "" msgid "Save GUI Settings" msgstr "" msgid "Save Stash" msgstr "" msgid "Save modified state to new stash" msgstr "" #, python-format msgid "Saved \"%(filename)s\" from \"%(ref)s\" to \"%(destination)s\"" msgstr "" msgid "Search" msgstr "" msgid "Search Authors" msgstr "" #, fuzzy msgid "Search Commit Messages" msgstr "Incheckningsmeddelande för sammanslagning:" #, fuzzy msgid "Search Committers" msgstr "Incheckare:" msgid "Search Date Range" msgstr "" msgid "Search Diffs" msgstr "" #, fuzzy msgid "Search by Expression" msgstr "Revisionsuttryck:" msgid "Search by Path" msgstr "" msgid "Search for a fixed string" msgstr "" msgid "Search using a POSIX basic regular expression" msgstr "" msgid "Search using a POSIX extended regular expression" msgstr "" #, fuzzy msgid "Search..." msgstr "Startar..." msgid "Select" msgstr "Välj" msgid "Select All" msgstr "Markera alla" #, fuzzy msgid "Select Branch to Review" msgstr "Ta bort gren" #, fuzzy msgid "Select Child" msgstr "Markera alla" #, fuzzy msgid "Select Commit" msgstr "Incheckningsmeddelande för sammanslagning:" #, fuzzy msgid "Select Directory..." msgstr "Gitarkiv" #, fuzzy msgid "Select New Upstream" msgstr "Välj" msgid "Select Newest Child" msgstr "" msgid "Select Oldest Parent" msgstr "" #, fuzzy msgid "Select Parent" msgstr "Välj" msgid "Select Previous Version" msgstr "" #, fuzzy msgid "Select Repository..." msgstr "Gitarkiv" msgid "Select a parent directory for the new clone" msgstr "" #, fuzzy msgid "Select manually..." msgstr "Markera alla" #, fuzzy msgid "Select output dir" msgstr "Incheckningsmeddelande för sammanslagning:" #, fuzzy msgid "Select output directory" msgstr "Gitarkiv" #, fuzzy msgid "Select patch file(s)..." msgstr "Ta bort..." #, fuzzy msgid "Select repository" msgstr "Gitarkiv" #, fuzzy msgid "Set Default Repository" msgstr "Gitarkiv" #, fuzzy msgid "Set Upstream Branch" msgstr "Välj" msgid "" "Set the sort order for branches and tags.\n" "Toggle between date-based and version-name-based sorting." msgstr "" #, fuzzy msgid "Set upstream" msgstr "Välj" #, fuzzy msgid "Settings" msgstr "Startar..." msgid "Shell arguments" msgstr "" msgid "Shift Down" msgstr "" msgid "Shift Up" msgstr "" msgid "Shortcuts" msgstr "" #, fuzzy msgid "Show Details..." msgstr "Ta bort..." msgid "Show Diffstat After Merge" msgstr "Visa diffstatistik efter sammanslagning" msgid "Show Full Paths in the Window Title" msgstr "" #, fuzzy msgid "Show Help" msgstr "Hjälp" msgid "Show History" msgstr "" msgid "Show file counts in Status titles" msgstr "" msgid "" "Show help\n" "Shortcut: ?" msgstr "" msgid "Show icon? (if available)" msgstr "" msgid "Show line numbers" msgstr "" msgid "Show whole surrounding functions of changes" msgstr "" #, fuzzy msgid "Showing changes since" msgstr "Sänder ändringar till %s" msgid "Side by side" msgstr "" msgid "Sign Off" msgstr "Skriv under" #, fuzzy msgid "Sign Tag" msgstr "Skriv under" #, fuzzy msgid "Sign off on this commit" msgstr "Köade för incheckning" msgid "Simplified Chinese translation" msgstr "" msgid "Skip" msgstr "" #, fuzzy msgid "Skip Current Patch" msgstr "Skapa gren" msgid "Sort bookmarks alphabetically" msgstr "" msgid "Spanish translation" msgstr "" msgid "Specifies the SHA-1 to tag" msgstr "" msgid "Specifies the tag message" msgstr "" msgid "Specifies the tag name" msgstr "" #, fuzzy msgid "Spelling Suggestions" msgstr "Inga förslag" #, fuzzy msgid "Squash" msgstr "Sänd" msgid "Squash the merged commits into a single commit" msgstr "" #, fuzzy msgid "Stage" msgstr "Spara" #, fuzzy msgid "Stage / Unstage" msgstr "Köa ändrade" msgid "Stage All Untracked" msgstr "" msgid "Stage Changed Files To Commit" msgstr "Köa ändrade filer för incheckning" #, fuzzy msgid "Stage Diff Hunk" msgstr "Inledande revision" msgid "Stage Modified" msgstr "" #, fuzzy msgid "Stage Selected" msgstr "Välj" #, fuzzy msgid "Stage Selected Lines" msgstr "Oköade ändringar" #, fuzzy msgid "Stage Unmerged" msgstr "Köa ändrade" #, fuzzy msgid "Stage Untracked" msgstr "Köa ändrade" #, fuzzy msgid "Stage and Commit" msgstr "Köa för incheckning" #, fuzzy msgid "Stage and commit?" msgstr "Köade för incheckning" #, fuzzy msgid "Stage conflicts" msgstr "Köade för incheckning" #, fuzzy msgid "Stage conflicts?" msgstr "Köade för incheckning" #, fuzzy msgid "Stage/unstage selected paths for commit" msgstr "Köade för incheckning" #, fuzzy msgid "Staged" msgstr "Köa ändrade" #, fuzzy, python-format msgid "Staging: %s" msgstr "Söker %s..." msgid "Start Interactive Rebase..." msgstr "" msgid "Starting Revision" msgstr "Inledande revision" msgid "Stash" msgstr "" #, fuzzy msgid "Stash Index" msgstr "Indexfel" #, fuzzy msgid "Stash staged changes only" msgstr "Checkar in ändringar..." #, fuzzy msgid "Stash unstaged changes only, keeping staged changes" msgstr "Återställ ändringarna i filen %s?" #, fuzzy msgid "Stash..." msgstr "Sänd..." msgid "Status" msgstr "" msgid "Stop tracking paths" msgstr "" msgid "Submodules" msgstr "" msgid "Summarize Merge Commits" msgstr "Summera sammanslagningsincheckningar" msgid "Summary" msgstr "" msgid "Tab Width" msgstr "" msgid "Tag" msgstr "Tagg" #, fuzzy msgid "Tag Created" msgstr "Skapa" msgid "Tag message..." msgstr "" msgid "Tag-signing was requested but the tag message is empty." msgstr "" msgid "Tags" msgstr "" msgid "Text Width" msgstr "" msgid "The branch will be no longer available." msgstr "" #, python-format msgid "The branch will be reset using \"git reset --hard %s\"" msgstr "" #, python-format msgid "The branch will be reset using \"git reset --merge %s\"" msgstr "" #, python-format msgid "The branch will be reset using \"git reset --mixed %s\"" msgstr "" #, python-format msgid "The branch will be reset using \"git reset --soft %s\"" msgstr "" #, fuzzy msgid "The commit message will be cleared." msgstr "Textbredd för incheckningsmeddelande" #, python-format msgid "The file \"%s\" exists and will be overwritten." msgstr "" msgid "The following files will be deleted:" msgstr "" #, fuzzy msgid "The revision expression cannot be empty." msgstr "Revisionsuttrycket är tomt." #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be reset using \"git reset --keep %s\"" msgstr "" msgid "This cannot be undone. Clear commit message?" msgstr "" msgid "" "This commit has already been published.\n" "This operation will rewrite published history.\n" "You probably don't want to do this." msgstr "" msgid "" "This operation drops uncommitted changes.\n" "These changes cannot be recovered." msgstr "" msgid "" "This operation removes uncommitted edits from selected files.\n" "These changes cannot be recovered." msgstr "" msgid "" "This operation removes unstaged edits from selected files.\n" "These changes cannot be recovered." msgstr "" msgid "" "This repository is currently being rebased.\n" "Resolve conflicts, commit changes, and run:\n" " Rebase > Continue" msgstr "" msgid "" "This repository is in the middle of a merge.\n" "Resolve conflicts and commit changes." msgstr "" msgid "Toggle Enabled" msgstr "" msgid "Toggle the branches filter" msgstr "" msgid "Toggle the paths filter" msgstr "" msgid "Tracking Branch" msgstr "Spårande gren" #, fuzzy msgid "Tracking branch" msgstr "Spårande gren" msgid "Traditional Chinese (Taiwan) translation" msgstr "" msgid "Translators" msgstr "" msgid "Turkish translation" msgstr "" msgid "URL" msgstr "Webbadress" #, fuzzy, python-format msgid "URL: %s" msgstr "Webbadress:" msgid "Ukranian translation" msgstr "" #, fuzzy msgid "Unable to rebase" msgstr "Kunde inte städa upp %s" #, python-format msgid "Unable to set URL for \"%(name)s\" to \"%(url)s\"" msgstr "" msgid "Undo" msgstr "Ångra" #, fuzzy msgid "Unmerged" msgstr "Slå ihop" #, fuzzy msgid "Unstage" msgstr "Oköade ändringar" msgid "Unstage All" msgstr "" msgid "Unstage Diff Hunk" msgstr "" msgid "Unstage From Commit" msgstr "Ta bort från incheckningskö" msgid "Unstage Selected" msgstr "" #, fuzzy msgid "Unstage Selected Lines" msgstr "Oköade ändringar" #, fuzzy, python-format msgid "Unstaging: %s" msgstr "Tar bort %s för incheckningskön" msgid "Untrack Selected" msgstr "" #, fuzzy msgid "Untracked" msgstr "Ej spårade, ej köade" #, python-format msgid "Untracking: %s" msgstr "" msgid "Update All Submodules..." msgstr "" msgid "Update Existing Branch:" msgstr "Uppdatera befintlig gren:" #, fuzzy msgid "Update Submodule" msgstr "Uppdaterad" msgid "Update Submodule..." msgstr "" msgid "Update Submodules" msgstr "" msgid "Update all submodules?" msgstr "" msgid "Update submodules..." msgstr "" msgid "Update this submodule" msgstr "" msgid "Update this submodule?" msgstr "" #, fuzzy msgid "Updating" msgstr "Startar..." msgid "User Name" msgstr "Användarnamn" #, fuzzy msgid "Version" msgstr "Revision" msgid "View" msgstr "" msgid "View History..." msgstr "" #, fuzzy msgid "View history for selected paths" msgstr "Återställ ändringarna i filen %s?" msgid "Visualize" msgstr "Visualisera" #, fuzzy msgid "Visualize All Branches..." msgstr "Visualisera alla grenars historik" #, fuzzy msgid "Visualize Current Branch..." msgstr "Visualisera grenens historik" msgid "Whether to sign the tag (git tag -s)" msgstr "" msgid "Would you like to stage and commit all modified files?" msgstr "" msgid "XOR" msgstr "" msgid "Yes" msgstr "" msgid "" "You are in the middle of a merge.\n" "Cannot amend while merging." msgstr "" #, fuzzy msgid "You cannot rebase with uncommitted changes." msgstr "Återställ ändringar" msgid "You must specify a revision to merge." msgstr "" msgid "You must specify a revision to view." msgstr "" msgid "Zoom In" msgstr "" msgid "Zoom Out" msgstr "" msgid "Zoom to Fit" msgstr "" msgid "command-line arguments" msgstr "" msgid "error: unable to execute git" msgstr "" #, fuzzy, python-format msgid "exit code %s" msgstr "hämta %s" #, python-format msgid "fatal: \"%s\" is not a directory. Please specify a correct --repo ." msgstr "" #, python-format msgid "git cola version %s" msgstr "" msgid "git-cola" msgstr "" msgid "git-cola diff" msgstr "" msgid "grep result..." msgstr "" msgid "hotkeys.html" msgstr "" msgid "unknown" msgstr "" msgid "vX.Y.Z" msgstr "" msgid "x 1" msgstr "" msgid "x 1.5" msgstr "" msgid "x 2" msgstr "" msgid "yyyy-MM-dd" msgstr "" #~ msgid "" #~ "\n" #~ "\n" #~ "A good replacement for %s\n" #~ "is placing values for the user.name and\n" #~ "user.email settings into your personal\n" #~ "~/.gitconfig file.\n" #~ msgstr "" #~ "\n" #~ "\n" #~ "Du kan ersätta %s\n" #~ "med att lägga in värden för inställningarna\n" #~ "user.name och user.email i din personliga\n" #~ "~/.gitconfig-fil.\n" #~ msgid "" #~ "\n" #~ "This is due to a known issue with the\n" #~ "Tcl binary distributed by Cygwin." #~ msgstr "" #~ "\n" #~ "Detta beror på ett känt problem med\n" #~ "Tcl-binären som följer med Cygwin." #~ msgid "%s ... %*i of %*i %s (%3i%%)" #~ msgstr "%s... %*i av %*i %s (%3i%%)" #~ msgid "%s Repository" #~ msgstr "Arkivet %s" #~ msgid "%s of %s" #~ msgstr "%s av %s" #~ msgid "'%s' is not an acceptable branch name." #~ msgstr "\"%s\" kan inte användas som namn på grenen." #~ msgid "* Binary file (not showing content)." #~ msgstr "* Binärfil (visar inte innehållet)." #~ msgid "A branch is required for 'Merged Into'." #~ msgstr "En gren krävs för \"Sammanslagen i\"." #~ msgid "Abort completed. Ready." #~ msgstr "Avbrytning fullbordad. Redo." #~ msgid "Abort failed." #~ msgstr "Misslyckades avbryta." #~ msgid "Aborted checkout of '%s' (file level merging is required)." #~ msgstr "Avbryter utcheckning av \"%s\" (sammanslagning på filnivå krävs)." #~ msgid "Always (Do not perform merge checks)" #~ msgstr "Alltid (utför inte sammanslagningstest)" #~ msgid "Always (Do not perform merge test.)" #~ msgstr "Alltid (utför inte sammanslagningstest)." #~ msgid "Amended Commit Message:" #~ msgstr "Utökat incheckningsmeddelande:" #~ msgid "Amended Initial Commit Message:" #~ msgstr "Utökat inledande incheckningsmeddelande:" #~ msgid "Amended Merge Commit Message:" #~ msgstr "Utökat incheckningsmeddelande för sammanslagning:" #~ msgid "Annotation complete." #~ msgstr "Annotering fullbordad." #~ msgid "Any unstaged changes will be permanently lost by the revert." #~ msgstr "Alla oköade ändringar kommer permanent gå förlorade vid återställningen." #~ msgid "Apply/Reverse Hunk" #~ msgstr "Använd/återställ del" #~ msgid "Arbitrary URL:" #~ msgstr "Godtycklig webbadress:" #~ msgid "" #~ "Branch '%s' already exists.\n" #~ "\n" #~ "It cannot fast-forward to %s.\n" #~ "A merge is required." #~ msgstr "" #~ "Grenen \"%s\" finns redan.\n" #~ "\n" #~ "Den kan inte snabbspolas till %s.\n" #~ "En sammanslagning krävs." #~ msgid "Branch '%s' does not exist." #~ msgstr "Grenen \"%s\" finns inte." #, fuzzy #~ msgid "Branch created" #~ msgstr "Namn på gren" #~ msgid "Browse %s's Files" #~ msgstr "Bläddra i filer för %s" #~ msgid "Browse Branch Files" #~ msgstr "Bläddra filer på grenen" #, fuzzy #~ msgid "Browse Revision..." #~ msgstr "Revision" #~ msgid "Calling commit-msg hook..." #~ msgstr "Anropar krok för incheckningsmeddelande..." #~ msgid "" #~ "Cannot abort while amending.\n" #~ "\n" #~ "You must finish amending this commit.\n" #~ msgstr "" #~ "Kan inte avbryta vid utökning.\n" #~ "\n" #~ "Du måste göra dig färdig med att utöka incheckningen.\n" #~ msgid "" #~ "Cannot amend while merging.\n" #~ "\n" #~ "You are currently in the middle of a merge that has not been fully completed. You cannot amend the prior commit unless you first abort the current merge activity.\n" #~ msgstr "" #~ "Kan inte utöka vid sammanslagning.\n" #~ "\n" #~ "Du är i mitten av en sammanslagning som inte är fullbordad. Du kan inte utöka tidigare incheckningar om du inte först avbryter den pågående sammanslagningen.\n" #~ msgid "Cannot determine HEAD. See console output for details." #~ msgstr "Kunde inte avgöra HEAD. Se konsolutdata för detaljer." #~ msgid "Cannot fetch branches and objects. See console output for details." #~ msgstr "Kunde inte hämta grenar och objekt. Se konsolutdata för detaljer." #~ msgid "Cannot fetch tags. See console output for details." #~ msgstr "Kunde inte hämta taggar. Se konsolutdata för detaljer." #~ msgid "Cannot find git in PATH." #~ msgstr "Hittar inte git i PATH." #~ msgid "" #~ "Cannot merge while amending.\n" #~ "\n" #~ "You must finish amending this commit before starting any type of merge.\n" #~ msgstr "" #~ "Kan inte slå ihop vid utökning.\n" #~ "\n" #~ "Du måste göra färdig utökningen av incheckningen innan du påbörjar någon slags sammanslagning.\n" #~ msgid "Cannot move to top of working directory:" #~ msgstr "Kan inte gå till början på arbetskatalogen:" #~ msgid "Cannot parse Git version string:" #~ msgstr "Kan inte tolka versionssträng från Git:" #~ msgid "Cannot resolve %s as a commit." #~ msgstr "Kunde inte slå upp %s till någon incheckning." #~ msgid "Cannot use funny .git directory:" #~ msgstr "Kan inte använda underlig .git-katalog:" #~ msgid "Cannot write shortcut:" #~ msgstr "Kan inte skriva genväg:" #~ msgid "Change Font" #~ msgstr "Byt teckensnitt" #~ msgid "Checked out '%s'." #~ msgstr "Checkade ut \"%s\"." #~ msgid "Clone Type:" #~ msgstr "Typ av klon:" #~ msgid "Clone failed." #~ msgstr "Kloning misslyckades." #~ msgid "Cloning from %s" #~ msgstr "Klonar från %s" #~ msgid "Commit %s appears to be corrupt" #~ msgstr "Incheckningen %s verkar vara trasig" #~ msgid "Commit declined by commit-msg hook." #~ msgstr "Incheckning avvisad av krok för incheckningsmeddelande." #~ msgid "Commit declined by pre-commit hook." #~ msgstr "Incheckningen avvisades av krok före incheckning." #, fuzzy #~ msgid "Commit failed: %s" #~ msgstr "Incheckningen misslyckades." #~ msgid "Commit@@noun" #~ msgstr "Incheckning" #~ msgid "Compress Database" #~ msgstr "Komprimera databas" #~ msgid "Compressing the object database" #~ msgstr "Komprimerar objektdatabasen" #~ msgid "Copied Or Moved Here By:" #~ msgstr "Kopierad eller flyttad hit av:" #~ msgid "Copying objects" #~ msgstr "Kopierar objekt" #~ msgid "Counting objects" #~ msgstr "Räknar objekt" #~ msgid "Create Desktop Icon" #~ msgstr "Skapa skrivbordsikon" #, fuzzy #~ msgid "Created commit: %s" #~ msgstr "Skapade incheckningen %s: %s" #~ msgid "Creating working directory" #~ msgstr "Skapar arbetskatalog" #~ msgid "Current Branch:" #~ msgstr "Aktuell gren:" #~ msgid "Database Statistics" #~ msgstr "Databasstatistik" #~ msgid "Decrease Font Size" #~ msgstr "Minska teckensnittsstorlek" #~ msgid "Delete Local Branch" #~ msgstr "Ta bort lokal gren" #~ msgid "Delete Only If" #~ msgstr "Ta endast bort om" #~ msgid "Delete Only If Merged Into" #~ msgstr "Ta bara bort om sammanslagen med" #~ msgid "Destination Repository" #~ msgstr "Destinationsarkiv" #~ msgid "Detach From Local Branch" #~ msgstr "Koppla bort från lokal gren" #~ msgid "Diff/Console Font" #~ msgstr "Diff/konsolteckensnitt" #~ msgid "Directory %s already exists." #~ msgstr "Katalogen %s finns redan." #~ msgid "Disk space used by loose objects" #~ msgstr "Diskutrymme använt av lösa objekt" #~ msgid "Disk space used by packed objects" #~ msgstr "Diskutrymme använt av packade objekt" #~ msgid "Do Nothing" #~ msgstr "Gör ingenting" #, fuzzy #~ msgid "Enter Git Repository" #~ msgstr "Gitarkiv" #, fuzzy #~ msgid "Error %s" #~ msgstr "fel" #~ msgid "Error loading commit data for amend:" #~ msgstr "Fel vid inläsning av incheckningsdata för utökning:" #~ msgid "Error: Command Failed" #~ msgstr "Fel: Kommando misslyckades" #~ msgid "Failed to completely save options:" #~ msgstr "Misslyckades med att helt spara alternativ:" #~ msgid "Failed to configure origin" #~ msgstr "Kunde inte konfigurera ursprung" #~ msgid "Failed to create repository %s:" #~ msgstr "Kunde inte skapa arkivet %s:" #~ msgid "" #~ "Failed to delete branches:\n" #~ "%s" #~ msgstr "" #~ "Kunde inte ta bort grenar:\n" #~ "%s" #~ msgid "Failed to open repository %s:" #~ msgstr "Kunde inte öppna arkivet %s:" #~ msgid "Failed to rename '%s'." #~ msgstr "Kunde inte byta namn på \"%s\"." #~ msgid "" #~ "Failed to set current branch.\n" #~ "\n" #~ "This working directory is only partially switched. We successfully updated your files, but failed to update an internal Git file.\n" #~ "\n" #~ "This should not have occurred. %s will now close and give up." #~ msgstr "" #~ "Kunde inte ställa in aktuell gren.\n" #~ "\n" #~ "Arbetskatalogen har bara växlats delvis. Vi uppdaterade filerna utan problem, men kunde inte uppdatera en intern fil i Git.\n" #~ "\n" #~ "Detta skulle inte ha hänt. %s kommer nu stängas och ge upp." #~ msgid "Failed to stage selected hunk." #~ msgstr "Kunde inte lägga till den valda delen till kön." #~ msgid "Failed to unstage selected hunk." #~ msgstr "Kunde inte ta bort den valda delen från kön." #~ msgid "Failed to update '%s'." #~ msgstr "Misslyckades med att uppdatera \"%s\"." #, fuzzy #~ msgid "Fast Forward Only " #~ msgstr "Endast snabbspolning" #~ msgid "Fetch from" #~ msgstr "Hämta från" #~ msgid "Fetching new changes from %s" #~ msgstr "Hämtar nya ändringar från %s" #~ msgid "File level merge required." #~ msgstr "Sammanslagning på filnivå krävs." #~ msgid "Font Example" #~ msgstr "Exempel" #~ msgid "Font Family" #~ msgstr "Teckensnittsfamilj" #~ msgid "Force overwrite existing branch (may discard changes)" #~ msgstr "Tvinga överskrivning av befintlig gren (kan kasta bort ändringar)" #~ msgid "From Repository" #~ msgstr "Från arkiv" #~ msgid "Full Copy (Slower, Redundant Backup)" #~ msgstr "Full kopia (långsammare, redundant säkerhetskopia)" #~ msgid "Garbage files" #~ msgstr "Skräpfiler" #~ msgid "Git Gui" #~ msgstr "Git Gui" #~ msgid "Git Repository (subproject)" #~ msgstr "Gitarkiv (underprojekt)" #~ msgid "Git directory not found:" #~ msgstr "Git-katalogen hittades inte:" #~ msgid "" #~ "Git version cannot be determined.\n" #~ "\n" #~ "%s claims it is version '%s'.\n" #~ "\n" #~ "%s requires at least Git 1.5.0 or later.\n" #~ "\n" #~ "Assume '%s' is version 1.5.0?\n" #~ msgstr "" #~ "Kan inte avgöra Gits version.\n" #~ "\n" #~ "%s säger att dess version är \"%s\".\n" #~ "\n" #~ "%s kräver minst Git 1.5.0 eller senare.\n" #~ "\n" #~ "Anta att \"%s\" är version 1.5.0?\n" #~ msgid "Hardlinks are unavailable. Falling back to copying." #~ msgstr "Hårda länkar är inte tillgängliga. Faller tillbaka på kopiering." #~ msgid "In File:" #~ msgstr "I filen:" #~ msgid "Increase Font Size" #~ msgstr "Öka teckensnittsstorlek" #~ msgid "Initial Commit Message:" #~ msgstr "Inledande incheckningsmeddelande:" #~ msgid "Initial file checkout failed." #~ msgstr "Inledande filutcheckning misslyckades." #~ msgid "Invalid GIT_COMMITTER_IDENT:" #~ msgstr "Felaktig GIT_COMMITTER_IDENT:" #~ msgid "Invalid date from Git: %s" #~ msgstr "Ogiltigt datum från Git: %s" #~ msgid "Invalid font specified in %s:" #~ msgstr "Ogiltigt teckensnitt angivet i %s:" #~ msgid "Invalid spell checking configuration" #~ msgstr "Ogiltig inställning för stavningskontroll" #~ msgid "KiB" #~ msgstr "KiB" #~ msgid "" #~ "Last scanned state does not match repository state.\n" #~ "\n" #~ "Another Git program has modified this repository since the last scan. A rescan must be performed before a merge can be performed.\n" #~ "\n" #~ "The rescan will be automatically started now.\n" #~ msgstr "" #~ "Det senaste inlästa tillståndet motsvarar inte tillståndet i arkivet.\n" #~ "\n" #~ "Ett annat Git-program har ändrat arkivet sedan senaste avsökningen. Du måste utföra en ny sökning innan du kan utföra en sammanslagning.\n" #~ "\n" #~ "Sökningen kommer att startas automatiskt nu.\n" #~ msgid "" #~ "Last scanned state does not match repository state.\n" #~ "\n" #~ "Another Git program has modified this repository since the last scan. A rescan must be performed before another commit can be created.\n" #~ "\n" #~ "The rescan will be automatically started now.\n" #~ msgstr "" #~ "Det senaste inlästa tillståndet motsvarar inte tillståndet i arkivet.\n" #~ "\n" #~ "Ett annat Git-program har ändrat arkivet sedan senaste avsökningen. Du måste utföra en ny sökning innan du kan göra en ny incheckning.\n" #~ "\n" #~ "Sökningen kommer att startas automatiskt nu.\n" #~ msgid "" #~ "Last scanned state does not match repository state.\n" #~ "\n" #~ "Another Git program has modified this repository since the last scan. A rescan must be performed before the current branch can be changed.\n" #~ "\n" #~ "The rescan will be automatically started now.\n" #~ msgstr "" #~ "Det senaste inlästa tillståndet motsvarar inte tillståndet i arkivet.\n" #~ "\n" #~ "Ett annat Git-program har ändrat arkivet sedan senaste avsökningen. Du måste utföra en ny sökning innan den aktuella grenen kan ändras.\n" #~ "\n" #~ "Sökningen kommer att startas automatiskt nu.\n" #~ msgid "Linking objects" #~ msgstr "Länkar objekt" #~ msgid "Loading annotation..." #~ msgstr "Läser in annotering..." #~ msgid "Loading copy/move tracking annotations..." #~ msgstr "Läser annoteringar för kopiering/flyttning..." #~ msgid "Loading original location annotations..." #~ msgstr "Läser in annotering av originalplacering..." #~ msgid "Local Branches" #~ msgstr "Lokala grenar" #~ msgid "Local Merge..." #~ msgstr "Lokal sammanslagning..." #~ msgid "Location %s already exists." #~ msgstr "Platsen %s finns redan." #~ msgid "Main Font" #~ msgstr "Huvudteckensnitt" #~ msgid "Match Tracking Branch Name" #~ msgstr "Använd namn på spårad gren" #~ msgid "Match Tracking Branches" #~ msgstr "Matcha spårade grenar" #~ msgid "Merge completed successfully." #~ msgstr "Sammanslagningen avslutades framgångsrikt." #~ msgid "Merge strategy '%s' not supported." #~ msgstr "Sammanslagningsstrategin \"%s\" stöds inte." #~ msgid "Merged Into:" #~ msgstr "Sammanslagen i:" #~ msgid "Merging %s and %s..." #~ msgstr "Slår ihop %s och %s..." #~ msgid "Modified, not staged" #~ msgstr "Förändrade, ej köade" #~ msgid "New Branch Name Template" #~ msgstr "Mall för namn på nya grenar" #~ msgid "New Commit" #~ msgstr "Ny incheckning" #~ msgid "New Name:" #~ msgstr "Nytt namn:" #~ msgid "" #~ "No changes to commit.\n" #~ "\n" #~ "No files were modified by this commit and it was not a merge commit.\n" #~ "\n" #~ "A rescan will be automatically started now.\n" #~ msgstr "" #~ "Inga ändringar att checka in.\n" #~ "\n" #~ "Inga filer ändrades av incheckningen och det var inte en sammanslagning.\n" #~ "\n" #~ "En sökning kommer att startas automatiskt nu.\n" #~ msgid "No default branch obtained." #~ msgstr "Hämtade ingen standardgren." #~ msgid "" #~ "No differences detected.\n" #~ "\n" #~ "%s has no changes.\n" #~ "\n" #~ "The modification date of this file was updated by another application, but the content within the file was not changed.\n" #~ "\n" #~ "A rescan will be automatically started to find other files which may have the same state." #~ msgstr "" #~ "Hittade inga skillnader.\n" #~ "\n" #~ "%s innehåller inga ändringar.\n" #~ "\n" #~ "Modifieringsdatum för filen uppdaterades av ett annat program, men innehållet i filen har inte ändrats.\n" #~ "\n" #~ "En sökning kommer automatiskt att startas för att hitta andra filer som kan vara i samma tillstånd." #~ msgid "No working directory" #~ msgstr "Ingen arbetskatalog" #~ msgid "Not connected to aspell" #~ msgstr "Inte ansluten till aspell" #~ msgid "Number of loose objects" #~ msgstr "Antal lösa objekt" #~ msgid "Number of packed objects" #~ msgstr "Antal packade objekt" #~ msgid "Number of packs" #~ msgstr "Antal paket" #~ msgid "One or more of the merge tests failed because you have not fetched the necessary commits. Try fetching from %s first." #~ msgstr "En eller flera av sammanslagningstesterna misslyckades eftersom du inte har hämtat de nödvändiga incheckningarna. Försök hämta från %s först." #~ msgid "Options" #~ msgstr "Alternativ" #~ msgid "Original File:" #~ msgstr "Ursprunglig fil:" #~ msgid "Originally By:" #~ msgstr "Ursprungligen av:" #~ msgid "Packed objects waiting for pruning" #~ msgstr "Packade objekt som väntar på städning" #, fuzzy #~ msgid "Path to git repository" #~ msgstr "Inte ett Gitarkiv: %s" #~ msgid "Please select one or more branches to delete." #~ msgstr "Välj en eller flera grenar att ta bort." #~ msgid "Please supply a branch name." #~ msgstr "Ange ett namn för grenen." #~ msgid "Portions staged for commit" #~ msgstr "Delar köade för incheckning" #~ msgid "" #~ "Possible environment issues exist.\n" #~ "\n" #~ "The following environment variables are probably\n" #~ "going to be ignored by any Git subprocess run\n" #~ "by %s:\n" #~ "\n" #~ msgstr "" #~ "Det finns möjliga problem med miljövariabler.\n" #~ "\n" #~ "Följande miljövariabler kommer troligen att\n" #~ "ignoreras av alla Git-underprocesser som körs\n" #~ "av %s:\n" #~ "\n" #~ msgid "Preferences..." #~ msgstr "Inställningar..." #~ msgid "Prune Tracking Branches During Fetch" #~ msgstr "Städa spårade grenar vid hämtning" #~ msgid "Pruning tracking branches deleted from %s" #~ msgstr "Tar bort spårande grenar som tagits bort från %s" #~ msgid "Push Branches" #~ msgstr "Sänder grenar" #~ msgid "Push to" #~ msgstr "Sänd till" #~ msgid "Pushing %s %s to %s" #~ msgstr "Sänder %s %s till %s" #~ msgid "Reading %s..." #~ msgstr "Läser %s..." #~ msgid "Ready to commit." #~ msgstr "Redo att checka in." #~ msgid "Ready." #~ msgstr "Klar." #, fuzzy #~ msgid "Rebase Branch" #~ msgstr "Byt namn på gren" #, fuzzy #~ msgid "Rebase..." #~ msgstr "Återställ..." #~ msgid "" #~ "Recovering deleted branches is difficult.\n" #~ "\n" #~ "Delete the selected branches?" #~ msgstr "" #~ "Det kan vara svårt att återställa borttagna grenar.\n" #~ "\n" #~ "Ta bort de valda grenarna?" #~ msgid "" #~ "Recovering deleted branches is difficult. \n" #~ "\n" #~ " Delete the selected branches?" #~ msgstr "" #~ "Det är svårt att återställa borttagna grenar.\n" #~ "\n" #~ " Ta bort valda grenar?" #~ msgid "Refreshing file status..." #~ msgstr "Uppdaterar filstatus..." #, fuzzy #~ msgid "Remote Branches" #~ msgstr "Byt namn på gren" #~ msgid "Remote:" #~ msgstr "Fjärr:" #, fuzzy #~ msgid "Rename remote?" #~ msgstr "Fjärr" #~ msgid "Repository" #~ msgstr "Arkiv" #~ msgid "Requires merge resolution" #~ msgstr "Kräver konflikthantering efter sammanslagning" #~ msgid "Rescan" #~ msgstr "Sök på nytt" #~ msgid "" #~ "Reset changes?\n" #~ "\n" #~ "Resetting the changes will cause *ALL* uncommitted changes to be lost.\n" #~ "\n" #~ "Continue with resetting the current changes?" #~ msgstr "" #~ "Återställ ändringar?\n" #~ "\n" #~ "Om du återställer ändringarna kommer *ALLA* ej incheckade ändringar att gå förlorade.\n" #~ "\n" #~ "Gå vidare med att återställa de aktuella ändringarna?" #~ msgid "Revert changes in these %i files?" #~ msgstr "Återställ ändringarna i dessa %i filer?" #, fuzzy #~ msgid "Select File" #~ msgstr "Markera alla" #, fuzzy #~ msgid "Select file from \"%s\"" #~ msgstr "Tar bort grenar från %s" #~ msgid "Shared (Fastest, Not Recommended, No Backup)" #~ msgstr "Delad (snabbast, rekommenderas ej, ingen säkerhetskopia)" #~ msgid "Shared only available for local repository." #~ msgstr "Delat är endast tillgängligt för lokala arkiv." #~ msgid "Show Less Context" #~ msgstr "Visa mindre sammanhang" #~ msgid "Show More Context" #~ msgstr "Visa mer sammanhang" #~ msgid "Source Branches" #~ msgstr "Källgrenar" #~ msgid "Spell Checker Failed" #~ msgstr "Stavningskontroll misslyckades" #~ msgid "Spell checker silently failed on startup" #~ msgstr "Stavningskontroll misslyckades tyst vid start" #~ msgid "Spell checking is unavailable" #~ msgstr "Stavningskontroll är ej tillgänglig" #~ msgid "Spelling Dictionary:" #~ msgstr "Stavningsordlista:" #~ msgid "Stage Hunk For Commit" #~ msgstr "Ställ del i incheckningskö" #~ msgid "Staged Changes (Will Commit)" #~ msgstr "Köade ändringar (kommer att checkas in)" #~ msgid "Staged for commit, missing" #~ msgstr "Köade för incheckning, saknade" #~ msgid "Staged for removal" #~ msgstr "Köade för borttagning" #~ msgid "Staged for removal, still present" #~ msgstr "Köade för borttagning, fortfarande närvarande" #, fuzzy #~ msgid "Staging Area" #~ msgstr "Söker %s..." #~ msgid "Staging area (index) is already locked." #~ msgstr "Köområdet (index) är redan låst." #~ msgid "Standard (Fast, Semi-Redundant, Hardlinks)" #~ msgstr "Standard (snabb, semiredundant, hårda länkar)" #~ msgid "Standard only available for local repository." #~ msgstr "Standard är endast tillgängligt för lokala arkiv." #~ msgid "Starting gitk... please wait..." #~ msgstr "Startar gitk... vänta..." #~ msgid "Staying on branch '%s'." #~ msgstr "Stannar på grenen \"%s\"." #~ msgid "Success" #~ msgstr "Lyckades" #~ msgid "The 'master' branch has not been initialized." #~ msgstr "Grenen \"master\" har inte initierats." #~ msgid "The following branches are not completely merged into %s:" #~ msgstr "Följande grenar är inte till fullo sammanslagna med %s:" #~ msgid "" #~ "The following branches are not completely merged into %s:\n" #~ "\n" #~ " - %s" #~ msgstr "" #~ "Följande grenar har inte helt slagits samman i %s:\n" #~ "\n" #~ " - %s" #~ msgid "" #~ "There is nothing to amend.\n" #~ "\n" #~ "You are about to create the initial commit. There is no commit before this to amend.\n" #~ msgstr "" #~ "Det finns ingenting att utöka.\n" #~ "\n" #~ "Du håller på att skapa den inledande incheckningen. Det finns ingen tidigare incheckning att utöka.\n" #~ msgid "This Detached Checkout" #~ msgstr "Denna frånkopplade utcheckning" #~ msgid "" #~ "This is example text.\n" #~ "If you like this text, it can be your font." #~ msgstr "" #~ "Detta är en exempeltext.\n" #~ "Om du tycker om den här texten kan den vara ditt teckensnitt." #~ msgid "" #~ "This repository currently has approximately %i loose objects.\n" #~ "\n" #~ "To maintain optimal performance it is strongly recommended that you compress the database when more than %i loose objects exist.\n" #~ "\n" #~ "Compress the database now?" #~ msgstr "" #~ "Arkivet har för närvarande omkring %i lösa objekt.\n" #~ "\n" #~ "För att bibehålla optimal prestanda rekommenderas det å det bestämdaste att du komprimerar databasen när den innehåller mer än %i lösa objekt.\n" #~ "\n" #~ "Komprimera databasen nu?" #~ msgid "Tracking branch %s is not a branch in the remote repository." #~ msgstr "Den spårade grenen %s är inte en gren i fjärrarkivet." #~ msgid "Transfer Options" #~ msgstr "Överföringsalternativ" #~ msgid "Unable to copy object: %s" #~ msgstr "Kunde inte kopiera objekt: %s" #~ msgid "Unable to copy objects/info/alternates: %s" #~ msgstr "Kunde inte kopiera objekt/info/alternativ: %s" #~ msgid "Unable to display %s" #~ msgstr "Kan inte visa %s" #~ msgid "Unable to hardlink object: %s" #~ msgstr "Kunde inte hårdlänka objekt: %s" #~ msgid "Unable to obtain your identity:" #~ msgstr "Kunde inte hämta din identitet:" #~ msgid "" #~ "Unable to start gitk:\n" #~ "\n" #~ "%s does not exist" #~ msgstr "" #~ "Kan inte starta gitk:\n" #~ "\n" #~ "%s finns inte" #~ msgid "Unable to unlock the index." #~ msgstr "Kunde inte låsa upp indexet." #~ msgid "Unexpected EOF from spell checker" #~ msgstr "Oväntat filslut från stavningskontroll" #~ msgid "" #~ "Unknown file state %s detected.\n" #~ "\n" #~ "File %s cannot be committed by this program.\n" #~ msgstr "" #~ "Okänd filstatus %s upptäckt.\n" #~ "\n" #~ "Filen %s kan inte checkas in av programmet.\n" #~ msgid "Unlock Index" #~ msgstr "Lås upp index" #~ msgid "" #~ "Unmerged files cannot be committed.\n" #~ "\n" #~ "File %s has merge conflicts. You must resolve them and stage the file before committing.\n" #~ msgstr "" #~ "Osammanslagna filer kan inte checkas in.\n" #~ "\n" #~ "Filen %s har sammanslagningskonflikter. Du måste lösa dem och köa filen innan du checkar in den.\n" #~ msgid "Unrecognized spell checker" #~ msgstr "Stavningskontrollprogrammet känns inte igen" #~ msgid "Unstage Hunk From Commit" #~ msgstr "Ta bort del ur incheckningskö" #~ msgid "Unsupported spell checker" #~ msgstr "Stavningskontrollprogrammet stöds inte" #~ msgid "Updating the Git index failed. A rescan will be automatically started to resynchronize git-gui." #~ msgstr "Misslyckades med att uppdatera Gitindexet. En omsökning kommer att startas automatiskt för att synkronisera om git-gui." #~ msgid "Updating working directory to '%s'..." #~ msgstr "Uppdaterar arbetskatalogen till \"%s\"..." #, fuzzy #~ msgid "Updating..." #~ msgstr "Startar..." #~ msgid "Use thin pack (for slow network connections)" #~ msgstr "Använd tunt paket (för långsamma nätverksanslutningar)" #~ msgid "Verify Database" #~ msgstr "Verifiera databas" #~ msgid "Verifying the object database with fsck-objects" #~ msgstr "Verifierar objektdatabasen med fsck-objects" #~ msgid "Visualize %s's History" #~ msgstr "Visualisera historik för %s" #~ msgid "Working... please wait..." #~ msgstr "Arbetar... vänta..." #~ msgid "" #~ "You are in the middle of a change.\n" #~ "\n" #~ "File %s is modified.\n" #~ "\n" #~ "You should complete the current commit before starting a merge. Doing so will help you abort a failed merge, should the need arise.\n" #~ msgstr "" #~ "Du är mitt i en ändring.\n" #~ "\n" #~ "Filen %s har ändringar.\n" #~ "\n" #~ "Du bör fullborda den aktuella incheckningen innan du påbörjar en sammanslagning. Om du gör det blir det enklare att avbryta en misslyckad sammanslagning, om det skulle vara nödvändigt.\n" #~ msgid "" #~ "You are in the middle of a conflicted merge.\n" #~ "\n" #~ "File %s has merge conflicts.\n" #~ "\n" #~ "You must resolve them, stage the file, and commit to complete the current merge. Only then can you begin another merge.\n" #~ msgstr "" #~ "Du är mitt i en sammanslagning med konflikter.\n" #~ "\n" #~ "Filen %s har sammanslagningskonflikter.\n" #~ "\n" #~ "Du måste lösa dem, köa filen och checka in för att fullborda den aktuella sammanslagningen. När du gjort det kan du påbörja en ny sammanslagning.\n" #~ msgid "" #~ "You are no longer on a local branch.\n" #~ "\n" #~ "If you wanted to be on a branch, create one now starting from 'This Detached Checkout'." #~ msgstr "" #~ "Du är inte längre på en lokal gren.\n" #~ "\n" #~ "Om du ville vara på en gren skapar du en nu, baserad på \"Denna frånkopplade utcheckning\"." #~ msgid "You must correct the above errors before committing." #~ msgstr "Du måste rätta till felen ovan innan du checkar in." #~ msgid "[Up To Parent]" #~ msgstr "[Upp till förälder]" #~ msgid "buckets" #~ msgstr "hinkar" #~ msgid "commit-tree failed:" #~ msgstr "commit-tree misslyckades:" #~ msgid "fatal: Cannot resolve %s" #~ msgstr "ödesdigert: Kunde inte slå upp %s" #~ msgid "files" #~ msgstr "filer" #~ msgid "files checked out" #~ msgstr "filer utcheckade" #~ msgid "files reset" #~ msgstr "filer återställda" #~ msgid "git-gui - a graphical user interface for Git." #~ msgstr "git-gui - ett grafiskt användargränssnitt för Git." #~ msgid "git-gui: fatal error" #~ msgstr "git-gui: ödesdigert fel" #~ msgid "lines annotated" #~ msgstr "rader annoterade" #~ msgid "objects" #~ msgstr "objekt" #~ msgid "pt." #~ msgstr "p." #~ msgid "push %s" #~ msgstr "sänd %s" #~ msgid "remote prune %s" #~ msgstr "fjärrborttagning %s" #~ msgid "update-ref failed:" #~ msgstr "update-ref misslyckades:" #~ msgid "warning" #~ msgstr "varning" #~ msgid "warning: Tcl does not support encoding '%s'." #~ msgstr "varning: Tcl stöder inte teckenkodningen \"%s\"." #~ msgid "write-tree failed:" #~ msgstr "write-tree misslyckades:" git-cola-3.6/po/tr_TR.po000066400000000000000000001222431356743264500151140ustar00rootroot00000000000000# Translation of git-cola to Turkish. # Copyright (C) 2015, 2017 Barış ÇELİK. # This file is distributed under the same license as the git-cola package. # # Barış ÇELİK , 2015. # Sabri ÜNAL , 2019 # Adil GÜRBÜZ , 2019 # msgid "" msgstr "" "Project-Id-Version: git-cola\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: \n" "PO-Revision-Date: 2019-11-15 10:20+0300\n" "Last-Translator: Adil GÜRBÜZ \n" "Language-Team: Turkish\n" "Language: tr_TR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.1.7\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgid "" "\n" "

\n" " Drag and drop or use the Add button to " "add\n" " patches to the list\n" "

\n" " " msgstr "" #, python-format msgid "" "\n" "
\n" " Git Cola has been translated into different languages thanks\n" " to the help of the individuals listed below.\n" "\n" "
\n" "

\n" " Translation is approximate. If you find a mistake,\n" " please let us know by opening an issue on Github:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " We invite you to participate in translation by adding or " "updating\n" " a translation and opening a pull request.\n" "

\n" "\n" "
\n" "\n" " " msgstr "" #, python-format msgid "" "\n" "
\n" " Git Cola version %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " msgstr "" #, python-format msgid "" "\n" "
\n" " Please use %(bug_link)s to report issues.\n" "
\n" " " msgstr "" #, python-format msgid "" "\n" " Format String Variables\n" " -----------------------\n" " %(path)s = relative file path\n" " %(abspath)s = absolute file path\n" " %(dirname)s = relative directory path\n" " %(absdirname)s = absolute directory path\n" " %(filename)s = file basename\n" " %(basename)s = file basename without extension\n" " %(ext)s = file extension\n" msgstr "" msgid "" "\n" "Commands\n" "--------\n" "pick = use commit\n" "reword = use commit, but edit the commit message\n" "edit = use commit, but stop for amending\n" "squash = use commit, but meld into previous commit\n" "fixup = like \"squash\", but discard this commit's log message\n" "exec = run command (the rest of the line) using shell\n" "\n" "These lines can be re-ordered; they are executed from top to bottom.\n" "\n" "If you disable a line here THAT COMMIT WILL BE LOST.\n" "\n" "However, if you disable everything, the rebase will be aborted.\n" "\n" "Keyboard Shortcuts\n" "------------------\n" "? = show help\n" "j = move down\n" "k = move up\n" "J = shift row down\n" "K = shift row up\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "spacebar = toggle enabled\n" "\n" "ctrl+enter = accept changes and rebase\n" "ctrl+q = cancel and abort the rebase\n" "ctrl+d = launch difftool\n" msgstr "" msgid "" "\n" "Keyboard Shortcuts\n" "------------------\n" "J, Down = Move Down\n" "K, Up = Move Up\n" "Enter = Edit Selected Files\n" "Spacebar = Open File Using Default Application\n" "Ctrl + L = Focus Text Entry Field\n" "? = Show Help\n" "\n" "The up and down arrows change focus between the text entry field\n" "and the results.\n" msgstr "" msgid " - DAG" msgstr "" msgid " commits ago" msgstr "" #, python-format msgid "\"%(branch)s\" has been deleted from \"%(remote)s\"." msgstr "\"%(branch)s\" öğesi \"%(remote)s\" uzak kaynağından silindi." #, python-format msgid "\"%(command)s\" returned exit status \"%(status)d\"" msgstr "" #, python-format msgid "\"%(command)s\" returned exit status %(status)d" msgstr "\"%(command)s\" çıkış durumu döndürdü %(status)d" #, python-format msgid "\"%s\" already exists" msgstr "" #, python-format msgid "\"%s\" already exists, cola will create a new directory" msgstr "" #, python-format msgid "\"%s\" requires a selected file." msgstr "" msgid "#" msgstr "" #, python-format msgid "%(project)s: %(branch)s - Browse" msgstr "" #, python-format msgid "%(project)s: %(ref)s - DAG" msgstr "" #, python-format msgid "%d days ago" msgstr "%d gün önce" #, python-format msgid "%d hours ago" msgstr "%d saat önce" #, python-format msgid "%d minutes ago" msgstr "%d dakika önce" #, python-format msgid "%d patch(es) applied." msgstr "%d düzeltme uygulandı." #, python-format msgid "%d skipped" msgstr "%d geçildi" #, python-format msgid "" "%s appears to contain merge conflicts.\n" "\n" "You should probably skip this file.\n" "Stage it anyways?" msgstr "" #, python-format msgid "%s is not a Git repository." msgstr "" #, python-format msgid "%s will be removed from your bookmarks." msgstr "%s işaretlerinizden kaldırılacak." #, python-format msgid "%s will be removed from your recent repositories." msgstr "%s son kullanılan repolardan silinecek." #, python-format msgid "%s: No such file or directory." msgstr "%s: Böyle bir dosya ya da dizin yok." msgid "&Edit" msgstr "" msgid "&File" msgstr "Dosya" msgid "(Amending)" msgstr "" msgid "*** Branch Point ***" msgstr "" msgid "*** Sandbox ***" msgstr "" msgid "100%" msgstr "" msgid "200%" msgstr "" msgid "25%" msgstr "" msgid "400%" msgstr "" msgid "50%" msgstr "" msgid "800%" msgstr "" msgid " ..." msgstr "" msgid "" "A commit template has not been configured.\n" "Use \"git config\" to define \"commit.template\"\n" "so that it points to a commit template." msgstr "" "Bir işleme şablonu doğru yapılandırılmadı\n" "\"commit.template\" tanımlamak için \"git config\" komutunu kullanın\n" "yaptığınız ayarla doğru yeri işaret edin." #, python-format msgid "A hook must be provided at \"%s\"" msgstr "" #, python-format msgid "A stash named \"%s\" already exists" msgstr "" msgid "Abort" msgstr "" msgid "Abort Action" msgstr "" msgid "Abort Merge" msgstr "" msgid "Abort Merge..." msgstr "" msgid "Abort the action?" msgstr "" msgid "" "Aborting the current merge will cause *ALL* uncommitted changes to be " "lost.\n" "Recovering uncommitted changes is not possible." msgstr "" msgid "Aborting the current merge?" msgstr "" msgid "About" msgstr "Hakkında" msgid "About git-cola" msgstr "" msgid "Accept" msgstr "" msgid "" "Accept changes and rebase\n" "Shortcut: Ctrl+Enter" msgstr "" msgid "Action Name" msgstr "Aksiyon Adı" msgid "Actions" msgstr "İşlemler" msgid "Actions..." msgstr "İşlemler..." msgid "Add" msgstr "Ekle" msgid "Add Favorite" msgstr "" msgid "Add Remote" msgstr "" msgid "Add Separator" msgstr "Ayraç Ekle" msgid "Add Toolbar" msgstr "Araç Çubuğu Ekle" msgid "" "Add and remove remote repositories using the \n" "Add(+) and Delete(-) buttons on the left-hand side.\n" "\n" "Remotes can be renamed by selecting one from the list\n" "and pressing \"enter\", or by double-clicking." msgstr "" msgid "Add new remote git repository" msgstr "Yeni uzak git deposu ekle" msgid "Add patches (+)" msgstr "" msgid "Add remote" msgstr "" msgid "Add to .gitignore" msgstr "" msgid "Add to Git Annex" msgstr "" msgid "Add to Git LFS" msgstr "" msgid "Additions" msgstr "" msgid "Advanced" msgstr "" msgid "Age" msgstr "Yaş" msgid "All Repositories" msgstr "Tüm Depolar" #, python-format msgid "" "All submodules will be updated using\n" "\"%s\"" msgstr "" msgid "" "Allow non-fast-forward updates. Using \"force\" can cause the remote " "repository to lose commits; use it with care" msgstr "" msgid "" "Always create a merge commit when enabled, even when the merge is a fast-" "forward update" msgstr "" msgid "Amend" msgstr "" msgid "Amend Commit" msgstr "" msgid "Amend Last Commit" msgstr "" msgid "Amend the published commit?" msgstr "" msgid "Amending" msgstr "" msgid "" "An action is still running.\n" "Terminating it could result in data loss." msgstr "" msgid "" "An unsigned, lightweight tag will be created instead.\n" "Create an unsigned tag?" msgstr "" msgid "Appearance" msgstr "" msgid "Apply" msgstr "Uygula" msgid "Apply Patches" msgstr "" msgid "Apply Patches..." msgstr "Düzeltmeleri Uygula..." msgid "Apply and drop the selected stash (git stash pop)" msgstr "" msgid "Apply the selected stash" msgstr "" msgid "Arguments" msgstr "Argümanlar" msgid "Attach" msgstr "" msgid "Author" msgstr "Yazar" msgid "Authors" msgstr "Yazarlar" msgid "Auto" msgstr "Otamatik" msgid "Auto-Wrap Lines" msgstr "" msgid "Basic Regexp" msgstr "" msgid "Blame Viewer" msgstr "" msgid "Blame selected paths" msgstr "" msgid "Blame..." msgstr "" msgid "Bold on dark headers instead of italic" msgstr "" msgid "Branch" msgstr "Dal" #, python-format msgid "" "Branch \"%(branch)s\" does not exist in \"%(remote)s\".\n" "A new remote branch will be published." msgstr "" #, python-format msgid "Branch \"%s\" already exists." msgstr "" msgid "Branch Diff Viewer" msgstr "" msgid "Branch Exists" msgstr "" msgid "Branch Name" msgstr "Dal Adı" #, python-format msgid "Branch: %s" msgstr "Dal: %s" msgid "Branches" msgstr "Dallar" msgid "Branches..." msgstr "Dallar..." msgid "Brazilian translation" msgstr "" msgid "Browse" msgstr "Gözat" msgid "Browse Commits..." msgstr "İşlemelere Gözat..." msgid "Browse Current Branch..." msgstr "Geçerli Dala Gözat..." msgid "Browse Other Branch..." msgstr "Diğer Dala Gözat..." msgid "Browse..." msgstr "Gözat..." msgid "Browser" msgstr "Görüntüleyici" #, python-format msgid "Browsing %s" msgstr "" msgid "Bypass Commit Hooks" msgstr "" msgid "Cancel" msgstr "İptal" msgid "" "Cancel rebase\n" "Shortcut: Ctrl+Q" msgstr "" msgid "Cannot Amend" msgstr "" #, python-format msgid "Cannot exec \"%s\": please configure a blame viewer" msgstr "" #, python-format msgid "Cannot exec \"%s\": please configure a history browser" msgstr "" #, python-format msgid "Cannot exec \"%s\": please configure your editor" msgstr "Çalıştırılamayan sorgu \"%s\": lütfen editörü ayarlayın" msgid "Changed Upstream" msgstr "" msgid "Check Spelling" msgstr "" msgid "Check spelling" msgstr "" msgid "Checkout" msgstr "" msgid "Checkout After Creation" msgstr "" msgid "Checkout Branch" msgstr "" msgid "Checkout Detached HEAD" msgstr "" msgid "Checkout as new branch" msgstr "" msgid "Checkout..." msgstr "" msgid "Cherry Pick" msgstr "" msgid "Cherry-Pick Commit" msgstr "" msgid "Cherry-Pick..." msgstr "" msgid "Choose Paths" msgstr "" msgid "Choose the \"git grep\" regular expression mode" msgstr "" msgid "Clear Default Repository" msgstr "Varsayılan Depoyu Temizle" msgid "Clear commit message" msgstr "" msgid "Clear commit message?" msgstr "" msgid "Clear..." msgstr "Temizle..." msgid "Clone" msgstr "" msgid "Clone Repository" msgstr "" msgid "Clone..." msgstr "" #, python-format msgid "Cloning repository at %s" msgstr "" msgid "Close" msgstr "Kapat" msgid "Close..." msgstr "Kapat..." msgid "Collapse all" msgstr "" msgid "Command" msgstr "Komut" msgid "Commit" msgstr "" msgid "Commit failed" msgstr "" msgid "Commit staged changes" msgstr "" msgid "" "Commit staged changes\n" "Shortcut: Ctrl+Enter" msgstr "" msgid "Commit summary" msgstr "" msgid "" "Commit the merge if there are no conflicts. Uncheck to leave the merge " "uncommitted" msgstr "" msgid "Commit@@verb" msgstr "" msgid "Compare" msgstr "" msgid "Compare All" msgstr "" msgid "Configure the remote branch as the the new upstream" msgstr "" msgid "Configure toolbar" msgstr "" msgid "Console" msgstr "Uçbirim" msgid "Continue" msgstr "Devam et" msgid "Copy" msgstr "Kopyala" msgid "Copy Basename to Clipboard" msgstr "Ana Adı Panoya Kopyala" msgid "Copy Leading Path to Clipboard" msgstr "" msgid "Copy Path to Clipboard" msgstr "Yolu Panoya Kopyala" msgid "Copy Relative Path to Clipboard" msgstr "Sabit Yolu Panoya Kopyala" msgid "Copy SHA-1" msgstr "Copy SHA-1" msgid "Copy..." msgstr "Kopyala..." #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "" msgid "Create Branch" msgstr "Dal Oluştur" msgid "Create Patch" msgstr "Yol Oluştur" msgid "Create Remote Branch" msgstr "Uzak Dal Oluştur" msgid "Create Signed Commit" msgstr "" msgid "Create Tag" msgstr "Etiket Oluştur" msgid "Create Tag..." msgstr "Etiket Oluştur..." msgid "Create Unsigned Tag" msgstr "" msgid "Create a merge commit even when the merge resolves as a fast-forward" msgstr "" msgid "Create a new remote branch?" msgstr "" msgid "Create..." msgstr "Oluştur..." #, python-format msgid "Created a new tag named \"%s\"" msgstr "" msgid "Current Repository" msgstr "Güncel Depo" msgid "Custom Copy Actions" msgstr "" msgid "Customize..." msgstr "" msgid "Cut" msgstr "Kes" msgid "Czech translation" msgstr "" msgid "DAG..." msgstr "" msgid "Dark Theme" msgstr "Koyu Tema" msgid "Date, Time" msgstr "Tarih, Saat" msgid "Default" msgstr "Varsayılan" msgid "Delete" msgstr "Sil" #, python-format msgid "Delete %d file(s)?" msgstr "%d dosyayı sil?" msgid "Delete Bookmark" msgstr "İşareti Sil" msgid "Delete Bookmark?" msgstr "İşareti Sil?" msgid "Delete Branch" msgstr "Dalı Sil" msgid "Delete Files" msgstr "Dosyaları Sil" msgid "Delete Files..." msgstr "Dosyaları Sil..." msgid "Delete Files?" msgstr "Dosyaları Sil?" msgid "Delete Remote" msgstr "Uzaktakini Sil" msgid "Delete Remote Branch" msgstr "" msgid "Delete Remote Branch..." msgstr "Uzaktaki Dalı Sil..." msgid "Delete remote" msgstr "" #, python-format msgid "Delete remote \"%s\"" msgstr "Uzaktakini sil \"%s\"" msgid "Delete remote?" msgstr "Uzaktakini sil?" msgid "Delete selected branch?" msgstr "" msgid "Delete toolbar" msgstr "Araç çubuğunu sil" msgid "Delete..." msgstr "Sil..." #, python-format msgid "Deleting \"%s\" failed" msgstr "\"%s\" silme işlemi başarısız" msgid "Deletions" msgstr "" msgid "Detach" msgstr "" msgid "Detect Conflict Markers" msgstr "" msgid "Detect conflict markers in unmerged files" msgstr "" msgid "Developer" msgstr "Geliştirici" msgid "Diff" msgstr "" msgid "Diff Against Predecessor..." msgstr "" msgid "Diff Options" msgstr "" msgid "Diff Tool" msgstr "Karşılaştırma Aracı" msgid "Diff selected -> this" msgstr "" msgid "Diff this -> selected" msgstr "" msgid "Diffstat" msgstr "" msgid "Difftool" msgstr "Karşılaştırma Aracı" msgid "Directory Exists" msgstr "" msgid "Display Untracked Files" msgstr "" msgid "Documentation" msgstr "Belgelendirme" msgid "Drop" msgstr "" msgid "Drop Stash" msgstr "" msgid "Drop Stash?" msgstr "" #, python-format msgid "Drop the \"%s\" stash?" msgstr "" msgid "Drop the selected stash" msgstr "" msgid "Edit" msgstr "Düzenle" msgid "Edit Rebase" msgstr "Konumlandırmayı Düzenle" msgid "Edit Remotes" msgstr "Uzaktakini Düzenle" msgid "Edit Remotes..." msgstr "Uzaktakini Düzenle..." msgid "Edit remotes by selecting them from the list" msgstr "" msgid "Edit selected paths" msgstr "" msgid "Edit..." msgstr "Düzenle..." msgid "Editor" msgstr "Düzenleyici" msgid "Email Address" msgstr "E-Posta Adresi" msgid "Email contributor" msgstr "" msgid "Enabled" msgstr "" msgid "Enter New Branch Name" msgstr "Yeni Dal Adı Gir" msgid "Enter a name for the new bare repo" msgstr "" msgid "Enter a name for the stash" msgstr "" msgid "Error" msgstr "Hata" msgid "Error Cloning" msgstr "" msgid "Error Creating Branch" msgstr "Hata Dalı Oluştur" msgid "Error Creating Repository" msgstr "Hata Deposu Oluştur" msgid "Error Deleting Remote Branch" msgstr "Uzak Dal Silinirken Hata" msgid "Error Editing File" msgstr "Dosyayı Düzenlemede Hata" msgid "Error Launching Blame Viewer" msgstr "" msgid "Error Launching History Browser" msgstr "" #, python-format msgid "Error creating remote \"%s\"" msgstr "Uzak \"%s\" oluşturulurken hata" msgid "Error creating stash" msgstr "" #, python-format msgid "Error deleting remote \"%s\"" msgstr "Uzaktaki silinirken hata \"%s\"" #, python-format msgid "Error renaming \"%(name)s\" to \"%(new_name)s\"" msgstr "" msgid "Error running prepare-commitmsg hook" msgstr "" #, python-format msgid "Error updating submodule %s" msgstr "" msgid "Error updating submodules" msgstr "" msgid "Error: Cannot find commit template" msgstr "Hata: İşleme şablonu bulunamadı" msgid "Error: Stash exists" msgstr "" msgid "Error: Unconfigured commit template" msgstr "Hata: Ayarlanmamış işleme şablonu" #, python-format msgid "Error: could not clone \"%s\"" msgstr "Hata: \"%s\" klonlanamadı" #, python-format msgid "Error: could not create tag \"%s\"" msgstr "" #, python-format msgid "Executing action %s" msgstr "" msgid "Expand all" msgstr "" msgid "Export Patches" msgstr "Düzeltmeleri Dışa Aktar" msgid "Export Patches..." msgstr "Düzeltmeleri Dışa Aktar..." msgid "Expression..." msgstr "İfade..." msgid "Extended Regexp" msgstr "" msgid "Extended description..." msgstr "" msgid "Fast Forward Only" msgstr "" msgid "Fast-forward only" msgstr "" msgid "Favorite repositories" msgstr "Favori depolar" msgid "Favorites" msgstr "Favoriler" msgid "Fetch" msgstr "" msgid "Fetch Tracking Branch" msgstr "" msgid "Fetch..." msgstr "" msgid "File Browser..." msgstr "" msgid "File Differences" msgstr "" msgid "File Saved" msgstr "Dosya Kaydedildi" #, python-format msgid "File saved to \"%s\"" msgstr "\"%s\" dosyası kaydedildi" msgid "" "File system change monitoring: disabled because \"cola.inotify\" is false.\n" msgstr "" msgid "" "File system change monitoring: disabled because libc does not support the " "inotify system calls.\n" msgstr "" msgid "" "File system change monitoring: disabled because pywin32 is not installed.\n" msgstr "" msgid "" "File system change monitoring: disabled because the limit on the total " "number of inotify watches was reached. You may be able to increase the " "limit on the number of watches by running:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf " "&& sudo sysctl -p\n" msgstr "" msgid "File system change monitoring: enabled.\n" msgstr "" msgid "Filename" msgstr "Dosya adı" msgid "Files" msgstr "Dosyalar" msgid "Filter branches..." msgstr "" msgid "Filter paths..." msgstr "" msgid "Find Files" msgstr "Dosyaları Bul" msgid "Fixed String" msgstr "" msgid "Fixed-Width Font" msgstr "" msgid "Fixup" msgstr "" msgid "Fixup Previous Commit" msgstr "" msgid "Flat dark blue" msgstr "Düz koyu mavi" msgid "Flat dark green" msgstr "Düz koyu yeşil" msgid "Flat dark grey" msgstr "Düz koyu gri" msgid "Flat dark red" msgstr "Düz koyu kırmızı" msgid "Flat light blue" msgstr "Düz açık mavi" msgid "Flat light green" msgstr "Düz açık yeşil" msgid "Flat light grey" msgstr "Düz açık gri" msgid "Flat light red" msgstr "Düz açık kırmızı" msgid "Font Size" msgstr "Yazı Tipi Boyutu" msgid "Force" msgstr "" msgid "Force Fetch" msgstr "" msgid "Force Fetch?" msgstr "" msgid "Force Push" msgstr "" msgid "Force Push?" msgstr "" #, python-format msgid "Force fetching from %s?" msgstr "" #, python-format msgid "Force push to %s?" msgstr "" msgid "Format String" msgstr "" msgid "French translation" msgstr "" msgid "GPG-sign the merge commit" msgstr "" msgid "GUI theme" msgstr "Arayüz teması" #, python-format msgid "Gathering info for \"%s\"..." msgstr "" msgid "German translation" msgstr "" msgid "Get Commit Message Template" msgstr "" msgid "Go Down" msgstr "" msgid "Go Up" msgstr "Yukarı Git" msgid "Grab File..." msgstr "" msgid "Graph" msgstr "" msgid "Grep" msgstr "" msgid "Have you rebased/pulled lately?" msgstr "" msgid "Help" msgstr "Yardım" msgid "Help - Custom Copy Actions" msgstr "" msgid "Help - Find Files" msgstr "Yardım - Dosyaları Ara" msgid "Help - git-xbase" msgstr "" msgid "Hide Details.." msgstr "" msgid "High DPI" msgstr "" msgid "History Browser" msgstr "Geçmiş Görüntüleyici" msgid "Hungarian translation" msgstr "" msgid "Icon theme" msgstr "Simge Teması" msgid "Ignore all whitespace" msgstr "" msgid "Ignore changes in amount of whitespace" msgstr "" msgid "Ignore changes in whitespace at EOL" msgstr "" msgid "Ignore custom pattern" msgstr "" msgid "Ignore exact filename" msgstr "" msgid "Ignore filename or pattern" msgstr "" msgid "Include tags " msgstr "" msgid "Indent Status paths" msgstr "" msgid "Indonesian translation" msgstr "" msgid "Initialize Git Annex" msgstr "" msgid "Initialize Git LFS" msgstr "" msgid "Inititalize submodules" msgstr "" msgid "Insert spaces instead of tabs" msgstr "" msgid "Interactive Rebase" msgstr "" msgid "Invalid Revision" msgstr "" msgid "Keep *.orig Merge Backups" msgstr "" msgid "Keep Index" msgstr "" msgid "Keyboard Shortcuts" msgstr "Klavye Kısayolları" msgid "Launch Diff Tool" msgstr "Karşılaştırma Aracını Çalıştır" msgid "Launch Directory Diff Tool" msgstr "" msgid "Launch Editor" msgstr "Editörü Çalıştır" msgid "Launch Terminal" msgstr "Terminali Çalıştır" msgid "" "Launch external diff tool\n" "Shortcut: Ctrl+D" msgstr "" msgid "Launch git-cola" msgstr "" msgid "Launch git-difftool against previous versions" msgstr "" msgid "Launch git-difftool on the current path" msgstr "" msgid "Light Theme" msgstr "Açık Tema" msgid "Load Commit Message" msgstr "İşleme Mesajını Yükle" msgid "Load Commit Message..." msgstr "İşleme Mesajını Yükle..." msgid "Load Previous Commit Message" msgstr "" msgid "Loading..." msgstr "Yükleniyor..." msgid "Local" msgstr "Yerel" msgid "Local Branch" msgstr "Yerel Dal" msgid "Local branch" msgstr "Yerel dal" msgid "Lock Layout" msgstr "" msgid "Log" msgstr "Kayıt" msgid "Maintainer (since 2007) and developer" msgstr "" msgid "Merge" msgstr "" #, python-format msgid "Merge \"%(revision)s\" into \"%(branch)s\"" msgstr "" msgid "Merge Tool" msgstr "Birleştirme Aracı" msgid "Merge Verbosity" msgstr "" msgid "Merge failed. Conflict resolution is required." msgstr "" #, python-format msgid "Merge into \"%s\"" msgstr "" msgid "Merge into current branch" msgstr "" msgid "Merge..." msgstr "" msgid "Merging" msgstr "Birleştiriliyor" msgid "Message" msgstr "Mesaj" msgid "Missing Commit Message" msgstr "" msgid "Missing Data" msgstr "Kayıp Veri" msgid "Missing Name" msgstr "Kayıp Ad" msgid "Missing Revision" msgstr "" msgid "Missing Tag Message" msgstr "" msgid "Modified" msgstr "Düzenlenmiş" msgid "More..." msgstr "" msgid "Move Down" msgstr "" msgid "Move Up" msgstr "Yukarı Kaydır" msgid "Move files to trash" msgstr "" msgid "Name" msgstr "Ad" msgid "Name for the new remote" msgstr "" msgid "New Bare Repository..." msgstr "" msgid "New Repository..." msgstr "Yeni Depo..." msgid "New..." msgstr "Yeni..." msgid "Next File" msgstr "Sonraki Dosya" msgid "No" msgstr "Hayır" msgid "No Revision Specified" msgstr "" msgid "" "No changes to commit.\n" "\n" "You must stage at least 1 file before you can commit." msgstr "" msgid "No commits exist in this branch." msgstr "" msgid "No fast forward" msgstr "" msgid "No fast-forward" msgstr "" msgid "No repository selected." msgstr "" msgid "Non-fast-forward fetch overwrites local history!" msgstr "" msgid "" "Non-fast-forward push overwrites published history!\n" "(Did you pull first?)" msgstr "" msgid "Nothing to commit" msgstr "" msgid "Nothing to do" msgstr "" msgid "Number of Diff Context Lines" msgstr "" msgid "Open" msgstr "Aç" msgid "Open Git Repository..." msgstr "Git Deposunu Aç..." msgid "Open Parent" msgstr "" msgid "Open Parent Directory" msgstr "Üst Klasörü Aç" msgid "Open Recent" msgstr "" msgid "Open Using Default Application" msgstr "Varsayılan Uygulamayla Aç" msgid "Open in New Window" msgstr "Yeni Pencere Aç" msgid "Open in New Window..." msgstr "Yeni Pencere Aç..." msgid "Open..." msgstr "Aç..." msgid "Other branches" msgstr "Diğer dallar" msgid "Overwrite" msgstr "" #, python-format msgid "Overwrite \"%s\"?" msgstr "" msgid "Overwrite File?" msgstr "" msgid "" "Parse arguments using a shell.\n" "Queries with spaces will require \"double quotes\"." msgstr "" msgid "Partially Staged" msgstr "" msgid "Paste" msgstr "Yapıştır" msgid "Patch(es) Applied" msgstr "Uygulanan Düzeltmeler" msgid "Path" msgstr "Yol" msgid "Path or URL to clone (Env. $VARS okay)" msgstr "" msgid "Pick" msgstr "" msgid "Pixel XOR" msgstr "" msgid "Please provide both a branch name and revision expression." msgstr "" msgid "Please select a file" msgstr "Lütfen bir dosya seçin" msgid "Please specify a name for the new tag." msgstr "" msgid "Please specify a revision to tag." msgstr "" msgid "" "Please supply a commit message.\n" "\n" "A good commit message has the following format:\n" "\n" "- First line: Describe in one sentence what you did.\n" "- Second line: Blank\n" "- Remaining lines: Describe why this change is good.\n" msgstr "" msgid "Point the current branch head to a new commit?" msgstr "" msgid "Polish translation" msgstr "" msgid "Pop" msgstr "" msgid "Preferences" msgstr "Seçenekler" msgid "Prefix" msgstr "Ön Ek" msgid "Prepare Commit Message" msgstr "" msgid "Prevent \"Stage\" from staging all files when nothing is selected" msgstr "" msgid "Previous File" msgstr "Önceki Dosya" msgid "Prompt on creation" msgstr "" msgid "Prompt when pushing creates new remote branches" msgstr "" msgid "Prune " msgstr "" msgid "Pull" msgstr "" msgid "Pull..." msgstr "" msgid "Push" msgstr "" msgid "Push..." msgstr "" msgid "Quit" msgstr "Çık" msgid "Rebase" msgstr "Konumlandır" #, python-format msgid "Rebase onto %s" msgstr "%s öğesine konumlandır" msgid "Rebase stopped" msgstr "" msgid "Rebase the current branch instead of merging" msgstr "" msgid "Rebasing" msgstr "" msgid "Recent" msgstr "Son" msgid "Recent repositories" msgstr "" msgid "Recent repository count" msgstr "" msgid "Recently Modified Files" msgstr "" msgid "Recently Modified Files..." msgstr "En Son Düzenlenen Dosyalar..." msgid "Recovering a dropped stash is not possible." msgstr "" msgid "Recovering lost commits may not be easy." msgstr "" msgid "Redo" msgstr "" msgid "Reduce commit history to minimum" msgstr "" msgid "Refresh" msgstr "Yenile" msgid "" "Refuse to merge unless the current HEAD is already up-to-date or the merge " "can be resolved as a fast-forward" msgstr "" msgid "Remote" msgstr "" msgid "Remote Branch" msgstr "" msgid "Remote Branch Deleted" msgstr "Uzaktaki Dal Silindi" msgid "Remote git repositories - double-click to rename" msgstr "" msgid "Remove" msgstr "Kaldır" #, python-format msgid "Remove %s from the recent list?" msgstr "%s öğesini son kullanılanlardan sil?" msgid "Remove Element" msgstr "" msgid "Remove remote-tracking branches that no longer exist on the remote" msgstr "" msgid "Remove selected (Delete)" msgstr "" msgid "Rename" msgstr "Yeniden Adlandır" #, python-format msgid "Rename \"%s\"" msgstr "" msgid "Rename Branch" msgstr "Dalı Yeniden Adlandır" msgid "Rename Branch..." msgstr "Dalı Yeniden Adlandır..." msgid "Rename Existing Branch" msgstr "" msgid "Rename Remote" msgstr "Uzaktakini Yeniden Adlandır" msgid "Rename Repository" msgstr "Depoyu Yeniden Adlandır" msgid "Rename branch" msgstr "Dalı yeniden adlandır" #, python-format msgid "Rename remote \"%(current)s\" to \"%(new)s\"?" msgstr "" msgid "Rename selected paths" msgstr "" #, python-format msgid "Repository: %s" msgstr "Depo: %s" msgid "Reset" msgstr "Sıfırla" #, python-format msgid "Reset \"%(branch)s\" to \"%(revision)s\"?" msgstr "" msgid "Reset Branch" msgstr "Dalı Sıfırla" msgid "Reset Branch Head" msgstr "" msgid "Reset Branch?" msgstr "Dalı Sıfırla?" msgid "Reset Hard" msgstr "" msgid "Reset Merge" msgstr "" msgid "Reset Soft" msgstr "" msgid "Reset Worktree" msgstr "" msgid "Reset hard?" msgstr "" msgid "Reset merge?" msgstr "" msgid "Reset soft?" msgstr "" msgid "Reset worktree?" msgstr "" #, python-format msgid "Resetting \"%(branch)s\" to \"%(revision)s\" will lose commits." msgstr "" msgid "Restart the application after changing appearance settings." msgstr "" msgid "Revert" msgstr "" msgid "Revert Diff Hunk" msgstr "" msgid "Revert Diff Hunk..." msgstr "" msgid "Revert Diff Hunk?" msgstr "" msgid "Revert Selected Lines" msgstr "" msgid "Revert Selected Lines..." msgstr "" msgid "Revert Selected Lines?" msgstr "" msgid "Revert Uncommitted Changes" msgstr "" msgid "Revert Uncommitted Changes?" msgstr "" msgid "Revert Uncommitted Edits..." msgstr "" msgid "Revert Unstaged Changes" msgstr "" msgid "Revert Unstaged Changes?" msgstr "" msgid "Revert Unstaged Edits..." msgstr "" msgid "Revert the uncommitted changes?" msgstr "" msgid "Revert the unstaged changes?" msgstr "" msgid "Revert uncommitted changes to selected paths" msgstr "" msgid "Revert unstaged changes to selected paths" msgstr "" msgid "Review" msgstr "Önizle" msgid "Review..." msgstr "Önizle..." msgid "Revision" msgstr "" msgid "Revision Expression:" msgstr "" msgid "Revision to Merge" msgstr "" msgid "Reword" msgstr "" msgid "Rewrite Published Commit?" msgstr "" msgid "Run" msgstr "Çalıştır" #, python-format msgid "Run \"%s\"?" msgstr "\"%s\" çalıştırılsın mı?" #, python-format msgid "Run %s?" msgstr "%s çalıştırılsın mı?" #, python-format msgid "Run the \"%s\" command?" msgstr "" #, python-format msgid "Running command: %s" msgstr "Komut çalıştırılıyor: %s" msgid "Russian translation" msgstr "" msgid "SHA-1" msgstr "" msgid "Safe Mode" msgstr "" msgid "Save" msgstr "Kaydet" msgid "Save Archive" msgstr "Arşivi Kaydet" msgid "Save As Tarball/Zip..." msgstr "" msgid "Save GUI Settings" msgstr "Arayüz Ayarlarını Kaydet" msgid "Save Stash" msgstr "" msgid "Save modified state to new stash" msgstr "" #, python-format msgid "Saved \"%(filename)s\" from \"%(ref)s\" to \"%(destination)s\"" msgstr "" msgid "Search" msgstr "Ara" msgid "Search Authors" msgstr "Yazarları Ara" msgid "Search Commit Messages" msgstr "" msgid "Search Committers" msgstr "" msgid "Search Date Range" msgstr "" msgid "Search Diffs" msgstr "" msgid "Search by Expression" msgstr "" msgid "Search by Path" msgstr "" msgid "Search for a fixed string" msgstr "" msgid "Search using a POSIX basic regular expression" msgstr "" msgid "Search using a POSIX extended regular expression" msgstr "" msgid "Search..." msgstr "Arama..." msgid "Select" msgstr "Seç" msgid "Select All" msgstr "" msgid "Select Branch to Review" msgstr "" msgid "Select Child" msgstr "" msgid "Select Commit" msgstr "" msgid "Select Directory..." msgstr "Dosyayı Seç..." msgid "Select New Upstream" msgstr "" msgid "Select Newest Child" msgstr "" msgid "Select Oldest Parent" msgstr "" msgid "Select Parent" msgstr "" msgid "Select Previous Version" msgstr "" msgid "Select Repository..." msgstr "Depoyu Seç..." msgid "Select a parent directory for the new clone" msgstr "" msgid "Select manually..." msgstr "" msgid "Select output dir" msgstr "" msgid "Select output directory" msgstr "" msgid "Select patch file(s)..." msgstr "" msgid "Select repository" msgstr "Depoyu seç" msgid "Set Default Repository" msgstr "Varsayılan Depoyu Seç" msgid "Set Upstream Branch" msgstr "" msgid "" "Set the sort order for branches and tags.\n" "Toggle between date-based and version-name-based sorting." msgstr "" msgid "Set upstream" msgstr "" msgid "Settings" msgstr "Ayarlar" msgid "Shell arguments" msgstr "" msgid "Shift Down" msgstr "" msgid "Shift Up" msgstr "" msgid "Shortcuts" msgstr "Kısayollar" msgid "Show Details..." msgstr "Ayrıntıları Göster..." msgid "Show Diffstat After Merge" msgstr "" msgid "Show Full Paths in the Window Title" msgstr "" msgid "Show Help" msgstr "Yardımı Göster" msgid "Show History" msgstr "Geçmişi Göster" msgid "Show file counts in Status titles" msgstr "" msgid "" "Show help\n" "Shortcut: ?" msgstr "" "Yardımı göster\n" "Kısayol: ?" msgid "Show icon? (if available)" msgstr "" msgid "Show line numbers" msgstr "" msgid "Show whole surrounding functions of changes" msgstr "" msgid "Showing changes since" msgstr "" msgid "Side by side" msgstr "" msgid "Sign Off" msgstr "" msgid "Sign Tag" msgstr "" msgid "Sign off on this commit" msgstr "" msgid "Simplified Chinese translation" msgstr "" msgid "Skip" msgstr "Atla" msgid "Skip Current Patch" msgstr "" msgid "Sort bookmarks alphabetically" msgstr "" msgid "Spanish translation" msgstr "" msgid "Specifies the SHA-1 to tag" msgstr "" msgid "Specifies the tag message" msgstr "" msgid "Specifies the tag name" msgstr "" msgid "Spelling Suggestions" msgstr "" msgid "Squash" msgstr "" msgid "Squash the merged commits into a single commit" msgstr "" msgid "Stage" msgstr "" msgid "Stage / Unstage" msgstr "" msgid "Stage All Untracked" msgstr "" msgid "Stage Changed Files To Commit" msgstr "" msgid "Stage Diff Hunk" msgstr "" msgid "Stage Modified" msgstr "" msgid "Stage Selected" msgstr "" msgid "Stage Selected Lines" msgstr "" msgid "Stage Unmerged" msgstr "" msgid "Stage Untracked" msgstr "" msgid "Stage and Commit" msgstr "" msgid "Stage and commit?" msgstr "" msgid "Stage conflicts" msgstr "" msgid "Stage conflicts?" msgstr "" msgid "Stage/unstage selected paths for commit" msgstr "" msgid "Staged" msgstr "" #, python-format msgid "Staging: %s" msgstr "" msgid "Start Interactive Rebase..." msgstr "" msgid "Starting Revision" msgstr "" msgid "Stash" msgstr "" msgid "Stash Index" msgstr "" msgid "Stash staged changes only" msgstr "" msgid "Stash unstaged changes only, keeping staged changes" msgstr "" msgid "Stash..." msgstr "" msgid "Status" msgstr "Durum" msgid "Stop tracking paths" msgstr "" msgid "Submodules" msgstr "" msgid "Summarize Merge Commits" msgstr "" msgid "Summary" msgstr "" msgid "Tab Width" msgstr "Tab Genişliği" msgid "Tag" msgstr "Etiket" msgid "Tag Created" msgstr "" msgid "Tag message..." msgstr "Etiket mesajı..." msgid "Tag-signing was requested but the tag message is empty." msgstr "" msgid "Tags" msgstr "Etiketler" msgid "Text Width" msgstr "Yazı Genişliği" msgid "The branch will be no longer available." msgstr "" #, python-format msgid "The branch will be reset using \"git reset --hard %s\"" msgstr "" #, python-format msgid "The branch will be reset using \"git reset --merge %s\"" msgstr "" #, python-format msgid "The branch will be reset using \"git reset --mixed %s\"" msgstr "" #, python-format msgid "The branch will be reset using \"git reset --soft %s\"" msgstr "" msgid "The commit message will be cleared." msgstr "" #, python-format msgid "The file \"%s\" exists and will be overwritten." msgstr "" msgid "The following files will be deleted:" msgstr "Aşağıdaki satırlar silinecek:" msgid "The revision expression cannot be empty." msgstr "" #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be reset using \"git reset --keep %s\"" msgstr "" msgid "This cannot be undone. Clear commit message?" msgstr "" msgid "" "This commit has already been published.\n" "This operation will rewrite published history.\n" "You probably don't want to do this." msgstr "" msgid "" "This operation drops uncommitted changes.\n" "These changes cannot be recovered." msgstr "" msgid "" "This operation removes uncommitted edits from selected files.\n" "These changes cannot be recovered." msgstr "" msgid "" "This operation removes unstaged edits from selected files.\n" "These changes cannot be recovered." msgstr "" msgid "" "This repository is currently being rebased.\n" "Resolve conflicts, commit changes, and run:\n" " Rebase > Continue" msgstr "" msgid "" "This repository is in the middle of a merge.\n" "Resolve conflicts and commit changes." msgstr "" msgid "Toggle Enabled" msgstr "" msgid "Toggle the branches filter" msgstr "" msgid "Toggle the paths filter" msgstr "" msgid "Tracking Branch" msgstr "" msgid "Tracking branch" msgstr "" msgid "Traditional Chinese (Taiwan) translation" msgstr "" msgid "Translators" msgstr "" msgid "Turkish translation" msgstr "Türkçe çeviri" msgid "URL" msgstr "URL" #, python-format msgid "URL: %s" msgstr "URL: %s" msgid "Ukranian translation" msgstr "" msgid "Unable to rebase" msgstr "" #, python-format msgid "Unable to set URL for \"%(name)s\" to \"%(url)s\"" msgstr "" msgid "Undo" msgstr "" msgid "Unmerged" msgstr "Birleştirilmemiş" msgid "Unstage" msgstr "" msgid "Unstage All" msgstr "" msgid "Unstage Diff Hunk" msgstr "" msgid "Unstage From Commit" msgstr "" msgid "Unstage Selected" msgstr "" msgid "Unstage Selected Lines" msgstr "" #, python-format msgid "Unstaging: %s" msgstr "" msgid "Untrack Selected" msgstr "" msgid "Untracked" msgstr "Takip Edilmemiş" #, python-format msgid "Untracking: %s" msgstr "" msgid "Update All Submodules..." msgstr "" msgid "Update Existing Branch:" msgstr "" msgid "Update Submodule" msgstr "" msgid "Update Submodule..." msgstr "" msgid "Update Submodules" msgstr "" msgid "Update all submodules?" msgstr "" msgid "Update submodules..." msgstr "" msgid "Update this submodule" msgstr "" msgid "Update this submodule?" msgstr "" msgid "Updating" msgstr "" msgid "User Name" msgstr "Kullanıcı Adı" msgid "Version" msgstr "Versiyon" msgid "View" msgstr "Göster" msgid "View History..." msgstr "Geçmişi Göster..." msgid "View history for selected paths" msgstr "" msgid "Visualize" msgstr "" msgid "Visualize All Branches..." msgstr "" msgid "Visualize Current Branch..." msgstr "" msgid "Whether to sign the tag (git tag -s)" msgstr "" msgid "Would you like to stage and commit all modified files?" msgstr "" msgid "XOR" msgstr "" msgid "Yes" msgstr "Evet" msgid "" "You are in the middle of a merge.\n" "Cannot amend while merging." msgstr "" "Bir birleştirme işleminin ortasındasınız.\n" "Birleştirme yapılırken değişiklik yapamazsınız." msgid "You cannot rebase with uncommitted changes." msgstr "" msgid "You must specify a revision to merge." msgstr "" msgid "You must specify a revision to view." msgstr "" msgid "Zoom In" msgstr "Yakınlaş" msgid "Zoom Out" msgstr "Uzaklaş" msgid "Zoom to Fit" msgstr "" msgid "command-line arguments" msgstr "" msgid "error: unable to execute git" msgstr "" #, python-format msgid "exit code %s" msgstr "" #, python-format msgid "" "fatal: \"%s\" is not a directory. Please specify a correct --repo ." msgstr "" #, python-format msgid "git cola version %s" msgstr "git cola sürümü %s" msgid "git-cola" msgstr "git-cola" msgid "git-cola diff" msgstr "git-cola diff" msgid "grep result..." msgstr "grep sonucu..." msgid "hotkeys.html" msgstr "hotkeys.html" msgid "unknown" msgstr "bilinmeyen" msgid "vX.Y.Z" msgstr "vX.Y.Z" msgid "x 1" msgstr "x 1" msgid "x 1.5" msgstr "x 1.5" msgid "x 2" msgstr "x 2" msgid "yyyy-MM-dd" msgstr "yyyy-AA-gg" #, fuzzy #~ msgid "\"%s\" returned exit status %d" #~ msgstr "\"%(command)s\" çıkış durumu döndürdü %(status)d" #~ msgid "\"git commit\" returned exit code %s" #~ msgstr "\"git commit\" returned exit code %s" #~ msgid "Already up-to-date." #~ msgstr "Already up-to-date." #~ msgid "Commit failed: %s" #~ msgstr "İşleme başarısız: %s" #~ msgid "Created commit: %s" #~ msgstr "Oluşturulan işleme: %s" #~ msgid "Enter Git Repository" #~ msgstr "Enter Git Repository" #, fuzzy #~ msgid "Error %s" #~ msgstr "Errors: %s" #~ msgid "Errors: %s" #~ msgstr "Errors: %s" #~ msgid "Exit code: %s" #~ msgstr "Exit code: %s" #~ msgid "Fast Forward Only " #~ msgstr "Fast Forward Only " #~ msgid "GPG-signed" #~ msgstr "GPG-signed" #, fuzzy #~ msgid "Local Branches" #~ msgstr "Local Branch" #~ msgid "On Debian-based systems try: sudo apt-get install python-pyinotify" #~ msgstr "On Debian-based systems try: sudo apt-get install python-pyinotify" #~ msgid "Options" #~ msgstr "Seçenekler" #~ msgid "" #~ "Output:\n" #~ "%s" #~ msgstr "" #~ "Output:\n" #~ "%s" #~ msgid "Output: %s" #~ msgstr "Output: %s" #~ msgid "Path to git repository" #~ msgstr "Path to git repository" #, fuzzy #~ msgid "Remote Branches" #~ msgstr "Remote Branch" #~ msgid "Rename remote?" #~ msgstr "Uzaktakini yeniden adlandır?" #~ msgid "Select File" #~ msgstr "Select File" #~ msgid "Select file from \"%s\"" #~ msgstr "Select file from \"%s\"" #~ msgid "Staging Area" #~ msgstr "Staging Area" #~ msgid "Summary:" #~ msgstr "Özet:" #~ msgid "" #~ "This PyQt4 does not include QtWebKit.\n" #~ "The keyboard shortcuts feature is unavailable." #~ msgstr "" #~ "This PyQt4 does not include QtWebKit.\n" #~ "The keyboard shortcuts feature is unavailable." #~ msgid "Updating..." #~ msgstr "Updating..." #~ msgid "" #~ "file notification: disabled\n" #~ "Note: install pywin32 to enable.\n" #~ msgstr "" #~ "file notification: disabled\n" #~ "Note: install pywin32 to enable.\n" #~ msgid "git clone returned exit code %s" #~ msgstr "git clone çıkış kodu döndürdü %s" #~ msgid "git tag returned exit code %s" #~ msgstr "git tag returned exit code %s" #~ msgid "inotify enabled." #~ msgstr "inotify enabled." #~ msgid "" #~ "inotify: disabled\n" #~ "Note: install python-pyinotify to enable inotify.\n" #~ msgstr "" #~ "inotify: disabled\n" #~ "Note: install python-pyinotify to enable inotify.\n" git-cola-3.6/po/uk.po000066400000000000000000002134411356743264500145020ustar00rootroot00000000000000# Translation of git-cola to ukrainian # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Igor Kopach , 2017. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-17 01:06-0700\n" "PO-Revision-Date: 2017-08-30 08:16+0200\n" "Last-Translator: Igor Kopach \n" "Language-Team: Ukrainian\n" "Language: uk_UA\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "" "\n" "

\n" " Drag and drop or use the Add button to add\n" " patches to the list\n" "

\n" " " msgstr "" "\n" "

\n" " Перетягніть та відпустіть або використовуйте кнопку\n" " Додати, щоб додати латки до списку\n" "

\n" " " #, python-format msgid "" "\n" "
\n" " Git Cola has been translated into different languages thanks\n" " to the help of the individuals listed below.\n" "\n" "
\n" "

\n" " Translation is approximate. If you find a mistake,\n" " please let us know by opening an issue on Github:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " We invite you to participate in translation by adding or updating\n" " a translation and opening a pull request.\n" "

\n" "\n" "
\n" "\n" " " msgstr "" "\n" "
\n" " Git Cola була перекладена на різні мови завдяки\n" " завдяки допомозі осіб вказаних нижче.\n" "\n" "
\n" "

\n" " Переклад є приблизним. Якщо ви знайшли помилку,\n" " будь ласка, дайте нам знати, створивши проблему на Github:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " Запрошуємо вас до участі в перекладі, додаючи або оновлюючи\n" " переклад та відкриванні запитів на стягнення (pull request).\n" "

\n" "\n" "
\n" "\n" " " #, fuzzy, python-format msgid "" "\n" "
\n" " Git Cola version %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " msgstr "" "\n" "
\n" " Git Cola версії %(cola_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " #, python-format msgid "" "\n" "
\n" " Please use %(bug_link)s to report issues.\n" "
\n" " " msgstr "" "\n" "
\n" " Будь ласка, використовуйте %(bug_link)s щоб повідомляти про проблеми.\n" "
\n" " " #, python-format msgid "" "\n" " Format String Variables\n" " -----------------------\n" " %(path)s = relative file path\n" " %(abspath)s = absolute file path\n" " %(dirname)s = relative directory path\n" " %(absdirname)s = absolute directory path\n" " %(filename)s = file basename\n" " %(basename)s = file basename without extension\n" " %(ext)s = file extension\n" msgstr "" msgid "" "\n" "Commands\n" "--------\n" "pick = use commit\n" "reword = use commit, but edit the commit message\n" "edit = use commit, but stop for amending\n" "squash = use commit, but meld into previous commit\n" "fixup = like \"squash\", but discard this commit's log message\n" "exec = run command (the rest of the line) using shell\n" "\n" "These lines can be re-ordered; they are executed from top to bottom.\n" "\n" "If you disable a line here THAT COMMIT WILL BE LOST.\n" "\n" "However, if you disable everything, the rebase will be aborted.\n" "\n" "Keyboard Shortcuts\n" "------------------\n" "? = show help\n" "j = move down\n" "k = move up\n" "J = shift row down\n" "K = shift row up\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "spacebar = toggle enabled\n" "\n" "ctrl+enter = accept changes and rebase\n" "ctrl+q = cancel and abort the rebase\n" "ctrl+d = launch difftool\n" msgstr "" msgid "" "\n" "Keyboard Shortcuts\n" "------------------\n" "J, Down = Move Down\n" "K, Up = Move Up\n" "Enter = Edit Selected Files\n" "Spacebar = Open File Using Default Application\n" "Ctrl + L = Focus Text Entry Field\n" "? = Show Help\n" "\n" "The up and down arrows change focus between the text entry field\n" "and the results.\n" msgstr "" "\n" "Поєднання клавіш\n" "------------------\n" "J, Down = Переміститись донизу\n" "K, Up = Перейменувати вгору\n" "Enter = Редагувати вибрані файли\n" "Spacebar = Відкрити файл, використовуючи застосунок за замовчуванням\n" "Ctrl + L = Фокус на полі для введення тексту\n" "? = Показати довідку\n" "\n" "Стрілки вготу та вниз змінюють фокус поміж полем для введення тексту\n" "та результатами.\n" msgid " - DAG" msgstr " - Граф (DAG)" msgid " commits ago" msgstr " комітів тому" #, python-format msgid "\"%(branch)s\" has been deleted from \"%(remote)s\"." msgstr "\"%(branch)s\" було видалено з \"%(remote)s\"." #, python-format msgid "\"%(command)s\" returned exit status \"%(status)d\"" msgstr "\"%(command)s\" завершилась з кодом \"%(status)d\"" #, python-format msgid "\"%(command)s\" returned exit status %(status)d" msgstr "\"%(command)s\" завершилась з кодом %(status)d" #, fuzzy, python-format msgid "\"%s\" already exists" msgstr "Гілка \"%s\" вже існує." #, python-format msgid "\"%s\" already exists, cola will create a new directory" msgstr "\"%s\" вже існує, cola створить новий каталог" #, python-format msgid "\"%s\" requires a selected file." msgstr "\"%s\" потребує вибраного файла." msgid "#" msgstr "" #, python-format msgid "%(project)s: %(branch)s - Browse" msgstr "%(project)s: %(branch)s - Переглянути" #, python-format msgid "%(project)s: %(ref)s - DAG" msgstr "%(project)s: %(ref)s - Граф (DAG)" #, python-format msgid "%d days ago" msgstr "%d днів тому" #, python-format msgid "%d hours ago" msgstr "%d годин тому" #, python-format msgid "%d minutes ago" msgstr "%d хвилин тому" #, python-format msgid "%d patch(es) applied." msgstr "%d латку(ок) застосовано." #, python-format msgid "%d skipped" msgstr "%d пропущено" #, python-format msgid "" "%s appears to contain merge conflicts.\n" "\n" "You should probably skip this file.\n" "Stage it anyways?" msgstr "" "%s здається містить конфлікт злиття.\n" "\n" "Скоріш за все, ви маєте пропустити цей файл.\n" "Проіндексувати в будь-якому випадку?" #, python-format msgid "%s is not a Git repository." msgstr "%s не є репозиторієм Git." #, python-format msgid "%s will be removed from your bookmarks." msgstr "%s буде видалено з ваших закладок." #, python-format msgid "%s will be removed from your recent repositories." msgstr "%s буде видалено зі списку останніх репозиторіїв." #, python-format msgid "%s: No such file or directory." msgstr "%s: Немає такого файла або каталогу." msgid "&Edit" msgstr "Редагувати" msgid "&File" msgstr "Файл" msgid "(Amending)" msgstr "(Зміна коміту)" msgid "*** Branch Point ***" msgstr "*** Вказівка на гілку ***" msgid "*** Sandbox ***" msgstr "*** Пісочниця ***" msgid "100%" msgstr "" msgid "200%" msgstr "" msgid "25%" msgstr "" msgid "400%" msgstr "" msgid "50%" msgstr "" msgid "800%" msgstr "" msgid " ..." msgstr "<шлях> ..." msgid "" "A commit template has not been configured.\n" "Use \"git config\" to define \"commit.template\"\n" "so that it points to a commit template." msgstr "" "Шаблон коміту не сконфігуровано.\n" "Використовуйте \"git config\" щоб задати \"commit.template\"\n" "так, щоб він вказував на шаблон коміту" #, python-format msgid "A hook must be provided at \"%s\"" msgstr "Гак (hook) має бути в \"%s\"" #, python-format msgid "A stash named \"%s\" already exists" msgstr "Сховок з назвою \"%s\" вже існує" msgid "Abort" msgstr "Перервати" msgid "Abort Action" msgstr "Перервати дію" msgid "Abort Merge" msgstr "Перервати злиття" msgid "Abort Merge..." msgstr "Перервати злиття..." msgid "Abort the action?" msgstr "Перервати дію?" msgid "" "Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" "Recovering uncommitted changes is not possible." msgstr "" "Переривання поточного злиття спричинить втрату *ВСІХ* незакомітованих змін.\n" "Відновлення незакомітованих змін неможливе." msgid "Aborting the current merge?" msgstr "Перервати поточне злиття?" msgid "About" msgstr "Про програму" msgid "About git-cola" msgstr "Про git-cola" msgid "Accept" msgstr "Погодитись" #, fuzzy msgid "" "Accept changes and rebase\n" "Shortcut: Ctrl+Enter" msgstr "" "Закомітувати проіндексовані зміни\n" "Поєднання клавіш: Ctrl+Enter" #, fuzzy msgid "Action Name" msgstr "Дії" msgid "Actions" msgstr "Дії" msgid "Actions..." msgstr "Дії..." msgid "Add" msgstr "Додати" msgid "Add Favorite" msgstr "Додати улюбление" msgid "Add Remote" msgstr "Додати віддалений репозиторій" msgid "Add Separator" msgstr "" msgid "Add Toolbar" msgstr "" msgid "" "Add and remove remote repositories using the \n" "Add(+) and Delete(-) buttons on the left-hand side.\n" "\n" "Remotes can be renamed by selecting one from the list\n" "and pressing \"enter\", or by double-clicking." msgstr "" "Додавайте та видаляйте віддалені репозиторіїї використовуючи\n" "кнопки Додати(+) та Видалити(-) в лівій частині програми.\n" "\n" "Віддалені репозиторіїї можна перейменувати, вибрабравши один зі списку\n" "та натиснувши \"enter\", або подвійним кліком мишки." msgid "Add new remote git repository" msgstr "Додати новий віддалений репозиторій git" msgid "Add patches (+)" msgstr "Додати латки (+)" msgid "Add remote" msgstr "Додати віддалений репозиторій" msgid "Add to .gitignore" msgstr "Додати до .gitignore" #, fuzzy msgid "Add to Git Annex" msgstr "Додати до .gitignore" msgid "Add to Git LFS" msgstr "" msgid "Additions" msgstr "Додано" msgid "Advanced" msgstr "Розширено" msgid "Age" msgstr "Вік" msgid "All Repositories" msgstr "Всі репозиторіїї" #, python-format msgid "" "All submodules will be updated using\n" "\"%s\"" msgstr "" msgid "Allow non-fast-forward updates. Using \"force\" can cause the remote repository to lose commits; use it with care" msgstr "Дозволити оновлення без перемотки. Використання \"примусу\" може призвести до того, що віддалений репозиторій втратить коміти; використовйте це з обережністю" msgid "Always create a merge commit when enabled, even when the merge is a fast-forward update" msgstr "Якщо увімкнено, завжди створювати коміт злиття, навіть якщо злиття може бути виконано використовуючи метод перемотки (fast-forward)" msgid "Amend" msgstr "Змінити" msgid "Amend Commit" msgstr "Змінити коміт" msgid "Amend Last Commit" msgstr "Змінити останній коміт" msgid "Amend the published commit?" msgstr "Змінити опублікований коміт?" msgid "Amending" msgstr "Змінення" msgid "" "An action is still running.\n" "Terminating it could result in data loss." msgstr "" "Дія все ще виконується.\n" "Переривання може призвести до втрати даних." msgid "" "An unsigned, lightweight tag will be created instead.\n" "Create an unsigned tag?" msgstr "" "Замість цього буде створено легкий непідписаний теґ.\n" "Створити непідписаний теґ?" msgid "Appearance" msgstr "" msgid "Apply" msgstr "Застосувати" msgid "Apply Patches" msgstr "Застосувати латки" msgid "Apply Patches..." msgstr "Примінити латки..." #, fuzzy msgid "Apply and drop the selected stash (git stash pop)" msgstr "Застосувати виділений сховок" msgid "Apply the selected stash" msgstr "Застосувати виділений сховок" msgid "Arguments" msgstr "Аргументи" msgid "Attach" msgstr "Прикріпити" msgid "Author" msgstr "Автор" msgid "Authors" msgstr "Автори" msgid "Auto" msgstr "" msgid "Auto-Wrap Lines" msgstr "Авто-перенос рядків" msgid "Basic Regexp" msgstr "Базовий регулярний вираз" msgid "Blame Viewer" msgstr "Переглядач анотацій (blame)" #, fuzzy msgid "Blame selected paths" msgstr "Редагувати вибрані шляхи" msgid "Blame..." msgstr "Анотувати (blame)..." msgid "Bold on dark headers instead of italic" msgstr "Напівжирний з темним фоном шрифт замість заголовків курсивом" msgid "Branch" msgstr "Гілка" #, python-format msgid "" "Branch \"%(branch)s\" does not exist in \"%(remote)s\".\n" "A new remote branch will be published." msgstr "" "Гілка \"%(branch)s\" не існує в \"%(remote)s\".\n" "Нова гілка буде опублікована." #, python-format msgid "Branch \"%s\" already exists." msgstr "Гілка \"%s\" вже існує." msgid "Branch Diff Viewer" msgstr "Переглядач різниц на гілкаї" msgid "Branch Exists" msgstr "Гілка існує" msgid "Branch Name" msgstr "Назва гілки" #, python-format msgid "Branch: %s" msgstr "Гілка: %s" msgid "Branches" msgstr "Гілки" msgid "Branches..." msgstr "Гілки..." msgid "Brazilian translation" msgstr "Бразильський переклад" msgid "Browse" msgstr "Переглянути" msgid "Browse Commits..." msgstr "Переглянути коміти..." msgid "Browse Current Branch..." msgstr "Переглянути поточну гілку..." msgid "Browse Other Branch..." msgstr "Переглянути іншу гілку..." msgid "Browse..." msgstr "Переглянути..." msgid "Browser" msgstr "Переглядач" #, python-format msgid "Browsing %s" msgstr "Перегляд %s" msgid "Bypass Commit Hooks" msgstr "Оминути гаки (hooks) коміту" msgid "Cancel" msgstr "" #, fuzzy msgid "" "Cancel rebase\n" "Shortcut: Ctrl+Q" msgstr "" "Закомітувати проіндексовані зміни\n" "Поєднання клавіш: Ctrl+Enter" msgid "Cannot Amend" msgstr "Не вдається змінити" #, python-format msgid "Cannot exec \"%s\": please configure a blame viewer" msgstr "Не вдалось виконати \"%s\": будь ласка налаштуйте переглядач анотацій (blame)" #, python-format msgid "Cannot exec \"%s\": please configure a history browser" msgstr "Не вдалось виконати \"%s\": будь ласка налаштуйте переглядач історії" #, python-format msgid "Cannot exec \"%s\": please configure your editor" msgstr "Не вдалось виконати \"%s\": будь ласка, налаштуйте ваш редактор" msgid "Changed Upstream" msgstr "Змінено в віддаленому джерелі" msgid "Check Spelling" msgstr "Перевірити правопис" msgid "Check spelling" msgstr "Перевірити правопис" msgid "Checkout" msgstr "Переключитись" msgid "Checkout After Creation" msgstr "Переключитись після створення" msgid "Checkout Branch" msgstr "Переключитись на гілку" #, fuzzy msgid "Checkout Detached HEAD" msgstr "Переключитись на гілку" #, fuzzy msgid "Checkout as new branch" msgstr "Переключитись на гілку" msgid "Checkout..." msgstr "Переключитись..." msgid "Cherry Pick" msgstr "Висмикнути коміт (cherry pick)" msgid "Cherry-Pick Commit" msgstr "Висмикнути коміт (cherry pick)" msgid "Cherry-Pick..." msgstr "Висмикнути коміт (cherry pick)..." msgid "Choose Paths" msgstr "Вибрати шляхи" msgid "Choose the \"git grep\" regular expression mode" msgstr "Виберіть режим регулярного виразу \"git grep\"" msgid "Clear Default Repository" msgstr "Очистити репозиторій за замовчуванням" msgid "Clear commit message" msgstr "Очистити повідомлення коміту" msgid "Clear commit message?" msgstr "Очистити повідомлення коміту?" msgid "Clear..." msgstr "Очистити..." #, fuzzy msgid "Clone" msgstr "Клонувати..." msgid "Clone Repository" msgstr "Клонувати репозиторій" msgid "Clone..." msgstr "Клонувати..." #, python-format msgid "Cloning repository at %s" msgstr "Клонувати репозиторій в %s" msgid "Close" msgstr "Закрити" msgid "Close..." msgstr "Закрити..." msgid "Collapse all" msgstr "Згорнути все" #, fuzzy msgid "Command" msgstr "Коміт" msgid "Commit" msgstr "Коміт" msgid "Commit failed" msgstr "Не вдалось зробити коміт" msgid "Commit staged changes" msgstr "Закомітувати проіндексовані зміни" msgid "" "Commit staged changes\n" "Shortcut: Ctrl+Enter" msgstr "" "Закомітувати проіндексовані зміни\n" "Поєднання клавіш: Ctrl+Enter" msgid "Commit summary" msgstr "Опис коміту" msgid "Commit the merge if there are no conflicts. Uncheck to leave the merge uncommitted" msgstr "Закомітувати злиття, якщо немає конфліктів. Зніміть прапорець щоб залишити злиття незакомітованим" msgid "Commit@@verb" msgstr "Закомітувати" msgid "Compare" msgstr "Порівняти" msgid "Compare All" msgstr "Порівняти все" msgid "Configure the remote branch as the the new upstream" msgstr "Налаштувати віддалену гілку як нове віддалене джерело" msgid "Configure toolbar" msgstr "" msgid "Console" msgstr "Консоль" msgid "Continue" msgstr "Продовжити" msgid "Copy" msgstr "Скопіювати" #, fuzzy msgid "Copy Basename to Clipboard" msgstr "Скопіювати шлях в буфер обміну" #, fuzzy msgid "Copy Leading Path to Clipboard" msgstr "Скопіювати відносний шлях в буфер обміну" msgid "Copy Path to Clipboard" msgstr "Скопіювати шлях в буфер обміну" msgid "Copy Relative Path to Clipboard" msgstr "Скопіювати відносний шлях в буфер обміну" msgid "Copy SHA-1" msgstr "Скопіювати SHA-1" #, fuzzy msgid "Copy..." msgstr "Скопіювати" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "Не вдалось розпізнати Git URL: \"%s\"" msgid "Create Branch" msgstr "Створити гілку" msgid "Create Patch" msgstr "Створити латку" msgid "Create Remote Branch" msgstr "Створити віддалену гілку" msgid "Create Signed Commit" msgstr "Створити підписаний коміт" msgid "Create Tag" msgstr "Створити теґ" msgid "Create Tag..." msgstr "Створити теґ..." msgid "Create Unsigned Tag" msgstr "Створити непідписаний теґ" msgid "Create a merge commit even when the merge resolves as a fast-forward" msgstr "Створити коміт злиття навіть якщо злиття може бути вирішено методом перемотки" msgid "Create a new remote branch?" msgstr "Створити нову віддалену гілку?" msgid "Create..." msgstr "Створити..." #, python-format msgid "Created a new tag named \"%s\"" msgstr "Створено новий теґ з назвою \"%s\"" msgid "Current Repository" msgstr "Поточний репозиторій" msgid "Custom Copy Actions" msgstr "" #, fuzzy msgid "Customize..." msgstr "Закрити..." msgid "Cut" msgstr "" #, fuzzy msgid "Czech translation" msgstr "Французький переклад" msgid "DAG..." msgstr "Граф (DAG)..." msgid "Dark Theme" msgstr "" msgid "Date, Time" msgstr "Дата, час" msgid "Default" msgstr "" msgid "Delete" msgstr "Видалити" #, python-format msgid "Delete %d file(s)?" msgstr "Видалити %d файл(ів)?" msgid "Delete Bookmark" msgstr "Видалити закладку" msgid "Delete Bookmark?" msgstr "Видалити закладку?" msgid "Delete Branch" msgstr "Видалити гілку" msgid "Delete Files" msgstr "Видалити файли" msgid "Delete Files..." msgstr "Видалити файли..." msgid "Delete Files?" msgstr "Видалити файли?" msgid "Delete Remote" msgstr "Видалити віддалений репозиторій" msgid "Delete Remote Branch" msgstr "Видалити віддалену гілку" msgid "Delete Remote Branch..." msgstr "Видалити віддалену гілку..." msgid "Delete remote" msgstr "Видалити віддалений репозиторій" #, python-format msgid "Delete remote \"%s\"" msgstr "Видалити віддалений репозиторій \"%s\"" msgid "Delete remote?" msgstr "Видалити віддалений репозиторій?" msgid "Delete selected branch?" msgstr "Видалити виділену гілку?" #, fuzzy msgid "Delete toolbar" msgstr "Видалити закладку" msgid "Delete..." msgstr "Видалити..." #, python-format msgid "Deleting \"%s\" failed" msgstr "Не вдалось видалити \"%s\"" msgid "Deletions" msgstr "Видалено" msgid "Detach" msgstr "Відкріпити" msgid "Detect Conflict Markers" msgstr "Виявити мітки конфліктів" msgid "Detect conflict markers in unmerged files" msgstr "Виявити мітки конфліктів в незлитих файлах" msgid "Developer" msgstr "Розробник" msgid "Diff" msgstr "Різниця" msgid "Diff Against Predecessor..." msgstr "Різниця до попередника..." msgid "Diff Options" msgstr "Опції порівняння" msgid "Diff Tool" msgstr "Інструмент порівняння" msgid "Diff selected -> this" msgstr "Порівняти виділене з цим" msgid "Diff this -> selected" msgstr "Порівняти це з виділеним" msgid "Diffstat" msgstr "Список різниць" #, fuzzy msgid "Difftool" msgstr "Інструмент порівняння" msgid "Directory Exists" msgstr "Каталог існує" msgid "Display Untracked Files" msgstr "Показати файли, що не відслідковуються" msgid "Documentation" msgstr "Документація" msgid "Drop" msgstr "Видалити" msgid "Drop Stash" msgstr "Видалити сховок" msgid "Drop Stash?" msgstr "Видалити сховок?" #, python-format msgid "Drop the \"%s\" stash?" msgstr "Видалити \"%s\" сховок?" msgid "Drop the selected stash" msgstr "Видалити вибраний сховок" #, fuzzy msgid "Edit" msgstr "Редагувати" msgid "Edit Rebase" msgstr "Редагувати переміщення (rebase)" msgid "Edit Remotes" msgstr "Редагувати віддалені репозиторіїї" msgid "Edit Remotes..." msgstr "Редагувати віддалені репозиторіїї..." msgid "Edit remotes by selecting them from the list" msgstr "" msgid "Edit selected paths" msgstr "Редагувати вибрані шляхи" msgid "Edit..." msgstr "Редагувати..." msgid "Editor" msgstr "Редактор" msgid "Email Address" msgstr "Адреса електронної пошти" msgid "Email contributor" msgstr "Електронна пошта учасника" msgid "Enabled" msgstr "" msgid "Enter New Branch Name" msgstr "Введіть ім'я для нової гілки" #, fuzzy msgid "Enter a name for the new bare repo" msgstr "Введіть назву для сховка" msgid "Enter a name for the stash" msgstr "Введіть назву для сховка" msgid "Error" msgstr "Помилка" msgid "Error Cloning" msgstr "Помилка клонування" msgid "Error Creating Branch" msgstr "Помилка при створенні гілки" msgid "Error Creating Repository" msgstr "Помилка створення репозиторію" msgid "Error Deleting Remote Branch" msgstr "Не вдалось видалити віддалену гілку" msgid "Error Editing File" msgstr "Помилка редагування файла" msgid "Error Launching Blame Viewer" msgstr "Помилка запуску переглядача анотацій (blame)" msgid "Error Launching History Browser" msgstr "Помилка запуску браузера історії" #, python-format msgid "Error creating remote \"%s\"" msgstr "Не вдалось створити віддалений репозиторій \"%s\"" #, fuzzy msgid "Error creating stash" msgstr "Помилка при створенні гілки" #, python-format msgid "Error deleting remote \"%s\"" msgstr "Не вдалось видалити віддалений репозиторій \"%s\"" #, fuzzy, python-format msgid "Error renaming \"%(name)s\" to \"%(new_name)s\"" msgstr "Позначення \"%(revision)s\" як \"%(name)s\"" msgid "Error running prepare-commitmsg hook" msgstr "Помилка застосування prepare-commitmsg гака (hook)" #, fuzzy, python-format msgid "Error updating submodule %s" msgstr "Не вдалось створити віддалений репозиторій \"%s\"" #, fuzzy msgid "Error updating submodules" msgstr "Помилка редагування файла" msgid "Error: Cannot find commit template" msgstr "Помилка: Не вдається знайти шаблон коміту" msgid "Error: Stash exists" msgstr "Помилка: сховок вже існує" msgid "Error: Unconfigured commit template" msgstr "Помилка: Шаблон коміту не сконфігуровано" #, python-format msgid "Error: could not clone \"%s\"" msgstr "Помилка: не вдалось клонувати \"%s\"" #, python-format msgid "Error: could not create tag \"%s\"" msgstr "Помилка: не вдалось створити теґ \"%s\"" #, python-format msgid "Executing action %s" msgstr "Виконання дії %s" msgid "Expand all" msgstr "Розгорнути все" msgid "Export Patches" msgstr "Експорт латок" msgid "Export Patches..." msgstr "Експортувати латки..." msgid "Expression..." msgstr "Вираз..." msgid "Extended Regexp" msgstr "Розширений регулярний вираз" msgid "Extended description..." msgstr "Розширений опис..." msgid "Fast Forward Only" msgstr "Лише перемотка (fast-forward)" msgid "Fast-forward only" msgstr "Лише перемотка (fast-forward)" msgid "Favorite repositories" msgstr "Улюблені репозиторіїї" msgid "Favorites" msgstr "Улюбене" msgid "Fetch" msgstr "Отримати" msgid "Fetch Tracking Branch" msgstr "Отримати гілку, що відстежується" msgid "Fetch..." msgstr "Отримати" msgid "File Browser..." msgstr "Переглядач файлів..." msgid "File Differences" msgstr "Різниця між файлами" msgid "File Saved" msgstr "Файл збережено" #, python-format msgid "File saved to \"%s\"" msgstr "Дайл збережено до \"%s\"" msgid "File system change monitoring: disabled because \"cola.inotify\" is false.\n" msgstr "Відстеження змін файлової системи: вимкнено, тому що \"cola.inotify\" є хибним (false).\n" msgid "File system change monitoring: disabled because libc does not support the inotify system calls.\n" msgstr "Відстеження змін файлової системи: вимкнено, тому що libc не підтримує системних викликів inotify.\n" msgid "File system change monitoring: disabled because pywin32 is not installed.\n" msgstr "Відстеження змін файлової системи: вимкнено, тому що не встановлено pywin32.\n" msgid "" "File system change monitoring: disabled because the limit on the total number of inotify watches was reached. You may be able to increase the limit on the number of watches by running:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" msgstr "" "Відстеження змін файлової системи: вимкнено, тому що досягнуто верхньої межі кількості спостерігачів inotify. Ви можете збільшити ліміт кількості спостерігачів, виконавши:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" msgid "File system change monitoring: enabled.\n" msgstr "Відстеження змін файлової системи: увімкнено.\n" msgid "Filename" msgstr "Ім'я файла" msgid "Files" msgstr "Файли" msgid "Filter branches..." msgstr "Фільтрувати гілки..." msgid "Filter paths..." msgstr "Фільтрувати шляхи..." msgid "Find Files" msgstr "Пошук файлів" msgid "Fixed String" msgstr "Фіксована послідовність знаків" msgid "Fixed-Width Font" msgstr "Моноширний шрифт" msgid "Fixup" msgstr "" msgid "Fixup Previous Commit" msgstr "Виправити попередній коміт" msgid "Flat dark blue" msgstr "" msgid "Flat dark green" msgstr "" msgid "Flat dark grey" msgstr "" msgid "Flat dark red" msgstr "" msgid "Flat light blue" msgstr "" msgid "Flat light green" msgstr "" msgid "Flat light grey" msgstr "" msgid "Flat light red" msgstr "" msgid "Font Size" msgstr "Розмір шрифта" msgid "Force" msgstr "Надіслати примусово" msgid "Force Fetch" msgstr "Отримати примусово" msgid "Force Fetch?" msgstr "Отримати примусово?" msgid "Force Push" msgstr "Надіслати примусово" msgid "Force Push?" msgstr "Надіслати примусово?" #, python-format msgid "Force fetching from %s?" msgstr "Примусове отримання з %s?" #, python-format msgid "Force push to %s?" msgstr "Надіслати примусово до %s?" #, fuzzy msgid "Format String" msgstr "Фіксована послідовність знаків" msgid "French translation" msgstr "Французький переклад" msgid "GPG-sign the merge commit" msgstr "Підписати-GPG коміт злиття" msgid "GUI theme" msgstr "" #, python-format msgid "Gathering info for \"%s\"..." msgstr "Збирання інформації для \"%s\"..." msgid "German translation" msgstr "Німецький переклад" msgid "Get Commit Message Template" msgstr "Отримати шаблон тексту коміту" msgid "Go Down" msgstr "Вниз" msgid "Go Up" msgstr "Вгору" msgid "Grab File..." msgstr "Взяти файл..." msgid "Graph" msgstr "Графік" msgid "Grep" msgstr "Пошук (grep)" msgid "Have you rebased/pulled lately?" msgstr "Чи ви робили переміщення/стягнення останнім часом?" msgid "Help" msgstr "Допомога" msgid "Help - Custom Copy Actions" msgstr "" msgid "Help - Find Files" msgstr "Допомога - Пошук файлів" msgid "Help - git-xbase" msgstr "" msgid "Hide Details.." msgstr "" msgid "High DPI" msgstr "" msgid "History Browser" msgstr "Переглядач історії" #, fuzzy msgid "Hungarian translation" msgstr "Російський переклад" msgid "Icon theme" msgstr "" msgid "Ignore all whitespace" msgstr "Ігнорувати всі пробіли" msgid "Ignore changes in amount of whitespace" msgstr "Ігнорувати зміни в кількості пробілів" msgid "Ignore changes in whitespace at EOL" msgstr "Ігнорувати зміни в пробільних знаках в кінці рядка" #, fuzzy msgid "Ignore custom pattern" msgstr "Ігнорувати специфічний шаблон" msgid "Ignore exact filename" msgstr "Ігнорувати точне ім'я файлу" msgid "Ignore filename or pattern" msgstr "Ігнорувати ім'я файлу або шаблон" msgid "Include tags " msgstr "Включити теґ" msgid "Indent Status paths" msgstr "" msgid "Indonesian translation" msgstr "Індонезійський переклад" msgid "Initialize Git Annex" msgstr "" msgid "Initialize Git LFS" msgstr "" msgid "Inititalize submodules" msgstr "" msgid "Insert spaces instead of tabs" msgstr "" msgid "Interactive Rebase" msgstr "Інтерактивне переміщення" msgid "Invalid Revision" msgstr "Неправильна ревізія" msgid "Keep *.orig Merge Backups" msgstr "Зберігати резервні копії *.orig файлів після злиття" msgid "Keep Index" msgstr "Зберегти індекс" msgid "Keyboard Shortcuts" msgstr "Поєднання клавіш" msgid "Launch Diff Tool" msgstr "Запустити інструмент порівняння" msgid "Launch Directory Diff Tool" msgstr "Запустити каталоговий інструмент порівняння" msgid "Launch Editor" msgstr "Відкрити редактор" msgid "Launch Terminal" msgstr "Запустити термінал" msgid "" "Launch external diff tool\n" "Shortcut: Ctrl+D" msgstr "" msgid "Launch git-cola" msgstr "Запустити git-cola" msgid "Launch git-difftool against previous versions" msgstr "Запустити git-difftool до попередньої версії" msgid "Launch git-difftool on the current path" msgstr "Запустити git-difftool для поточного шляху" msgid "Light Theme" msgstr "" msgid "Load Commit Message" msgstr "Завантажити повідомлення коміту" msgid "Load Commit Message..." msgstr "Завантажити текст коміту..." msgid "Load Previous Commit Message" msgstr "Завантажити повідомлення попереднього коміту" msgid "Loading..." msgstr "Завантаження..." msgid "Local" msgstr "Локальна" msgid "Local Branch" msgstr "Локальна гілка" msgid "Local branch" msgstr "Локальна гілка" msgid "Lock Layout" msgstr "Закріпити положення елементів" msgid "Log" msgstr "Журнал подій" msgid "Maintainer (since 2007) and developer" msgstr "Супроводжуючий (з 2007) та розробник" msgid "Merge" msgstr "Злиття" #, python-format msgid "Merge \"%(revision)s\" into \"%(branch)s\"" msgstr "Злити \"%(revision)s\" в \"%(branch)s\"" msgid "Merge Tool" msgstr "Інструмент злиття" msgid "Merge Verbosity" msgstr "Детальність злиття" msgid "Merge failed. Conflict resolution is required." msgstr "" #, python-format msgid "Merge into \"%s\"" msgstr "Злити в \"%s\"" msgid "Merge into current branch" msgstr "Злити до поточної гілки" msgid "Merge..." msgstr "Злиття" msgid "Merging" msgstr "Злиття" msgid "Message" msgstr "Повідомлення" msgid "Missing Commit Message" msgstr "Відсутнє повідомлення коміту" msgid "Missing Data" msgstr "Дані відсутні" msgid "Missing Name" msgstr "Назва відсутня" msgid "Missing Revision" msgstr "Ревізія відсутня" msgid "Missing Tag Message" msgstr "Назва теґу відсутня" msgid "Modified" msgstr "Змінене" msgid "More..." msgstr "Більше..." msgid "Move Down" msgstr "Перемістити вниз" msgid "Move Up" msgstr "Перемістити вгору" msgid "Move files to trash" msgstr "Перемістити файл до смітника" msgid "Name" msgstr "Ім'я" msgid "Name for the new remote" msgstr "Назва нового віддаленого репозиторію" #, fuzzy msgid "New Bare Repository..." msgstr "Новий репозиторій..." msgid "New Repository..." msgstr "Новий репозиторій..." msgid "New..." msgstr "Новий..." msgid "Next File" msgstr "Наступний файл" msgid "No" msgstr "Ні" msgid "No Revision Specified" msgstr "Ревізію не вказано" msgid "" "No changes to commit.\n" "\n" "You must stage at least 1 file before you can commit." msgstr "" "Немає змін для коміту.\n" "\n" "Ви маєте проіндексувати принаймні 1 файл перед тим, як ви зможете зробити коміт." msgid "No commits exist in this branch." msgstr "На цій гілці немає комітів." msgid "No fast forward" msgstr "Без перемотки (fast-forward)" msgid "No fast-forward" msgstr "Без перемотки" msgid "No repository selected." msgstr "Не вибрано жодного репозиторію." msgid "Non-fast-forward fetch overwrites local history!" msgstr "Отримання без використання методу перемотки перезапише локальну історію!" msgid "" "Non-fast-forward push overwrites published history!\n" "(Did you pull first?)" msgstr "" "Надсилання без використання методу перемотки перезапише опубліковану історію!\n" "(Чи всі зміни стягнуто?)" msgid "Nothing to commit" msgstr "Немає що комітувати" msgid "Nothing to do" msgstr "Нічого робити" msgid "Number of Diff Context Lines" msgstr "Число рядків контексту різниці" msgid "Open" msgstr "Відкрити" msgid "Open Git Repository..." msgstr "Відкрити Git репозиторій..." #, fuzzy msgid "Open Parent" msgstr "Відкрити останній" msgid "Open Parent Directory" msgstr "Відкрити батьківський каталог" msgid "Open Recent" msgstr "Відкрити останній" msgid "Open Using Default Application" msgstr "Відкрити, використовуючи застосунок за замовчуванням" msgid "Open in New Window" msgstr "Відкрити в новому вікні" msgid "Open in New Window..." msgstr "Відкрити в новому вікні..." msgid "Open..." msgstr "Відкрити" #, fuzzy msgid "Other branches" msgstr "Фільтрувати гілки..." msgid "Overwrite" msgstr "Перезаписати" #, python-format msgid "Overwrite \"%s\"?" msgstr "Перезаписати \"%s\"?" msgid "Overwrite File?" msgstr "Перезаписати файл?" msgid "" "Parse arguments using a shell.\n" "Queries with spaces will require \"double quotes\"." msgstr "" "Розібрати аргументи використовуючи командну стрічку.\n" "Запити з пробілами вимагатимуть \"лапок\"." msgid "Partially Staged" msgstr "Частково проіндексоване" msgid "Paste" msgstr "" msgid "Patch(es) Applied" msgstr "Латку(и) застосовано" msgid "Path" msgstr "Шлях" msgid "Path or URL to clone (Env. $VARS okay)" msgstr "Шлях або URL для клонування (Env. $VARS okay)" msgid "Pick" msgstr "" msgid "Pixel XOR" msgstr "" msgid "Please provide both a branch name and revision expression." msgstr "Будь ласка, надайте як ім'я гілки так і вираз ревізії." msgid "Please select a file" msgstr "Будь ласка, виберіть файл" msgid "Please specify a name for the new tag." msgstr "Будь ласка, вкажіть назву для теґу." msgid "Please specify a revision to tag." msgstr "Будь ласка, вкажіть ревізію для теґу." msgid "" "Please supply a commit message.\n" "\n" "A good commit message has the following format:\n" "\n" "- First line: Describe in one sentence what you did.\n" "- Second line: Blank\n" "- Remaining lines: Describe why this change is good.\n" msgstr "" "Будь ласка, напишіть текст коміту.\n" "\n" "Хороше повідомлення коміту має наступний формат:\n" "\n" "- Перший рядок: Опишіть одним повідомленням що ви робили.\n" "- Другий рядок: Пусто\n" "- Решта рядків: Опишіть, чому ці зміни хороші.\n" msgid "Point the current branch head to a new commit?" msgstr "Встановити HEAD поточної гілки на новий коміт?" msgid "Polish translation" msgstr "Польський переклад" msgid "Pop" msgstr "" msgid "Preferences" msgstr "Налаштування" msgid "Prefix" msgstr "Префікс" msgid "Prepare Commit Message" msgstr "Підготувати текст коміту" msgid "Prevent \"Stage\" from staging all files when nothing is selected" msgstr "" msgid "Previous File" msgstr "Попередній файл" msgid "Prompt on creation" msgstr "Підказати при створенні" msgid "Prompt when pushing creates new remote branches" msgstr "Підказати коли надсилаются новостворені віддалені гілки" msgid "Prune " msgstr "" msgid "Pull" msgstr "Стягнути" msgid "Pull..." msgstr "Стягнути" msgid "Push" msgstr "Надіслати" msgid "Push..." msgstr "Надіслати" msgid "Quit" msgstr "Вихід" msgid "Rebase" msgstr "Перемістити (rebase)" #, python-format msgid "Rebase onto %s" msgstr "Перемістити (rebase) на %s" #, fuzzy msgid "Rebase stopped" msgstr "Перемістити (rebase) на %s" msgid "Rebase the current branch instead of merging" msgstr "Перемістити поточну гілку замість злиття" msgid "Rebasing" msgstr "Переміщення" msgid "Recent" msgstr "Недавнє" msgid "Recent repositories" msgstr "Недавні репозиторіїї" #, fuzzy msgid "Recent repository count" msgstr "Недавні репозиторіїї" msgid "Recently Modified Files" msgstr "Недавно змінені файли" msgid "Recently Modified Files..." msgstr "Недавно змінені файли..." msgid "Recovering a dropped stash is not possible." msgstr "Неможливо відновити видалений сховок." msgid "Recovering lost commits may not be easy." msgstr "Відновлення втрачених комітів може бути нелегким." msgid "Redo" msgstr "" msgid "Reduce commit history to minimum" msgstr "" msgid "Refresh" msgstr "Оновити" msgid "Refuse to merge unless the current HEAD is already up-to-date or the merge can be resolved as a fast-forward" msgstr "Відмовтесь від злиття за винятком, коли поточний HEAD є оновленим або злиття може бети вирішено методом перемотки" msgid "Remote" msgstr "Віддалений репозиторій" msgid "Remote Branch" msgstr "Віддалена гілка" msgid "Remote Branch Deleted" msgstr "Видалено віддалену гілку" msgid "Remote git repositories - double-click to rename" msgstr "Віддалені репозиторіїї git - подвійний клік для перейменування" msgid "Remove" msgstr "Видалити" #, python-format msgid "Remove %s from the recent list?" msgstr "Видалити %s зі списку останніх?" msgid "Remove Element" msgstr "Видалити елемент" msgid "Remove remote-tracking branches that no longer exist on the remote" msgstr "" msgid "Remove selected (Delete)" msgstr "Видалити виділене (Видалити)" msgid "Rename" msgstr "Перейменувати" #, fuzzy, python-format msgid "Rename \"%s\"" msgstr "Перейменувати" msgid "Rename Branch" msgstr "Перейменувати гілку" msgid "Rename Branch..." msgstr "Перейменувати гілку..." msgid "Rename Existing Branch" msgstr "Перейменувати існуючу гілку" msgid "Rename Remote" msgstr "Перейменувати віддалений репозиторій" msgid "Rename Repository" msgstr "Перейменувати репозиторій" msgid "Rename branch" msgstr "Перейменувати гілку" #, python-format msgid "Rename remote \"%(current)s\" to \"%(new)s\"?" msgstr "Перейменувати віддалений репозиторій \"%(current)s\" в \"%(new)s\"?" #, fuzzy msgid "Rename selected paths" msgstr "Редагувати вибрані шляхи" #, python-format msgid "Repository: %s" msgstr "Репозиторій: %s" msgid "Reset" msgstr "Скинути" #, python-format msgid "Reset \"%(branch)s\" to \"%(revision)s\"?" msgstr "Скинути \"%(branch)s\" до \"%(revision)s\"?" msgid "Reset Branch" msgstr "Скинути гілку" msgid "Reset Branch Head" msgstr "Скинути HEAD гілки" msgid "Reset Branch?" msgstr "Скинути гілку?" #, fuzzy msgid "Reset Hard" msgstr "Скинути HEAD гілки" #, fuzzy msgid "Reset Merge" msgstr "Ревізія для злиття" #, fuzzy msgid "Reset Soft" msgstr "Скинути робоче дерево" msgid "Reset Worktree" msgstr "Скинути робоче дерево" #, fuzzy msgid "Reset hard?" msgstr "Скинути гілку?" #, fuzzy msgid "Reset merge?" msgstr "Скинути робоче дерево?" #, fuzzy msgid "Reset soft?" msgstr "Скинути робоче дерево?" msgid "Reset worktree?" msgstr "Скинути робоче дерево?" #, python-format msgid "Resetting \"%(branch)s\" to \"%(revision)s\" will lose commits." msgstr "Скидання \"%(branch)s\" до \"%(revision)s\" призведе до втрати комітів." msgid "Restart the application after changing appearance settings." msgstr "" msgid "Revert" msgstr "" msgid "Revert Diff Hunk" msgstr "Скасувати частину різниці" msgid "Revert Diff Hunk..." msgstr "Скасувати частину різниці..." msgid "Revert Diff Hunk?" msgstr "Скасувати частину різниці?" msgid "Revert Selected Lines" msgstr "Скасувати виділені рядки" msgid "Revert Selected Lines..." msgstr "Скасування виділених рядків..." msgid "Revert Selected Lines?" msgstr "Скасувати виділені рядки?" msgid "Revert Uncommitted Changes" msgstr "Відмінити незакомітовані зміни" msgid "Revert Uncommitted Changes?" msgstr "Відмінити незакомітовані зміни?" msgid "Revert Uncommitted Edits..." msgstr "Відмінити незакомітовані зміни..." msgid "Revert Unstaged Changes" msgstr "Відмінити непроіндексовані зміни" msgid "Revert Unstaged Changes?" msgstr "Відмінити непроіндексовані зміни?" msgid "Revert Unstaged Edits..." msgstr "Відмінити непроіндексовані зміни..." msgid "Revert the uncommitted changes?" msgstr "Відмінити незакомітовані зміни?" msgid "Revert the unstaged changes?" msgstr "Відмінити непроіндексовані зміни?" msgid "Revert uncommitted changes to selected paths" msgstr "Відмінити незакомітовані зміни на вибраних шляхах" msgid "Revert unstaged changes to selected paths" msgstr "Відмінити непроіндексовані зміни на вибраних шляхах" msgid "Review" msgstr "Перевірка" msgid "Review..." msgstr "Перевірка..." msgid "Revision" msgstr "Ревізія" msgid "Revision Expression:" msgstr "Вираз для визначення ревізії:" msgid "Revision to Merge" msgstr "Ревізія для злиття" msgid "Reword" msgstr "" msgid "Rewrite Published Commit?" msgstr "Перезаписати опублікований коміт?" msgid "Run" msgstr "Запустити" #, python-format msgid "Run \"%s\"?" msgstr "Виконати \"%s\"?" #, python-format msgid "Run %s?" msgstr "Запустити %s?" #, python-format msgid "Run the \"%s\" command?" msgstr "Виконати команду \"%s\"?" #, python-format msgid "Running command: %s" msgstr "Запуск команди: %s" msgid "Russian translation" msgstr "Російський переклад" #, fuzzy msgid "SHA-1" msgstr "Скопіювати SHA-1" #, fuzzy msgid "Safe Mode" msgstr "Проіндексувати зміни" msgid "Save" msgstr "Зберегти" msgid "Save Archive" msgstr "Зберегти архів" msgid "Save As Tarball/Zip..." msgstr "Зберегти як Tarball/Zip..." msgid "Save GUI Settings" msgstr "Зберегти налаштування графічного інтерфейсу" msgid "Save Stash" msgstr "Зберегти сховок" msgid "Save modified state to new stash" msgstr "Зберегти змінений стан до нового сховка" #, python-format msgid "Saved \"%(filename)s\" from \"%(ref)s\" to \"%(destination)s\"" msgstr "Збережено \"%(filename)s\" з \"%(ref)s\" до \"%(destination)s\"" msgid "Search" msgstr "Пошук" msgid "Search Authors" msgstr "Пошук авторів" msgid "Search Commit Messages" msgstr "Пошук тексту коіта" msgid "Search Committers" msgstr "Пошук комітерів" msgid "Search Date Range" msgstr "Пошук діапазону дат" msgid "Search Diffs" msgstr "Пошук різниць" msgid "Search by Expression" msgstr "Пошук за виразом" msgid "Search by Path" msgstr "Пошук за шляхом" msgid "Search for a fixed string" msgstr "Шукати фіксовану послідовність знаків" msgid "Search using a POSIX basic regular expression" msgstr "Шукати, використовуючи базовий регулярний вираз POSIX" msgid "Search using a POSIX extended regular expression" msgstr "Шукати, використовуючи розширений регулярний вираз POSIX" msgid "Search..." msgstr "Пошук..." msgid "Select" msgstr "Вибрати" msgid "Select All" msgstr "Виділити все" msgid "Select Branch to Review" msgstr "Виберіть гілку для перевірки" msgid "Select Child" msgstr "Вибрати потомка" msgid "Select Commit" msgstr "Вибрати коміт" #, fuzzy msgid "Select Directory..." msgstr "Вибрати репозиторій..." msgid "Select New Upstream" msgstr "Вибрати нове віддалене джерело" msgid "Select Newest Child" msgstr "Вибрати найновішого потомка" msgid "Select Oldest Parent" msgstr "Вибрати найстаршого предка" msgid "Select Parent" msgstr "Вибрати предка" msgid "Select Previous Version" msgstr "Вибрати попередню версію" msgid "Select Repository..." msgstr "Вибрати репозиторій..." msgid "Select a parent directory for the new clone" msgstr "Виберіть батьківський каталог для нового клонування" msgid "Select manually..." msgstr "Вибрати вручну..." #, fuzzy msgid "Select output dir" msgstr "Вибрати коміт" #, fuzzy msgid "Select output directory" msgstr "Вибрати репозиторій..." msgid "Select patch file(s)..." msgstr "Виберіть файл(и) латки(ок)..." #, fuzzy msgid "Select repository" msgstr "Вибрати репозиторій..." msgid "Set Default Repository" msgstr "Встановити репозиторій за замовчуванням" #, fuzzy msgid "Set Upstream Branch" msgstr "Встановити віддалене джерело" msgid "" "Set the sort order for branches and tags.\n" "Toggle between date-based and version-name-based sorting." msgstr "" msgid "Set upstream" msgstr "Встановити віддалене джерело" msgid "Settings" msgstr "Налаштування" msgid "Shell arguments" msgstr "Аргументи командної стрічки" msgid "Shift Down" msgstr "" msgid "Shift Up" msgstr "" msgid "Shortcuts" msgstr "Поєднання клавіш" #, fuzzy msgid "Show Details..." msgstr "Видалити файли..." msgid "Show Diffstat After Merge" msgstr "Показати список різниць після злиття" msgid "Show Full Paths in the Window Title" msgstr "" msgid "Show Help" msgstr "Показати допомогу" msgid "Show History" msgstr "Показати історію" msgid "Show file counts in Status titles" msgstr "" msgid "" "Show help\n" "Shortcut: ?" msgstr "" "Показати допомогу\n" "Клавіша: ?" msgid "Show icon? (if available)" msgstr "" msgid "Show line numbers" msgstr "Показати нумерацію рядків" msgid "Show whole surrounding functions of changes" msgstr "Показати всі оточуючі функції при змінах" msgid "Showing changes since" msgstr "Показ змін від" msgid "Side by side" msgstr "" msgid "Sign Off" msgstr "Підписати" msgid "Sign Tag" msgstr "Підписати теґ" msgid "Sign off on this commit" msgstr "Підписатись під цим комітом" #, fuzzy msgid "Simplified Chinese translation" msgstr "Китайський переклад" msgid "Skip" msgstr "Пропустити" msgid "Skip Current Patch" msgstr "Пропустити поточну латку" msgid "Sort bookmarks alphabetically" msgstr "Сортувати закладки за алфавітом" msgid "Spanish translation" msgstr "Іспанський переклад" msgid "Specifies the SHA-1 to tag" msgstr "Визначає SHA-1 теґу" msgid "Specifies the tag message" msgstr "Визначає повідомлення теґу" msgid "Specifies the tag name" msgstr "Задає ім'я теґу" msgid "Spelling Suggestions" msgstr "Поради з правопису" msgid "Squash" msgstr "Об'єднати" msgid "Squash the merged commits into a single commit" msgstr "Об'єднати злиті коміти в один коміт" msgid "Stage" msgstr "Проіндексувати" msgid "Stage / Unstage" msgstr "Проіндексувати / Видалити з проіндексованого" msgid "Stage All Untracked" msgstr "Проіндексувати всі непроіндексовані файли" msgid "Stage Changed Files To Commit" msgstr "Додати змінені файли до коміту" msgid "Stage Diff Hunk" msgstr "Додати частину різниці до проіндексованого" msgid "Stage Modified" msgstr "Проіндексувати зміни" msgid "Stage Selected" msgstr "Додати виділене до проіндексованого" msgid "Stage Selected Lines" msgstr "Додати виділені рядки до проіндексованого" msgid "Stage Unmerged" msgstr "Проіндексувати незлите" msgid "Stage Untracked" msgstr "Проіндексувати файли, що не відслідковуються" msgid "Stage and Commit" msgstr "Проіндексувати та закомітувати" msgid "Stage and commit?" msgstr "Проіндексувати та закомітувати?" msgid "Stage conflicts" msgstr "Проіндексувати конфлікт" msgid "Stage conflicts?" msgstr "Проіндексувати конфлікт?" msgid "Stage/unstage selected paths for commit" msgstr "Додати/видалити з проіндексованого шляхи для коміту" msgid "Staged" msgstr "Проіндексоване" #, python-format msgid "Staging: %s" msgstr "Індексація: %s" msgid "Start Interactive Rebase..." msgstr "Розпочати інтерактивне переміщення..." msgid "Starting Revision" msgstr "Початкова ревізія" msgid "Stash" msgstr "Сховати (stash)" #, fuzzy msgid "Stash Index" msgstr "Сховати (stash)" #, fuzzy msgid "Stash staged changes only" msgstr "Закомітувати проіндексовані зміни" #, fuzzy msgid "Stash unstaged changes only, keeping staged changes" msgstr "Відмінити непроіндексовані зміни на вибраних шляхах" msgid "Stash..." msgstr "Сховок" msgid "Status" msgstr "Статус" msgid "Stop tracking paths" msgstr "Перестати відслідковувати виділене" msgid "Submodules" msgstr "" msgid "Summarize Merge Commits" msgstr "Підсумувати коміти злиття" msgid "Summary" msgstr "Опис" msgid "Tab Width" msgstr "Ширина табуляції" msgid "Tag" msgstr "Теґ" msgid "Tag Created" msgstr "Теґ створено" msgid "Tag message..." msgstr "Повідомлення теґу..." msgid "Tag-signing was requested but the tag message is empty." msgstr "Вібувся запит на підписання теґу, але повідомлення для теґу порожнє." msgid "Tags" msgstr "Теґи" msgid "Text Width" msgstr "Ширина тексту" msgid "The branch will be no longer available." msgstr "Гілка не буде більше доступна." #, fuzzy, python-format msgid "The branch will be reset using \"git reset --hard %s\"" msgstr "Глку буде скинуто, використовуючи \"git reset --mixed %s\"" #, fuzzy, python-format msgid "The branch will be reset using \"git reset --merge %s\"" msgstr "Глку буде скинуто, використовуючи \"git reset --mixed %s\"" #, python-format msgid "The branch will be reset using \"git reset --mixed %s\"" msgstr "Глку буде скинуто, використовуючи \"git reset --mixed %s\"" #, fuzzy, python-format msgid "The branch will be reset using \"git reset --soft %s\"" msgstr "Глку буде скинуто, використовуючи \"git reset --mixed %s\"" msgid "The commit message will be cleared." msgstr "Повідомлення коміту буде очищено." #, python-format msgid "The file \"%s\" exists and will be overwritten." msgstr "Файл \"%s\" вже існує і буде перезаписаний." msgid "The following files will be deleted:" msgstr "Наступні файли будуть видалені:" msgid "The revision expression cannot be empty." msgstr "Поле ревізії не може бути порожнім." #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, fuzzy, python-format msgid "The worktree will be reset using \"git reset --keep %s\"" msgstr "Робче дерево буде скинуто, використовуючи \"git reset --merge %s\"" msgid "This cannot be undone. Clear commit message?" msgstr "Це неможливо буде відмінити. Очистити повідомлення коміту?" msgid "" "This commit has already been published.\n" "This operation will rewrite published history.\n" "You probably don't want to do this." msgstr "" "Цей коміт вже опубліковано.\n" "Ця операція перезапише опубліковану історію.\n" "Скоріш за все ви не хочете цього." #, fuzzy msgid "" "This operation drops uncommitted changes.\n" "These changes cannot be recovered." msgstr "" "Ця операція відмінить незакомітовані зміни.\n" "Ці зміни не можна буде відновити." msgid "" "This operation removes uncommitted edits from selected files.\n" "These changes cannot be recovered." msgstr "" "Ця операція відмінить незакомітовані зміни.\n" "Ці зміни не можна буде відновити." msgid "" "This operation removes unstaged edits from selected files.\n" "These changes cannot be recovered." msgstr "" "Ця операція відмінить непроіндексовані зміни.\n" "Ці зміни не можна буде відновити." msgid "" "This repository is currently being rebased.\n" "Resolve conflicts, commit changes, and run:\n" " Rebase > Continue" msgstr "" "Цей репозиторій переміщено.\n" "Виправте конфлікти, закомітуйте зміни, і виконайте:\n" " Перемістити (rebase) > Продовжити" msgid "" "This repository is in the middle of a merge.\n" "Resolve conflicts and commit changes." msgstr "" "Цей репозиторій в процесі злиття.\n" "Виправте конфлікти та закомітуйте зміни." msgid "Toggle Enabled" msgstr "" msgid "Toggle the branches filter" msgstr "Перемкнути фільтр гілок" msgid "Toggle the paths filter" msgstr "Перемкнути фільтр шляхів" msgid "Tracking Branch" msgstr "Гілка, що відслідковуються" msgid "Tracking branch" msgstr "Гілка, що відстежується" msgid "Traditional Chinese (Taiwan) translation" msgstr "Традиційний китайський (Тайвань) переклад" msgid "Translators" msgstr "Перекладачі" msgid "Turkish translation" msgstr "Турецький переклад" msgid "URL" msgstr "Адреса URL" #, python-format msgid "URL: %s" msgstr "Адреса URL: %s" msgid "Ukranian translation" msgstr "Український переклад" msgid "Unable to rebase" msgstr "Не вдалось перемістити (rebase)" #, python-format msgid "Unable to set URL for \"%(name)s\" to \"%(url)s\"" msgstr "" msgid "Undo" msgstr "" msgid "Unmerged" msgstr "Незлите" msgid "Unstage" msgstr "Видалити з індексу" msgid "Unstage All" msgstr "Видалити все з проіндексованого" msgid "Unstage Diff Hunk" msgstr "Видалити частину різниці з проіндексованого" msgid "Unstage From Commit" msgstr "Прибрати з коміту" msgid "Unstage Selected" msgstr "Видалити виділене з проіндексованого" msgid "Unstage Selected Lines" msgstr "Видалити виділені рядки з проіндексованого" #, python-format msgid "Unstaging: %s" msgstr "Видалення з проіндексованого: %s" msgid "Untrack Selected" msgstr "Не відслідковувати виділене" msgid "Untracked" msgstr "Не відслідковується" #, python-format msgid "Untracking: %s" msgstr "Видалення зі списку файлів, що відслідковуються: %s" msgid "Update All Submodules..." msgstr "" msgid "Update Existing Branch:" msgstr "Оновити існуючу гілку:" msgid "Update Submodule" msgstr "" msgid "Update Submodule..." msgstr "" msgid "Update Submodules" msgstr "" msgid "Update all submodules?" msgstr "" msgid "Update submodules..." msgstr "" msgid "Update this submodule" msgstr "" msgid "Update this submodule?" msgstr "" msgid "Updating" msgstr "Оновлення" msgid "User Name" msgstr "Ім'я користувача" msgid "Version" msgstr "Версія" msgid "View" msgstr "Вигляд" msgid "View History..." msgstr "Переглянути історію..." msgid "View history for selected paths" msgstr "Подивитись історію для вибраних шляхів" msgid "Visualize" msgstr "Відобразити" msgid "Visualize All Branches..." msgstr "Відобразити всі гілки..." msgid "Visualize Current Branch..." msgstr "Відобразити поточну гілку..." msgid "Whether to sign the tag (git tag -s)" msgstr "Визначає, чи піписувати теґ (git tag -s)" msgid "Would you like to stage and commit all modified files?" msgstr "Хочете проіндексувати та закомітувати всі змінені файли?" msgid "XOR" msgstr "" msgid "Yes" msgstr "" msgid "" "You are in the middle of a merge.\n" "Cannot amend while merging." msgstr "" "Ви знаходитесь в процесі злиття.\n" "Не можна робити зміни під час злиття." msgid "You cannot rebase with uncommitted changes." msgstr "Не можна робити переміщення (rebase), якщо є незакомітовані зміни." msgid "You must specify a revision to merge." msgstr "Ви маєте вказати ревізію для злиття." msgid "You must specify a revision to view." msgstr "Ви маєте вказати ревізію для перегляду." msgid "Zoom In" msgstr "Приблизити" msgid "Zoom Out" msgstr "Віддалити" msgid "Zoom to Fit" msgstr "Допасувати за розміром" msgid "command-line arguments" msgstr "аргументи командного рядка" msgid "error: unable to execute git" msgstr "" #, python-format msgid "exit code %s" msgstr "код завершення %s" #, python-format msgid "fatal: \"%s\" is not a directory. Please specify a correct --repo ." msgstr "критично: \"%s\" не є каталогом. Будь ласка, вкажіть коректний --repo <шлях>." #, python-format msgid "git cola version %s" msgstr "версія git cola %s" msgid "git-cola" msgstr "git-cola" msgid "git-cola diff" msgstr "Різниця git-cola" msgid "grep result..." msgstr "шукати в результатах..." msgid "hotkeys.html" msgstr "" msgid "unknown" msgstr "невідомий" msgid "vX.Y.Z" msgstr "vX.Y.Z" msgid "x 1" msgstr "" msgid "x 1.5" msgstr "" msgid "x 2" msgstr "" msgid "yyyy-MM-dd" msgstr "рррр-ММ-дд" #~ msgid "\"%s\" returned exit status %d" #~ msgstr "\"%s\" завершилась з кодом %d" #~ msgid "\"git commit\" returned exit code %s" #~ msgstr "команда \"git commit\" поверула код виходу %s" #~ msgid "Already up-to-date." #~ msgstr "Вже оновлено." #~ msgid "Commit failed: %s" #~ msgstr "Не вдалось створити коміт: %s" #~ msgid "Created commit: %s" #~ msgstr "Створено коміт: %s" #~ msgid "Error %s" #~ msgstr "Помилка %s" #~ msgid "Errors: %s" #~ msgstr "Помилки: %s" #~ msgid "Exit code: %s" #~ msgstr "Код завершення: %s" #~ msgid "GPG-signed" #~ msgstr "Підписане GPG" #~ msgid "" #~ "Output:\n" #~ "%s" #~ msgstr "" #~ "Вивід:\n" #~ "%s" #~ msgid "Output: %s" #~ msgstr "Вивід: %s" #~ msgid "PATCH %(current)d/%(count)d" #~ msgstr "Латка %(current)d/%(count)d" #~ msgid "Rename remote?" #~ msgstr "Перейменувати віддалений репозиторій?" #~ msgid "Select File" #~ msgstr "Вибрати файл" #~ msgid "Select file from \"%s\"" #~ msgstr "Вибрати файл з \"%s\"" #~ msgid "Summary:" #~ msgstr "Підсумок:" #~ msgid "git clone returned exit code %s" #~ msgstr "git clone завершилась з кодом %s" #~ msgid "git tag returned exit code %s" #~ msgstr "команда git tag завершилась з кодом %s" git-cola-3.6/po/zh_CN.po000066400000000000000000002274131356743264500150700ustar00rootroot00000000000000# Translation of git-cola to Chinese # Copyright (C) 2007, 2008 Shawn Pearce # This file is distributed under the same license as the git-cola package. # Xudong Guan , 2007. # Eric Miao , 2008. # ZH , 2014-2015. # # Please use the following translation throughout the file for consistence: # # repository 版本库 # commit 提交 # revision 版本 # branch 分支 # tag 标签 # annotation 标注 # merge 合并 # fast forward 快进合并 # stage 缓存 (译自 index/cache) # amend 修正 # reset 复位 # checkout 签出 # cherry-pick 挑取 # # Refer to 术语表 / Git Community Book 中文版 # http://gitbook.liuhui998.com/7_8.html # msgid "" msgstr "" "Project-Id-Version: git-cola VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: \n" "PO-Revision-Date: 2019-04-22 00:10+0300\n" "Last-Translator: Guo Yunhe \n" "Language-Team: Chinese\n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Language: zh_CN\n" "X-Source-Language: C\n" "X-Generator: Poedit 2.2.1\n" msgid "" "\n" "

\n" " Drag and drop or use the Add button to add\n" " patches to the list\n" "

\n" " " msgstr "" "\n" "

\n" " 拖放或使用 添加 按钮\n" " 将补丁加入列表\n" "

\n" " " #, python-format msgid "" "\n" "
\n" " Git Cola has been translated into different languages thanks\n" " to the help of the individuals listed below.\n" "\n" "
\n" "

\n" " Translation is approximate. If you find a mistake,\n" " please let us know by opening an issue on Github:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " We invite you to participate in translation by adding or " "updating\n" " a translation and opening a pull request.\n" "

\n" "\n" "
\n" "\n" " " msgstr "" #, python-format msgid "" "\n" "
\n" " Git Cola version %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " msgstr "" #, python-format msgid "" "\n" "
\n" " Please use %(bug_link)s to report issues.\n" "
\n" " " msgstr "" #, python-format msgid "" "\n" " Format String Variables\n" " -----------------------\n" " %(path)s = relative file path\n" " %(abspath)s = absolute file path\n" " %(dirname)s = relative directory path\n" " %(absdirname)s = absolute directory path\n" " %(filename)s = file basename\n" " %(basename)s = file basename without extension\n" " %(ext)s = file extension\n" msgstr "" msgid "" "\n" "Commands\n" "--------\n" "pick = use commit\n" "reword = use commit, but edit the commit message\n" "edit = use commit, but stop for amending\n" "squash = use commit, but meld into previous commit\n" "fixup = like \"squash\", but discard this commit's log message\n" "exec = run command (the rest of the line) using shell\n" "\n" "These lines can be re-ordered; they are executed from top to bottom.\n" "\n" "If you disable a line here THAT COMMIT WILL BE LOST.\n" "\n" "However, if you disable everything, the rebase will be aborted.\n" "\n" "Keyboard Shortcuts\n" "------------------\n" "? = show help\n" "j = move down\n" "k = move up\n" "J = shift row down\n" "K = shift row up\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "spacebar = toggle enabled\n" "\n" "ctrl+enter = accept changes and rebase\n" "ctrl+q = cancel and abort the rebase\n" "ctrl+d = launch difftool\n" msgstr "" #, fuzzy msgid "" "\n" "Keyboard Shortcuts\n" "------------------\n" "J, Down = Move Down\n" "K, Up = Move Up\n" "Enter = Edit Selected Files\n" "Spacebar = Open File Using Default Application\n" "Ctrl + L = Focus Text Entry Field\n" "? = Show Help\n" "\n" "The up and down arrows change focus between the text entry field\n" "and the results.\n" msgstr "" "\n" "键盘快捷键\n" "------------------\n" "J, 向上 = 下移\n" "K, 向下 = 上移\n" "Enter = 编辑所选文件\n" "Spacebar = 使用默认程序打开文件\n" "Ctrl+L = 聚焦于文本输入区\n" "? = 显示帮助\n" "\n" "在文本输入区和结果区之间\n" "使用向上/向下键以切换聚焦\n" msgid " - DAG" msgstr " - 历史视图" msgid " commits ago" msgstr " 个提交之前" #, python-format msgid "\"%(branch)s\" has been deleted from \"%(remote)s\"." msgstr "已从远程 \"%(remote)s\" 删除分支 \"%(branch)s\"." #, python-format msgid "\"%(command)s\" returned exit status \"%(status)d\"" msgstr "\"%(command)s\" 命令返回状态 \"%(status)d\"" #, python-format msgid "\"%(command)s\" returned exit status %(status)d" msgstr "\"%(command)s\" 命令返回状态 %(status)d" #, fuzzy, python-format msgid "\"%s\" already exists" msgstr "分支 '%s' 已经存在." #, python-format msgid "\"%s\" already exists, cola will create a new directory" msgstr "\"%s\" 已经存在, 程序会新建文件夹" #, python-format msgid "\"%s\" requires a selected file." msgstr "\"%s\" 需要选择一个文件." msgid "#" msgstr "" #, python-format msgid "%(project)s: %(branch)s - Browse" msgstr "%(project)s: %(branch)s - 浏览器" #, python-format msgid "%(project)s: %(ref)s - DAG" msgstr "%(project)s: %(ref)s - 历史视图" #, python-format msgid "%d days ago" msgstr "%d 天前" #, python-format msgid "%d hours ago" msgstr "%d 小时前" #, python-format msgid "%d minutes ago" msgstr "%d 分钟前" #, python-format msgid "%d patch(es) applied." msgstr "已应用 %d 个补丁." #, python-format msgid "%d skipped" msgstr "%d 已跳过" #, python-format msgid "" "%s appears to contain merge conflicts.\n" "\n" "You should probably skip this file.\n" "Stage it anyways?" msgstr "" #, python-format msgid "%s is not a Git repository." msgstr "%s 不是 Git 版本库。" #, python-format msgid "%s will be removed from your bookmarks." msgstr "%s 会将被从书签中移除。" #, python-format msgid "%s will be removed from your recent repositories." msgstr "%s 将从最近使用的版本库列表中被移除。" #, python-format msgid "%s: No such file or directory." msgstr "%s: 此文件或文件夹不存在." msgid "&Edit" msgstr "编辑" msgid "&File" msgstr "文件" msgid "(Amending)" msgstr "(正在修正)" msgid "*** Branch Point ***" msgstr "*** 分支点 ***" msgid "*** Sandbox ***" msgstr "*** 沙盒 ***" msgid "100%" msgstr "100%" msgid "200%" msgstr "200%" msgid "25%" msgstr "25%" msgid "400%" msgstr "400%" msgid "50%" msgstr "50%" msgid "800%" msgstr "800%" msgid " ..." msgstr "<路径> ..." msgid "" "A commit template has not been configured.\n" "Use \"git config\" to define \"commit.template\"\n" "so that it points to a commit template." msgstr "" "提交模板未创建.\n" "使用 \"git config\" 定义 \"commit template\"\n" "而指定一个提交模板." #, python-format msgid "A hook must be provided at \"%s\"" msgstr "钩子必须位于 \"%s\"" #, python-format msgid "A stash named \"%s\" already exists" msgstr "名为 \"%s\" 的暂存已存在" msgid "Abort" msgstr "中止" msgid "Abort Action" msgstr "中止操作" msgid "Abort Merge" msgstr "中止合并" msgid "Abort Merge..." msgstr "中止合并..." msgid "Abort the action?" msgstr "终止此操作?" msgid "" "Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" "Recovering uncommitted changes is not possible." msgstr "" "中止当前的合并会丢失所有未提交的修改.\n" "将无法恢复未提交的修改." msgid "Aborting the current merge?" msgstr "终止当前合并吗?" msgid "About" msgstr "关于" msgid "About git-cola" msgstr "关于 git-cola" msgid "Accept" msgstr "接受" msgid "" "Accept changes and rebase\n" "Shortcut: Ctrl+Enter" msgstr "" "接受变更并衍合\n" "快捷键:Ctrl+Enter" msgid "Action Name" msgstr "操作名称" msgid "Actions" msgstr "操作" msgid "Actions..." msgstr "操作..." msgid "Add" msgstr "添加" msgid "Add Favorite" msgstr "添加收藏" msgid "Add Remote" msgstr "添加远程" msgid "Add Separator" msgstr "添加分隔符" msgid "Add Toolbar" msgstr "添加工具栏" msgid "" "Add and remove remote repositories using the \n" "Add(+) and Delete(-) buttons on the left-hand side.\n" "\n" "Remotes can be renamed by selecting one from the list\n" "and pressing \"enter\", or by double-clicking." msgstr "" "用左边的添加(+)和删除(-)按钮\n" "来添加或移除远程版本库\n" "\n" "从列表中选定可为远程改名\n" "完成后按回车键或直接双击." msgid "Add new remote git repository" msgstr "添加新远程版本库" msgid "Add patches (+)" msgstr "添加补丁 (+)" msgid "Add remote" msgstr "添加远程" msgid "Add to .gitignore" msgstr "添加至 .gitignore" msgid "Add to Git Annex" msgstr "添加至 Git Annex" msgid "Add to Git LFS" msgstr "添加至 Git LFS" msgid "Additions" msgstr "添加内容" msgid "Advanced" msgstr "高级" msgid "Age" msgstr "修改时间" msgid "All Repositories" msgstr "全部版本库" #, python-format msgid "" "All submodules will be updated using\n" "\"%s\"" msgstr "" msgid "" "Allow non-fast-forward updates. Using \"force\" can cause the remote " "repository to lose commits; use it with care" msgstr "" msgid "" "Always create a merge commit when enabled, even when the merge is a fast-" "forward update" msgstr "启用时总是在合并时创建一个提交,即使是快进合并方式" msgid "Amend" msgstr "修正" msgid "Amend Commit" msgstr "修正提交" msgid "Amend Last Commit" msgstr "修正上次提交" msgid "Amend the published commit?" msgstr "修正已发布的提交吗?" msgid "Amending" msgstr "修正中" msgid "" "An action is still running.\n" "Terminating it could result in data loss." msgstr "" "操作正在进行中.\n" "若终止有可能造成数据损失." msgid "" "An unsigned, lightweight tag will be created instead.\n" "Create an unsigned tag?" msgstr "" "一个无签名的轻量标签会取而代之.\n" "创建无签名标签吗?" msgid "Appearance" msgstr "外观" msgid "Apply" msgstr "应用" msgid "Apply Patches" msgstr "应用补丁" msgid "Apply Patches..." msgstr "应用补丁..." msgid "Apply and drop the selected stash (git stash pop)" msgstr "应用并丢弃所选暂存 (git stash pop)" msgid "Apply the selected stash" msgstr "应用所选暂存" msgid "Arguments" msgstr "参数" msgid "Attach" msgstr "结合" msgid "Author" msgstr "作者" msgid "Authors" msgstr "作者" msgid "Auto" msgstr "自动" msgid "Auto-Wrap Lines" msgstr "自动换行" msgid "Basic Regexp" msgstr "基本正则表达式" msgid "Blame Viewer" msgstr "问责查看器" #, fuzzy msgid "Blame selected paths" msgstr "编辑所选路径" msgid "Blame..." msgstr "问责..." msgid "Bold on dark headers instead of italic" msgstr "暗色背景粗体字体而斜体头部" msgid "Branch" msgstr "分支" #, python-format msgid "" "Branch \"%(branch)s\" does not exist in \"%(remote)s\".\n" "A new remote branch will be published." msgstr "" "远程 \"%(remote)s\" 不存在分支 \"%(branch)s\".\n" "一个新的远程分支会被建立." #, python-format msgid "Branch \"%s\" already exists." msgstr "分支 '%s' 已经存在." msgid "Branch Diff Viewer" msgstr "分支差异查看器" msgid "Branch Exists" msgstr "分支已存在" msgid "Branch Name" msgstr "分支名" #, python-format msgid "Branch: %s" msgstr "分支: %s" msgid "Branches" msgstr "分支" msgid "Branches..." msgstr "分支..." msgid "Brazilian translation" msgstr "巴西语翻译" msgid "Browse" msgstr "浏览" msgid "Browse Commits..." msgstr "浏览提交..." msgid "Browse Current Branch..." msgstr "浏览当前分支上的文件..." msgid "Browse Other Branch..." msgstr "浏览其他分支..." msgid "Browse..." msgstr "浏览..." msgid "Browser" msgstr "浏览器" #, python-format msgid "Browsing %s" msgstr "浏览 %s" msgid "Bypass Commit Hooks" msgstr "跳过提交钩子" msgid "Cancel" msgstr "取消" msgid "" "Cancel rebase\n" "Shortcut: Ctrl+Q" msgstr "" "取消衍合\n" "快捷键: Ctrl+Q" msgid "Cannot Amend" msgstr "无法修正" #, python-format msgid "Cannot exec \"%s\": please configure a blame viewer" msgstr "无法执行 \"%s\": 请配置问责查看器" #, python-format msgid "Cannot exec \"%s\": please configure a history browser" msgstr "无法执行 \"%s\": 请配置历史浏览器" #, python-format msgid "Cannot exec \"%s\": please configure your editor" msgstr "无法执行 \"%s\": 请配置编辑器" msgid "Changed Upstream" msgstr "上游已更改" msgid "Check Spelling" msgstr "检查拼写" msgid "Check spelling" msgstr "检查拼写" msgid "Checkout" msgstr "签出" msgid "Checkout After Creation" msgstr "在创建后签出" msgid "Checkout Branch" msgstr "签出分支" msgid "Checkout Detached HEAD" msgstr "签出分离的 HEAD" msgid "Checkout as new branch" msgstr "签出为新分支" msgid "Checkout..." msgstr "签出..." msgid "Cherry Pick" msgstr "挑取(Cherry Pick)" msgid "Cherry-Pick Commit" msgstr "挑取(Cherry-Pick)提交" msgid "Cherry-Pick..." msgstr "挑取(Cherry-Pick)..." msgid "Choose Paths" msgstr "选择路径" msgid "Choose the \"git grep\" regular expression mode" msgstr "选择 \"git grep\" 正则表达式模式" msgid "Clear Default Repository" msgstr "清除默认版本库" msgid "Clear commit message" msgstr "清除提交信息" msgid "Clear commit message?" msgstr "清除提交消息吗?" msgid "Clear..." msgstr "清除..." msgid "Clone" msgstr "克隆" msgid "Clone Repository" msgstr "克隆已有版本库" msgid "Clone..." msgstr "克隆(clone)..." #, python-format msgid "Cloning repository at %s" msgstr "克隆位于 %s 的已有版本库" msgid "Close" msgstr "关闭" msgid "Close..." msgstr "关闭..." msgid "Collapse all" msgstr "全部合起" msgid "Command" msgstr "命令" msgid "Commit" msgstr "提交" msgid "Commit failed" msgstr "克隆失败" msgid "Commit staged changes" msgstr "提交已缓存修改" msgid "" "Commit staged changes\n" "Shortcut: Ctrl+Enter" msgstr "" "提交已缓存变更\n" "快捷键: Ctrl+Enter" msgid "Commit summary" msgstr "提交概要" msgid "" "Commit the merge if there are no conflicts. Uncheck to leave the merge " "uncommitted" msgstr "若合并无冲突即可提交.取消勾选以保持此合并操作的未提交状态" msgid "Commit@@verb" msgstr "提交@@verb" msgid "Compare" msgstr "比较" msgid "Compare All" msgstr "比较全部" msgid "Configure the remote branch as the the new upstream" msgstr "将远程分支设为新的上游" msgid "Configure toolbar" msgstr "配置工具栏" msgid "Console" msgstr "控制台" msgid "Continue" msgstr "继续" msgid "Copy" msgstr "复制" msgid "Copy Basename to Clipboard" msgstr "复制基名到剪贴板" msgid "Copy Leading Path to Clipboard" msgstr "复制前导路径到剪贴板" msgid "Copy Path to Clipboard" msgstr "复制路径到剪贴板" msgid "Copy Relative Path to Clipboard" msgstr "复制相对路径到剪贴板" msgid "Copy SHA-1" msgstr "复制 SHA-1" #, fuzzy msgid "Copy..." msgstr "复制" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "无法解析 URL \"%s\"" msgid "Create Branch" msgstr "创建分支" msgid "Create Patch" msgstr "创建补丁" msgid "Create Remote Branch" msgstr "创建远程分支" msgid "Create Signed Commit" msgstr "创建带签名提交: %s" msgid "Create Tag" msgstr "创建标签" msgid "Create Tag..." msgstr "新建标签..." msgid "Create Unsigned Tag" msgstr "创建无签名标签" #, fuzzy msgid "Create a merge commit even when the merge resolves as a fast-forward" msgstr "启用时总是在合并时创建一个提交,即使是快进合并方式" msgid "Create a new remote branch?" msgstr "创建远程分支吗?" msgid "Create..." msgstr "新建..." #, python-format msgid "Created a new tag named \"%s\"" msgstr "创建了名为“%s”的新标签" msgid "Current Repository" msgstr "当前版本库" msgid "Custom Copy Actions" msgstr "自定义复制操作" msgid "Customize..." msgstr "自定义..." msgid "Cut" msgstr "剪切" msgid "Czech translation" msgstr "捷克语翻译" msgid "DAG..." msgstr "历史视图..." msgid "Dark Theme" msgstr "" msgid "Date, Time" msgstr "日期, 时间" msgid "Default" msgstr "默认" msgid "Delete" msgstr "删除" #, python-format msgid "Delete %d file(s)?" msgstr "删除 %d 个文件吗?" msgid "Delete Bookmark" msgstr "删除书签" msgid "Delete Bookmark?" msgstr "删除书签吗?" msgid "Delete Branch" msgstr "删除分支" msgid "Delete Files" msgstr "删除文件" msgid "Delete Files..." msgstr "删除文件..." msgid "Delete Files?" msgstr "删除文件吗?" msgid "Delete Remote" msgstr "删除远程" msgid "Delete Remote Branch" msgstr "删除远程分支" msgid "Delete Remote Branch..." msgstr "删除远程分支..." msgid "Delete remote" msgstr "删除远程" #, python-format msgid "Delete remote \"%s\"" msgstr "删除远程 \"%s\"" msgid "Delete remote?" msgstr "删除远程吗?" msgid "Delete selected branch?" msgstr "删除选中分支?" msgid "Delete toolbar" msgstr "删除工具栏" msgid "Delete..." msgstr "删除..." #, python-format msgid "Deleting \"%s\" failed" msgstr "删除 \"%s\" 失败" msgid "Deletions" msgstr "删除内容" msgid "Detach" msgstr "分离" msgid "Detect Conflict Markers" msgstr "检测冲突标记" msgid "Detect conflict markers in unmerged files" msgstr "在未合并文件中检测冲突标记" msgid "Developer" msgstr "开发者" msgid "Diff" msgstr "差异比较" msgid "Diff Against Predecessor..." msgstr "与之前提交比较差异..." msgid "Diff Options" msgstr "差异选项" msgid "Diff Tool" msgstr "差异比较工具" msgid "Diff selected -> this" msgstr "所选文件 -> 此文件 比较差异" msgid "Diff this -> selected" msgstr "此文件 -> 所选文件 比较差异" msgid "Diffstat" msgstr "差异统计" msgid "Difftool" msgstr "差异工具" msgid "Directory Exists" msgstr "目录已存在" msgid "Display Untracked Files" msgstr "显示未跟踪文件" msgid "Documentation" msgstr "帮助文档" msgid "Drop" msgstr "丢弃" msgid "Drop Stash" msgstr "丢弃暂存" msgid "Drop Stash?" msgstr "丢弃暂存吗?" #, python-format msgid "Drop the \"%s\" stash?" msgstr "丢弃暂存 \"%s\" 吗?" msgid "Drop the selected stash" msgstr "丢弃所选暂存" msgid "Edit" msgstr "编辑" msgid "Edit Rebase" msgstr "编辑衍合" msgid "Edit Remotes" msgstr "编辑远程" msgid "Edit Remotes..." msgstr "编辑远程..." msgid "Edit remotes by selecting them from the list" msgstr "从列表中选择远程进行编辑" msgid "Edit selected paths" msgstr "编辑所选路径" msgid "Edit..." msgstr "编辑..." msgid "Editor" msgstr "编辑器" msgid "Email Address" msgstr "电子邮件地址" msgid "Email contributor" msgstr "电子邮件贡献者" msgid "Enabled" msgstr "已启用" msgid "Enter New Branch Name" msgstr "输入新分支名" #, fuzzy msgid "Enter a name for the new bare repo" msgstr "为暂存输入名称" msgid "Enter a name for the stash" msgstr "为暂存输入名称" msgid "Error" msgstr "错误" msgid "Error Cloning" msgstr "克隆出错" msgid "Error Creating Branch" msgstr "创建分支出错" msgid "Error Creating Repository" msgstr "创建版本库出错" msgid "Error Deleting Remote Branch" msgstr "删除远程分支出错" msgid "Error Editing File" msgstr "编辑文件出错" msgid "Error Launching Blame Viewer" msgstr "启动问责查看器出错" msgid "Error Launching History Browser" msgstr "启动历史浏览器出错" #, python-format msgid "Error creating remote \"%s\"" msgstr "创建远程 \"%s\" 出错" msgid "Error creating stash" msgstr "创建暂存出错" #, python-format msgid "Error deleting remote \"%s\"" msgstr "删除远程 \"%s\" 出错" #, python-format msgid "Error renaming \"%(name)s\" to \"%(new_name)s\"" msgstr "重命名 \"%(name)s\" 为 \"%(new_name)s\" 出错" msgid "Error running prepare-commitmsg hook" msgstr "运行 prepare-commitmsg 钩子出错" #, python-format msgid "Error updating submodule %s" msgstr "更新子模块 \"%s\" 出错" msgid "Error updating submodules" msgstr "更新子模块出错" msgid "Error: Cannot find commit template" msgstr "错误: 无法找到提交模板" msgid "Error: Stash exists" msgstr "错误: 暂存已存在" msgid "Error: Unconfigured commit template" msgstr "错误: 未配置提交模板" #, python-format msgid "Error: could not clone \"%s\"" msgstr "错误: 无法克隆 \"%s\"" #, python-format msgid "Error: could not create tag \"%s\"" msgstr "错误: 无法创建标签 \"%s\"" #, python-format msgid "Executing action %s" msgstr "执行动作 %s" msgid "Expand all" msgstr "全部展开" msgid "Export Patches" msgstr "导出补丁" msgid "Export Patches..." msgstr "导出补丁..." msgid "Expression..." msgstr "表达式..." msgid "Extended Regexp" msgstr "拓展正则表达式" msgid "Extended description..." msgstr "拓展描述..." msgid "Fast Forward Only" msgstr "仅快速合并" msgid "Fast-forward only" msgstr "仅快速合并" msgid "Favorite repositories" msgstr "版本库收藏夹" msgid "Favorites" msgstr "收藏夹" msgid "Fetch" msgstr "获取" msgid "Fetch Tracking Branch" msgstr "获取跟踪分支" msgid "Fetch..." msgstr "获取..." msgid "File Browser..." msgstr "文件浏览器..." msgid "File Differences" msgstr "文件差异" msgid "File Saved" msgstr "文件已保存" #, python-format msgid "File saved to \"%s\"" msgstr "文件保存为 \"%s\"" msgid "" "File system change monitoring: disabled because \"cola.inotify\" is false.\n" msgstr "监视文件系统更改:已禁用,因为 cola.notify 选项设置为 false。\n" msgid "" "File system change monitoring: disabled because libc does not support the " "inotify system calls.\n" msgstr "" msgid "" "File system change monitoring: disabled because pywin32 is not installed.\n" msgstr "" msgid "" "File system change monitoring: disabled because the limit on the total " "number of inotify watches was reached. You may be able to increase the " "limit on the number of watches by running:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf " "&& sudo sysctl -p\n" msgstr "" msgid "File system change monitoring: enabled.\n" msgstr "监视文件系统更改:已开启。\n" msgid "Filename" msgstr "文件名" msgid "Files" msgstr "文件" msgid "Filter branches..." msgstr "过滤分支..." msgid "Filter paths..." msgstr "对路径进行过滤..." msgid "Find Files" msgstr "查找文件" msgid "Fixed String" msgstr "特定字符串" msgid "Fixed-Width Font" msgstr "等宽字体" msgid "Fixup" msgstr "修正" msgid "Fixup Previous Commit" msgstr "修正前一次提交" msgid "Flat dark blue" msgstr "扁平深蓝" msgid "Flat dark green" msgstr "扁平深绿" msgid "Flat dark grey" msgstr "扁平深灰" msgid "Flat dark red" msgstr "扁平深红" msgid "Flat light blue" msgstr "扁平浅蓝" msgid "Flat light green" msgstr "扁平浅绿" msgid "Flat light grey" msgstr "扁平浅灰" msgid "Flat light red" msgstr "扁平浅红" msgid "Font Size" msgstr "字体大小" msgid "Force" msgstr "强制" msgid "Force Fetch" msgstr "强制获取" msgid "Force Fetch?" msgstr "强制获取?" msgid "Force Push" msgstr "强制推送" msgid "Force Push?" msgstr "强制推送吗?" #, python-format msgid "Force fetching from %s?" msgstr "强制获取从 %s 吗?" #, python-format msgid "Force push to %s?" msgstr "强制推送到 %s 吗?" msgid "Format String" msgstr "格式化字符串" msgid "French translation" msgstr "法语翻译" msgid "GPG-sign the merge commit" msgstr "GPG 签名合并提交" msgid "GUI theme" msgstr "界面主题" #, python-format msgid "Gathering info for \"%s\"..." msgstr "为 \"%s\" 收集信息..." msgid "German translation" msgstr "德语翻译" msgid "Get Commit Message Template" msgstr "取得提交信息模板" msgid "Go Down" msgstr "下一项" msgid "Go Up" msgstr "上一项" msgid "Grab File..." msgstr "抓取文件..." msgid "Graph" msgstr "图示" msgid "Grep" msgstr "筛选 (grep)" msgid "Have you rebased/pulled lately?" msgstr "最近有衍合或拉取操作吗?" msgid "Help" msgstr "帮助" msgid "Help - Custom Copy Actions" msgstr "帮助 - 自定义复制操作" msgid "Help - Find Files" msgstr "帮助 - 查找文件" msgid "Help - git-xbase" msgstr "帮助 - git-xbase" msgid "Hide Details.." msgstr "隐藏细节.." msgid "High DPI" msgstr "高分辨率" msgid "History Browser" msgstr "历史浏览器" msgid "Hungarian translation" msgstr "匈牙利语翻译" msgid "Icon theme" msgstr "" msgid "Ignore all whitespace" msgstr "忽略所有空格" msgid "Ignore changes in amount of whitespace" msgstr "忽略空格数量" msgid "Ignore changes in whitespace at EOL" msgstr "行尾忽略空格" msgid "Ignore custom pattern" msgstr "忽略自定义模式" msgid "Ignore exact filename" msgstr "忽略精确文件名" msgid "Ignore filename or pattern" msgstr "忽略文件名或匹配模式" msgid "Include tags " msgstr "包含标签 " msgid "Indent Status paths" msgstr "缩进状态路径" msgid "Indonesian translation" msgstr "印尼语翻译" #, fuzzy msgid "Initialize Git Annex" msgstr "初始化..." #, fuzzy msgid "Initialize Git LFS" msgstr "初始化..." msgid "Inititalize submodules" msgstr "初始化子模块" msgid "Insert spaces instead of tabs" msgstr "插入空格而非制表符" msgid "Interactive Rebase" msgstr "交互式衍合" msgid "Invalid Revision" msgstr "无效版本" msgid "Keep *.orig Merge Backups" msgstr "保留合并备份 (*.orig)" msgid "Keep Index" msgstr "保留索引" msgid "Keyboard Shortcuts" msgstr "键盘快捷键" msgid "Launch Diff Tool" msgstr "启动差异工具" msgid "Launch Directory Diff Tool" msgstr "启动目录差异工具" msgid "Launch Editor" msgstr "启动编辑器" msgid "Launch Terminal" msgstr "启动终端" msgid "" "Launch external diff tool\n" "Shortcut: Ctrl+D" msgstr "" "加载外部差异工具\n" "快捷键: Ctrl+D" msgid "Launch git-cola" msgstr "启动 git-cola" msgid "Launch git-difftool against previous versions" msgstr "对之前的版本启动 git-difftool" msgid "Launch git-difftool on the current path" msgstr "在当前路径运行 git-difftool" msgid "Light Theme" msgstr "" msgid "Load Commit Message" msgstr "加载提交消息" msgid "Load Commit Message..." msgstr "加载提交信息..." msgid "Load Previous Commit Message" msgstr "加载前一次提交信息" msgid "Loading..." msgstr "加载中..." msgid "Local" msgstr "本地" msgid "Local Branch" msgstr "本地分支" msgid "Local branch" msgstr "本地分支" msgid "Lock Layout" msgstr "锁定布局" msgid "Log" msgstr "记录" msgid "Maintainer (since 2007) and developer" msgstr "维护者 (从 2007 年开始) 和开发者" msgid "Merge" msgstr "合并" #, python-format msgid "Merge \"%(revision)s\" into \"%(branch)s\"" msgstr "合并 \"%(revision)s\" 到分支 \"%(branch)s\"" msgid "Merge Tool" msgstr "合并工具" msgid "Merge Verbosity" msgstr "合并冗余度" msgid "Merge failed. Conflict resolution is required." msgstr "合并失败. 需要解决冲突." #, python-format msgid "Merge into \"%s\"" msgstr "合并到 \"%s\"" msgid "Merge into current branch" msgstr "合并到当前分支" msgid "Merge..." msgstr "合并 (merge)..." msgid "Merging" msgstr "合并中" msgid "Message" msgstr "消息" msgid "Missing Commit Message" msgstr "提交信息不存在" msgid "Missing Data" msgstr "数据不存在" msgid "Missing Name" msgstr "名称不存在" msgid "Missing Revision" msgstr "版本不存在" msgid "Missing Tag Message" msgstr "标签信息不存在" msgid "Modified" msgstr "已修改" msgid "More..." msgstr "更多..." msgid "Move Down" msgstr "下移" msgid "Move Up" msgstr "上移" msgid "Move files to trash" msgstr "移动文件到回收站" msgid "Name" msgstr "名称" msgid "Name for the new remote" msgstr "新远程的名称" msgid "New Bare Repository..." msgstr "新建空版本库..." msgid "New Repository..." msgstr "新建版本库..." msgid "New..." msgstr "新建..." msgid "Next File" msgstr "下一个文件" msgid "No" msgstr "号码" msgid "No Revision Specified" msgstr "没有指定版本" msgid "" "No changes to commit.\n" "\n" "You must stage at least 1 file before you can commit." msgstr "" "没有需要提交的改动.\n" "\n" "提交前你必须首先缓存至少一个文件." msgid "No commits exist in this branch." msgstr "此分支内没有提交." msgid "No fast forward" msgstr "不进行快速合并" msgid "No fast-forward" msgstr "不进行快速合并" msgid "No repository selected." msgstr "没有选择版本库." msgid "Non-fast-forward fetch overwrites local history!" msgstr "非快进合并式获取会覆盖本地历史!" msgid "" "Non-fast-forward push overwrites published history!\n" "(Did you pull first?)" msgstr "" "非快进合并式上传会覆盖远程历史!\n" "(之前拉取了吗?)" msgid "Nothing to commit" msgstr "没有改动可提交" msgid "Nothing to do" msgstr "不做操作" msgid "Number of Diff Context Lines" msgstr "Diff 上下文行数" msgid "Open" msgstr "打开" msgid "Open Git Repository..." msgstr "打开已有版本库..." msgid "Open Parent" msgstr "打开父级" msgid "Open Parent Directory" msgstr "打开上级目录" msgid "Open Recent" msgstr "打开最近版本库" msgid "Open Using Default Application" msgstr "用默认程序打开" msgid "Open in New Window" msgstr "新窗口打开" msgid "Open in New Window..." msgstr "在新窗口打开..." msgid "Open..." msgstr "打开..." msgid "Other branches" msgstr "其他分支" msgid "Overwrite" msgstr "覆盖" #, python-format msgid "Overwrite \"%s\"?" msgstr "覆盖 \"%s\" 吗?" msgid "Overwrite File?" msgstr "覆盖文件吗?" msgid "" "Parse arguments using a shell.\n" "Queries with spaces will require \"double quotes\"." msgstr "" "用 Shell 解析参数\n" "若命令行条目包含空格, 请添加双引号." msgid "Partially Staged" msgstr "部分已缓存" msgid "Paste" msgstr "粘贴" msgid "Patch(es) Applied" msgstr "已应用补丁" msgid "Path" msgstr "路径" msgid "Path or URL to clone (Env. $VARS okay)" msgstr "克隆路径或 URL (可以使用环境变量)" msgid "Pick" msgstr "" msgid "Pixel XOR" msgstr "像素异或" msgid "Please provide both a branch name and revision expression." msgstr "请同时提供分支名称和版本表达式." msgid "Please select a file" msgstr "请选择一个文件" msgid "Please specify a name for the new tag." msgstr "请为新标签指定名称." msgid "Please specify a revision to tag." msgstr "请指定一个版本进行标记." msgid "" "Please supply a commit message.\n" "\n" "A good commit message has the following format:\n" "\n" "- First line: Describe in one sentence what you did.\n" "- Second line: Blank\n" "- Remaining lines: Describe why this change is good.\n" msgstr "" "请提供一条提交信息.\n" "\n" "一条好的提交信息有下列格式:\n" "\n" "- 第一行: 一句话概括你做的修改.\n" "- 第二行: 空行\n" "- 剩余行: 请描述为什么你做的这些改动是好的.\n" msgid "Point the current branch head to a new commit?" msgstr "" msgid "Polish translation" msgstr "波兰语翻译" msgid "Pop" msgstr "弹出" msgid "Preferences" msgstr "首选项" msgid "Prefix" msgstr "前缀" msgid "Prepare Commit Message" msgstr "准备提交信息" msgid "Prevent \"Stage\" from staging all files when nothing is selected" msgstr "" msgid "Previous File" msgstr "上一个文件" msgid "Prompt on creation" msgstr "在创建时提醒" msgid "Prompt when pushing creates new remote branches" msgstr "推送创建远程分支时提醒" msgid "Prune " msgstr "从..清除(prune) " msgid "Pull" msgstr "拉取" msgid "Pull..." msgstr "拉取..." msgid "Push" msgstr "推送" msgid "Push..." msgstr "上传..." msgid "Quit" msgstr "退出" msgid "Rebase" msgstr "衍合" #, python-format msgid "Rebase onto %s" msgstr "衍合到 %s" msgid "Rebase stopped" msgstr "衍合已停止" msgid "Rebase the current branch instead of merging" msgstr "衍合当前分支而不是合并" msgid "Rebasing" msgstr "衍合中" msgid "Recent" msgstr "最近" msgid "Recent repositories" msgstr "最近使用版本库" msgid "Recent repository count" msgstr "最近使用版本库数目" msgid "Recently Modified Files" msgstr "最近修改过的文件" msgid "Recently Modified Files..." msgstr "最近修改过的文件 ..." msgid "Recovering a dropped stash is not possible." msgstr "已丢弃的暂存是无法恢复的." msgid "Recovering lost commits may not be easy." msgstr "恢复丢失的提交是比较困难的." msgid "Redo" msgstr "重做" msgid "Reduce commit history to minimum" msgstr "尽量减少提交历史" msgid "Refresh" msgstr "刷新" msgid "" "Refuse to merge unless the current HEAD is already up-to-date or the merge " "can be resolved as a fast-forward" msgstr "" msgid "Remote" msgstr "远程(remote)" msgid "Remote Branch" msgstr "远程分支" msgid "Remote Branch Deleted" msgstr "远程分支已删除" msgid "Remote git repositories - double-click to rename" msgstr "远程版本库 - 双击以改名" msgid "Remove" msgstr "移除" #, python-format msgid "Remove %s from the recent list?" msgstr "将 %s 从最近使用列表中移除吗?" msgid "Remove Element" msgstr "移除元素" msgid "Remove remote-tracking branches that no longer exist on the remote" msgstr "" msgid "Remove selected (Delete)" msgstr "移除所选 (删除)" msgid "Rename" msgstr "重命名" #, python-format msgid "Rename \"%s\"" msgstr "重命名 \"%s\"" msgid "Rename Branch" msgstr "重命名分支" msgid "Rename Branch..." msgstr "重命名分支..." msgid "Rename Existing Branch" msgstr "重命名已有分支" msgid "Rename Remote" msgstr "重命名远程" msgid "Rename Repository" msgstr "重命名版本库" msgid "Rename branch" msgstr "重命名分支" #, python-format msgid "Rename remote \"%(current)s\" to \"%(new)s\"?" msgstr "重命名远程 \"%(current)s\" 为 \"%(new)s\"?" msgid "Rename selected paths" msgstr "重命名所选路径" #, python-format msgid "Repository: %s" msgstr "版本库: %s" msgid "Reset" msgstr "复位" #, python-format msgid "Reset \"%(branch)s\" to \"%(revision)s\"?" msgstr "复位分支 \"%(branch)s\" 到 \"%(revision)s\" 吗?" msgid "Reset Branch" msgstr "重置分支" msgid "Reset Branch Head" msgstr "复位分支头" msgid "Reset Branch?" msgstr "重置分支吗?" #, fuzzy msgid "Reset Hard" msgstr "复位分支头" #, fuzzy msgid "Reset Merge" msgstr "要合并的版本" #, fuzzy msgid "Reset Soft" msgstr "重置工作树" msgid "Reset Worktree" msgstr "重置工作树" #, fuzzy msgid "Reset hard?" msgstr "重置分支吗?" #, fuzzy msgid "Reset merge?" msgstr "要重置工作树吗?" #, fuzzy msgid "Reset soft?" msgstr "复位 '%s'?" msgid "Reset worktree?" msgstr "要重置工作树吗?" #, python-format msgid "Resetting \"%(branch)s\" to \"%(revision)s\" will lose commits." msgstr "复位 \"%(branch)s\" to \"%(revision)s\" 将丢失提交." msgid "Restart the application after changing appearance settings." msgstr "" msgid "Revert" msgstr "撤销" msgid "Revert Diff Hunk" msgstr "撤销差异区域" msgid "Revert Diff Hunk..." msgstr "撤销差异区域..." msgid "Revert Diff Hunk?" msgstr "撤销差异区域吗?" msgid "Revert Selected Lines" msgstr "撤销所选行" msgid "Revert Selected Lines..." msgstr "撤销所选行..." msgid "Revert Selected Lines?" msgstr "撤销所选行吗?" msgid "Revert Uncommitted Changes" msgstr "撤销未提交的修改" msgid "Revert Uncommitted Changes?" msgstr "撤销未提交的修改吗?" msgid "Revert Uncommitted Edits..." msgstr "撤销未缓存修订..." msgid "Revert Unstaged Changes" msgstr "恢复未缓存的改动" msgid "Revert Unstaged Changes?" msgstr "恢复未缓存的改动?" msgid "Revert Unstaged Edits..." msgstr "恢复未缓存修订..." msgid "Revert the uncommitted changes?" msgstr "撤销未提交的修改吗?" msgid "Revert the unstaged changes?" msgstr "恢复这个未缓存的改动?" msgid "Revert uncommitted changes to selected paths" msgstr "撤销所选路径未提交的改动" msgid "Revert unstaged changes to selected paths" msgstr "撤销所选路径未缓存的改动" msgid "Review" msgstr "审阅" msgid "Review..." msgstr "审阅..." msgid "Revision" msgstr "版本" msgid "Revision Expression:" msgstr "版本表达式:" msgid "Revision to Merge" msgstr "要合并的版本" msgid "Reword" msgstr "改写" msgid "Rewrite Published Commit?" msgstr "重写已发布的提交吗?" msgid "Run" msgstr "运行" #, python-format msgid "Run \"%s\"?" msgstr "运行 \"%s\"?" #, python-format msgid "Run %s?" msgstr "运行 %s?" #, python-format msgid "Run the \"%s\" command?" msgstr "运行 \"%s\" 命令吗?" #, python-format msgid "Running command: %s" msgstr "正运行命令:%s" msgid "Russian translation" msgstr "俄语翻译" msgid "SHA-1" msgstr "SHA-1" msgid "Safe Mode" msgstr "安全模式" msgid "Save" msgstr "保存" msgid "Save Archive" msgstr "保存归档" msgid "Save As Tarball/Zip..." msgstr "存为压缩存档 Tar/Zip..." msgid "Save GUI Settings" msgstr "保存界面设定" msgid "Save Stash" msgstr "进行暂存" msgid "Save modified state to new stash" msgstr "保存修改状态到新暂存" #, python-format msgid "Saved \"%(filename)s\" from \"%(ref)s\" to \"%(destination)s\"" msgstr "已从 \"%(ref)s\" 保存 \"%(filename)s\" 到 \"%(destination)s\"" msgid "Search" msgstr "搜寻" msgid "Search Authors" msgstr "查找作者" msgid "Search Commit Messages" msgstr "查找提交信息" msgid "Search Committers" msgstr "查找提交者" msgid "Search Date Range" msgstr "查找日期范围" msgid "Search Diffs" msgstr "查找差异" msgid "Search by Expression" msgstr "按表达式查找" msgid "Search by Path" msgstr "按路径查找" msgid "Search for a fixed string" msgstr "用特定字符串查找" msgid "Search using a POSIX basic regular expression" msgstr "使用 POSIX 基本正则表达式查找" msgid "Search using a POSIX extended regular expression" msgstr "使用 POSIX 拓展正则表达式查找" msgid "Search..." msgstr "查找..." msgid "Select" msgstr "选择" msgid "Select All" msgstr "全选" msgid "Select Branch to Review" msgstr "选择分支进行审阅" msgid "Select Child" msgstr "选择子项目" msgid "Select Commit" msgstr "选择提交" msgid "Select Directory..." msgstr "选择目录..." msgid "Select New Upstream" msgstr "选择上游项目" msgid "Select Newest Child" msgstr "选择最新子项目" msgid "Select Oldest Parent" msgstr "选择最旧父项目" msgid "Select Parent" msgstr "选择父项目" msgid "Select Previous Version" msgstr "选择之前版本" msgid "Select Repository..." msgstr "选择版本库..." msgid "Select a parent directory for the new clone" msgstr "为新克隆选择上级文件夹" msgid "Select manually..." msgstr "手动选择..." msgid "Select output dir" msgstr "选择输出目录" #, fuzzy msgid "Select output directory" msgstr "选择版本库..." msgid "Select patch file(s)..." msgstr "选择补丁文件..." #, fuzzy msgid "Select repository" msgstr "选择版本库..." msgid "Set Default Repository" msgstr "选择默认版本库" msgid "Set Upstream Branch" msgstr "设置上游分支" msgid "" "Set the sort order for branches and tags.\n" "Toggle between date-based and version-name-based sorting." msgstr "" msgid "Set upstream" msgstr "设置上游" msgid "Settings" msgstr "设置" msgid "Shell arguments" msgstr "Shell 参数" msgid "Shift Down" msgstr "Shift 上箭" msgid "Shift Up" msgstr "Shift 下键" msgid "Shortcuts" msgstr "快捷键" msgid "Show Details..." msgstr "显示细节..." msgid "Show Diffstat After Merge" msgstr "在合并后显示 Diffstat" msgid "Show Full Paths in the Window Title" msgstr "在窗口标题中显示完整路径" msgid "Show Help" msgstr "显示帮助" msgid "Show History" msgstr "显示历史" msgid "Show file counts in Status titles" msgstr "在状态标题中显示文件计数" msgid "" "Show help\n" "Shortcut: ?" msgstr "" "显示帮助\n" "快捷键: ?" msgid "Show icon? (if available)" msgstr "显示图标?(如果可用)" msgid "Show line numbers" msgstr "显示行号" msgid "Show whole surrounding functions of changes" msgstr "显示包含修改的整个函数" msgid "Showing changes since" msgstr "显示改动自" msgid "Side by side" msgstr "并排" msgid "Sign Off" msgstr "签名(Sign Off)" msgid "Sign Tag" msgstr "为标签签名" msgid "Sign off on this commit" msgstr "对本次提交签名" msgid "Simplified Chinese translation" msgstr "简体中文翻译" msgid "Skip" msgstr "跳过" msgid "Skip Current Patch" msgstr "跳过当前补丁" msgid "Sort bookmarks alphabetically" msgstr "按字母顺序排列书签" msgid "Spanish translation" msgstr "西班牙语翻译" msgid "Specifies the SHA-1 to tag" msgstr "指定标签的 SHA-1 值" msgid "Specifies the tag message" msgstr "指定标签信息" msgid "Specifies the tag name" msgstr "指定标签名称" msgid "Spelling Suggestions" msgstr "拼写建议" msgid "Squash" msgstr "压缩" msgid "Squash the merged commits into a single commit" msgstr "压缩合并中提交成单一提交" msgid "Stage" msgstr "缓存" msgid "Stage / Unstage" msgstr "缓存 / 取消缓存" msgid "Stage All Untracked" msgstr "缓存所有未跟踪项目" msgid "Stage Changed Files To Commit" msgstr "缓存修改的文件为提交" msgid "Stage Diff Hunk" msgstr "缓存差异区域" msgid "Stage Modified" msgstr "缓存已修改的文件" msgid "Stage Selected" msgstr "缓存已选项目" msgid "Stage Selected Lines" msgstr "缓存所选行" msgid "Stage Unmerged" msgstr "缓存未合并的文件" msgid "Stage Untracked" msgstr "缓存未跟踪的文件" msgid "Stage and Commit" msgstr "缓存并提交" msgid "Stage and commit?" msgstr "缓存并提交吗?" msgid "Stage conflicts" msgstr "缓存冲突" msgid "Stage conflicts?" msgstr "缓存冲突?" msgid "Stage/unstage selected paths for commit" msgstr "缓存/取消缓存已选路径以提交" msgid "Staged" msgstr "已缓存" #, python-format msgid "Staging: %s" msgstr "正在缓存: %s" msgid "Start Interactive Rebase..." msgstr "开始交互式衍合..." msgid "Starting Revision" msgstr "起始版本" msgid "Stash" msgstr "暂存" msgid "Stash Index" msgstr "暂存索引" #, fuzzy msgid "Stash staged changes only" msgstr "提交已缓存修改" #, fuzzy msgid "Stash unstaged changes only, keeping staged changes" msgstr "撤销所选路径未缓存的改动" msgid "Stash..." msgstr "暂存..." msgid "Status" msgstr "状态" msgid "Stop tracking paths" msgstr "停止跟踪路径" msgid "Submodules" msgstr "子模块" msgid "Summarize Merge Commits" msgstr "概述合并提交" msgid "Summary" msgstr "概要" msgid "Tab Width" msgstr "Tab 宽度" msgid "Tag" msgstr "标签" msgid "Tag Created" msgstr "标签已创建" msgid "Tag message..." msgstr "标签信息..." msgid "Tag-signing was requested but the tag message is empty." msgstr "标签需要签名但其内容为空." msgid "Tags" msgstr "标签" msgid "Text Width" msgstr "字符宽度" msgid "The branch will be no longer available." msgstr "分支已不可用。" #, python-format msgid "The branch will be reset using \"git reset --hard %s\"" msgstr "" #, python-format msgid "The branch will be reset using \"git reset --merge %s\"" msgstr "" #, python-format msgid "The branch will be reset using \"git reset --mixed %s\"" msgstr "" #, python-format msgid "The branch will be reset using \"git reset --soft %s\"" msgstr "" msgid "The commit message will be cleared." msgstr "提交消息会被清除。" #, python-format msgid "The file \"%s\" exists and will be overwritten." msgstr "文件 \"%s\" 已存在,将被覆盖." msgid "The following files will be deleted:" msgstr "如下文件会被删除:" msgid "The revision expression cannot be empty." msgstr "版本表达式不能为空." #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be reset using \"git reset --keep %s\"" msgstr "" msgid "This cannot be undone. Clear commit message?" msgstr "此操作无法恢复. 清空提交消息吗?" msgid "" "This commit has already been published.\n" "This operation will rewrite published history.\n" "You probably don't want to do this." msgstr "" "此提交已发布.\n" "此操作会重写同步历史.\n" "很可能这不是你的心意." #, fuzzy msgid "" "This operation drops uncommitted changes.\n" "These changes cannot be recovered." msgstr "" "此操作将丢弃未提交的修改.\n" "造成的改动将无法撤销." msgid "" "This operation removes uncommitted edits from selected files.\n" "These changes cannot be recovered." msgstr "" "此操作将丢弃未提交的修改.\n" "造成的改动将无法撤销." msgid "" "This operation removes unstaged edits from selected files.\n" "These changes cannot be recovered." msgstr "" "这个操作会留下未缓存的改动.\n" "这些改动将无法恢复." msgid "" "This repository is currently being rebased.\n" "Resolve conflicts, commit changes, and run:\n" " Rebase > Continue" msgstr "" "此版本库正在衍合中.\n" "解决内容冲突, 提交更改, 并执行\n" " 衍合 > 继续" msgid "" "This repository is in the middle of a merge.\n" "Resolve conflicts and commit changes." msgstr "" "此版本库正在合并中.\n" "解决内容冲突并提交更改." msgid "Toggle Enabled" msgstr "切换已启用" msgid "Toggle the branches filter" msgstr "切换分支过滤器" msgid "Toggle the paths filter" msgstr "切换路径过滤器开关" msgid "Tracking Branch" msgstr "正跟踪分支" msgid "Tracking branch" msgstr "跟踪分支" msgid "Traditional Chinese (Taiwan) translation" msgstr "繁体中文 (台湾) 翻译" msgid "Translators" msgstr "翻译者" msgid "Turkish translation" msgstr "土耳其语翻译" msgid "URL" msgstr "URL" #, python-format msgid "URL: %s" msgstr "URL: %s" msgid "Ukranian translation" msgstr "乌克兰语翻译" msgid "Unable to rebase" msgstr "无法进行衍合" #, python-format msgid "Unable to set URL for \"%(name)s\" to \"%(url)s\"" msgstr "" msgid "Undo" msgstr "撤销" msgid "Unmerged" msgstr "未合并" msgid "Unstage" msgstr "取消缓存" msgid "Unstage All" msgstr "全部取消缓存" msgid "Unstage Diff Hunk" msgstr "取消缓存差异区域" msgid "Unstage From Commit" msgstr "从本次提交撤除" msgid "Unstage Selected" msgstr "取消缓存已选项目" msgid "Unstage Selected Lines" msgstr "取消缓存所选行(&S)" #, python-format msgid "Unstaging: %s" msgstr "正取消缓存: %s" msgid "Untrack Selected" msgstr "取消跟踪所选项目" msgid "Untracked" msgstr "未跟踪" #, python-format msgid "Untracking: %s" msgstr "跟踪: %s" msgid "Update All Submodules..." msgstr "更新所有子模块..." msgid "Update Existing Branch:" msgstr "更新已有分支:" msgid "Update Submodule" msgstr "更新子模块" msgid "Update Submodule..." msgstr "更新子模块..." msgid "Update Submodules" msgstr "更新子模块" msgid "Update all submodules?" msgstr "更新所有子模块?" msgid "Update submodules..." msgstr "更新子模块..." msgid "Update this submodule" msgstr "更新此子模块" msgid "Update this submodule?" msgstr "更新此子模块?" msgid "Updating" msgstr "更新" msgid "User Name" msgstr "用户名" msgid "Version" msgstr "版本" msgid "View" msgstr "视图" msgid "View History..." msgstr "查看历史..." msgid "View history for selected paths" msgstr "查看所选路径历史" msgid "Visualize" msgstr "图示" msgid "Visualize All Branches..." msgstr "图示所有分支的历史..." msgid "Visualize Current Branch..." msgstr "图示当前分支的历史..." msgid "Whether to sign the tag (git tag -s)" msgstr "是否为标签签名 (git tag -s)" msgid "Would you like to stage and commit all modified files?" msgstr "要缓存并提交所有已修改文件吗?" msgid "XOR" msgstr "异或" msgid "Yes" msgstr "是" msgid "" "You are in the middle of a merge.\n" "Cannot amend while merging." msgstr "" "合并正在进行中.\n" "在合并过程中无法修正." msgid "You cannot rebase with uncommitted changes." msgstr "有未提交修改时无法衍合。" msgid "You must specify a revision to merge." msgstr "指定一个版本进行合并." msgid "You must specify a revision to view." msgstr "指定一个版本进行查看." msgid "Zoom In" msgstr "放大" msgid "Zoom Out" msgstr "缩小" msgid "Zoom to Fit" msgstr "缩放到适合" msgid "command-line arguments" msgstr "命令行参数" msgid "error: unable to execute git" msgstr "错误: 无法执行 git" #, python-format msgid "exit code %s" msgstr "退出代码 %s" #, python-format msgid "" "fatal: \"%s\" is not a directory. Please specify a correct --repo ." msgstr "致命错误: \"%s\" 不是有效目录. 请用 --repo <路径> 指定." #, python-format msgid "git cola version %s" msgstr "git cola 版本 %s" msgid "git-cola" msgstr "git-cola" msgid "git-cola diff" msgstr "git-cola 比较差异" msgid "grep result..." msgstr "筛选结果..." msgid "hotkeys.html" msgstr "hotkeys_zh_CN.html" msgid "unknown" msgstr "未知" msgid "vX.Y.Z" msgstr "vX.Y.Z" msgid "x 1" msgstr "x 1" msgid "x 1.5" msgstr "x 1.5" msgid "x 2" msgstr "x 2" msgid "yyyy-MM-dd" msgstr "yyyy-MM-dd" #~ msgid "" #~ "\n" #~ "\n" #~ "A good replacement for %s\n" #~ "is placing values for the user.name and\n" #~ "user.email settings into your personal\n" #~ "~/.gitconfig file.\n" #~ msgstr "" #~ "\n" #~ "\n" #~ "%s 的一个很好的替代方案是将 user.name 以及\n" #~ "user.email 设置放在你的个人 ~/.gitconfig 文件中.\n" #~ msgid "" #~ "\n" #~ "This is due to a known issue with the\n" #~ "Tcl binary distributed by Cygwin." #~ msgstr "" #~ "\n" #~ "这是由 Cygwin 发布的 Tcl 代码中一个\n" #~ "已知问题所引起." #, fuzzy #~ msgid "\"%s\" returned exit status %d" #~ msgstr "\"%(command)s\" 命令返回状态 %(status)d" #~ msgid "\"git commit\" returned exit code %s" #~ msgstr "\"git commit\" 命令返回状态 %s" #~ msgid "%s ... %*i of %*i %s (%3i%%)" #~ msgstr "%s ... %*i of %*i %s (%3i%%)" #~ msgid "%s Repository" #~ msgstr "%s 版本库" #~ msgid "'%s' is not an acceptable branch name." #~ msgstr "'%s'不是一个可接受的分支名." #~ msgid "* Binary file (not showing content)." #~ msgstr "* 二进制文件 (不显示内容)." #~ msgid "A branch is required for 'Merged Into'." #~ msgstr "'合并到' 需要指定某个分支" #~ msgid "Abort completed. Ready." #~ msgstr "中止完成. 就绪." #~ msgid "Abort failed." #~ msgstr "中止失败" #~ msgid "Aborted checkout of '%s' (file level merging is required)." #~ msgstr "中止 '%s' 的 checkout 操作 (需要做文件级合并)." #~ msgid "Already up-to-date." #~ msgstr "已为最新版本." #~ msgid "Always (Do not perform merge checks)" #~ msgstr "总是合并 (不作合并检查)" #~ msgid "Always (Do not perform merge test.)" #~ msgstr "总是合并 (不作合并测试.)" #~ msgid "Amended Commit Message:" #~ msgstr "修正的提交描述:" #~ msgid "Amended Initial Commit Message:" #~ msgstr "修正的初始提交描述:" #~ msgid "Amended Merge Commit Message:" #~ msgstr "修正的合并提交描述:" #~ msgid "Annotation complete." #~ msgstr "标注完成." #~ msgid "Any unstaged changes will be permanently lost by the revert." #~ msgstr "任何未缓存的改动将在这次撤销中永久丢失." #~ msgid "Apply Diff Selection to Work Tree" #~ msgstr "应用所选差异到工作目录" #~ msgid "Apply/Reverse Hunk" #~ msgstr "应用/撤消此修改块" #~ msgid "Arbitrary URL:" #~ msgstr "任意 URL:" #~ msgid "Bookmarks" #~ msgstr "书签" #~ msgid "Bookmarks..." #~ msgstr "书签..." #~ msgid "" #~ "Branch '%s' already exists.\n" #~ "\n" #~ "It cannot fast-forward to %s.\n" #~ "A merge is required." #~ msgstr "" #~ "分支 '%s' 已经存在.\n" #~ "\n" #~ "无法快速合并到 %s.\n" #~ "需要普通合并." #~ msgid "Branch '%s' does not exist." #~ msgstr "分支 '%s' 并不存在." #~ msgid "Branch created" #~ msgstr "分支名" #~ msgid "Browse %s's Files" #~ msgstr "浏览 %s 上的文件" #~ msgid "Browse Branch Files" #~ msgstr "浏览分支文件" #~ msgid "Browse Revision..." #~ msgstr "版本" #~ msgid "" #~ "Cannot abort while amending.\n" #~ "\n" #~ "You must finish amending this commit.\n" #~ msgstr "" #~ "修正操作中无法中止.\n" #~ "\n" #~ "你必须先完成本次修正操作.\n" #~ msgid "" #~ "Cannot amend while merging.\n" #~ "\n" #~ "You are currently in the middle of a merge that has not been fully " #~ "completed. You cannot amend the prior commit unless you first abort the " #~ "current merge activity.\n" #~ msgstr "" #~ "在合并时无法修正.\n" #~ "\n" #~ "你当前正在一次尚未完成的合并操作过程中. 除非中止当前合并活动,\n" #~ "否则无法修正之前的提交.\n" #~ msgid "Cannot determine HEAD. See console output for details." #~ msgstr "无法确定 HEAD. 请查看控制终端的输出." #~ msgid "Cannot fetch branches and objects. See console output for details." #~ msgstr "无法获取分支和对象. 请查看控制终端的输出." #~ msgid "Cannot fetch tags. See console output for details." #~ msgstr "无法获取标签. 请查看控制终端的输出." #~ msgid "Cannot find git in PATH." #~ msgstr "PATH 中没有找到 git" #~ msgid "" #~ "Cannot merge while amending.\n" #~ "\n" #~ "You must finish amending this commit before starting any type of merge.\n" #~ msgstr "" #~ "修正时无法做合并.\n" #~ "\n" #~ "你必须完成对该提交的修正才能继续任何类型的合并操作.\n" #~ msgid "Cannot move to top of working directory:" #~ msgstr "无法移动到工作根目录:" #~ msgid "Cannot parse Git version string:" #~ msgstr "无法解析 Git 的版本信息:" #~ msgid "Cannot resolve %s as a commit." #~ msgstr "无法解析 %s 为提交." #~ msgid "Cannot use funny .git directory:" #~ msgstr "无法使用 .git 目录:" #~ msgid "Cannot write shortcut:" #~ msgstr "无法修改快捷方式:" #~ msgid "Change Font" #~ msgstr "更改字体" #~ msgid "Checked out '%s'." #~ msgstr "'%s' 已被 checkout" #~ msgid "Clone Type:" #~ msgstr "克隆类型:" #~ msgid "Clone failed." #~ msgstr "克隆失败." #~ msgid "Cloning from %s" #~ msgstr "从 %s 克隆" #~ msgid "Commit %s appears to be corrupt" #~ msgstr "提交 %s 似乎已损坏" #~ msgid "Commit failed: %s" #~ msgstr "提交失败: %s" #~ msgid "Commit@@noun" #~ msgstr "提交(commit)" #~ msgid "Compress Database" #~ msgstr "压缩数据库" #~ msgid "Compressing the object database" #~ msgstr "压缩对象数据库" #~ msgid "Copied Or Moved Here By:" #~ msgstr "由复制或移动至此:" #~ msgid "Copying objects" #~ msgstr "复制 objects" #~ msgid "Counting objects" #~ msgstr "清点对象" #~ msgid "Create Desktop Icon" #~ msgstr "创建桌面图标" #~ msgid "Created commit: %s" #~ msgstr "创建了提交: %s" #~ msgid "Creating working directory" #~ msgstr "创建工作目录" #~ msgid "Current Branch:" #~ msgstr "当前分支:" #~ msgid "Database Statistics" #~ msgstr "数据库统计信息" #~ msgid "Decrease Font Size" #~ msgstr "缩小字体" #~ msgid "Delete Local Branch" #~ msgstr "删除本地分支" #~ msgid "Delete Only If" #~ msgstr "删除仅当" #~ msgid "Delete Only If Merged Into" #~ msgstr "仅在合并后删除" #~ msgid "Destination Repository" #~ msgstr "目标版本库" #~ msgid "Detach From Local Branch" #~ msgstr "从本地分支脱离" #~ msgid "Diff/Console Font" #~ msgstr "Diff/控制终端字体" #~ msgid "Directory %s already exists." #~ msgstr "目录 %s 已经存在." #~ msgid "Disk space used by loose objects" #~ msgstr "松散对象所使用的磁盘空间" #~ msgid "Disk space used by packed objects" #~ msgstr "压缩对象所使用的磁盘空间" #~ msgid "Do Nothing" #~ msgstr "不做操作" #~ msgid "Enter Git Repository" #~ msgstr "输入版本库" #, fuzzy #~ msgid "Error %s" #~ msgstr "错误: %s" #~ msgid "Error loading commit data for amend:" #~ msgstr "为修正装载提交数据出错:" #~ msgid "Error: Command Failed" #~ msgstr "错误: 命令失败" #~ msgid "Errors: %s" #~ msgstr "错误: %s" #~ msgid "Exit code: %s" #~ msgstr "退出代码: %s" #~ msgid "Failed to completely save options:" #~ msgstr "无法完全保存选项:" #~ msgid "Failed to configure origin" #~ msgstr "无法配置 origin" #~ msgid "Failed to create repository %s:" #~ msgstr "无法创建版本库 %s:" #~ msgid "" #~ "Failed to delete branches:\n" #~ "%s" #~ msgstr "" #~ "无法删除分支:\n" #~ "%s" #~ msgid "Failed to open repository %s:" #~ msgstr "无法打开版本库 %s:" #~ msgid "Failed to rename '%s'." #~ msgstr "无法更名 '%s'." #~ msgid "" #~ "Failed to set current branch.\n" #~ "\n" #~ "This working directory is only partially switched. We successfully " #~ "updated your files, but failed to update an internal Git file.\n" #~ "\n" #~ "This should not have occurred. %s will now close and give up." #~ msgstr "" #~ "无法设定当前分支.\n" #~ "\n" #~ "当前工作目录仅有部分被切换出, 我们已成功的更新了您的文件但是无法更新某个内" #~ "部的Git文件.\n" #~ "\n" #~ "这本不该发生, %s 将关闭并放弃." #~ msgid "Failed to stage selected hunk." #~ msgstr "无法缓存所选代码段." #~ msgid "Failed to unstage selected hunk." #~ msgstr "无法将选择的代码段从缓存中删除." #~ msgid "Failed to update '%s'." #~ msgstr "无法更新 '%s'." #~ msgid "Fast Forward Only " #~ msgstr "仅快进合并" #~ msgid "Fetch from" #~ msgstr "从..获取(fetch)" #~ msgid "Fetching new changes from %s" #~ msgstr "从 %s 处获取新的改动" #~ msgid "File level merge required." #~ msgstr "需要文件级合并." #~ msgid "Font Example" #~ msgstr "字体样例" #~ msgid "Font Family" #~ msgstr "字体族" #~ msgid "Force overwrite existing branch (may discard changes)" #~ msgstr "强制覆盖已有的分支 (可能会丢失改动)" #~ msgid "From Repository" #~ msgstr "从版本库" #~ msgid "Full Copy (Slower, Redundant Backup)" #~ msgstr "全部复制 (较慢, 做备份)" #~ msgid "GPG-signed" #~ msgstr "GPG 已签名" #~ msgid "Garbage files" #~ msgstr "垃圾文件" #~ msgid "Git Gui" #~ msgstr "Git Gui" #~ msgid "Git Repository (subproject)" #~ msgstr "Git 版本库 (子项目)" #~ msgid "Git directory not found:" #~ msgstr "Git 目录无法找到:" #~ msgid "" #~ "Git version cannot be determined.\n" #~ "\n" #~ "%s claims it is version '%s'.\n" #~ "\n" #~ "%s requires at least Git 1.5.0 or later.\n" #~ "\n" #~ "Assume '%s' is version 1.5.0?\n" #~ msgstr "" #~ "无法确定 Git 的版本.\n" #~ "\n" #~ "%s 声明其版本为 '%s'.\n" #~ "\n" #~ "而 %s 需要 1.5.0 或这以后的 Git 版本.\n" #~ "\n" #~ "是否假定 '%s' 为版本 1.5.0?\n" #~ msgid "Hardlinks are unavailable. Falling back to copying." #~ msgstr "硬连接不可用. 使用复制." #~ msgid "In File:" #~ msgstr "在文件:" #~ msgid "Increase Font Size" #~ msgstr "放大字体" #~ msgid "Index" #~ msgstr "缓存(Index)错误" #~ msgid "Initial Commit Message:" #~ msgstr "初始的提交描述:" #~ msgid "Initial file checkout failed." #~ msgstr "初始的文件checkout失败" #~ msgid "Invalid GIT_COMMITTER_IDENT:" #~ msgstr "无效的 GIT_COMMITTER_IDENT" #~ msgid "Invalid date from Git: %s" #~ msgstr "无效的日期: %s" #~ msgid "Invalid font specified in %s:" #~ msgstr "%s 中指定的字体无效:" #~ msgid "KiB" #~ msgstr "KiB" #~ msgid "" #~ "Last scanned state does not match repository state.\n" #~ "\n" #~ "Another Git program has modified this repository since the last scan. A " #~ "rescan must be performed before a merge can be performed.\n" #~ "\n" #~ "The rescan will be automatically started now.\n" #~ msgstr "" #~ "最后一次扫描的状态和当前版本库状态不符.\n" #~ "\n" #~ "另一 Git 程序自上次扫描后修改了本版本库. 在修改当前分支之前需要重新做一次" #~ "扫描.\n" #~ "\n" #~ "重新扫描将自动开始.\n" #~ msgid "" #~ "Last scanned state does not match repository state.\n" #~ "\n" #~ "Another Git program has modified this repository since the last scan. A " #~ "rescan must be performed before another commit can be created.\n" #~ "\n" #~ "The rescan will be automatically started now.\n" #~ msgstr "" #~ "最后一次扫描的状态和当前版本库状态不符.\n" #~ "\n" #~ "另一 Git 程序自上次扫描后修改了本版本库. 在修改当前分支之前需要重新做一次" #~ "扫描.\n" #~ "\n" #~ "重新扫描将自动开始.\n" #~ msgid "" #~ "Last scanned state does not match repository state.\n" #~ "\n" #~ "Another Git program has modified this repository since the last scan. A " #~ "rescan must be performed before the current branch can be changed.\n" #~ "\n" #~ "The rescan will be automatically started now.\n" #~ msgstr "" #~ "最后一次扫描的状态和当前版本库状态不符.\n" #~ "\n" #~ "另一 Git 程序自上次扫描后修改了本版本库. 在修改当前分支之前需要重新做一次" #~ "扫描.\n" #~ "\n" #~ "重新扫描将自动开始.\n" #~ msgid "Linking objects" #~ msgstr "链接 objects" #~ msgid "Loading annotation..." #~ msgstr "裝載标注..." #~ msgid "Loading copy/move tracking annotations..." #~ msgstr "装载复制/移动跟踪标注..." #~ msgid "Loading original location annotations..." #~ msgstr "装载原始位置标注..." #~ msgid "Local Branches" #~ msgstr "本地分支" #~ msgid "Local Merge..." #~ msgstr "本地合并..." #~ msgid "Location %s already exists." #~ msgstr "位置 %s 已经存在." #~ msgid "Main Font" #~ msgstr "主要字体" #~ msgid "Match Tracking Branch Name" #~ msgstr "匹配跟踪分支名字" #~ msgid "Match Tracking Branches" #~ msgstr "匹配跟踪分支" #~ msgid "Merge completed successfully." #~ msgstr "合并成功完成." #~ msgid "Merge strategy '%s' not supported." #~ msgstr "合并策略 '%s' 不支持." #~ msgid "Merged Into:" #~ msgstr "合并到" #~ msgid "Merging %s and %s..." #~ msgstr "合并 %s 和 %s" #~ msgid "Modified, not staged" #~ msgstr "修改但未缓存" #~ msgid "New Branch Name Template" #~ msgstr "新建分支命名模板" #~ msgid "New Commit" #~ msgstr "新建提交" #~ msgid "New Name:" #~ msgstr "新名字:" #~ msgid "" #~ "No changes to commit.\n" #~ "\n" #~ "No files were modified by this commit and it was not a merge commit.\n" #~ "\n" #~ "A rescan will be automatically started now.\n" #~ msgstr "" #~ "没有改动提交.\n" #~ "\n" #~ "该提交没有改动任何文件也不是一个合并提交.\n" #~ "\n" #~ "重新扫描将自动开始.\n" #~ msgid "No default branch obtained." #~ msgstr "没有获取缺省分支" #~ msgid "" #~ "No differences detected.\n" #~ "\n" #~ "%s has no changes.\n" #~ "\n" #~ "The modification date of this file was updated by another application, " #~ "but the content within the file was not changed.\n" #~ "\n" #~ "A rescan will be automatically started to find other files which may have " #~ "the same state." #~ msgstr "" #~ "未检测到改动.\n" #~ "\n" #~ "该文件的修改日期被另一个程序所更新, 但其内容并没有变化.\n" #~ "\n" #~ "对于类似情况的其他文件的重新扫描将自动开始." #~ msgid "No files selected for checkout from HEAD." #~ msgstr "未选择从 HEAD 中签出的文件." #~ msgid "No working directory" #~ msgstr "没有工作目录" #~ msgid "Number of loose objects" #~ msgstr "松散对象的数量" #~ msgid "Number of packed objects" #~ msgstr "压缩对象数量" #~ msgid "Number of packs" #~ msgstr "压缩包数量" #~ msgid "On Debian-based systems try: sudo apt-get install python-pyinotify" #~ msgstr "" #~ "若使用 Debian 系统, 请尝试如下命令: sudo apt-get install python-pyinotify" #~ msgid "" #~ "One or more of the merge tests failed because you have not fetched the " #~ "necessary commits. Try fetching from %s first." #~ msgstr "" #~ "由于没有获取到必要的提交,一个或多个合并测试失败。请尝试从 %s 处先获取。" #~ msgid "Options" #~ msgstr "选项" #~ msgid "Original File:" #~ msgstr "原始文件:" #~ msgid "Originally By:" #~ msgstr "最初由:" #~ msgid "" #~ "Output:\n" #~ "%s" #~ msgstr "" #~ "输出:\n" #~ "%s" #~ msgid "Output: %s" #~ msgstr "输出: %s" #~ msgid "PATCH %(current)d/%(count)d" #~ msgstr "补丁 %(current)d/%(count)d" #~ msgid "Packed objects waiting for pruning" #~ msgstr "压缩对象等待清理" #~ msgid "Path to git repository" #~ msgstr "版本库路径" #~ msgid "Please select one or more branches to delete." #~ msgstr "请选择某个或多个分支来删除" #~ msgid "Please supply a branch name." #~ msgstr "请提供分支名字." #~ msgid "Portions staged for commit" #~ msgstr "部分缓存为提交" #~ msgid "" #~ "Possible environment issues exist.\n" #~ "\n" #~ "The following environment variables are probably\n" #~ "going to be ignored by any Git subprocess run\n" #~ "by %s:\n" #~ "\n" #~ msgstr "" #~ "可能存在环境变量的问题.\n" #~ "\n" #~ "由 %s 执行的 Git 子进程可能忽略下列环境变量:\n" #~ "\n" #~ msgid "Preferences..." #~ msgstr "首选项..." #~ msgid "Process Diff Hunk" #~ msgstr "处理差异部分" #~ msgid "Process Selection" #~ msgstr "处理所选部分" #~ msgid "Prune Tracking Branches During Fetch" #~ msgstr "获取时清除跟踪分支" #~ msgid "Pruning tracking branches deleted from %s" #~ msgstr "清除" #~ msgid "Push Branches" #~ msgstr "上传分支" #~ msgid "Push to" #~ msgstr "上传到(push)" #~ msgid "Pushing %s %s to %s" #~ msgstr "上传 %s %s 到 %s" #~ msgid "Reading %s..." #~ msgstr "读取 %s..." #~ msgid "Ready to commit." #~ msgstr "缓存为提交" #~ msgid "Ready." #~ msgstr "就绪" #~ msgid "Rebase Branch" #~ msgstr "更改分支名:" #~ msgid "Rebase..." #~ msgstr "复位(Reset)..." #~ msgid "" #~ "Recovering deleted branches is difficult.\n" #~ "\n" #~ "Delete the selected branches?" #~ msgstr "" #~ "恢复被删除的分支非常困难.\n" #~ "\n" #~ "是否要删除所选分支?" #~ msgid "" #~ "Recovering deleted branches is difficult. \n" #~ "\n" #~ " Delete the selected branches?" #~ msgstr "" #~ "恢复被删除的分支非常困难.\n" #~ "\n" #~ "是否要删除所选分支?" #~ msgid "Refreshing file status..." #~ msgstr "更新文件状态..." #, fuzzy #~ msgid "Remote Branches" #~ msgstr "远程分支" #~ msgid "Remote:" #~ msgstr "Remote:" #~ msgid "Remove selected paths from the staging area." #~ msgstr "从缓存区移除所选路径." #~ msgid "Rename remote?" #~ msgstr "重命名远程吗?" #~ msgid "Repository" #~ msgstr "版本库(repository)" #~ msgid "Requires merge resolution" #~ msgstr "需要解决合并冲突" #~ msgid "Rescan" #~ msgstr "重新扫描" #~ msgid "" #~ "Reset changes?\n" #~ "\n" #~ "Resetting the changes will cause *ALL* uncommitted changes to be lost.\n" #~ "\n" #~ "Continue with resetting the current changes?" #~ msgstr "" #~ "是否复位当前改动?\n" #~ "\n" #~ "复位当前的改动将导致 *所有* 未提交的改动丢失.\n" #~ "\n" #~ "是否要继续复位当前的改动?" #~ msgid "Revert Uncommitted Changes..." #~ msgstr "撤销未提交修改..." #~ msgid "Revert changes in these %i files?" #~ msgstr "撤销这些 (%i个) 文件的改动?" #~ msgid "Select File" #~ msgstr "选择文件" #~ msgid "Select file from \"%s\"" #~ msgstr "从“%s”中选择文件" #~ msgid "Shared (Fastest, Not Recommended, No Backup)" #~ msgstr "共享方式 (最快, 不推荐, 不做备份)" #~ msgid "Shared only available for local repository." #~ msgstr "共享方式仅当是本地版本库时有效." #~ msgid "Show Less Context" #~ msgstr "显示更少上下文" #~ msgid "Show More Context" #~ msgstr "显示更多上下文" #~ msgid "Source Branches" #~ msgstr "源端分支:" #~ msgid "Stage Hunk For Commit" #~ msgstr "缓存修改块为提交" #~ msgid "Staged Changes (Will Commit)" #~ msgstr "已缓存的改动 (将被提交)" #~ msgid "Staged for commit, missing" #~ msgstr "缓存为提交, 不存在" #~ msgid "Staged for removal" #~ msgstr "缓存为删除" #~ msgid "Staged for removal, still present" #~ msgstr "缓存为删除, 但仍存在" #~ msgid "Staging Area" #~ msgstr "缓存区" #~ msgid "Staging area (index) is already locked." #~ msgstr "缓存区域 (index) 已被锁定." #~ msgid "Standard (Fast, Semi-Redundant, Hardlinks)" #~ msgstr "标准方式 (快速, 部分备份, 作硬连接)" #~ msgid "Standard only available for local repository." #~ msgstr "标准方式仅当是本地版本库时有效." #~ msgid "Starting gitk... please wait..." #~ msgstr "启动 gitk... 请等待..." #~ msgid "Staying on branch '%s'." #~ msgstr "停留在分支 '%s'." #~ msgid "Success" #~ msgstr "成功" #~ msgid "Summary:" #~ msgstr "概要:" #~ msgid "The 'master' branch has not been initialized." #~ msgstr "'master'分支尚未初始化." #~ msgid "The following branches are not completely merged into %s:" #~ msgstr "下列分支没有完全被合并到 %s:" #~ msgid "" #~ "The following branches are not completely merged into %s:\n" #~ "\n" #~ " - %s" #~ msgstr "" #~ "下列分支没有被全部合并到 %s 中:\n" #~ "\n" #~ " - %s" #~ msgid "" #~ "There is nothing to amend.\n" #~ "\n" #~ "You are about to create the initial commit. There is no commit before " #~ "this to amend.\n" #~ msgstr "" #~ "没有改动需要修正.\n" #~ "\n" #~ "你正在创建最初的提交. 在此之前没有提交可以修正.\n" #~ msgid "This Detached Checkout" #~ msgstr "该脱节的Checkout" #~ msgid "" #~ "This PyQt4 does not include QtWebKit.\n" #~ "The keyboard shortcuts feature is unavailable." #~ msgstr "" #~ "此程序使用的 PyQt4 不包含 QtWebkit 模块.\n" #~ "键盘快捷键功能不可用." #~ msgid "" #~ "This is example text.\n" #~ "If you like this text, it can be your font." #~ msgstr "" #~ "这是样例文本.\n" #~ "如果你喜欢, 你可以设置该字体." #~ msgid "" #~ "This repository currently has approximately %i loose objects.\n" #~ "\n" #~ "To maintain optimal performance it is strongly recommended that you " #~ "compress the database when more than %i loose objects exist.\n" #~ "\n" #~ "Compress the database now?" #~ msgstr "" #~ "该版本库当前约有 %i 个松散对象.\n" #~ "\n" #~ "为达到较优的性能,强烈建议你在松散对象多于 %i 时压缩数据库.\n" #~ "\n" #~ "现在就压缩数据库么?" #~ msgid "Tracking branch %s is not a branch in the remote repository." #~ msgstr "跟踪分支 %s 并不是远程版本库中的一个分支" #~ msgid "Transfer Options" #~ msgstr "传输选项" #~ msgid "Unable to copy object: %s" #~ msgstr "无法复制 object: %s" #~ msgid "Unable to copy objects/info/alternates: %s" #~ msgstr "无法复制 objects/info/alternates: %s" #~ msgid "Unable to display %s" #~ msgstr "无法显示 %s" #~ msgid "Unable to hardlink object: %s" #~ msgstr "无法硬链接 object: %s" #~ msgid "Unable to obtain your identity:" #~ msgstr "无法获知你的身份:" #~ msgid "" #~ "Unable to start gitk:\n" #~ "\n" #~ "%s does not exist" #~ msgstr "" #~ "无法启动 gitk:\n" #~ "\n" #~ "%s 不存在" #~ msgid "Unable to unlock the index." #~ msgstr "无法解锁缓存 (index)" #~ msgid "" #~ "Unknown file state %s detected.\n" #~ "\n" #~ "File %s cannot be committed by this program.\n" #~ msgstr "" #~ "检测到未知文件状态 %s.\n" #~ "\n" #~ "文件 %s 无法由该程序提交.\n" #~ msgid "Unlock Index" #~ msgstr "解锁 Index" #~ msgid "" #~ "Unmerged files cannot be committed.\n" #~ "\n" #~ "File %s has merge conflicts. You must resolve them and stage the file " #~ "before committing.\n" #~ msgstr "" #~ "尚未合并的文件没有办法提交.\n" #~ "\n" #~ "文件 %s 有合并冲突, 你必须解决这些冲突并缓存该文件作提交.\n" #~ msgid "Unstage Hunk From Commit" #~ msgstr "从提交中撤除修改块" #~ msgid "" #~ "Updating the Git index failed. A rescan will be automatically started to " #~ "resynchronize git-gui." #~ msgstr "更新 Git 缓存(Index)失败, 重新扫描将自动开始以重新同步 git-gui." #~ msgid "Updating working directory to '%s'..." #~ msgstr "更新工作目录到 '%s'..." #~ msgid "Updating..." #~ msgstr "更新..." #~ msgid "Use thin pack (for slow network connections)" #~ msgstr "使用 thin pack (适用于低速网络连接)" #~ msgid "Verify Database" #~ msgstr "验证数据库" #~ msgid "Verifying the object database with fsck-objects" #~ msgstr "使用 fsck-objects 验证对象数据库" #~ msgid "Visualize %s's History" #~ msgstr "图示 %s 分支的历史" #~ msgid "Working... please wait..." #~ msgstr "工作中... 请等待..." #~ msgid "" #~ "You are in the middle of a change.\n" #~ "\n" #~ "File %s is modified.\n" #~ "\n" #~ "You should complete the current commit before starting a merge. Doing so " #~ "will help you abort a failed merge, should the need arise.\n" #~ msgstr "" #~ "你正处在一个改动当中.\n" #~ "\n" #~ "文件 %s 已被修改.\n" #~ "\n" #~ "你必须完成当前的提交后才能开始合并. 如果需要, 这么做将有助于中止一次失败的" #~ "合并.\n" #~ msgid "" #~ "You are in the middle of a conflicted merge.\n" #~ "\n" #~ "File %s has merge conflicts.\n" #~ "\n" #~ "You must resolve them, stage the file, and commit to complete the current " #~ "merge. Only then can you begin another merge.\n" #~ msgstr "" #~ "你正处在一个有冲突的合并操作中.\n" #~ "\n" #~ "文件 %s 有合并冲突.\n" #~ "\n" #~ "你必须解决这些冲突, 缓存该文件, 并提交来完成当前的合并.仅当这样后才能开始" #~ "下一个合并操作.\n" #~ msgid "" #~ "You are no longer on a local branch.\n" #~ "\n" #~ "If you wanted to be on a branch, create one now starting from 'This " #~ "Detached Checkout'." #~ msgstr "" #~ "你不在某个本地分支上.\n" #~ "\n" #~ "如果你想位于某分支上, 从当前脱节的Checkout中创建一个新分支." #~ msgid "You must correct the above errors before committing." #~ msgstr "你必须在提交前修正上述错误." #~ msgid "[Up To Parent]" #~ msgstr "[上层目录]" #~ msgid "buckets" #~ msgstr "水桶??" #~ msgid "commit-tree failed:" #~ msgstr "commit-tree 失败:" #~ msgid "fatal: Cannot resolve %s" #~ msgstr "致命错误: 无法解决 %s" #~ msgid "" #~ "file notification: disabled\n" #~ "Note: install pywin32 to enable.\n" #~ msgstr "" #~ "文件提示已禁用\n" #~ "注: 安装 pywin32 以启用.\n" #~ msgid "files" #~ msgstr "文件" #~ msgid "files reset" #~ msgstr "文件" #~ msgid "git clone returned exit code %s" #~ msgstr "git clone 命令返回状态 %s" #~ msgid "git tag returned exit code %s" #~ msgstr "git tag 命令返回状态 %s" #~ msgid "git-gui - a graphical user interface for Git." #~ msgstr "git-gui - Git 的图形化用户界面" #~ msgid "git-gui: fatal error" #~ msgstr "git-gui: 致命错误" #~ msgid "inotify enabled." #~ msgstr "inotify 已启用." #~ msgid "" #~ "inotify: disabled\n" #~ "Note: install python-pyinotify to enable inotify.\n" #~ msgstr "" #~ "inotify 已禁用\n" #~ "提示: 安装 python-pyinotify 以启用 inotify.\n" #~ msgid "lines annotated" #~ msgstr "标注行" #~ msgid "objects" #~ msgstr "objects" #~ msgid "pt." #~ msgstr "磅" #~ msgid "push %s" #~ msgstr "上传 %s" #~ msgid "remote prune %s" #~ msgstr "清除远程 %s" #~ msgid "update-ref failed:" #~ msgstr "update-ref 失败:" #~ msgid "warning" #~ msgstr "警告" #~ msgid "warning: Tcl does not support encoding '%s'." #~ msgstr "警告: Tcl 不支持编码方式 '%s'." #~ msgid "write-tree failed:" #~ msgstr "write-tree 失败:" git-cola-3.6/po/zh_TW.po000066400000000000000000002525571356743264500151310ustar00rootroot00000000000000# Translation of git-cola to Traditional Chinese(Taiwan) # Copyright (C) 2007, 2008 Shawn Pearce at el. # This file is distributed under the same license as the git-cola package. # # 敬請參考 glossary/zh_tw.po 的辭彙翻譯 # # Xudong Guan , 2007. # Eric Miao , 2008. # V字龍(Vdragon) , 2017, 2018. # 林博仁(Buo-ren, Lin) , 2018. msgid "" msgstr "" "Project-Id-Version: git-cola VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-17 01:06-0700\n" "PO-Revision-Date: 2018-08-30 13:29+0800\n" "Last-Translator: 林博仁(Buo-ren, Lin) \n" "Language-Team: Chinese l10n \n" "Language: zh_TW\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n>1);\n" msgid "" "\n" "

\n" " Drag and drop or use the Add button to add\n" " patches to the list\n" "

\n" " " msgstr "" "\n" "

\n" " 拖放或使用新增按鈕以將\n" " 修正檔加到清單中\n" "

\n" " " #, python-format msgid "" "\n" "
\n" " Git Cola has been translated into different languages thanks\n" " to the help of the individuals listed below.\n" "\n" "
\n" "

\n" " Translation is approximate. If you find a mistake,\n" " please let us know by opening an issue on Github:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " We invite you to participate in translation by adding or updating\n" " a translation and opening a pull request.\n" "

\n" "\n" "
\n" "\n" " " msgstr "" "\n" "
\n" " 感謝下列眾位的協助,\n" " Git Cola 已被翻譯為多種不同的語言。\n" "\n" "
\n" "

\n" " 翻譯不一定都是精確的。惝若您發現了翻譯不當之處,\n" " 請透過在 GitHub 上建立議題的方式讓我們知道:\n" "

\n" "\n" "

\n" " %(bug_link)s\n" "

\n" "\n" "
\n" "

\n" " 我們邀請您透過新增或更新翻譯並提交變更拉取請求的方式\n" " 來參與本軟體的翻譯\n" "

\n" "\n" "
\n" "\n" " " #, python-format msgid "" "\n" "
\n" " Git Cola version %(cola_version)s %(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) %(python_version)s\n" "
  • Git %(git_version)s\n" "
  • Qt %(qt_version)s\n" "
  • QtPy %(qtpy_version)s\n" "
  • %(pyqt_api_name)s %(pyqt_api_version)s\n" "
\n" " " msgstr "" "\n" "
\n" " Git Cola 第 %(cola_version)s 版%(build_version)s\n" "
    \n" "
  • %(platform_version)s\n" "
  • Python (%(python_path)s) 第 %(python_version)s 版\n" "
  • Git 第 %(git_version)s 版\n" "
  • Qt 第 %(qt_version)s 版\n" "
  • QtPy 第 %(qtpy_version)s 版\n" "
  • %(pyqt_api_name)s 第 %(pyqt_api_version)s 版\n" "
\n" " " #, python-format msgid "" "\n" "
\n" " Please use %(bug_link)s to report issues.\n" "
\n" " " msgstr "" "\n" "
\n" " 請透過 %(bug_link)s 來回報使用問題\n" "
\n" " " #, python-format msgid "" "\n" " Format String Variables\n" " -----------------------\n" " %(path)s = relative file path\n" " %(abspath)s = absolute file path\n" " %(dirname)s = relative directory path\n" " %(absdirname)s = absolute directory path\n" " %(filename)s = file basename\n" " %(basename)s = file basename without extension\n" " %(ext)s = file extension\n" msgstr "" "\n" " 格式化字串變數\n" " -------\n" " %(path)s = 相對檔案路徑\n" " %(abspath)s = 絕對檔案路徑\n" " %(dirname)s = 相對目錄路徑\n" " %(absdirname)s = 絕對目錄路徑\n" " %(filename)s = 檔名\n" " %(basename)s = 檔名(去副檔名)\n" " %(ext)s = 副檔名\n" msgid "" "\n" "Commands\n" "--------\n" "pick = use commit\n" "reword = use commit, but edit the commit message\n" "edit = use commit, but stop for amending\n" "squash = use commit, but meld into previous commit\n" "fixup = like \"squash\", but discard this commit's log message\n" "exec = run command (the rest of the line) using shell\n" "\n" "These lines can be re-ordered; they are executed from top to bottom.\n" "\n" "If you disable a line here THAT COMMIT WILL BE LOST.\n" "\n" "However, if you disable everything, the rebase will be aborted.\n" "\n" "Keyboard Shortcuts\n" "------------------\n" "? = show help\n" "j = move down\n" "k = move up\n" "J = shift row down\n" "K = shift row up\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "spacebar = toggle enabled\n" "\n" "ctrl+enter = accept changes and rebase\n" "ctrl+q = cancel and abort the rebase\n" "ctrl+d = launch difftool\n" msgstr "" "\n" "可用命令\n" "--------\n" "pick = 選用這個修訂版提交\n" "reword = 選用這個修訂版提交,但編輯修訂版提交訊息\n" "edit = 選用這個修訂版提交,但停下來以進行修正(amending)\n" "squash = 選用這個修訂版提交,但是將其併入前一個修訂版提交\n" "fixup = 跟 squash 雷同,但丟棄此修訂版提交的紀錄訊息\n" "exec = 使用殼層(shell)執行命令(剩下的行)\n" "\n" "這些行可以被更動順序,他們將被從上至下執行。\n" "\n" "如果你停用任一行**該修訂版提交將會遺失**。\n" "\n" "但是,如果您停用所有行,這次變更基底(rebase)將被中止。\n" "\n" "鍵盤快捷鍵\n" "------------------\n" "? = 顯示此幫助訊息\n" "j = 往下移動\n" "k = 往上移動\n" "J = 將選取的行往下平移\n" "K = 將選取的行往上平移\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "空白鍵 = 切換啟用/停用\n" "\n" "ctrl+enter = 接受變更並變更基底\n" "ctrl+q = 取消並中止變更基底程序\n" "ctrl+d = 啟動內容差異檢視工具\n" msgid "" "\n" "Keyboard Shortcuts\n" "------------------\n" "J, Down = Move Down\n" "K, Up = Move Up\n" "Enter = Edit Selected Files\n" "Spacebar = Open File Using Default Application\n" "Ctrl + L = Focus Text Entry Field\n" "? = Show Help\n" "\n" "The up and down arrows change focus between the text entry field\n" "and the results.\n" msgstr "" "\n" "鍵盤快捷鍵\n" "------------------\n" "J, Down = 往下移動\n" "K, Up = 往上移動\n" "Enter = 編輯選取的檔案\n" "Spacebar = 以預設應用軟體開啟檔案\n" "Ctrl+L = 將焦點移至文字輸入欄位\n" "? = 顯示幫助訊息\n" "\n" "用上、下方向鍵在文字輸入欄位與執行結果間\n" "變更焦點。\n" msgid " - DAG" msgstr " - 有向無環圖(DAG)" msgid " commits ago" msgstr " 個修訂版提交前" #, python-format msgid "\"%(branch)s\" has been deleted from \"%(remote)s\"." msgstr "「%(branch)s」分支已從「%(remote)s」版控庫中移除。" #, python-format msgid "\"%(command)s\" returned exit status \"%(status)d\"" msgstr "「%(command)s」命令傳回了 %(status)d 結束狀態代碼" #, python-format msgid "\"%(command)s\" returned exit status %(status)d" msgstr "「%(command)s」命令傳回了 %(status)d 結束狀態碼" #, python-format msgid "\"%s\" already exists" msgstr "「%s」早已存在" #, python-format msgid "\"%s\" already exists, cola will create a new directory" msgstr "「%s」目錄已存在,cola 將會另外建立一個新的目錄" #, python-format msgid "\"%s\" requires a selected file." msgstr "「%s」操作需要有選取檔案才能執行。" msgid "#" msgstr "" #, python-format msgid "%(project)s: %(branch)s - Browse" msgstr "%(project)s:%(branch)s - 瀏覽" #, python-format msgid "%(project)s: %(ref)s - DAG" msgstr "%(project)s: %(ref)s - 有向無環圖(DAG)" #, python-format msgid "%d days ago" msgstr "%d 天前" #, python-format msgid "%d hours ago" msgstr "%d 小時前" #, python-format msgid "%d minutes ago" msgstr "%d 分鐘前" #, python-format msgid "%d patch(es) applied." msgstr "已套用 %d 個修正。" #, python-format msgid "%d skipped" msgstr "%d 個跳過了" #, python-format msgid "" "%s appears to contain merge conflicts.\n" "\n" "You should probably skip this file.\n" "Stage it anyways?" msgstr "" "%s 看起來包含未解決的合併衝突。\n" "\n" "您可能應該要跳過這個檔案。\n" "無論如何都要將它移入新修訂版準備區域嗎?" #, python-format msgid "%s is not a Git repository." msgstr "%s 不是一個 Git 版控庫。" #, python-format msgid "%s will be removed from your bookmarks." msgstr "「%s」版控庫將會從您的書籤中被刪除。" #, python-format msgid "%s will be removed from your recent repositories." msgstr "「%s」版控庫將從您最近使用的版控庫中移除。" #, python-format msgid "%s: No such file or directory." msgstr "%s:無此檔案或目錄。" msgid "&Edit" msgstr "編輯" msgid "&File" msgstr "檔案" msgid "(Amending)" msgstr "(正在修正前一個修訂版提交)" msgid "*** Branch Point ***" msgstr "*** 分支點 ***" msgid "*** Sandbox ***" msgstr "*** 沙盒 ***" msgid "100%" msgstr "100%" msgid "200%" msgstr "200%" msgid "25%" msgstr "25%" msgid "400%" msgstr "400%" msgid "50%" msgstr "50%" msgid "800%" msgstr "800%" msgid " ..." msgstr "〈路徑〉……" msgid "" "A commit template has not been configured.\n" "Use \"git config\" to define \"commit.template\"\n" "so that it points to a commit template." msgstr "" "修訂版提交範本尚未被設定。\n" "使用「git config」命令來定義「commit.template」設定值\n" "使其指向一個修訂版提交範本。" #, python-format msgid "A hook must be provided at \"%s\"" msgstr "一個掛勾程式必須在「%s」被提供" #, python-format msgid "A stash named \"%s\" already exists" msgstr "名為「%s」的珍藏項目已經存在" msgid "Abort" msgstr "中止" msgid "Abort Action" msgstr "中止操作" msgid "Abort Merge" msgstr "中止分支合併(merge)" msgid "Abort Merge..." msgstr "中止分支合併(merge)……" msgid "Abort the action?" msgstr "要中止操作嗎?" msgid "" "Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" "Recovering uncommitted changes is not possible." msgstr "" "中止目前的分支合併操作將導致 *所有* 尚未提交到版控庫的內容變更遺失,\n" "且所有遺失的變更將無法被復原或找回。" msgid "Aborting the current merge?" msgstr "中止目前正在進行的分支合併?" msgid "About" msgstr "關於" msgid "About git-cola" msgstr "關於 git-cola" msgid "Accept" msgstr "接受" msgid "" "Accept changes and rebase\n" "Shortcut: Ctrl+Enter" msgstr "" "接受變更並變更基底(rebase)\n" "鍵盤快捷鍵:Ctrl+Enter" msgid "Action Name" msgstr "操作名稱" msgid "Actions" msgstr "操作" msgid "Actions..." msgstr "操作……" msgid "Add" msgstr "新增" msgid "Add Favorite" msgstr "新增喜愛的版控庫" msgid "Add Remote" msgstr "新增遠端版控庫" msgid "Add Separator" msgstr "新增分隔器" msgid "Add Toolbar" msgstr "新增工具列" msgid "" "Add and remove remote repositories using the \n" "Add(+) and Delete(-) buttons on the left-hand side.\n" "\n" "Remotes can be renamed by selecting one from the list\n" "and pressing \"enter\", or by double-clicking." msgstr "" "使用左手測的新增(+)與移除(-)按鈕\n" "新增或移除遠端版控庫\n" "\n" "選取其中一個清單中的遠端版控庫\n" "再按下 Enter 或是連續點兩下就可以將其重新命名。" msgid "Add new remote git repository" msgstr "加一個新的遠端 Git 版控庫" msgid "Add patches (+)" msgstr "加入修正檔 (+)" msgid "Add remote" msgstr "新增遠端版控庫" msgid "Add to .gitignore" msgstr "新增到 Git 忽略規則(.gitignore)" msgid "Add to Git Annex" msgstr "新增到 Git Annex" msgid "Add to Git LFS" msgstr "新增到 Git LFS" msgid "Additions" msgstr "新增行數" msgid "Advanced" msgstr "進階選項" msgid "Age" msgstr "建立時間" msgid "All Repositories" msgstr "所有的版控庫" #, python-format msgid "" "All submodules will be updated using\n" "\"%s\"" msgstr "" msgid "Allow non-fast-forward updates. Using \"force\" can cause the remote repository to lose commits; use it with care" msgstr "允許非快速前移式更新。使用「強制」可能會造成遠端版控庫遺失修訂版提交;請小心使用" msgid "Always create a merge commit when enabled, even when the merge is a fast-forward update" msgstr "於啟用時,就算該合併是一個快速前移式更新也總是建立一個合併修訂版提交" msgid "Amend" msgstr "修正前一次的修訂版提交" msgid "Amend Commit" msgstr "修正前一個修訂版提交" msgid "Amend Last Commit" msgstr "修正上次提交" msgid "Amend the published commit?" msgstr "要修正已被推送出去的修訂版提交嗎?" msgid "Amending" msgstr "正在修正前一個修訂版提交" msgid "" "An action is still running.\n" "Terminating it could result in data loss." msgstr "" "一個操作仍在進行。\n" "將其中止可能會造成資料損失。" msgid "" "An unsigned, lightweight tag will be created instead.\n" "Create an unsigned tag?" msgstr "" "一個無簽名的,輕量的標籤將會被建立。\n" "要建立此無簽名的標籤嗎?" msgid "Appearance" msgstr "" msgid "Apply" msgstr "套用" msgid "Apply Patches" msgstr "套用修正" msgid "Apply Patches..." msgstr "套用修正……" msgid "Apply and drop the selected stash (git stash pop)" msgstr "套用並丟棄被選取的珍藏項目(git stash pop)" msgid "Apply the selected stash" msgstr "套用被選取的珍藏項目" msgid "Arguments" msgstr "參數" msgid "Attach" msgstr "連接" msgid "Author" msgstr "作者" msgid "Authors" msgstr "作者群" msgid "Auto" msgstr "" msgid "Auto-Wrap Lines" msgstr "自動折行" msgid "Basic Regexp" msgstr "基本正規表達式" msgid "Blame Viewer" msgstr "指謫(blame)查看器" #, fuzzy msgid "Blame selected paths" msgstr "重新命名選取的路徑" msgid "Blame..." msgstr "指摘(Blame)..." msgid "Bold on dark headers instead of italic" msgstr "標題用帶深色底色的粗體而非斜體" msgid "Branch" msgstr "分支" #, python-format msgid "" "Branch \"%(branch)s\" does not exist in \"%(remote)s\".\n" "A new remote branch will be published." msgstr "" "「%(branch)s」分支並無存在於「%(remote)s」遠端版控庫。\n" "一個新的遠端方支將被發佈。" #, python-format msgid "Branch \"%s\" already exists." msgstr "「%s」分支早已存在。" msgid "Branch Diff Viewer" msgstr "分支差異檢視器" msgid "Branch Exists" msgstr "分支已存在" msgid "Branch Name" msgstr "分支名稱" #, python-format msgid "Branch: %s" msgstr "分支:%s" msgid "Branches" msgstr "分支" msgid "Branches..." msgstr "比較分支之間的內容差異……" msgid "Brazilian translation" msgstr "巴西語翻譯" msgid "Browse" msgstr "瀏覽" msgid "Browse Commits..." msgstr "瀏覽修訂版提交……" msgid "Browse Current Branch..." msgstr "瀏覽目前分支中的檔案……" msgid "Browse Other Branch..." msgstr "瀏覽其他分支中的檔案……" msgid "Browse..." msgstr "瀏覽……" msgid "Browser" msgstr "檔案瀏覽器" #, python-format msgid "Browsing %s" msgstr "正在瀏覽 %s" msgid "Bypass Commit Hooks" msgstr "不執行提交掛勾程式" msgid "Cancel" msgstr "取消" msgid "" "Cancel rebase\n" "Shortcut: Ctrl+Q" msgstr "" "取消變更基底\n" "鍵盤快捷鍵:Ctrl+Q" msgid "Cannot Amend" msgstr "無法修正前一次的修訂版提交" #, python-format msgid "Cannot exec \"%s\": please configure a blame viewer" msgstr "無法執行「%s」:請設定您慣用的 Blame 檢視器" #, python-format msgid "Cannot exec \"%s\": please configure a history browser" msgstr "無法執行「%s」:請設定一個變動紀錄瀏覽器" #, python-format msgid "Cannot exec \"%s\": please configure your editor" msgstr "無法執行「%s」:請設定您慣用的文字編輯器" msgid "Changed Upstream" msgstr "在上游被變更" msgid "Check Spelling" msgstr "檢查拼字問題" msgid "Check spelling" msgstr "檢查拼字問題" msgid "Checkout" msgstr "取出" msgid "Checkout After Creation" msgstr "在建立新分支後取出該分支" msgid "Checkout Branch" msgstr "取出分支內容" msgid "Checkout Detached HEAD" msgstr "取出脫離的 HEAD 指標版本" msgid "Checkout as new branch" msgstr "取出為一新分支" msgid "Checkout..." msgstr "取出……" msgid "Cherry Pick" msgstr "挑取(cherry-pick)" msgid "Cherry-Pick Commit" msgstr "挑取(cherry-pick)修訂版提交並合併至當前分支" msgid "Cherry-Pick..." msgstr "挑取(cherry-pick)……" msgid "Choose Paths" msgstr "選取路徑" msgid "Choose the \"git grep\" regular expression mode" msgstr "選擇「git grep」命令的正規表達式模式" msgid "Clear Default Repository" msgstr "清除預設版控庫" msgid "Clear commit message" msgstr "清除修訂版提交訊息" msgid "Clear commit message?" msgstr "清除修訂版提交訊息?" msgid "Clear..." msgstr "清除……" msgid "Clone" msgstr "克隆" msgid "Clone Repository" msgstr "克隆版控庫" msgid "Clone..." msgstr "克隆另一個版控庫……" #, python-format msgid "Cloning repository at %s" msgstr "正在克隆位於 %s 的版控庫" msgid "Close" msgstr "關閉" msgid "Close..." msgstr "關閉……" msgid "Collapse all" msgstr "全部折疊" # V字龍:注意此應翻譯為動詞。 msgid "Command" msgstr "命令" # V字龍:注意此應翻譯為動詞。 msgid "Commit" msgstr "提交變更" msgid "Commit failed" msgstr "提交失敗" msgid "Commit staged changes" msgstr "提交新修訂版準備區域中的變更" msgid "" "Commit staged changes\n" "Shortcut: Ctrl+Enter" msgstr "" "提交新修訂版準備區域中的變更\n" "鍵盤快捷鍵:Ctrl+Enter" msgid "Commit summary" msgstr "修訂版提交描述" msgid "Commit the merge if there are no conflicts. Uncheck to leave the merge uncommitted" msgstr "若不存在版本衝突時提交該合併。取消勾選以保持合併於尚未提交狀態" msgid "Commit@@verb" msgstr "提交" msgid "Compare" msgstr "比較差異" msgid "Compare All" msgstr "比較全部檔案差異" msgid "Configure the remote branch as the the new upstream" msgstr "將此遠端分支設為新的上游分支" msgid "Configure toolbar" msgstr "設定工具列" msgid "Console" msgstr "終端機輸出" msgid "Continue" msgstr "繼續" msgid "Copy" msgstr "複製" msgid "Copy Basename to Clipboard" msgstr "將基底檔名複製到剪貼簿" msgid "Copy Leading Path to Clipboard" msgstr "將前導路徑複製到剪貼簿" msgid "Copy Path to Clipboard" msgstr "將路徑複製到剪貼簿" msgid "Copy Relative Path to Clipboard" msgstr "將相對路徑複製到剪貼簿" msgid "Copy SHA-1" msgstr "複製 SHA-1 雜湊" msgid "Copy..." msgstr "複製……" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "無法分析 Git URL:「%s」" msgid "Create Branch" msgstr "建立一個新的分支" msgid "Create Patch" msgstr "產生修正檔" msgid "Create Remote Branch" msgstr "建立新的遠端分支" msgid "Create Signed Commit" msgstr "建立經 GPG 簽署過的修訂版提交" msgid "Create Tag" msgstr "建立新的標籤" msgid "Create Tag..." msgstr "建立新的標籤(tag)……" msgid "Create Unsigned Tag" msgstr "建立一個無簽名的標籤" msgid "Create a merge commit even when the merge resolves as a fast-forward" msgstr "就算該合併是一個快速前移式合併也總是建立一個合併修訂版提交" msgid "Create a new remote branch?" msgstr "要建立新的遠端分支嗎?" msgid "Create..." msgstr "新建……" #, python-format msgid "Created a new tag named \"%s\"" msgstr "建立了一個名為「%s」的新標籤" msgid "Current Repository" msgstr "當前的版控庫" msgid "Custom Copy Actions" msgstr "自訂複製操作" msgid "Customize..." msgstr "自訂……" msgid "Cut" msgstr "剪切" msgid "Czech translation" msgstr "捷克語翻譯" msgid "DAG..." msgstr "有向無環圖(DAG)……" msgid "Dark Theme" msgstr "" msgid "Date, Time" msgstr "時間,日期" #, fuzzy msgid "Default" msgstr "恢復默認值" msgid "Delete" msgstr "移除" #, python-format msgid "Delete %d file(s)?" msgstr "刪除 %d 個檔案?" msgid "Delete Bookmark" msgstr "刪除書籤" msgid "Delete Bookmark?" msgstr "要刪除書籤嗎?" msgid "Delete Branch" msgstr "移除分支" msgid "Delete Files" msgstr "刪除檔案" msgid "Delete Files..." msgstr "刪除檔案……" msgid "Delete Files?" msgstr "要刪除檔案嗎?" msgid "Delete Remote" msgstr "移除遠端版控庫" msgid "Delete Remote Branch" msgstr "移除遠端分支" msgid "Delete Remote Branch..." msgstr "移除遠端分支……" msgid "Delete remote" msgstr "移除遠端版控庫" #, python-format msgid "Delete remote \"%s\"" msgstr "移除「%s」遠端版控庫" msgid "Delete remote?" msgstr "要移除遠端版控庫嗎?" msgid "Delete selected branch?" msgstr "要移除選取的分支嗎?" msgid "Delete toolbar" msgstr "刪除工具列" msgid "Delete..." msgstr "移除..." #, python-format msgid "Deleting \"%s\" failed" msgstr "「%s」移除失敗" msgid "Deletions" msgstr "移除行數" msgid "Detach" msgstr "分離" msgid "Detect Conflict Markers" msgstr "偵測衝突標記" msgid "Detect conflict markers in unmerged files" msgstr "偵測尚未合併檔案中的衝突標記" msgid "Developer" msgstr "軟體開發者" msgid "Diff" msgstr "內容差異" msgid "Diff Against Predecessor..." msgstr "與過去版本比較內容差異……" msgid "Diff Options" msgstr "內容差異選項" msgid "Diff Tool" msgstr "顯示內容差異的工具" msgid "Diff selected -> this" msgstr "顯示被選取的修訂版→此修訂版的內容差異" msgid "Diff this -> selected" msgstr "顯示此修訂版→被選取的修訂版的內容差異" msgid "Diffstat" msgstr "顯示內容差異" msgid "Difftool" msgstr "內容差異檢視器" msgid "Directory Exists" msgstr "目錄已存在" msgid "Display Untracked Files" msgstr "顯示未納入版本追蹤的檔案" msgid "Documentation" msgstr "說明文件" msgid "Drop" msgstr "丟棄" msgid "Drop Stash" msgstr "丟棄珍藏項目" msgid "Drop Stash?" msgstr "要丟棄珍藏項目嗎?" #, python-format msgid "Drop the \"%s\" stash?" msgstr "是否要丟棄名為「%s」的珍藏項目?" msgid "Drop the selected stash" msgstr "丟棄被選取的珍藏項目" msgid "Edit" msgstr "編輯" msgid "Edit Rebase" msgstr "編輯變更基底" msgid "Edit Remotes" msgstr "編輯遠端版控庫" msgid "Edit Remotes..." msgstr "編輯遠端版控庫……" msgid "Edit remotes by selecting them from the list" msgstr "藉由從清單中選取它們來編輯遠端版控庫" msgid "Edit selected paths" msgstr "編輯選取的路徑" msgid "Edit..." msgstr "編輯……" msgid "Editor" msgstr "文字編輯器" msgid "Email Address" msgstr "電子郵件地址" msgid "Email contributor" msgstr "寄電子郵件給這位貢獻者" msgid "Enabled" msgstr "啟用" msgid "Enter New Branch Name" msgstr "輸入新的分支名稱" msgid "Enter a name for the new bare repo" msgstr "輸入新裸裝版本庫(bare repo)的名稱" msgid "Enter a name for the stash" msgstr "輸入珍藏項目的名稱" msgid "Error" msgstr "發生錯誤" msgid "Error Cloning" msgstr "克隆發生錯誤" msgid "Error Creating Branch" msgstr "建立新的分支時發生錯誤" msgid "Error Creating Repository" msgstr "無法建立新的版控庫" msgid "Error Deleting Remote Branch" msgstr "移除遠端分支失敗" msgid "Error Editing File" msgstr "編輯檔案發生錯誤" msgid "Error Launching Blame Viewer" msgstr "啟動指謫(Blame)檢視器時發生錯誤" msgid "Error Launching History Browser" msgstr "無法啟動變動紀錄瀏覽器" #, python-format msgid "Error creating remote \"%s\"" msgstr "建立「%s」遠端分支時發生錯誤" msgid "Error creating stash" msgstr "建立新的珍藏項目時發生錯誤" #, python-format msgid "Error deleting remote \"%s\"" msgstr "移除「%s」遠端分支時發生錯誤" #, python-format msgid "Error renaming \"%(name)s\" to \"%(new_name)s\"" msgstr "將「%(name)s」更名為「%(new_name)s」時發生錯誤" msgid "Error running prepare-commitmsg hook" msgstr "執行 prepare-commitmsg 掛勾程式時發生錯誤" #, fuzzy, python-format msgid "Error updating submodule %s" msgstr "建立「%s」遠端分支時發生錯誤" #, fuzzy msgid "Error updating submodules" msgstr "編輯檔案發生錯誤" msgid "Error: Cannot find commit template" msgstr "錯誤:無法找到修訂版提交範本" msgid "Error: Stash exists" msgstr "錯誤:珍藏項目已存在" msgid "Error: Unconfigured commit template" msgstr "錯誤:未被設定的修訂版提交範本" #, python-format msgid "Error: could not clone \"%s\"" msgstr "錯誤:無法克隆「%s」版控庫" #, python-format msgid "Error: could not create tag \"%s\"" msgstr "錯誤:無法建立標籤「%s」" #, python-format msgid "Executing action %s" msgstr "正在執行「%s」動作" msgid "Expand all" msgstr "全部展開" msgid "Export Patches" msgstr "匯出修正檔" msgid "Export Patches..." msgstr "匯出修正……" msgid "Expression..." msgstr "比較表達式之間的內容差異……" msgid "Extended Regexp" msgstr "延伸正規表達式" msgid "Extended description..." msgstr "延伸描述……" msgid "Fast Forward Only" msgstr "僅更新可進行快速前移式合併者" msgid "Fast-forward only" msgstr "只允許快速前移式合併" msgid "Favorite repositories" msgstr "喜愛的版控庫" msgid "Favorites" msgstr "喜愛的版控庫" msgid "Fetch" msgstr "自遠端版控庫撈取(fetch)" msgid "Fetch Tracking Branch" msgstr "撈取(fetch)追蹤分支" msgid "Fetch..." msgstr "自遠端版控庫撈取(fetch)……" msgid "File Browser..." msgstr "檔案瀏覽器……" msgid "File Differences" msgstr "檔案變化" msgid "File Saved" msgstr "檔案已保存" #, python-format msgid "File saved to \"%s\"" msgstr "檔案已保存至「%s」" msgid "File system change monitoring: disabled because \"cola.inotify\" is false.\n" msgstr "檔案系統變動監控:因為「cola.inotify」 Git 設定值被設定為 false 而被停用。\n" msgid "File system change monitoring: disabled because libc does not support the inotify system calls.\n" msgstr "檔案系統變動監控:因為 libc 程式庫不支援 inotify 系統呼叫而被停用。\n" msgid "File system change monitoring: disabled because pywin32 is not installed.\n" msgstr "檔案系統變動監控:因為 pywin32 沒有安裝而被停用。\n" msgid "" "File system change monitoring: disabled because the limit on the total number of inotify watches was reached. You may be able to increase the limit on the number of watches by running:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" msgstr "" "檔案系統變動監控:因為已經達到 inotify watch 的總數上限而被停用。您可以執行下列命令來增加 watch 的數量限制:\n" "\n" " echo fs.inotify.max_user_watches=100000 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p\n" msgid "File system change monitoring: enabled.\n" msgstr "檔案系統變動監控:已啟用。\n" msgid "Filename" msgstr "檔案名稱" msgid "Files" msgstr "檔案" msgid "Filter branches..." msgstr "過濾分支名稱……" msgid "Filter paths..." msgstr "過濾檔案路徑……" msgid "Find Files" msgstr "尋找檔案" msgid "Fixed String" msgstr "固定內容字串" msgid "Fixed-Width Font" msgstr "等寬字型" msgid "Fixup" msgstr "修理" msgid "Fixup Previous Commit" msgstr "修理先前的修訂版提交" msgid "Flat dark blue" msgstr "" msgid "Flat dark green" msgstr "" msgid "Flat dark grey" msgstr "" msgid "Flat dark red" msgstr "" msgid "Flat light blue" msgstr "" msgid "Flat light green" msgstr "" msgid "Flat light grey" msgstr "" msgid "Flat light red" msgstr "" msgid "Font Size" msgstr "字體大小" msgid "Force" msgstr "強制" msgid "Force Fetch" msgstr "強制撈取(fetch)" msgid "Force Fetch?" msgstr "要進行強制撈取(fetch)嗎?" msgid "Force Push" msgstr "強制推送" msgid "Force Push?" msgstr "要進行強制推送(push)嗎?" #, python-format msgid "Force fetching from %s?" msgstr "是否要強制自「%s」撈取(fetch)?" #, python-format msgid "Force push to %s?" msgstr "要強制推送至「%s」遠端版控庫嗎?" msgid "Format String" msgstr "格式字串" msgid "French translation" msgstr "法語翻譯" msgid "GPG-sign the merge commit" msgstr "用 GPG 簽署合併修訂版提交" msgid "GUI theme" msgstr "" #, python-format msgid "Gathering info for \"%s\"..." msgstr "正在蒐集「%s」遠端版控庫的資訊……" msgid "German translation" msgstr "德語翻譯" msgid "Get Commit Message Template" msgstr "取得修訂版提交訊息範本" msgid "Go Down" msgstr "往下移動" msgid "Go Up" msgstr "往上移動" msgid "Grab File..." msgstr "提取檔案……" msgid "Graph" msgstr "圖" msgid "Grep" msgstr "搜尋(grep)" msgid "Have you rebased/pulled lately?" msgstr "您最近有作變更基底或 pull 操作嗎?" msgid "Help" msgstr "尋求幫助" msgid "Help - Custom Copy Actions" msgstr "求助 - 自訂複製操作" msgid "Help - Find Files" msgstr "尋求幫助 - 尋找檔案" msgid "Help - git-xbase" msgstr "尋求幫助 - git-xbase" msgid "Hide Details.." msgstr "隱藏詳細資訊……" msgid "High DPI" msgstr "" msgid "History Browser" msgstr "變更紀錄瀏覽器" msgid "Hungarian translation" msgstr "匈牙利語翻譯" msgid "Icon theme" msgstr "" msgid "Ignore all whitespace" msgstr "忽略所有的空白" msgid "Ignore changes in amount of whitespace" msgstr "忽略空白數量的變更" msgid "Ignore changes in whitespace at EOL" msgstr "忽略行結尾處空白的變更" msgid "Ignore custom pattern" msgstr "忽略自訂式樣" msgid "Ignore exact filename" msgstr "忽略完全一致的檔名" msgid "Ignore filename or pattern" msgstr "忽略檔案名稱或是式樣" msgid "Include tags " msgstr "包含標籤 " msgid "Indent Status paths" msgstr "" msgid "Indonesian translation" msgstr "印度尼西亞語翻譯" msgid "Initialize Git Annex" msgstr "初始化 Git Annex" msgid "Initialize Git LFS" msgstr "初始化 Git LFS" msgid "Inititalize submodules" msgstr "初始化子模組" msgid "Insert spaces instead of tabs" msgstr "插入空白字元而非跨欄字元(tab)" msgid "Interactive Rebase" msgstr "互動式變更基底" msgid "Invalid Revision" msgstr "無效的修訂版" msgid "Keep *.orig Merge Backups" msgstr "保留 *.orig merge 備份檔" msgid "Keep Index" msgstr "保留 index" msgid "Keyboard Shortcuts" msgstr "鍵盤快捷鍵" msgid "Launch Diff Tool" msgstr "啟動差異檢視工具" msgid "Launch Directory Diff Tool" msgstr "啟動目錄差異檢視工具" msgid "Launch Editor" msgstr "啟動文字編輯器" msgid "Launch Terminal" msgstr "啟動終端機" msgid "" "Launch external diff tool\n" "Shortcut: Ctrl+D" msgstr "" "啟動外部內容差異檢視工具\n" "鍵盤快捷鍵:Ctrl+D" msgid "Launch git-cola" msgstr "啟動 git-cola" msgid "Launch git-difftool against previous versions" msgstr "對先前的版本啟動 git-difftool" msgid "Launch git-difftool on the current path" msgstr "在當前路徑中啟動 git-difftool" msgid "Light Theme" msgstr "" msgid "Load Commit Message" msgstr "自檔案載入修訂版提交訊息" msgid "Load Commit Message..." msgstr "自檔案載入修訂版提交訊息……" msgid "Load Previous Commit Message" msgstr "載入先前的修訂版提交的訊息" msgid "Loading..." msgstr "正在載入……" msgid "Local" msgstr "本地" msgid "Local Branch" msgstr "本地分支" msgid "Local branch" msgstr "本地分支" msgid "Lock Layout" msgstr "鎖住版面" msgid "Log" msgstr "紀錄" msgid "Maintainer (since 2007) and developer" msgstr "(自從 2007 年開始)維護者與開發者" msgid "Merge" msgstr "合併" #, python-format msgid "Merge \"%(revision)s\" into \"%(branch)s\"" msgstr "合併「%(revision)s」修訂版至「%(branch)s」分支中" msgid "Merge Tool" msgstr "合併(merge)工具" msgid "Merge Verbosity" msgstr "合併資訊詳細程度" msgid "Merge failed. Conflict resolution is required." msgstr "合併失敗. 需要解決衝突." #, python-format msgid "Merge into \"%s\"" msgstr "合併到「%s」分支" msgid "Merge into current branch" msgstr "合併進當前分支" msgid "Merge..." msgstr "分支合併(merge)……" msgid "Merging" msgstr "正在進行分支合併" msgid "Message" msgstr "訊息" msgid "Missing Commit Message" msgstr "缺少修訂版提交訊息" msgid "Missing Data" msgstr "缺少資料" msgid "Missing Name" msgstr "缺少標籤名稱" msgid "Missing Revision" msgstr "缺少的修訂版" msgid "Missing Tag Message" msgstr "缺少標籤訊息" msgid "Modified" msgstr "已被修改" msgid "More..." msgstr "更多……" msgid "Move Down" msgstr "往下移動" msgid "Move Up" msgstr "往上移動" msgid "Move files to trash" msgstr "將檔案移動到資源回收筒" msgid "Name" msgstr "名稱" msgid "Name for the new remote" msgstr "新遠端版控庫的名稱" msgid "New Bare Repository..." msgstr "新的裸裝版控庫(bare repository)……" msgid "New Repository..." msgstr "新版控庫……" msgid "New..." msgstr "新建……" msgid "Next File" msgstr "下個檔案" msgid "No" msgstr "不更新" msgid "No Revision Specified" msgstr "沒有選取修訂版" msgid "" "No changes to commit.\n" "\n" "You must stage at least 1 file before you can commit." msgstr "" "沒有可以提交的內容變動。\n" "\n" "提交前你必須至少將至少一個檔案移入新修訂版準備區域。" msgid "No commits exist in this branch." msgstr "此分支中無任何修訂版提交。" msgid "No fast forward" msgstr "不進行快速前移式合併" msgid "No fast-forward" msgstr "不進行快速前移式合併" msgid "No repository selected." msgstr "沒有選擇版控庫。" msgid "Non-fast-forward fetch overwrites local history!" msgstr "非快速前移式的撈取(fetch)將會覆寫本地版控庫的變更紀錄!" msgid "" "Non-fast-forward push overwrites published history!\n" "(Did you pull first?)" msgstr "" "非快速前移式的推送(push)將會覆寫遠端版控庫的變更紀錄!\n" "(您有先 Pull 過了嗎?)" msgid "Nothing to commit" msgstr "沒有東西可以提交" msgid "Nothing to do" msgstr "沒有事情可做" msgid "Number of Diff Context Lines" msgstr "內容差異上下文行數" msgid "Open" msgstr "開啟" msgid "Open Git Repository..." msgstr "開啟一個 Git 版控庫……" #, fuzzy msgid "Open Parent" msgstr "打開最近使用的版控庫" msgid "Open Parent Directory" msgstr "開啟上一層目錄" msgid "Open Recent" msgstr "打開最近使用的版控庫" msgid "Open Using Default Application" msgstr "以系統預設的軟體開啟" msgid "Open in New Window" msgstr "於新 git-cola 視窗中開啟" msgid "Open in New Window..." msgstr "於新 git-cola 視窗中開啟版控庫……" msgid "Open..." msgstr "打開版控庫……" msgid "Other branches" msgstr "其他分支" msgid "Overwrite" msgstr "覆寫" #, python-format msgid "Overwrite \"%s\"?" msgstr "要覆寫「%s」嗎?" msgid "Overwrite File?" msgstr "要覆寫檔案嗎?" msgid "" "Parse arguments using a shell.\n" "Queries with spaces will require \"double quotes\"." msgstr "" "使用殼程式(shell)來解析參數。\n" "內含空白字元的查詢需使用 \"雙引號\" 括住。" msgid "Partially Staged" msgstr "部份內容變更被移入新修訂版準備區域" msgid "Paste" msgstr "粘貼" msgid "Patch(es) Applied" msgstr "已套用所有修正" msgid "Path" msgstr "所在路徑" msgid "Path or URL to clone (Env. $VARS okay)" msgstr "要克隆的路徑或 URL(可使用環境 $變數 )" msgid "Pick" msgstr "" msgid "Pixel XOR" msgstr "像素互斥或(XOR)" msgid "Please provide both a branch name and revision expression." msgstr "請填寫分支名稱與修訂版表達式。" msgid "Please select a file" msgstr "請選擇一個檔案" msgid "Please specify a name for the new tag." msgstr "請指定新標籤的名稱。" msgid "Please specify a revision to tag." msgstr "請指定一個修訂版來套用標籤。" msgid "" "Please supply a commit message.\n" "\n" "A good commit message has the following format:\n" "\n" "- First line: Describe in one sentence what you did.\n" "- Second line: Blank\n" "- Remaining lines: Describe why this change is good.\n" msgstr "" "請提供一條修訂版提交訊息。\n" "\n" "一條好的修訂版提交有下列格式:\n" "\n" "- 第一行: 一句話概括您所做的變更。\n" "- 第二行: 空行\n" "- 剩餘行: 描述為什麼您所做的變更是好的。\n" msgid "Point the current branch head to a new commit?" msgstr "將當前分支的 head 指向一個新的修訂版提交?" msgid "Polish translation" msgstr "波蘭語翻譯" msgid "Pop" msgstr "POP" msgid "Preferences" msgstr "偏好設定" msgid "Prefix" msgstr "前綴路徑" msgid "Prepare Commit Message" msgstr "準備修訂版提交訊息" msgid "Prevent \"Stage\" from staging all files when nothing is selected" msgstr "避免 Stage 快捷鍵在沒有選取任何項目時將所有檔案移至修訂版提交準備區域" msgid "Previous File" msgstr "上個檔案" msgid "Prompt on creation" msgstr "建新分支時提示" msgid "Prompt when pushing creates new remote branches" msgstr "在建立新的遠端分支時提示使用者" msgid "Prune " msgstr "清除(prune) " msgid "Pull" msgstr "自遠端分支撈取並合併(pull)" msgid "Pull..." msgstr "自遠端分支撈取並合併(pull)……" msgid "Push" msgstr "推送至遠端版控庫" msgid "Push..." msgstr "推送至遠端版控庫(push)……" msgid "Quit" msgstr "結束" msgid "Rebase" msgstr "變更基底" #, python-format msgid "Rebase onto %s" msgstr "變更基底至 %s" msgid "Rebase stopped" msgstr "變更基底已停止" msgid "Rebase the current branch instead of merging" msgstr "不合併分支,而是將遠端分支變更基底到當前分支" msgid "Rebasing" msgstr "正在進行變更基底程序" msgid "Recent" msgstr "最近使用的版控庫" msgid "Recent repositories" msgstr "最近使用的版控庫" msgid "Recent repository count" msgstr "最近使用的版控庫數量" msgid "Recently Modified Files" msgstr "最近修改過的檔案" msgid "Recently Modified Files..." msgstr "最近修改過的檔案……" msgid "Recovering a dropped stash is not possible." msgstr "要救回一個丟棄的珍藏項目是不可能的。" msgid "Recovering lost commits may not be easy." msgstr "恢復丟失的提交是比較困難的." msgid "Redo" msgstr "重做" msgid "Reduce commit history to minimum" msgstr "將版本提交歷史量降到最低" msgid "Refresh" msgstr "重新整理" msgid "Refuse to merge unless the current HEAD is already up-to-date or the merge can be resolved as a fast-forward" msgstr "除非當前 HEAD 指標早就是最新版本或是分支合併能以快速前移式處理否則拒絕合併分支" msgid "Remote" msgstr "遠端" msgid "Remote Branch" msgstr "遠端分支名" msgid "Remote Branch Deleted" msgstr "已移除遠端分支" msgid "Remote git repositories - double-click to rename" msgstr "遠端 Git 版控庫 - 連續點兩下以重新命名" msgid "Remove" msgstr "移除" #, python-format msgid "Remove %s from the recent list?" msgstr "要將「%s」版控庫從最近使用的版控庫清單中移除嗎?" msgid "Remove Element" msgstr "移除元素" msgid "Remove remote-tracking branches that no longer exist on the remote" msgstr "移除不再存在於遠端板控庫上的遠端追蹤分支" msgid "Remove selected (Delete)" msgstr "移除被選取的項目(刪除)" msgid "Rename" msgstr "重新命名" #, python-format msgid "Rename \"%s\"" msgstr "重新命名「%s」" msgid "Rename Branch" msgstr "重新命名分支" msgid "Rename Branch..." msgstr "重新命名分支……" msgid "Rename Existing Branch" msgstr "重新命名已存在的分支" msgid "Rename Remote" msgstr "重新命名遠端版控庫" msgid "Rename Repository" msgstr "更名版控庫" msgid "Rename branch" msgstr "重新命名分支" #, python-format msgid "Rename remote \"%(current)s\" to \"%(new)s\"?" msgstr "要將「%(current)s」遠端版控庫改名為「%(new)s」嗎?" msgid "Rename selected paths" msgstr "重新命名選取的路徑" #, python-format msgid "Repository: %s" msgstr "版控庫:%s" msgid "Reset" msgstr "重設" #, python-format msgid "Reset \"%(branch)s\" to \"%(revision)s\"?" msgstr "要重設「%(branch)s」分支到 「%(revision)s」修訂版嗎?" msgid "Reset Branch" msgstr "重設分支" msgid "Reset Branch Head" msgstr "重設分支 Head" msgid "Reset Branch?" msgstr "要重設分支嗎?" msgid "Reset Hard" msgstr "硬式重設" msgid "Reset Merge" msgstr "合併式重設" msgid "Reset Soft" msgstr "軟式重設" msgid "Reset Worktree" msgstr "重設工作目錄樹" msgid "Reset hard?" msgstr "要進行硬式重設嗎?" msgid "Reset merge?" msgstr "要進行合併式重設嗎?" msgid "Reset soft?" msgstr "要進行軟式重設嗎?" msgid "Reset worktree?" msgstr "要重設工作目錄樹嗎?" #, python-format msgid "Resetting \"%(branch)s\" to \"%(revision)s\" will lose commits." msgstr "重置「%(branch)s」分支到「%(revision)s」修訂版將導致修訂版提交的丟失。" msgid "Restart the application after changing appearance settings." msgstr "" msgid "Revert" msgstr "撤銷修訂版提交" msgid "Revert Diff Hunk" msgstr "撤銷選取內容差異區塊的內容變更" msgid "Revert Diff Hunk..." msgstr "撤銷此內容差異區塊的內容變更……" msgid "Revert Diff Hunk?" msgstr "要撤銷選取內容差異區塊的內容變更嗎?" msgid "Revert Selected Lines" msgstr "撤銷選取行的內容變更" msgid "Revert Selected Lines..." msgstr "撤銷選取行的內容變更……" msgid "Revert Selected Lines?" msgstr "要撤銷選取行的內容變更嗎?" msgid "Revert Uncommitted Changes" msgstr "撤銷尚未提交至版控庫的內容變更" msgid "Revert Uncommitted Changes?" msgstr "要撤銷尚未提交至版控庫的內容變更嗎?" msgid "Revert Uncommitted Edits..." msgstr "撤銷尚未提交到版控庫的內容變更……" msgid "Revert Unstaged Changes" msgstr "撤銷尚未移入新修訂版準備區域的內容變動" msgid "Revert Unstaged Changes?" msgstr "要撤銷尚未移入新修訂版準備區域的內容變動嗎?" msgid "Revert Unstaged Edits..." msgstr "撤銷尚未移入新修訂版準備區域的內容修改……" msgid "Revert the uncommitted changes?" msgstr "要撤銷尚未提交至版控庫的內容變更嗎?" msgid "Revert the unstaged changes?" msgstr "要撤銷尚未移入新修訂版準備區域的內容變動嗎?" msgid "Revert uncommitted changes to selected paths" msgstr "在被選取的路徑中撤銷尚未提交進版控的內容變更" msgid "Revert unstaged changes to selected paths" msgstr "在被選取的路徑中撤銷尚未移入新修訂版準備區域的內容變更" msgid "Review" msgstr "審視(review)" msgid "Review..." msgstr "審視(review)……" msgid "Revision" msgstr "修訂版" msgid "Revision Expression:" msgstr "修訂版表達式:" msgid "Revision to Merge" msgstr "要合併的修訂版" msgid "Reword" msgstr "重新敘述" msgid "Rewrite Published Commit?" msgstr "要重寫已推送出去的修訂版提交嗎?" msgid "Run" msgstr "執行" #, python-format msgid "Run \"%s\"?" msgstr "要執行「%s」操作嗎?" #, python-format msgid "Run %s?" msgstr "執行 %s?" #, python-format msgid "Run the \"%s\" command?" msgstr "要執行「%s」命令嗎?" #, python-format msgid "Running command: %s" msgstr "執行命令:%s" msgid "Russian translation" msgstr "俄羅斯語翻譯" msgid "SHA-1" msgstr "SHA-1 雜湊" msgid "Safe Mode" msgstr "安全模式" msgid "Save" msgstr "保存" msgid "Save Archive" msgstr "保存封存檔" msgid "Save As Tarball/Zip..." msgstr "保存為 Tarball/Zip 封存檔…" msgid "Save GUI Settings" msgstr "保存圖形介面設定" msgid "Save Stash" msgstr "保存珍藏項目" msgid "Save modified state to new stash" msgstr "將被修改的狀態保存為一個新的珍藏項目" #, python-format msgid "Saved \"%(filename)s\" from \"%(ref)s\" to \"%(destination)s\"" msgstr "已將「%(filename)s」檔案自「%(ref)s」修訂版保存至「%(destination)s」目錄" msgid "Search" msgstr "搜尋" msgid "Search Authors" msgstr "搜尋作者名" msgid "Search Commit Messages" msgstr "搜尋修訂版提交訊息" msgid "Search Committers" msgstr "搜尋提交者名" msgid "Search Date Range" msgstr "搜尋日期範圍" msgid "Search Diffs" msgstr "搜尋內容變更" msgid "Search by Expression" msgstr "以表達式搜尋" msgid "Search by Path" msgstr "以路徑搜尋" msgid "Search for a fixed string" msgstr "搜尋一個固定內容字串" msgid "Search using a POSIX basic regular expression" msgstr "使用 POSIX 基本正規表達式來搜尋" msgid "Search using a POSIX extended regular expression" msgstr "使用 POSIX 延伸正規表達式來搜尋" msgid "Search..." msgstr "尋找……" msgid "Select" msgstr "選擇" msgid "Select All" msgstr "全選" msgid "Select Branch to Review" msgstr "選擇要審視(review)的分支" msgid "Select Child" msgstr "選擇子節點" msgid "Select Commit" msgstr "選取修訂版提交" msgid "Select Directory..." msgstr "選擇目錄……" msgid "Select New Upstream" msgstr "選擇新的上游版本" msgid "Select Newest Child" msgstr "選取最新的子節點" msgid "Select Oldest Parent" msgstr "選取最舊的母節點" msgid "Select Parent" msgstr "選取" msgid "Select Previous Version" msgstr "選擇先前版本" msgid "Select Repository..." msgstr "選擇版控庫……" msgid "Select a parent directory for the new clone" msgstr "選取新克隆的 Git 版控庫要放置的目錄" msgid "Select manually..." msgstr "手動選取……" msgid "Select output dir" msgstr "選取輸出目錄" msgid "Select output directory" msgstr "選擇要輸出的目錄" msgid "Select patch file(s)..." msgstr "選擇修正檔……" msgid "Select repository" msgstr "選擇版控庫" msgid "Set Default Repository" msgstr "設定預設版控庫" msgid "Set Upstream Branch" msgstr "設為上游追蹤分支" msgid "" "Set the sort order for branches and tags.\n" "Toggle between date-based and version-name-based sorting." msgstr "" msgid "Set upstream" msgstr "設為上游追蹤分支" msgid "Settings" msgstr "設定值" msgid "Shell arguments" msgstr "殼程式參數" msgid "Shift Down" msgstr "往下平移" msgid "Shift Up" msgstr "往上平移" msgid "Shortcuts" msgstr "鍵盤快捷鍵" msgid "Show Details..." msgstr "顯示詳細資訊……" msgid "Show Diffstat After Merge" msgstr "在合併後顯示內容差異" msgid "Show Full Paths in the Window Title" msgstr "在視窗標題列中顯示版控庫的完整路徑" msgid "Show Help" msgstr "顯示幫助訊息" msgid "Show History" msgstr "檢視變更紀錄" msgid "Show file counts in Status titles" msgstr "" msgid "" "Show help\n" "Shortcut: ?" msgstr "" "顯示幫助訊息\n" "鍵盤快捷鍵:?" msgid "Show icon? (if available)" msgstr "要顯示圖示嗎(如果有)?" msgid "Show line numbers" msgstr "顯示行號" msgid "Show whole surrounding functions of changes" msgstr "秀出整個包含變更的函式內容" msgid "Showing changes since" msgstr "顯示變更自前" msgid "Side by side" msgstr "並列檢視" msgid "Sign Off" msgstr "署名(Sign Off)" msgid "Sign Tag" msgstr "為標籤簽名" msgid "Sign off on this commit" msgstr "於此修訂版提交上簽名" msgid "Simplified Chinese translation" msgstr "簡體中文翻譯" msgid "Skip" msgstr "跳過" msgid "Skip Current Patch" msgstr "跳過目前的修正" msgid "Sort bookmarks alphabetically" msgstr "以字母順序排序書籤" msgid "Spanish translation" msgstr "西班牙語翻譯" msgid "Specifies the SHA-1 to tag" msgstr "指定 SHA-1 雜湊給標籤" msgid "Specifies the tag message" msgstr "指定標籤訊息" msgid "Specifies the tag name" msgstr "指定標籤的名稱" msgid "Spelling Suggestions" msgstr "拼字建議" msgid "Squash" msgstr "壓為單一修訂版提交" msgid "Squash the merged commits into a single commit" msgstr "將合併之修訂版提交(們)壓為單一修訂版提交" msgid "Stage" msgstr "移動到新修訂版準備區域" msgid "Stage / Unstage" msgstr "移入/移出新修訂版準備區域" msgid "Stage All Untracked" msgstr "將所有尚未追蹤其版本的項目移動到新修訂版準備區域" msgid "Stage Changed Files To Commit" msgstr "將所有被修改的檔案移入新修訂版準備區域" msgid "Stage Diff Hunk" msgstr "將此內容差異區塊移入新修訂版準備區域" msgid "Stage Modified" msgstr "將已變更的項目移入新修訂版準備區域" msgid "Stage Selected" msgstr "將被選取的項目移入新修訂版準備區域" msgid "Stage Selected Lines" msgstr "將選取的行移入新修訂版準備區域(&S)" msgid "Stage Unmerged" msgstr "將尚未合併的檔案移動到新修訂版準備區域" msgid "Stage Untracked" msgstr "將尚未追蹤其版本的項目移動到新修訂版準備區域" msgid "Stage and Commit" msgstr "移入新修訂版準備區域並提交出去" msgid "Stage and commit?" msgstr "要移入新修訂版準備區域並提交出去嗎?" msgid "Stage conflicts" msgstr "將合併衝突移入新修訂版準備區域" msgid "Stage conflicts?" msgstr "要將合併衝突移入新修訂版準備區域嗎?" msgid "Stage/unstage selected paths for commit" msgstr "將被選取的路徑移進/移出新修訂版準備區域" msgid "Staged" msgstr "已被移入新修訂版準備區域" #, python-format msgid "Staging: %s" msgstr "正在移動到新修訂版準備區域:%s" msgid "Start Interactive Rebase..." msgstr "開始互動式變更基底……" msgid "Starting Revision" msgstr "起始修訂版" msgid "Stash" msgstr "珍藏項目" msgid "Stash Index" msgstr "將修訂版提交準備區域中的變更存為珍藏項目" msgid "Stash staged changes only" msgstr "只將移入新修訂版提交準備區域中的變更存為珍藏項目" msgid "Stash unstaged changes only, keeping staged changes" msgstr "只將尚未移入新修訂版提交準備區域的變更存入珍藏項目,保留移入新修訂版提交準備區域的變更" msgid "Stash..." msgstr "珍藏項目(STASH)..." msgid "Status" msgstr "狀態" msgid "Stop tracking paths" msgstr "停止追蹤路徑" msgid "Submodules" msgstr "" msgid "Summarize Merge Commits" msgstr "概述合併進來的內容提交(commit)" msgid "Summary" msgstr "總結" msgid "Tab Width" msgstr "Tab 字元的顯示寬度" msgid "Tag" msgstr "標籤" msgid "Tag Created" msgstr "標籤已建立" msgid "Tag message..." msgstr "標籤訊息……" msgid "Tag-signing was requested but the tag message is empty." msgstr "被要求要有標籤簽名但是標籤訊息是空的。" msgid "Tags" msgstr "標籤" msgid "Text Width" msgstr "單行文字寬度限制" msgid "The branch will be no longer available." msgstr "此分支將不再存在。" #, python-format msgid "The branch will be reset using \"git reset --hard %s\"" msgstr "這個分支將會被用「git reset --hard %s」命令重設" #, python-format msgid "The branch will be reset using \"git reset --merge %s\"" msgstr "這個分支將會被用「git reset --merge %s」命令重設" #, python-format msgid "The branch will be reset using \"git reset --mixed %s\"" msgstr "這個分支將會被用「git reset --mixed %s」命令重設" #, python-format msgid "The branch will be reset using \"git reset --soft %s\"" msgstr "這個分支將會被用「git reset --soft %s」命令重設" msgid "The commit message will be cleared." msgstr "修訂版提交訊息將會被移除。" #, python-format msgid "The file \"%s\" exists and will be overwritten." msgstr "檔案「%s」已存在且將會被覆寫。" msgid "The following files will be deleted:" msgstr "下列檔案將會被移除:" msgid "The revision expression cannot be empty." msgstr "修訂版表達式不可以是空的。" #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be reset using \"git reset --keep %s\"" msgstr "工作目錄樹將被用「git reset --keep %s」命令重設" msgid "This cannot be undone. Clear commit message?" msgstr "此操作將無法復原。要清除提交訊息嗎?" msgid "" "This commit has already been published.\n" "This operation will rewrite published history.\n" "You probably don't want to do this." msgstr "" "此修訂版提交已經被推送到遠端版控庫。\n" "此操作將會重寫已推送出去的變更紀錄。\n" "您可能不想要做此操作。" msgid "" "This operation drops uncommitted changes.\n" "These changes cannot be recovered." msgstr "" "此操作將會丟棄尚未提交進版控庫的內容變更。\n" "這些內容變更將無法被救回。" msgid "" "This operation removes uncommitted edits from selected files.\n" "These changes cannot be recovered." msgstr "" "此操作將會丟棄尚未提交至版控庫的內容變更。\n" "這些內容變更將無法被救回。" msgid "" "This operation removes unstaged edits from selected files.\n" "These changes cannot be recovered." msgstr "" "此操作將丟棄尚未移入新修訂版準備區域的內容變動。\n" "這些內容變動將無法被還原。" msgid "" "This repository is currently being rebased.\n" "Resolve conflicts, commit changes, and run:\n" " Rebase > Continue" msgstr "" "這個版控庫正在進行變更基底程序。\n" "解決所有的變更基底衝突,提交變更,然後執行:\n" " 變更基底 > 繼續" msgid "" "This repository is in the middle of a merge.\n" "Resolve conflicts and commit changes." msgstr "" "本版控庫正在進行分支合併程序。\n" "將所有的合併衝突解決並提交內容變更。" msgid "Toggle Enabled" msgstr "切換為啟用" msgid "Toggle the branches filter" msgstr "切換分支過濾器開關" msgid "Toggle the paths filter" msgstr "切換路徑過濾器開關" msgid "Tracking Branch" msgstr "跟蹤分支" msgid "Tracking branch" msgstr "追蹤分支" msgid "Traditional Chinese (Taiwan) translation" msgstr "傳統中文(台灣)翻譯" msgid "Translators" msgstr "翻譯者群" msgid "Turkish translation" msgstr "土耳其語翻譯" msgid "URL" msgstr "URL" #, python-format msgid "URL: %s" msgstr "URL: %s" msgid "Ukranian translation" msgstr "烏克蘭語翻譯" msgid "Unable to rebase" msgstr "無法變更基底" #, python-format msgid "Unable to set URL for \"%(name)s\" to \"%(url)s\"" msgstr "無法將「%(name)s」的 URL 設定為 %(url)s" msgid "Undo" msgstr "撤銷" msgid "Unmerged" msgstr "尚未合併" msgid "Unstage" msgstr "移出新修訂版準備區域" msgid "Unstage All" msgstr "將所有項目移出新修訂版準備區域" msgid "Unstage Diff Hunk" msgstr "將此內容差異區塊移出新修訂版準備區域" msgid "Unstage From Commit" msgstr "移出新修訂版準備區域" msgid "Unstage Selected" msgstr "將被選取的項目移出新修訂版準備區域" msgid "Unstage Selected Lines" msgstr "將被選取的行移出新修訂版準備區域" #, python-format msgid "Unstaging: %s" msgstr "正在將「%s」移出新修訂版準備區域" msgid "Untrack Selected" msgstr "將被選取的項目移出新修訂版準備區域" msgid "Untracked" msgstr "未納入版本追蹤" #, python-format msgid "Untracking: %s" msgstr "正在將「%s」移出新修訂版準備區域" msgid "Update All Submodules..." msgstr "" msgid "Update Existing Branch:" msgstr "是否更新既有分支:" #, fuzzy msgid "Update Submodule" msgstr "已更新" msgid "Update Submodule..." msgstr "" #, fuzzy msgid "Update Submodules" msgstr "初始化子模組" #, fuzzy msgid "Update all submodules?" msgstr "初始化子模組" #, fuzzy msgid "Update submodules..." msgstr "初始化子模組" #, fuzzy msgid "Update this submodule" msgstr "初始化子模組" msgid "Update this submodule?" msgstr "" msgid "Updating" msgstr "正在更新" msgid "User Name" msgstr "使用者名稱" msgid "Version" msgstr "版本" msgid "View" msgstr "檢視" msgid "View History..." msgstr "檢視變更紀錄……" msgid "View history for selected paths" msgstr "檢視被選取的路徑(們)的變更紀錄" msgid "Visualize" msgstr "視覺化顯示" msgid "Visualize All Branches..." msgstr "視覺化顯示所有分支……" msgid "Visualize Current Branch..." msgstr "視覺化顯示當前分支……" msgid "Whether to sign the tag (git tag -s)" msgstr "是否簽名此標籤 (git tag -s)" msgid "Would you like to stage and commit all modified files?" msgstr "您要將所有被修改的檔案移入新修訂版準備區域並提交出去嗎?" msgid "XOR" msgstr "互斥或(XOR)" msgid "Yes" msgstr "是" msgid "" "You are in the middle of a merge.\n" "Cannot amend while merging." msgstr "" "您現在正在進行分支合併。\n" "您不能在進行分支合併時修正前一次的修訂版提交。" msgid "You cannot rebase with uncommitted changes." msgstr "您不能在還有尚未提交至版控庫的內容變更的時候進行變更基底。" msgid "You must specify a revision to merge." msgstr "您必須要選擇一個修訂版來合併。" msgid "You must specify a revision to view." msgstr "您必須要選擇一個修訂版來檢視。" msgid "Zoom In" msgstr "放大" msgid "Zoom Out" msgstr "縮小" msgid "Zoom to Fit" msgstr "縮放以符合視窗大小" msgid "command-line arguments" msgstr "命令列參數" msgid "error: unable to execute git" msgstr "錯誤:無法執行 git" #, python-format msgid "exit code %s" msgstr "程式以 %s 狀態碼結束" #, python-format msgid "fatal: \"%s\" is not a directory. Please specify a correct --repo ." msgstr "致命錯誤:「%s」並不是個目錄。請指定一個正確的 --repo 〈路徑〉。" #, python-format msgid "git cola version %s" msgstr "git cola 第 %s 版" msgid "git-cola" msgstr "git-cola" msgid "git-cola diff" msgstr "git-cola diff" msgid "grep result..." msgstr "搜尋結果……" msgid "hotkeys.html" msgstr "hotkeys_zh_TW.html" msgid "unknown" msgstr "未知使用者" msgid "vX.Y.Z" msgstr "X.Y.Z版本" msgid "x 1" msgstr "" msgid "x 1.5" msgstr "" msgid "x 2" msgstr "" msgid "yyyy-MM-dd" msgstr "yyyy-MM-dd" #~ msgid "" #~ "\n" #~ "\n" #~ "A good replacement for %s\n" #~ "is placing values for the user.name and\n" #~ "user.email settings into your personal\n" #~ "~/.gitconfig file.\n" #~ msgstr "" #~ "\n" #~ "\n" #~ "%s 的一個很好的替代方案是將 user.name 以及\n" #~ "user.email 設置放在你的個人 ~/.gitconfig 文件中.\n" #~ msgid "" #~ "\n" #~ "This is due to a known issue with the\n" #~ "Tcl binary distributed by Cygwin." #~ msgstr "" #~ "\n" #~ "這是由 Cygwin 發佈的 Tcl 代碼中一個\n" #~ "已知問題所引起." #~ msgid "\"%s\" returned exit status %d" #~ msgstr "「%s」命令傳回了 %d 結束狀態碼" #~ msgid "\"git commit\" returned exit code %s" #~ msgstr "「git commit」命令傳回 %s 結束狀態碼" #~ msgid "%s ... %*i of %*i %s (%3i%%)" #~ msgstr "%s ... %*i of %*i %s (%3i%%)" #~ msgid "%s Repository" #~ msgstr "%s 版本庫" #~ msgid "'%s' is not an acceptable branch name." #~ msgstr "'%s'不是一個可接受的分支名." #~ msgid "* Binary file (not showing content)." #~ msgstr "* 二進制文件 (不顯示內容)." #~ msgid "A branch is required for 'Merged Into'." #~ msgstr "'合併到' 需要指定某個分支" #~ msgid "Abort completed. Ready." #~ msgstr "中止完成. 就緒." #~ msgid "Abort failed." #~ msgstr "中止失敗" #~ msgid "Aborted checkout of '%s' (file level merging is required)." #~ msgstr "中止 '%s' 的 checkout 操作 (需要做文件級合併)." #~ msgid "Already up-to-date." #~ msgstr "早就已經是最新版本。" #~ msgid "Always (Do not perform merge checks)" #~ msgstr "總是合併 (不作合併檢查)" #~ msgid "Always (Do not perform merge test.)" #~ msgstr "總是合併 (不作合併測試.)" #~ msgid "Amended Commit Message:" #~ msgstr "修正的提交描述:" #~ msgid "Amended Initial Commit Message:" #~ msgstr "修正的初始提交描述:" #~ msgid "Amended Merge Commit Message:" #~ msgstr "修正的合併提交描述:" #~ msgid "Annotation complete." #~ msgstr "標註完成." #~ msgid "Any unstaged changes will be permanently lost by the revert." #~ msgstr "任何未緩存的改動將在這次撤銷中永久丟失." #~ msgid "Apply Diff Selection to Work Tree" #~ msgstr "套用選取的內容差異至當前工作目錄樹" #~ msgid "Apply/Reverse Hunk" #~ msgstr "應用/撤消此修改塊" #~ msgid "Arbitrary URL:" #~ msgstr "任意 URL:" #~ msgid "Bookmarks" #~ msgstr "書籤" #~ msgid "Bookmarks..." #~ msgstr "書籤……" #~ msgid "" #~ "Branch '%s' already exists.\n" #~ "\n" #~ "It cannot fast-forward to %s.\n" #~ "A merge is required." #~ msgstr "" #~ "分支 '%s' 已經存在.\n" #~ "\n" #~ "無法快速合併到 %s.\n" #~ "需要普通合併." #~ msgid "Branch '%s' does not exist." #~ msgstr "分支 '%s' 並不存在." #~ msgid "Branch created" #~ msgstr "分支已建立" #~ msgid "Browse %s's Files" #~ msgstr "瀏覽 %s 上的文件" #~ msgid "Browse Branch Files" #~ msgstr "瀏覽分支文件" #, fuzzy #~ msgid "Browse Revision..." #~ msgstr "版本" #~ msgid "" #~ "Cannot abort while amending.\n" #~ "\n" #~ "You must finish amending this commit.\n" #~ msgstr "" #~ "修正操作中無法中止.\n" #~ "\n" #~ "你必須先完成本次修正操作.\n" #~ msgid "" #~ "Cannot amend while merging.\n" #~ "\n" #~ "You are currently in the middle of a merge that has not been fully completed. You cannot amend the prior commit unless you first abort the current merge activity.\n" #~ msgstr "" #~ "在合併時無法修正.\n" #~ "\n" #~ "你當前正在一次尚未完成的合併操作過程中. 除非中止當前合併活動,\n" #~ "否則無法修正之前的提交.\n" #~ msgid "Cannot determine HEAD. See console output for details." #~ msgstr "無法確定 HEAD. 請查看控制終端的輸出." #~ msgid "Cannot fetch branches and objects. See console output for details." #~ msgstr "無法獲取分支和對象. 請查看控制終端的輸出." #~ msgid "Cannot fetch tags. See console output for details." #~ msgstr "無法獲取標籤. 請查看控制終端的輸出." #~ msgid "Cannot find git in PATH." #~ msgstr "PATH 中沒有找到 git" #~ msgid "" #~ "Cannot merge while amending.\n" #~ "\n" #~ "You must finish amending this commit before starting any type of merge.\n" #~ msgstr "" #~ "修正時無法做合併.\n" #~ "\n" #~ "你必須完成對該提交的修正才能繼續任何類型的合併操作.\n" #~ msgid "Cannot move to top of working directory:" #~ msgstr "無法移動到工作根目錄:" #~ msgid "Cannot parse Git version string:" #~ msgstr "無法解析 Git 的版本信息:" #~ msgid "Cannot resolve %s as a commit." #~ msgstr "無法解析 %s 為提交." #~ msgid "Cannot use funny .git directory:" #~ msgstr "無法使用 .git 目錄:" #~ msgid "Cannot write shortcut:" #~ msgstr "無法修改快捷方式:" #~ msgid "Change Font" #~ msgstr "更改字體" #~ msgid "Checked out '%s'." #~ msgstr "'%s' 已被 checkout" #~ msgid "Clone Type:" #~ msgstr "克隆類型:" #~ msgid "Clone failed." #~ msgstr "克隆失敗." #~ msgid "Cloning from %s" #~ msgstr "從 %s 克隆" #~ msgid "Commit %s appears to be corrupt" #~ msgstr "提交 %s 似乎已損壞" #~ msgid "Commit failed: %s" #~ msgstr "提交失敗:%s" #~ msgid "Commit@@noun" #~ msgstr "提交(commit)" #~ msgid "Compress Database" #~ msgstr "壓縮數據庫" #~ msgid "Compressing the object database" #~ msgstr "壓縮對象數據庫" #~ msgid "Copied Or Moved Here By:" #~ msgstr "由複製或移動至此:" #~ msgid "Copying objects" #~ msgstr "複製 objects" #~ msgid "Counting objects" #~ msgstr "清點對象" #~ msgid "Create Desktop Icon" #~ msgstr "創建桌面圖標" #~ msgid "Created commit: %s" #~ msgstr "建立了一個新的修訂版提交:%s" #~ msgid "Creating working directory" #~ msgstr "創建工作目錄" #~ msgid "Current Branch:" #~ msgstr "當前分支:" #~ msgid "Database Statistics" #~ msgstr "數據庫統計信息" #~ msgid "Decrease Font Size" #~ msgstr "縮小字體" #~ msgid "Delete Local Branch" #~ msgstr "刪除本地分支" #~ msgid "Delete Only If" #~ msgstr "刪除僅當" #~ msgid "Delete Only If Merged Into" #~ msgstr "僅在合併後刪除" #~ msgid "Destination Repository" #~ msgstr "目標版本庫" #~ msgid "Detach From Local Branch" #~ msgstr "從本地分支脫離" #~ msgid "Diff/Console Font" #~ msgstr "Diff/控制終端字體" #~ msgid "Directory %s already exists." #~ msgstr "目錄 %s 已經存在." #~ msgid "Disk space used by loose objects" #~ msgstr "鬆散對象所使用的磁盤空間" #~ msgid "Disk space used by packed objects" #~ msgstr "壓縮對象所使用的磁盤空間" #~ msgid "Do Nothing" #~ msgstr "不做操作" #~ msgid "Enter Git Repository" #~ msgstr "請輸入 Git 版本倉庫的路徑" #, fuzzy #~ msgid "Error %s" #~ msgstr "錯誤:%s" #~ msgid "Error loading commit data for amend:" #~ msgstr "為修正裝載提交數據出錯:" #~ msgid "Error: Command Failed" #~ msgstr "錯誤: 命令失敗" #~ msgid "Errors: %s" #~ msgstr "錯誤:%s" #~ msgid "Exit code: %s" #~ msgstr "結束狀態碼:%s" #~ msgid "Failed to completely save options:" #~ msgstr "無法完全保存選項:" #~ msgid "Failed to configure origin" #~ msgstr "無法配置 origin" #~ msgid "Failed to create repository %s:" #~ msgstr "無法創建版本庫 %s:" #~ msgid "" #~ "Failed to delete branches:\n" #~ "%s" #~ msgstr "" #~ "無法刪除分支:\n" #~ "%s" #~ msgid "Failed to open repository %s:" #~ msgstr "無法打開版本庫 %s:" #~ msgid "Failed to rename '%s'." #~ msgstr "無法更名 '%s'." #~ msgid "" #~ "Failed to set current branch.\n" #~ "\n" #~ "This working directory is only partially switched. We successfully updated your files, but failed to update an internal Git file.\n" #~ "\n" #~ "This should not have occurred. %s will now close and give up." #~ msgstr "" #~ "無法設定當前分支.\n" #~ "\n" #~ "當前工作目錄僅有部分被切換出, 我們已成功的更新了您的文件但是無法更新某個內部的Git文件.\n" #~ "\n" #~ "這本不該發生, %s 將關閉並放棄." #~ msgid "Failed to stage selected hunk." #~ msgstr "無法緩存所選代碼段." #~ msgid "Failed to unstage selected hunk." #~ msgstr "無法將選擇的代碼段從緩存中刪除." #~ msgid "Failed to update '%s'." #~ msgstr "無法更新 '%s'." #~ msgid "Fast Forward Only " #~ msgstr "只允許快速前移式的合併" #~ msgid "Fetch from" #~ msgstr "從..獲取(fetch)" #~ msgid "Fetching new changes from %s" #~ msgstr "從 %s 處獲取新的改動" #~ msgid "File level merge required." #~ msgstr "需要文件級合併." #~ msgid "Font Example" #~ msgstr "字體樣例" #~ msgid "Font Family" #~ msgstr "字體族" #~ msgid "Force overwrite existing branch (may discard changes)" #~ msgstr "強制覆蓋已有的分支 (可能會丟失改動)" #~ msgid "From Repository" #~ msgstr "從版本庫" #~ msgid "Full Copy (Slower, Redundant Backup)" #~ msgstr "全部複製 (較慢, 做備份)" #~ msgid "GPG-signed" #~ msgstr "已簽署 GPG 簽章" #~ msgid "Garbage files" #~ msgstr "垃圾文件" #~ msgid "Git Gui" #~ msgstr "Git Gui" #~ msgid "Git Repository (subproject)" #~ msgstr "Git 版本庫 (子項目)" #~ msgid "Git directory not found:" #~ msgstr "Git 目錄無法找到:" #~ msgid "" #~ "Git version cannot be determined.\n" #~ "\n" #~ "%s claims it is version '%s'.\n" #~ "\n" #~ "%s requires at least Git 1.5.0 or later.\n" #~ "\n" #~ "Assume '%s' is version 1.5.0?\n" #~ msgstr "" #~ "無法確定 Git 的版本.\n" #~ "\n" #~ "%s 聲明其版本為 '%s'.\n" #~ "\n" #~ "而 %s 需要 1.5.0 或這以後的 Git 版本.\n" #~ "\n" #~ "是否假定 '%s' 為版本 1.5.0?\n" #~ msgid "Hardlinks are unavailable. Falling back to copying." #~ msgstr "硬連接不可用. 使用複製." #~ msgid "In File:" #~ msgstr "在文件:" #~ msgid "Increase Font Size" #~ msgstr "放大字體" #~ msgid "Index" #~ msgstr "修訂版提交準備區域" #~ msgid "Initial Commit Message:" #~ msgstr "初始的提交描述:" #~ msgid "Initial file checkout failed." #~ msgstr "初始的文件checkout失敗" #~ msgid "Invalid GIT_COMMITTER_IDENT:" #~ msgstr "無效的 GIT_COMMITTER_IDENT" #~ msgid "Invalid date from Git: %s" #~ msgstr "無效的日期: %s" #~ msgid "Invalid font specified in %s:" #~ msgstr "%s 中指定的字體無效:" #~ msgid "KiB" #~ msgstr "KiB" #~ msgid "" #~ "Last scanned state does not match repository state.\n" #~ "\n" #~ "Another Git program has modified this repository since the last scan. A rescan must be performed before a merge can be performed.\n" #~ "\n" #~ "The rescan will be automatically started now.\n" #~ msgstr "" #~ "最後一次掃瞄的狀態和當前版本庫狀態不符.\n" #~ "\n" #~ "另一 Git 程序自上次掃瞄後修改了本版本庫. 在修改當前分支之前需要重新做一次掃瞄.\n" #~ "\n" #~ "重新掃瞄將自動開始.\n" #~ msgid "" #~ "Last scanned state does not match repository state.\n" #~ "\n" #~ "Another Git program has modified this repository since the last scan. A rescan must be performed before another commit can be created.\n" #~ "\n" #~ "The rescan will be automatically started now.\n" #~ msgstr "" #~ "最後一次掃瞄的狀態和當前版本庫狀態不符.\n" #~ "\n" #~ "另一 Git 程序自上次掃瞄後修改了本版本庫. 在修改當前分支之前需要重新做一次掃瞄.\n" #~ "\n" #~ "重新掃瞄將自動開始.\n" #~ msgid "" #~ "Last scanned state does not match repository state.\n" #~ "\n" #~ "Another Git program has modified this repository since the last scan. A rescan must be performed before the current branch can be changed.\n" #~ "\n" #~ "The rescan will be automatically started now.\n" #~ msgstr "" #~ "最後一次掃瞄的狀態和當前版本庫狀態不符.\n" #~ "\n" #~ "另一 Git 程序自上次掃瞄後修改了本版本庫. 在修改當前分支之前需要重新做一次掃瞄.\n" #~ "\n" #~ "重新掃瞄將自動開始.\n" #~ msgid "Linking objects" #~ msgstr "鏈接 objects" #~ msgid "Loading annotation..." #~ msgstr "裝載標註..." #~ msgid "Loading copy/move tracking annotations..." #~ msgstr "裝載複製/移動跟蹤標註..." #~ msgid "Loading original location annotations..." #~ msgstr "裝載原始位置標註..." #~ msgid "Local Branches" #~ msgstr "本地分支" #~ msgid "Local Merge..." #~ msgstr "本地合併..." #~ msgid "Location %s already exists." #~ msgstr "位置 %s 已經存在." #~ msgid "Main Font" #~ msgstr "主要字體" #~ msgid "Match Tracking Branch Name" #~ msgstr "匹配跟蹤分支名字" #~ msgid "Match Tracking Branches" #~ msgstr "匹配跟蹤分支" #~ msgid "Merge completed successfully." #~ msgstr "合併成功完成." #~ msgid "Merge strategy '%s' not supported." #~ msgstr "合併策略 '%s' 不支持." #~ msgid "Merged Into:" #~ msgstr "合併到" #, fuzzy #~ msgid "Merging %s and %s..." #~ msgstr "合併 %s 和 %s" #~ msgid "Modified, not staged" #~ msgstr "修改但未緩存" #~ msgid "New Branch Name Template" #~ msgstr "新建分支命名模板" #~ msgid "New Commit" #~ msgstr "新建提交" #~ msgid "New Name:" #~ msgstr "新名字:" #~ msgid "" #~ "No changes to commit.\n" #~ "\n" #~ "No files were modified by this commit and it was not a merge commit.\n" #~ "\n" #~ "A rescan will be automatically started now.\n" #~ msgstr "" #~ "沒有改動提交.\n" #~ "\n" #~ "該提交沒有改動任何文件也不是一個合併提交.\n" #~ "\n" #~ "重新掃瞄將自動開始.\n" #~ msgid "No default branch obtained." #~ msgstr "沒有獲取缺省分支" #~ msgid "" #~ "No differences detected.\n" #~ "\n" #~ "%s has no changes.\n" #~ "\n" #~ "The modification date of this file was updated by another application, but the content within the file was not changed.\n" #~ "\n" #~ "A rescan will be automatically started to find other files which may have the same state." #~ msgstr "" #~ "未檢測到改動.\n" #~ "\n" #~ "該文件的修改日期被另一個程序所更新, 但其內容並沒有變化.\n" #~ "\n" #~ "對於類似情況的其他文件的重新掃瞄將自動開始." #~ msgid "No files selected for checkout from HEAD." #~ msgstr "沒有選取任何需要自 HEAD 取出的檔案" #~ msgid "No working directory" #~ msgstr "沒有工作目錄" #~ msgid "Number of loose objects" #~ msgstr "鬆散對象的數量" #~ msgid "Number of packed objects" #~ msgstr "壓縮對象數量" #~ msgid "Number of packs" #~ msgstr "壓縮包數量" #~ msgid "On Debian-based systems try: sudo apt-get install python-pyinotify" #~ msgstr "於基於 Debian 的系統中嘗試於終端機下執行:sudo apt-get install python-pyinotify" #~ msgid "One or more of the merge tests failed because you have not fetched the necessary commits. Try fetching from %s first." #~ msgstr "由於沒有獲取到必要的提交,一個或多個合併測試失敗。請嘗試從 %s 處先獲取。" #~ msgid "Options" #~ msgstr "選項..." #~ msgid "Original File:" #~ msgstr "原始文件:" #~ msgid "Originally By:" #~ msgstr "最初由:" #~ msgid "" #~ "Output:\n" #~ "%s" #~ msgstr "" #~ "命令輸出:\n" #~ "%s" #~ msgid "Output: %s" #~ msgstr "輸出:%s" #~ msgid "PATCH %(current)d/%(count)d" #~ msgstr "正在套用 %(current)d/%(count)d 修正" #~ msgid "Packed objects waiting for pruning" #~ msgstr "壓縮對象等待清理" #~ msgid "Path to git repository" #~ msgstr "Git 版本倉庫的路徑" #~ msgid "Please select one or more branches to delete." #~ msgstr "請選擇某個或多個分支來刪除" #~ msgid "Please supply a branch name." #~ msgstr "請提供分支名字." #~ msgid "Portions staged for commit" #~ msgstr "部分緩存為提交" #~ msgid "" #~ "Possible environment issues exist.\n" #~ "\n" #~ "The following environment variables are probably\n" #~ "going to be ignored by any Git subprocess run\n" #~ "by %s:\n" #~ "\n" #~ msgstr "" #~ "可能存在環境變量的問題.\n" #~ "\n" #~ "由 %s 執行的 Git 子進程可能忽略下列環境變量:\n" #~ "\n" #~ msgid "Preferences..." #~ msgstr "首選項..." #~ msgid "Process Diff Hunk" #~ msgstr "處理內容差異區域" #~ msgid "Process Selection" #~ msgstr "處理選取的項目" #~ msgid "Prune Tracking Branches During Fetch" #~ msgstr "獲取時清除跟蹤分支" #~ msgid "Pruning tracking branches deleted from %s" #~ msgstr "清除" #~ msgid "Push Branches" #~ msgstr "上傳分支" #~ msgid "Push to" #~ msgstr "上傳到(push)" #~ msgid "Pushing %s %s to %s" #~ msgstr "上傳 %s %s 到 %s" #~ msgid "Reading %s..." #~ msgstr "讀取 %s..." #, fuzzy #~ msgid "Ready to commit." #~ msgstr "緩存為提交" #~ msgid "Ready." #~ msgstr "就緒" #, fuzzy #~ msgid "Rebase Branch" #~ msgstr "更改分支名:" #, fuzzy #~ msgid "Rebase..." #~ msgstr "復位(Reset)..." #~ msgid "" #~ "Recovering deleted branches is difficult.\n" #~ "\n" #~ "Delete the selected branches?" #~ msgstr "" #~ "恢復被刪除的分支非常困難.\n" #~ "\n" #~ "是否要刪除所選分支?" #~ msgid "" #~ "Recovering deleted branches is difficult. \n" #~ "\n" #~ " Delete the selected branches?" #~ msgstr "" #~ "恢復被刪除的分支非常困難.\n" #~ "\n" #~ "是否要刪除所選分支?" #~ msgid "Refreshing file status..." #~ msgstr "更新文件狀態..." #, fuzzy #~ msgid "Remote Branches" #~ msgstr "遠端分支名" #~ msgid "Remote:" #~ msgstr "Remote:" #~ msgid "Remove selected paths from the staging area" #~ msgstr "將選取的路徑自修訂版提交準備區域中移除" #~ msgid "Rename remote?" #~ msgstr "要重新命名遠端版控庫嗎?" #~ msgid "Repository" #~ msgstr "版本庫(repository)" #~ msgid "Requires merge resolution" #~ msgstr "需要解決合併衝突" #~ msgid "Rescan" #~ msgstr "重新掃瞄" #~ msgid "" #~ "Reset changes?\n" #~ "\n" #~ "Resetting the changes will cause *ALL* uncommitted changes to be lost.\n" #~ "\n" #~ "Continue with resetting the current changes?" #~ msgstr "" #~ "是否復位當前改動?\n" #~ "\n" #~ "復位當前的改動將導致 *所有* 未提交的改動丟失.\n" #~ "\n" #~ "是否要繼續復位當前的改動?" #~ msgid "Revert Uncommitted Changes..." #~ msgstr "撤銷尚未建立修訂版提交的內容變動" #~ msgid "Revert changes in these %i files?" #~ msgstr "撤銷這些 (%i個) 文件的改動?" #~ msgid "Select File" #~ msgstr "選取檔案" #~ msgid "Select file from \"%s\"" #~ msgstr "於「%s」中選取檔案" #~ msgid "Shared (Fastest, Not Recommended, No Backup)" #~ msgstr "共享方式 (最快, 不推薦, 不做備份)" #~ msgid "Shared only available for local repository." #~ msgstr "共享方式僅當是本地版本庫時有效." #~ msgid "Show Less Context" #~ msgstr "顯示更少上下文" #~ msgid "Show More Context" #~ msgstr "顯示更多上下文" #~ msgid "Source Branches" #~ msgstr "源端分支:" #~ msgid "Stage Hunk For Commit" #~ msgstr "緩存修改塊為提交" #~ msgid "Staged Changes (Will Commit)" #~ msgstr "已緩存的改動 (將被提交)" #~ msgid "Staged for commit, missing" #~ msgstr "緩存為提交, 不存在" #~ msgid "Staged for removal" #~ msgstr "緩存為刪除" #~ msgid "Staged for removal, still present" #~ msgstr "緩存為刪除, 但仍存在" #~ msgid "Staging Area" #~ msgstr "新修訂版準備區域" #~ msgid "Staging area (index) is already locked." #~ msgstr "緩存區域 (index) 已被鎖定." #~ msgid "Standard (Fast, Semi-Redundant, Hardlinks)" #~ msgstr "標準方式 (快速, 部分備份, 作硬連接)" #~ msgid "Standard only available for local repository." #~ msgstr "標準方式僅當是本地版本庫時有效." #~ msgid "Starting gitk... please wait..." #~ msgstr "啟動 gitk... 請等待..." #~ msgid "Staying on branch '%s'." #~ msgstr "停留在分支 '%s'." #~ msgid "Success" #~ msgstr "成功" #~ msgid "Summary:" #~ msgstr "總結:" #~ msgid "The 'master' branch has not been initialized." #~ msgstr "'master'分支尚未初始化." #~ msgid "The following branches are not completely merged into %s:" #~ msgstr "下列分支沒有完全被合併到 %s:" #~ msgid "" #~ "The following branches are not completely merged into %s:\n" #~ "\n" #~ " - %s" #~ msgstr "" #~ "下列分支沒有被全部合併到 %s 中:\n" #~ "\n" #~ " - %s" #~ msgid "" #~ "There is nothing to amend.\n" #~ "\n" #~ "You are about to create the initial commit. There is no commit before this to amend.\n" #~ msgstr "" #~ "沒有改動需要修正.\n" #~ "\n" #~ "你正在創建最初的提交. 在此之前沒有提交可以修正.\n" #~ msgid "This Detached Checkout" #~ msgstr "該脫節的Checkout" #~ msgid "" #~ "This PyQt4 does not include QtWebKit.\n" #~ "The keyboard shortcuts feature is unavailable." #~ msgstr "" #~ "此 PyQt4 並未包含 QtWebKit。\n" #~ "不支援顯示軟體的鍵盤快捷鍵列表。翻譯者注:" #~ msgid "" #~ "This is example text.\n" #~ "If you like this text, it can be your font." #~ msgstr "" #~ "這是樣例文本.\n" #~ "如果你喜歡, 你可以設置該字體." #~ msgid "" #~ "This repository currently has approximately %i loose objects.\n" #~ "\n" #~ "To maintain optimal performance it is strongly recommended that you compress the database when more than %i loose objects exist.\n" #~ "\n" #~ "Compress the database now?" #~ msgstr "" #~ "該版本庫當前約有 %i 個鬆散對象.\n" #~ "\n" #~ "為達到較優的性能,強烈建議你在鬆散對象多於 %i 時壓縮數據庫.\n" #~ "\n" #~ "現在就壓縮數據庫麼?" #~ msgid "Tracking branch %s is not a branch in the remote repository." #~ msgstr "跟蹤分支 %s 並不是遠端版本庫中的一個分支" #~ msgid "Transfer Options" #~ msgstr "傳輸選項" #~ msgid "Unable to copy object: %s" #~ msgstr "無法複製 object: %s" #~ msgid "Unable to copy objects/info/alternates: %s" #~ msgstr "無法複製 objects/info/alternates: %s" #~ msgid "Unable to display %s" #~ msgstr "無法顯示 %s" #~ msgid "Unable to hardlink object: %s" #~ msgstr "無法硬鏈接 object: %s" #~ msgid "Unable to obtain your identity:" #~ msgstr "無法獲知你的身份:" #~ msgid "" #~ "Unable to start gitk:\n" #~ "\n" #~ "%s does not exist" #~ msgstr "" #~ "無法啟動 gitk:\n" #~ "\n" #~ "%s 不存在" #~ msgid "Unable to unlock the index." #~ msgstr "無法解鎖緩存 (index)" #~ msgid "" #~ "Unknown file state %s detected.\n" #~ "\n" #~ "File %s cannot be committed by this program.\n" #~ msgstr "" #~ "檢測到未知文件狀態 %s.\n" #~ "\n" #~ "文件 %s 無法由該程序提交.\n" #~ msgid "Unlock Index" #~ msgstr "解鎖 Index" #~ msgid "" #~ "Unmerged files cannot be committed.\n" #~ "\n" #~ "File %s has merge conflicts. You must resolve them and stage the file before committing.\n" #~ msgstr "" #~ "尚未合併的文件沒有辦法提交.\n" #~ "\n" #~ "文件 %s 有合併衝突, 你必須解決這些衝突並緩存該文件作提交.\n" #~ msgid "Unstage Hunk From Commit" #~ msgstr "從提交中撤除修改塊" #~ msgid "Updating the Git index failed. A rescan will be automatically started to resynchronize git-gui." #~ msgstr "更新 Git 緩存(Index)失敗, 重新掃瞄將自動開始以重新同步 git-gui." #~ msgid "Updating working directory to '%s'..." #~ msgstr "更新工作目錄到 '%s'..." #~ msgid "Updating..." #~ msgstr "正在更新……" #~ msgid "Use thin pack (for slow network connections)" #~ msgstr "使用 thin pack (適用於低速網絡連接)" #~ msgid "Verify Database" #~ msgstr "驗證數據庫" #~ msgid "Verifying the object database with fsck-objects" #~ msgstr "使用 fsck-objects 驗證對象數據庫" #~ msgid "Visualize %s's History" #~ msgstr "圖示 %s 分支的歷史" #~ msgid "Working... please wait..." #~ msgstr "工作中... 請等待..." #~ msgid "" #~ "You are in the middle of a change.\n" #~ "\n" #~ "File %s is modified.\n" #~ "\n" #~ "You should complete the current commit before starting a merge. Doing so will help you abort a failed merge, should the need arise.\n" #~ msgstr "" #~ "你正處在一個改動當中.\n" #~ "\n" #~ "文件 %s 已被修改.\n" #~ "\n" #~ "你必須完成當前的提交後才能開始合併. 如果需要, 這麼做將有助於中止一次失敗的合併.\n" #~ msgid "" #~ "You are in the middle of a conflicted merge.\n" #~ "\n" #~ "File %s has merge conflicts.\n" #~ "\n" #~ "You must resolve them, stage the file, and commit to complete the current merge. Only then can you begin another merge.\n" #~ msgstr "" #~ "你正處在一個有衝突的合併操作中.\n" #~ "\n" #~ "文件 %s 有合併衝突.\n" #~ "\n" #~ "你必須解決這些衝突, 緩存該文件, 並提交來完成當前的合併.僅當這樣後才能開始下一個合併操作.\n" #~ msgid "" #~ "You are no longer on a local branch.\n" #~ "\n" #~ "If you wanted to be on a branch, create one now starting from 'This Detached Checkout'." #~ msgstr "" #~ "你不在某個本地分支上.\n" #~ "\n" #~ "如果你想位於某分支上, 從當前脫節的Checkout中創建一個新分支." #~ msgid "You must correct the above errors before committing." #~ msgstr "你必須在提交前修正上述錯誤." #~ msgid "[Up To Parent]" #~ msgstr "[上層目錄]" #, fuzzy #~ msgid "buckets" #~ msgstr "水桶??" #~ msgid "commit-tree failed:" #~ msgstr "commit-tree 失敗:" #~ msgid "fatal: Cannot resolve %s" #~ msgstr "致命錯誤: 無法解決 %s" #~ msgid "" #~ "file notification: disabled\n" #~ "Note: install pywin32 to enable.\n" #~ msgstr "" #~ "inotify 檔案變更通知:停用\n" #~ "注意:安裝 pywin32 以啟用此功能。\n" #~ msgid "files" #~ msgstr "文件" #, fuzzy #~ msgid "files reset" #~ msgstr "文件" #~ msgid "git clone returned exit code %s" #~ msgstr "git clone 命令傳回了 %s 錯誤狀態碼" #~ msgid "git tag returned exit code %s" #~ msgstr "git tag 命令傳回了 %s 錯誤狀態碼" #~ msgid "git-gui - a graphical user interface for Git." #~ msgstr "git-gui - Git 的圖形化用戶界面" #~ msgid "git-gui: fatal error" #~ msgstr "git-gui: 致命錯誤" #~ msgid "inotify enabled." #~ msgstr "inotify 已啟用。" #~ msgid "" #~ "inotify: disabled\n" #~ "Note: install python-pyinotify to enable inotify.\n" #~ msgstr "" #~ "inotify:停用\n" #~ "注意:安裝 python-pyinotify 軟體包以啟用 inotify 檔案變更通知功能。\n" #~ msgid "lines annotated" #~ msgstr "標註行" #~ msgid "objects" #~ msgstr "objects" #~ msgid "pt." #~ msgstr "磅" #~ msgid "push %s" #~ msgstr "上傳 %s" #~ msgid "remote prune %s" #~ msgstr "清除遠端 %s" #~ msgid "update-ref failed:" #~ msgstr "update-ref 失敗:" #~ msgid "warning" #~ msgstr "警告" #~ msgid "warning: Tcl does not support encoding '%s'." #~ msgstr "警告: Tcl 不支持編碼方式 '%s'." #~ msgid "write-tree failed:" #~ msgstr "write-tree 失敗:" git-cola-3.6/pynsist.cfg000066400000000000000000000017571356743264500153040ustar00rootroot00000000000000# https://pynsist.readthedocs.io/en/latest/cfgfile.html [Application] name = git-cola version = 3.6 entry_point = cola.main:shortcut_launch icon = share/git-cola/icons/git-cola.ico extra_preamble = contrib/win32/pynsist-preamble.py # We might want to pursue shell integration, which would at minimum require a # custom template. https://pynsist.readthedocs.io/en/latest/design.html # [Build] # nsi_template = contrib/win32/pynsist-template.nsi [Python] version = 3.6.4 bitness = 32 format = bundled [Shortcut git-dag] entry_point = cola.dag:shortcut_launch icon = share/git-cola/icons/git-cola.ico extra_preamble = contrib/win32/pynsist-preamble.py [Command git-cola] entry_point = cola.main:winmain extra_preamble = contrib/win32/pynsist-preamble.py [Command git-dag] entry_point = cola.dag:winmain extra_preamble = contrib/win32/pynsist-preamble.py [Include] packages = cola qtpy pypi_wheels = PyQt5==5.10.1 sip==4.19.8 pywin32==223 files = share/ exclude = pkgs/PyQt5/QtBluetooth.pyd git-cola-3.6/qtpy/000077500000000000000000000000001356743264500140755ustar00rootroot00000000000000git-cola-3.6/qtpy/Qt3DAnimation.py000066400000000000000000000017141356743264500170650ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Provides Qt3DAnimation classes and functions.""" # Local imports from . import PYQT5, PYSIDE2, PythonQtError, PYSIDE_VERSION from .py3compat import PY2 if PYQT5: from PyQt5.Qt3DAnimation import * elif PYSIDE2: if not PY2 or (PY2 and PYSIDE_VERSION < '5.12.4'): # https://bugreports.qt.io/projects/PYSIDE/issues/PYSIDE-1026 import PySide2.Qt3DAnimation as __temp import inspect for __name in inspect.getmembers(__temp.Qt3DAnimation): globals()[__name[0]] = __name[1] else: raise PythonQtError('A bug in Shiboken prevents this') else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/Qt3DCore.py000066400000000000000000000016701356743264500160370ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Provides Qt3DCore classes and functions.""" # Local imports from . import PYQT5, PYSIDE2, PythonQtError, PYSIDE_VERSION from .py3compat import PY2 if PYQT5: from PyQt5.Qt3DCore import * elif PYSIDE2: if not PY2 or (PY2 and PYSIDE_VERSION < '5.12.4'): # https://bugreports.qt.io/projects/PYSIDE/issues/PYSIDE-1026 import PySide2.Qt3DCore as __temp import inspect for __name in inspect.getmembers(__temp.Qt3DCore): globals()[__name[0]] = __name[1] else: raise PythonQtError('A bug in Shiboken prevents this') else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/Qt3DExtras.py000066400000000000000000000017001356743264500164070ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Provides Qt3DExtras classes and functions.""" # Local imports from . import PYQT5, PYSIDE2, PythonQtError, PYSIDE_VERSION from .py3compat import PY2 if PYQT5: from PyQt5.Qt3DExtras import * elif PYSIDE2: if not PY2 or (PY2 and PYSIDE_VERSION < '5.12.4'): # https://bugreports.qt.io/projects/PYSIDE/issues/PYSIDE-1026 import PySide2.Qt3DExtras as __temp import inspect for __name in inspect.getmembers(__temp.Qt3DExtras): globals()[__name[0]] = __name[1] else: raise PythonQtError('A bug in Shiboken prevents this') else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/Qt3DInput.py000066400000000000000000000016741356743264500162520ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Provides Qt3DInput classes and functions.""" # Local imports from . import PYQT5, PYSIDE2, PythonQtError, PYSIDE_VERSION from .py3compat import PY2 if PYQT5: from PyQt5.Qt3DInput import * elif PYSIDE2: if not PY2 or (PY2 and PYSIDE_VERSION < '5.12.4'): # https://bugreports.qt.io/projects/PYSIDE/issues/PYSIDE-1026 import PySide2.Qt3DInput as __temp import inspect for __name in inspect.getmembers(__temp.Qt3DInput): globals()[__name[0]] = __name[1] else: raise PythonQtError('A bug in Shiboken prevents this') else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/Qt3DLogic.py000066400000000000000000000016741356743264500162100ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Provides Qt3DLogic classes and functions.""" # Local imports from . import PYQT5, PYSIDE2, PythonQtError, PYSIDE_VERSION from .py3compat import PY2 if PYQT5: from PyQt5.Qt3DLogic import * elif PYSIDE2: if not PY2 or (PY2 and PYSIDE_VERSION < '5.12.4'): # https://bugreports.qt.io/projects/PYSIDE/issues/PYSIDE-1026 import PySide2.Qt3DLogic as __temp import inspect for __name in inspect.getmembers(__temp.Qt3DLogic): globals()[__name[0]] = __name[1] else: raise PythonQtError('A bug in Shiboken prevents this') else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/Qt3DRender.py000066400000000000000000000017001356743264500163600ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Provides Qt3DRender classes and functions.""" # Local imports from . import PYQT5, PYSIDE2, PythonQtError, PYSIDE_VERSION from .py3compat import PY2 if PYQT5: from PyQt5.Qt3DRender import * elif PYSIDE2: if not PY2 or (PY2 and PYSIDE_VERSION < '5.12.4'): # https://bugreports.qt.io/projects/PYSIDE/issues/PYSIDE-1026 import PySide2.Qt3DRender as __temp import inspect for __name in inspect.getmembers(__temp.Qt3DRender): globals()[__name[0]] = __name[1] else: raise PythonQtError('A bug in Shiboken prevents this') else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/QtCharts.py000066400000000000000000000013751356743264500162060ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright © 2019- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Provides QtChart classes and functions.""" # Local imports from . import PYQT5, PYSIDE2, PythonQtError if PYQT5: try: from PyQt5 import QtChart as QtCharts except ImportError: raise PythonQtError('The QtChart module was not found. ' 'It needs to be installed separately for PyQt5.') elif PYSIDE2: from PySide2.QtCharts import * else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/QtCore.py000066400000000000000000000105561356743264500156530ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Copyright © 2014-2015 Colin Duquesnoy # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) """ Provides QtCore classes and functions. """ from . import PYQT5, PYSIDE2, PYQT4, PYSIDE, PythonQtError if PYQT5: from PyQt5.QtCore import * from PyQt5.QtCore import pyqtSignal as Signal from PyQt5.QtCore import pyqtSlot as Slot from PyQt5.QtCore import pyqtProperty as Property from PyQt5.QtCore import QT_VERSION_STR as __version__ # For issue #153 from PyQt5.QtCore import QDateTime QDateTime.toPython = QDateTime.toPyDateTime # Those are imported from `import *` del pyqtSignal, pyqtSlot, pyqtProperty, QT_VERSION_STR elif PYSIDE2: from PySide2.QtCore import * try: # may be limited to PySide-5.11a1 only from PySide2.QtGui import QStringListModel except: pass import PySide2.QtCore __version__ = PySide2.QtCore.__version__ elif PYQT4: from PyQt4.QtCore import * # Those are things we inherited from Spyder that fix crazy crashes under # some specific situations. (See #34) from PyQt4.QtCore import QCoreApplication from PyQt4.QtCore import Qt from PyQt4.QtCore import pyqtSignal as Signal from PyQt4.QtCore import pyqtSlot as Slot from PyQt4.QtCore import pyqtProperty as Property from PyQt4.QtGui import (QItemSelection, QItemSelectionModel, QItemSelectionRange, QSortFilterProxyModel, QStringListModel) from PyQt4.QtCore import QT_VERSION_STR as __version__ from PyQt4.QtCore import qInstallMsgHandler as qInstallMessageHandler # QDesktopServices has has been split into (QDesktopServices and # QStandardPaths) in Qt5 # This creates a dummy class that emulates QStandardPaths from PyQt4.QtGui import QDesktopServices as _QDesktopServices class QStandardPaths(): StandardLocation = _QDesktopServices.StandardLocation displayName = _QDesktopServices.displayName DesktopLocation = _QDesktopServices.DesktopLocation DocumentsLocation = _QDesktopServices.DocumentsLocation FontsLocation = _QDesktopServices.FontsLocation ApplicationsLocation = _QDesktopServices.ApplicationsLocation MusicLocation = _QDesktopServices.MusicLocation MoviesLocation = _QDesktopServices.MoviesLocation PicturesLocation = _QDesktopServices.PicturesLocation TempLocation = _QDesktopServices.TempLocation HomeLocation = _QDesktopServices.HomeLocation DataLocation = _QDesktopServices.DataLocation CacheLocation = _QDesktopServices.CacheLocation writableLocation = _QDesktopServices.storageLocation # Those are imported from `import *` del pyqtSignal, pyqtSlot, pyqtProperty, QT_VERSION_STR, qInstallMsgHandler elif PYSIDE: from PySide.QtCore import * from PySide.QtGui import (QItemSelection, QItemSelectionModel, QItemSelectionRange, QSortFilterProxyModel, QStringListModel) from PySide.QtCore import qInstallMsgHandler as qInstallMessageHandler del qInstallMsgHandler # QDesktopServices has has been split into (QDesktopServices and # QStandardPaths) in Qt5 # This creates a dummy class that emulates QStandardPaths from PySide.QtGui import QDesktopServices as _QDesktopServices class QStandardPaths(): StandardLocation = _QDesktopServices.StandardLocation displayName = _QDesktopServices.displayName DesktopLocation = _QDesktopServices.DesktopLocation DocumentsLocation = _QDesktopServices.DocumentsLocation FontsLocation = _QDesktopServices.FontsLocation ApplicationsLocation = _QDesktopServices.ApplicationsLocation MusicLocation = _QDesktopServices.MusicLocation MoviesLocation = _QDesktopServices.MoviesLocation PicturesLocation = _QDesktopServices.PicturesLocation TempLocation = _QDesktopServices.TempLocation HomeLocation = _QDesktopServices.HomeLocation DataLocation = _QDesktopServices.DataLocation CacheLocation = _QDesktopServices.CacheLocation writableLocation = _QDesktopServices.storageLocation import PySide.QtCore __version__ = PySide.QtCore.__version__ else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/QtDatavisualization.py000066400000000000000000000014451356743264500204530ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Provides QtDataVisualization classes and functions.""" # Local imports from . import PYQT5, PYSIDE2, PythonQtError if PYQT5: from PyQt5.QtDataVisualization import * elif PYSIDE2: # https://bugreports.qt.io/projects/PYSIDE/issues/PYSIDE-1026 import PySide2.QtDataVisualization as __temp import inspect for __name in inspect.getmembers(__temp.QtDataVisualization): globals()[__name[0]] = __name[1] else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/QtDesigner.py000066400000000000000000000006171356743264500165200ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Copyright © 2014-2015 Colin Duquesnoy # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) """ Provides QtDesigner classes and functions. """ from . import PYQT5, PYQT4, PythonQtError if PYQT5: from PyQt5.QtDesigner import * elif PYQT4: from PyQt4.QtDesigner import * else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/QtGui.py000066400000000000000000000204721356743264500155050ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Copyright © 2014-2015 Colin Duquesnoy # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) """ Provides QtGui classes and functions. .. warning:: Only PyQt4/PySide QtGui classes compatible with PyQt5.QtGui are exposed here. Therefore, you need to treat/use this package as if it were the ``PyQt5.QtGui`` module. """ import warnings from . import PYQT5, PYQT4, PYSIDE, PYSIDE2, PythonQtError if PYQT5: from PyQt5.QtGui import * elif PYSIDE2: from PySide2.QtGui import * elif PYQT4: try: # Older versions of PyQt4 do not provide these from PyQt4.QtGui import (QGlyphRun, QMatrix2x2, QMatrix2x3, QMatrix2x4, QMatrix3x2, QMatrix3x3, QMatrix3x4, QMatrix4x2, QMatrix4x3, QMatrix4x4, QTouchEvent, QQuaternion, QRadialGradient, QRawFont, QStaticText, QVector2D, QVector3D, QVector4D, qFuzzyCompare) except ImportError: pass from PyQt4.Qt import QKeySequence, QTextCursor from PyQt4.QtGui import (QAbstractTextDocumentLayout, QActionEvent, QBitmap, QBrush, QClipboard, QCloseEvent, QColor, QConicalGradient, QContextMenuEvent, QCursor, QDoubleValidator, QDrag, QDragEnterEvent, QDragLeaveEvent, QDragMoveEvent, QDropEvent, QFileOpenEvent, QFocusEvent, QFont, QFontDatabase, QFontInfo, QFontMetrics, QFontMetricsF, QGradient, QHelpEvent, QHideEvent, QHoverEvent, QIcon, QIconDragEvent, QIconEngine, QImage, QImageIOHandler, QImageReader, QImageWriter, QInputEvent, QInputMethodEvent, QKeyEvent, QLinearGradient, QMouseEvent, QMoveEvent, QMovie, QPaintDevice, QPaintEngine, QPaintEngineState, QPaintEvent, QPainter, QPainterPath, QPainterPathStroker, QPalette, QPen, QPicture, QPictureIO, QPixmap, QPixmapCache, QPolygon, QPolygonF, QRegExpValidator, QRegion, QResizeEvent, QSessionManager, QShortcutEvent, QShowEvent, QStandardItem, QStandardItemModel, QStatusTipEvent, QSyntaxHighlighter, QTabletEvent, QTextBlock, QTextBlockFormat, QTextBlockGroup, QTextBlockUserData, QTextCharFormat, QTextDocument, QTextDocumentFragment, QTextDocumentWriter, QTextFormat, QTextFragment, QTextFrame, QTextFrameFormat, QTextImageFormat, QTextInlineObject, QTextItem, QTextLayout, QTextLength, QTextLine, QTextList, QTextListFormat, QTextObject, QTextObjectInterface, QTextOption, QTextTable, QTextTableCell, QTextTableCellFormat, QTextTableFormat, QTransform, QValidator, QWhatsThisClickedEvent, QWheelEvent, QWindowStateChangeEvent, qAlpha, qBlue, qGray, qGreen, qIsGray, qRed, qRgb, qRgba, QIntValidator) # QDesktopServices has has been split into (QDesktopServices and # QStandardPaths) in Qt5 # It only exposes QDesktopServices that are still in pyqt5 from PyQt4.QtGui import QDesktopServices as _QDesktopServices class QDesktopServices(): openUrl = _QDesktopServices.openUrl setUrlHandler = _QDesktopServices.setUrlHandler unsetUrlHandler = _QDesktopServices.unsetUrlHandler def __getattr__(self, name): attr = getattr(_QDesktopServices, name) new_name = name if name == 'storageLocation': new_name = 'writableLocation' warnings.warn(("Warning QDesktopServices.{} is deprecated in Qt5" "we recommend you use QDesktopServices.{} instead").format(name, new_name), DeprecationWarning) return attr QDesktopServices = QDesktopServices() elif PYSIDE: from PySide.QtGui import (QAbstractTextDocumentLayout, QActionEvent, QBitmap, QBrush, QClipboard, QCloseEvent, QColor, QConicalGradient, QContextMenuEvent, QCursor, QDoubleValidator, QDrag, QDragEnterEvent, QDragLeaveEvent, QDragMoveEvent, QDropEvent, QFileOpenEvent, QFocusEvent, QFont, QFontDatabase, QFontInfo, QFontMetrics, QFontMetricsF, QGradient, QHelpEvent, QHideEvent, QHoverEvent, QIcon, QIconDragEvent, QIconEngine, QImage, QImageIOHandler, QImageReader, QImageWriter, QInputEvent, QInputMethodEvent, QKeyEvent, QKeySequence, QLinearGradient, QMatrix2x2, QMatrix2x3, QMatrix2x4, QMatrix3x2, QMatrix3x3, QMatrix3x4, QMatrix4x2, QMatrix4x3, QMatrix4x4, QMouseEvent, QMoveEvent, QMovie, QPaintDevice, QPaintEngine, QPaintEngineState, QPaintEvent, QPainter, QPainterPath, QPainterPathStroker, QPalette, QPen, QPicture, QPictureIO, QPixmap, QPixmapCache, QPolygon, QPolygonF, QQuaternion, QRadialGradient, QRegExpValidator, QRegion, QResizeEvent, QSessionManager, QShortcutEvent, QShowEvent, QStandardItem, QStandardItemModel, QStatusTipEvent, QSyntaxHighlighter, QTabletEvent, QTextBlock, QTextBlockFormat, QTextBlockGroup, QTextBlockUserData, QTextCharFormat, QTextCursor, QTextDocument, QTextDocumentFragment, QTextFormat, QTextFragment, QTextFrame, QTextFrameFormat, QTextImageFormat, QTextInlineObject, QTextItem, QTextLayout, QTextLength, QTextLine, QTextList, QTextListFormat, QTextObject, QTextObjectInterface, QTextOption, QTextTable, QTextTableCell, QTextTableCellFormat, QTextTableFormat, QTouchEvent, QTransform, QValidator, QVector2D, QVector3D, QVector4D, QWhatsThisClickedEvent, QWheelEvent, QWindowStateChangeEvent, qAlpha, qBlue, qGray, qGreen, qIsGray, qRed, qRgb, qRgba, QIntValidator) # QDesktopServices has has been split into (QDesktopServices and # QStandardPaths) in Qt5 # It only exposes QDesktopServices that are still in pyqt5 from PySide.QtGui import QDesktopServices as _QDesktopServices class QDesktopServices(): openUrl = _QDesktopServices.openUrl setUrlHandler = _QDesktopServices.setUrlHandler unsetUrlHandler = _QDesktopServices.unsetUrlHandler def __getattr__(self, name): attr = getattr(_QDesktopServices, name) new_name = name if name == 'storageLocation': new_name = 'writableLocation' warnings.warn(("Warning QDesktopServices.{} is deprecated in Qt5" "we recommend you use QDesktopServices.{} instead").format(name, new_name), DeprecationWarning) return attr QDesktopServices = QDesktopServices() else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/QtHelp.py000066400000000000000000000007101356743264500156420ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) """QtHelp Wrapper.""" import warnings from . import PYQT5 from . import PYQT4 from . import PYSIDE from . import PYSIDE2 if PYQT5: from PyQt5.QtHelp import * elif PYSIDE2: from PySide2.QtHelp import * elif PYQT4: from PyQt4.QtHelp import * elif PYSIDE: from PySide.QtHelp import * git-cola-3.6/qtpy/QtLocation.py000066400000000000000000000011071356743264500165230ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Provides QtLocation classes and functions.""" # Local imports from . import PYQT5, PYSIDE2, PythonQtError if PYQT5: from PyQt5.QtLocation import * elif PYSIDE2: from PySide2.QtLocation import * else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/QtMultimedia.py000066400000000000000000000005641356743264500170530ustar00rootroot00000000000000import warnings from . import PYQT5 from . import PYQT4 from . import PYSIDE from . import PYSIDE2 if PYQT5: from PyQt5.QtMultimedia import * elif PYSIDE2: from PySide2.QtMultimedia import * elif PYQT4: from PyQt4.QtMultimedia import * from PyQt4.QtGui import QSound elif PYSIDE: from PySide.QtMultimedia import * from PySide.QtGui import QSound git-cola-3.6/qtpy/QtMultimediaWidgets.py000066400000000000000000000011421356743264500203730ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Provides QtMultimediaWidgets classes and functions.""" # Local imports from . import PYSIDE2, PYQT5, PythonQtError if PYQT5: from PyQt5.QtMultimediaWidgets import * elif PYSIDE2: from PySide2.QtMultimediaWidgets import * else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/QtNetwork.py000066400000000000000000000010601356743264500164020ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Copyright © 2014-2015 Colin Duquesnoy # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) """ Provides QtNetwork classes and functions. """ from . import PYQT5, PYSIDE2, PYQT4, PYSIDE, PythonQtError if PYQT5: from PyQt5.QtNetwork import * elif PYSIDE2: from PySide2.QtNetwork import * elif PYQT4: from PyQt4.QtNetwork import * elif PYSIDE: from PySide.QtNetwork import * else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/QtOpenGL.py000066400000000000000000000013171356743264500161020ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Provides QtOpenGL classes and functions.""" # Local imports from . import PYQT4, PYQT5, PYSIDE, PYSIDE2, PythonQtError if PYQT5: from PyQt5.QtOpenGL import * elif PYSIDE2: from PySide2.QtOpenGL import * elif PYQT4: from PyQt4.QtOpenGL import * elif PYSIDE: from PySide.QtOpenGL import * else: raise PythonQtError('No Qt bindings could be found') del PYQT4, PYQT5, PYSIDE, PYSIDE2 git-cola-3.6/qtpy/QtPrintSupport.py000066400000000000000000000016151356743264500174500ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) """ Provides QtPrintSupport classes and functions. """ from . import PYQT5, PYQT4,PYSIDE2, PYSIDE, PythonQtError if PYQT5: from PyQt5.QtPrintSupport import * elif PYSIDE2: from PySide2.QtPrintSupport import * elif PYQT4: from PyQt4.QtGui import (QAbstractPrintDialog, QPageSetupDialog, QPrintDialog, QPrintEngine, QPrintPreviewDialog, QPrintPreviewWidget, QPrinter, QPrinterInfo) elif PYSIDE: from PySide.QtGui import (QAbstractPrintDialog, QPageSetupDialog, QPrintDialog, QPrintEngine, QPrintPreviewDialog, QPrintPreviewWidget, QPrinter, QPrinterInfo) else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/QtQml.py000066400000000000000000000010701356743264500155030ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Provides QtQml classes and functions.""" # Local imports from . import PYQT5, PYSIDE2, PythonQtError if PYQT5: from PyQt5.QtQml import * elif PYSIDE2: from PySide2.QtQml import * else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/QtQuick.py000066400000000000000000000010761356743264500160340ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Provides QtQuick classes and functions.""" # Local imports from . import PYQT5, PYSIDE2, PythonQtError if PYQT5: from PyQt5.QtQuick import * elif PYSIDE2: from PySide2.QtQuick import * else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/QtQuickWidgets.py000066400000000000000000000011231356743264500173540ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Provides QtQuickWidgets classes and functions.""" # Local imports from . import PYQT5, PYSIDE2, PythonQtError if PYQT5: from PyQt5.QtQuickWidgets import * elif PYSIDE2: from PySide2.QtQuickWidgets import * else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/QtSql.py000066400000000000000000000013001356743264500155050ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Provides QtSql classes and functions.""" # Local imports from . import PYQT5, PYSIDE2, PYQT4, PYSIDE, PythonQtError if PYQT5: from PyQt5.QtSql import * elif PYSIDE2: from PySide2.QtSql import * elif PYQT4: from PyQt4.QtSql import * elif PYSIDE: from PySide.QtSql import * else: raise PythonQtError('No Qt bindings could be found') del PYQT4, PYQT5, PYSIDE, PYSIDE2 git-cola-3.6/qtpy/QtSvg.py000066400000000000000000000013001356743264500155050ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Provides QtSvg classes and functions.""" # Local imports from . import PYQT4, PYSIDE2, PYQT5, PYSIDE, PythonQtError if PYQT5: from PyQt5.QtSvg import * elif PYSIDE2: from PySide2.QtSvg import * elif PYQT4: from PyQt4.QtSvg import * elif PYSIDE: from PySide.QtSvg import * else: raise PythonQtError('No Qt bindings could be found') del PYQT4, PYQT5, PYSIDE, PYSIDE2 git-cola-3.6/qtpy/QtTest.py000066400000000000000000000013011356743264500156660ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Copyright © 2014-2015 Colin Duquesnoy # Copyright © 2009- The Spyder Developmet Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) """ Provides QtTest and functions """ from . import PYQT5,PYSIDE2, PYQT4, PYSIDE, PythonQtError if PYQT5: from PyQt5.QtTest import QTest elif PYSIDE2: from PySide2.QtTest import QTest elif PYQT4: from PyQt4.QtTest import QTest as OldQTest class QTest(OldQTest): @staticmethod def qWaitForWindowActive(QWidget): OldQTest.qWaitForWindowShown(QWidget) elif PYSIDE: from PySide.QtTest import QTest else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/QtWebChannel.py000066400000000000000000000011151356743264500167600ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Provides QtWebChannel classes and functions.""" # Local imports from . import PYSIDE2, PYQT5, PythonQtError if PYQT5: from PyQt5.QtWebChannel import * elif PYSIDE2: from PySide2.QtWebChannel import * else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/QtWebEngineWidgets.py000066400000000000000000000027761356743264500201620ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Copyright © 2014-2015 Colin Duquesnoy # Copyright © 2009- The Spyder development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) """ Provides QtWebEngineWidgets classes and functions. """ from . import PYQT5,PYSIDE2, PYQT4, PYSIDE, PythonQtError # To test if we are using WebEngine or WebKit WEBENGINE = True if PYQT5: try: from PyQt5.QtWebEngineWidgets import QWebEnginePage from PyQt5.QtWebEngineWidgets import QWebEngineView from PyQt5.QtWebEngineWidgets import QWebEngineSettings except ImportError: from PyQt5.QtWebKitWidgets import QWebPage as QWebEnginePage from PyQt5.QtWebKitWidgets import QWebView as QWebEngineView from PyQt5.QtWebKit import QWebSettings as QWebEngineSettings WEBENGINE = False elif PYSIDE2: from PySide2.QtWebEngineWidgets import QWebEnginePage from PySide2.QtWebEngineWidgets import QWebEngineView from PySide2.QtWebEngineWidgets import QWebEngineSettings elif PYQT4: from PyQt4.QtWebKit import QWebPage as QWebEnginePage from PyQt4.QtWebKit import QWebView as QWebEngineView from PyQt4.QtWebKit import QWebSettings as QWebEngineSettings WEBENGINE = False elif PYSIDE: from PySide.QtWebKit import QWebPage as QWebEnginePage from PySide.QtWebKit import QWebView as QWebEngineView from PySide.QtWebKit import QWebSettings as QWebEngineSettings WEBENGINE = False else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/QtWebSockets.py000066400000000000000000000011151356743264500170230ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Provides QtWebSockets classes and functions.""" # Local imports from . import PYSIDE2, PYQT5, PythonQtError if PYQT5: from PyQt5.QtWebSockets import * elif PYSIDE2: from PySide2.QtWebSockets import * else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/QtWidgets.py000066400000000000000000000143031356743264500163630ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Copyright © 2014-2015 Colin Duquesnoy # Copyright © 2009- The Spyder Developmet Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) """ Provides widget classes and functions. .. warning:: Only PyQt4/PySide QtGui classes compatible with PyQt5.QtWidgets are exposed here. Therefore, you need to treat/use this package as if it were the ``PyQt5.QtWidgets`` module. """ from . import PYQT5, PYSIDE2, PYQT4, PYSIDE, PythonQtError from ._patch.qcombobox import patch_qcombobox from ._patch.qheaderview import introduce_renamed_methods_qheaderview if PYQT5: from PyQt5.QtWidgets import * elif PYSIDE2: from PySide2.QtWidgets import * elif PYQT4: from PyQt4.QtGui import * QStyleOptionViewItem = QStyleOptionViewItemV4 del QStyleOptionViewItemV4 # These objects belong to QtGui try: # Older versions of PyQt4 do not provide these del (QGlyphRun, QMatrix2x2, QMatrix2x3, QMatrix2x4, QMatrix3x2, QMatrix3x3, QMatrix3x4, QMatrix4x2, QMatrix4x3, QMatrix4x4, QQuaternion, QRadialGradient, QRawFont, QRegExpValidator, QStaticText, QTouchEvent, QVector2D, QVector3D, QVector4D, qFuzzyCompare) except NameError: pass del (QAbstractTextDocumentLayout, QActionEvent, QBitmap, QBrush, QClipboard, QCloseEvent, QColor, QConicalGradient, QContextMenuEvent, QCursor, QDesktopServices, QDoubleValidator, QDrag, QDragEnterEvent, QDragLeaveEvent, QDragMoveEvent, QDropEvent, QFileOpenEvent, QFocusEvent, QFont, QFontDatabase, QFontInfo, QFontMetrics, QFontMetricsF, QGradient, QHelpEvent, QHideEvent, QHoverEvent, QIcon, QIconDragEvent, QIconEngine, QImage, QImageIOHandler, QImageReader, QImageWriter, QInputEvent, QInputMethodEvent, QKeyEvent, QKeySequence, QLinearGradient, QMouseEvent, QMoveEvent, QMovie, QPaintDevice, QPaintEngine, QPaintEngineState, QPaintEvent, QPainter, QPainterPath, QPainterPathStroker, QPalette, QPen, QPicture, QPictureIO, QPixmap, QPixmapCache, QPolygon, QPolygonF, QRegion, QResizeEvent, QSessionManager, QShortcutEvent, QShowEvent, QStandardItem, QStandardItemModel, QStatusTipEvent, QSyntaxHighlighter, QTabletEvent, QTextBlock, QTextBlockFormat, QTextBlockGroup, QTextBlockUserData, QTextCharFormat, QTextCursor, QTextDocument, QTextDocumentFragment, QTextDocumentWriter, QTextFormat, QTextFragment, QTextFrame, QTextFrameFormat, QTextImageFormat, QTextInlineObject, QTextItem, QTextLayout, QTextLength, QTextLine, QTextList, QTextListFormat, QTextObject, QTextObjectInterface, QTextOption, QTextTable, QTextTableCell, QTextTableCellFormat, QTextTableFormat, QTransform, QValidator, QWhatsThisClickedEvent, QWheelEvent, QWindowStateChangeEvent, qAlpha, qBlue, qGray, qGreen, qIsGray, qRed, qRgb, qRgba, QIntValidator, QStringListModel) # These objects belong to QtPrintSupport del (QAbstractPrintDialog, QPageSetupDialog, QPrintDialog, QPrintEngine, QPrintPreviewDialog, QPrintPreviewWidget, QPrinter, QPrinterInfo) # These objects belong to QtCore del (QItemSelection, QItemSelectionModel, QItemSelectionRange, QSortFilterProxyModel) # Patch QComboBox to allow Python objects to be passed to userData patch_qcombobox(QComboBox) # QHeaderView: renamed methods introduce_renamed_methods_qheaderview(QHeaderView) elif PYSIDE: from PySide.QtGui import * QStyleOptionViewItem = QStyleOptionViewItemV4 del QStyleOptionViewItemV4 # These objects belong to QtGui del (QAbstractTextDocumentLayout, QActionEvent, QBitmap, QBrush, QClipboard, QCloseEvent, QColor, QConicalGradient, QContextMenuEvent, QCursor, QDesktopServices, QDoubleValidator, QDrag, QDragEnterEvent, QDragLeaveEvent, QDragMoveEvent, QDropEvent, QFileOpenEvent, QFocusEvent, QFont, QFontDatabase, QFontInfo, QFontMetrics, QFontMetricsF, QGradient, QHelpEvent, QHideEvent, QHoverEvent, QIcon, QIconDragEvent, QIconEngine, QImage, QImageIOHandler, QImageReader, QImageWriter, QInputEvent, QInputMethodEvent, QKeyEvent, QKeySequence, QLinearGradient, QMatrix2x2, QMatrix2x3, QMatrix2x4, QMatrix3x2, QMatrix3x3, QMatrix3x4, QMatrix4x2, QMatrix4x3, QMatrix4x4, QMouseEvent, QMoveEvent, QMovie, QPaintDevice, QPaintEngine, QPaintEngineState, QPaintEvent, QPainter, QPainterPath, QPainterPathStroker, QPalette, QPen, QPicture, QPictureIO, QPixmap, QPixmapCache, QPolygon, QPolygonF, QQuaternion, QRadialGradient, QRegExpValidator, QRegion, QResizeEvent, QSessionManager, QShortcutEvent, QShowEvent, QStandardItem, QStandardItemModel, QStatusTipEvent, QSyntaxHighlighter, QTabletEvent, QTextBlock, QTextBlockFormat, QTextBlockGroup, QTextBlockUserData, QTextCharFormat, QTextCursor, QTextDocument, QTextDocumentFragment, QTextFormat, QTextFragment, QTextFrame, QTextFrameFormat, QTextImageFormat, QTextInlineObject, QTextItem, QTextLayout, QTextLength, QTextLine, QTextList, QTextListFormat, QTextObject, QTextObjectInterface, QTextOption, QTextTable, QTextTableCell, QTextTableCellFormat, QTextTableFormat, QTouchEvent, QTransform, QValidator, QVector2D, QVector3D, QVector4D, QWhatsThisClickedEvent, QWheelEvent, QWindowStateChangeEvent, qAlpha, qBlue, qGray, qGreen, qIsGray, qRed, qRgb, qRgba, QIntValidator, QStringListModel) # These objects belong to QtPrintSupport del (QAbstractPrintDialog, QPageSetupDialog, QPrintDialog, QPrintEngine, QPrintPreviewDialog, QPrintPreviewWidget, QPrinter, QPrinterInfo) # These objects belong to QtCore del (QItemSelection, QItemSelectionModel, QItemSelectionRange, QSortFilterProxyModel) # Patch QComboBox to allow Python objects to be passed to userData patch_qcombobox(QComboBox) # QHeaderView: renamed methods introduce_renamed_methods_qheaderview(QHeaderView) else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/QtXmlPatterns.py000066400000000000000000000013051356743264500172340ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Provides QtXmlPatterns classes and functions.""" # Local imports from . import PYQT4, PYSIDE2, PYQT5, PYSIDE, PythonQtError if PYQT5: from PyQt5.QtXmlPatterns import * elif PYSIDE2: from PySide2.QtXmlPatterns import * elif PYQT4: from PyQt4.QtXmlPatterns import * elif PYSIDE: from PySide.QtXmlPatterns import * else: raise PythonQtError('No Qt bindings could be found') git-cola-3.6/qtpy/__init__.py000066400000000000000000000156771356743264500162260ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Copyright © 2009- The Spyder Development Team # Copyright © 2014-2015 Colin Duquesnoy # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) """ **QtPy** is a shim over the various Python Qt bindings. It is used to write Qt binding indenpendent libraries or applications. If one of the APIs has already been imported, then it will be used. Otherwise, the shim will automatically select the first available API (PyQt5, PySide2, PyQt4 and finally PySide); in that case, you can force the use of one specific bindings (e.g. if your application is using one specific bindings and you need to use library that use QtPy) by setting up the ``QT_API`` environment variable. PyQt5 ===== For PyQt5, you don't have to set anything as it will be used automatically:: >>> from qtpy import QtGui, QtWidgets, QtCore >>> print(QtWidgets.QWidget) PySide2 ====== Set the QT_API environment variable to 'pyside2' before importing other packages:: >>> import os >>> os.environ['QT_API'] = 'pyside2' >>> from qtpy import QtGui, QtWidgets, QtCore >>> print(QtWidgets.QWidget) PyQt4 ===== Set the ``QT_API`` environment variable to 'pyqt' before importing any python package:: >>> import os >>> os.environ['QT_API'] = 'pyqt' >>> from qtpy import QtGui, QtWidgets, QtCore >>> print(QtWidgets.QWidget) PySide ====== Set the QT_API environment variable to 'pyside' before importing other packages:: >>> import os >>> os.environ['QT_API'] = 'pyside' >>> from qtpy import QtGui, QtWidgets, QtCore >>> print(QtWidgets.QWidget) """ from distutils.version import LooseVersion import os import platform import sys import warnings # Version of QtPy from ._version import __version__ class PythonQtError(RuntimeError): """Error raise if no bindings could be selected.""" pass class PythonQtWarning(Warning): """Warning if some features are not implemented in a binding.""" pass # Qt API environment variable name QT_API = 'QT_API' # Names of the expected PyQt5 api PYQT5_API = ['pyqt5'] # Names of the expected PyQt4 api PYQT4_API = [ 'pyqt', # name used in IPython.qt 'pyqt4' # pyqode.qt original name ] # Names of the expected PySide api PYSIDE_API = ['pyside'] # Names of the expected PySide2 api PYSIDE2_API = ['pyside2'] # Detecting if a binding was specified by the user binding_specified = QT_API in os.environ # Setting a default value for QT_API os.environ.setdefault(QT_API, 'pyqt5') API = os.environ[QT_API].lower() initial_api = API assert API in (PYQT5_API + PYQT4_API + PYSIDE_API + PYSIDE2_API) is_old_pyqt = is_pyqt46 = False PYQT5 = True PYQT4 = PYSIDE = PYSIDE2 = False # When `FORCE_QT_API` is set, we disregard # any previously imported python bindings. if os.environ.get('FORCE_QT_API') is not None: if 'PyQt5' in sys.modules: API = initial_api if initial_api in PYQT5_API else 'pyqt5' elif 'PySide2' in sys.modules: API = initial_api if initial_api in PYSIDE2_API else 'pyside2' elif 'PyQt4' in sys.modules: API = initial_api if initial_api in PYQT4_API else 'pyqt4' elif 'PySide' in sys.modules: API = initial_api if initial_api in PYSIDE_API else 'pyside' if API in PYQT5_API: try: from PyQt5.QtCore import PYQT_VERSION_STR as PYQT_VERSION # analysis:ignore from PyQt5.QtCore import QT_VERSION_STR as QT_VERSION # analysis:ignore PYSIDE_VERSION = None if sys.platform == 'darwin': macos_version = LooseVersion(platform.mac_ver()[0]) if macos_version < LooseVersion('10.10'): if LooseVersion(QT_VERSION) >= LooseVersion('5.9'): raise PythonQtError("Qt 5.9 or higher only works in " "macOS 10.10 or higher. Your " "program will fail in this " "system.") elif macos_version < LooseVersion('10.11'): if LooseVersion(QT_VERSION) >= LooseVersion('5.11'): raise PythonQtError("Qt 5.11 or higher only works in " "macOS 10.11 or higher. Your " "program will fail in this " "system.") del macos_version except ImportError: API = os.environ['QT_API'] = 'pyside2' if API in PYSIDE2_API: try: from PySide2 import __version__ as PYSIDE_VERSION # analysis:ignore from PySide2.QtCore import __version__ as QT_VERSION # analysis:ignore PYQT_VERSION = None PYQT5 = False PYSIDE2 = True if sys.platform == 'darwin': macos_version = LooseVersion(platform.mac_ver()[0]) if macos_version < LooseVersion('10.11'): if LooseVersion(QT_VERSION) >= LooseVersion('5.11'): raise PythonQtError("Qt 5.11 or higher only works in " "macOS 10.11 or higher. Your " "program will fail in this " "system.") del macos_version except ImportError: API = os.environ['QT_API'] = 'pyqt' if API in PYQT4_API: try: import sip try: sip.setapi('QString', 2) sip.setapi('QVariant', 2) sip.setapi('QDate', 2) sip.setapi('QDateTime', 2) sip.setapi('QTextStream', 2) sip.setapi('QTime', 2) sip.setapi('QUrl', 2) except (AttributeError, ValueError): # PyQt < v4.6 pass from PyQt4.Qt import PYQT_VERSION_STR as PYQT_VERSION # analysis:ignore from PyQt4.Qt import QT_VERSION_STR as QT_VERSION # analysis:ignore PYSIDE_VERSION = None PYQT5 = False PYQT4 = True except ImportError: API = os.environ['QT_API'] = 'pyside' else: is_old_pyqt = PYQT_VERSION.startswith(('4.4', '4.5', '4.6', '4.7')) is_pyqt46 = PYQT_VERSION.startswith('4.6') if API in PYSIDE_API: try: from PySide import __version__ as PYSIDE_VERSION # analysis:ignore from PySide.QtCore import __version__ as QT_VERSION # analysis:ignore PYQT_VERSION = None PYQT5 = PYSIDE2 = False PYSIDE = True except ImportError: raise PythonQtError('No Qt bindings could be found') # If a correct API name is passed to QT_API and it could not be found, # switches to another and informs through the warning if API != initial_api and binding_specified: warnings.warn('Selected binding "{}" could not be found, ' 'using "{}"'.format(initial_api, API), RuntimeWarning) API_NAME = {'pyqt5': 'PyQt5', 'pyqt': 'PyQt4', 'pyqt4': 'PyQt4', 'pyside': 'PySide', 'pyside2':'PySide2'}[API] if PYQT4: import sip try: API_NAME += (" (API v{0})".format(sip.getapi('QString'))) except AttributeError: pass git-cola-3.6/qtpy/_patch/000077500000000000000000000000001356743264500153335ustar00rootroot00000000000000git-cola-3.6/qtpy/_patch/__init__.py000066400000000000000000000000001356743264500174320ustar00rootroot00000000000000git-cola-3.6/qtpy/_patch/qcombobox.py000066400000000000000000000100461356743264500176770ustar00rootroot00000000000000# The code below, as well as the associated test were adapted from # qt-helpers, which was released under a 3-Clause BSD license: # # Copyright (c) 2015, Chris Beaumont and Thomas Robitaille # # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the # distribution. # * Neither the name of the Glue project nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. def patch_qcombobox(QComboBox): """ In PySide, using Python objects as userData in QComboBox causes Segmentation faults under certain conditions. Even in cases where it doesn't, findData does not work correctly. Likewise, findData also does not work correctly with Python objects when using PyQt4. On the other hand, PyQt5 deals with this case correctly. We therefore patch QComboBox when using PyQt4 and PySide to avoid issues. """ from ..QtGui import QIcon from ..QtCore import Qt, QObject class userDataWrapper(): """ This class is used to wrap any userData object. If we don't do this, then certain types of objects can cause segmentation faults or issues depending on whether/how __getitem__ is defined. """ def __init__(self, data): self.data = data _addItem = QComboBox.addItem def addItem(self, *args, **kwargs): if len(args) == 3 or (not isinstance(args[0], QIcon) and len(args) == 2): args, kwargs['userData'] = args[:-1], args[-1] if 'userData' in kwargs: kwargs['userData'] = userDataWrapper(kwargs['userData']) _addItem(self, *args, **kwargs) _insertItem = QComboBox.insertItem def insertItem(self, *args, **kwargs): if len(args) == 4 or (not isinstance(args[1], QIcon) and len(args) == 3): args, kwargs['userData'] = args[:-1], args[-1] if 'userData' in kwargs: kwargs['userData'] = userDataWrapper(kwargs['userData']) _insertItem(self, *args, **kwargs) _setItemData = QComboBox.setItemData def setItemData(self, index, value, role=Qt.UserRole): value = userDataWrapper(value) _setItemData(self, index, value, role=role) _itemData = QComboBox.itemData def itemData(self, index, role=Qt.UserRole): userData = _itemData(self, index, role=role) if isinstance(userData, userDataWrapper): userData = userData.data return userData def findData(self, value): for i in range(self.count()): if self.itemData(i) == value: return i return -1 QComboBox.addItem = addItem QComboBox.insertItem = insertItem QComboBox.setItemData = setItemData QComboBox.itemData = itemData QComboBox.findData = findDatagit-cola-3.6/qtpy/_patch/qheaderview.py000066400000000000000000000064201356743264500202130ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Copyright © The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) import warnings def introduce_renamed_methods_qheaderview(QHeaderView): _isClickable = QHeaderView.isClickable def sectionsClickable(self): """ QHeaderView.sectionsClickable() -> bool """ return _isClickable(self) QHeaderView.sectionsClickable = sectionsClickable def isClickable(self): warnings.warn('isClickable is only available in Qt4. Use ' 'sectionsClickable instead.', stacklevel=2) return _isClickable(self) QHeaderView.isClickable = isClickable _isMovable = QHeaderView.isMovable def sectionsMovable(self): """ QHeaderView.sectionsMovable() -> bool """ return _isMovable(self) QHeaderView.sectionsMovable = sectionsMovable def isMovable(self): warnings.warn('isMovable is only available in Qt4. Use ' 'sectionsMovable instead.', stacklevel=2) return _isMovable(self) QHeaderView.isMovable = isMovable _resizeMode = QHeaderView.resizeMode def sectionResizeMode(self, logicalIndex): """ QHeaderView.sectionResizeMode(int) -> QHeaderView.ResizeMode """ return _resizeMode(self, logicalIndex) QHeaderView.sectionResizeMode = sectionResizeMode def resizeMode(self, logicalIndex): warnings.warn('resizeMode is only available in Qt4. Use ' 'sectionResizeMode instead.', stacklevel=2) return _resizeMode(self, logicalIndex) QHeaderView.resizeMode = resizeMode _setClickable = QHeaderView.setClickable def setSectionsClickable(self, clickable): """ QHeaderView.setSectionsClickable(bool) """ return _setClickable(self, clickable) QHeaderView.setSectionsClickable = setSectionsClickable def setClickable(self, clickable): warnings.warn('setClickable is only available in Qt4. Use ' 'setSectionsClickable instead.', stacklevel=2) return _setClickable(self, clickable) QHeaderView.setClickable = setClickable _setMovable = QHeaderView.setMovable def setSectionsMovable(self, movable): """ QHeaderView.setSectionsMovable(bool) """ return _setMovable(self, movable) QHeaderView.setSectionsMovable = setSectionsMovable def setMovable(self, movable): warnings.warn('setMovable is only available in Qt4. Use ' 'setSectionsMovable instead.', stacklevel=2) return _setMovable(self, movable) QHeaderView.setMovable = setMovable _setResizeMode = QHeaderView.setResizeMode def setSectionResizeMode(self, *args): """ QHeaderView.setSectionResizeMode(QHeaderView.ResizeMode) QHeaderView.setSectionResizeMode(int, QHeaderView.ResizeMode) """ _setResizeMode(self, *args) QHeaderView.setSectionResizeMode = setSectionResizeMode def setResizeMode(self, *args): warnings.warn('setResizeMode is only available in Qt4. Use ' 'setSectionResizeMode instead.', stacklevel=2) _setResizeMode(self, *args) QHeaderView.setResizeMode = setResizeMode git-cola-3.6/qtpy/_version.py000066400000000000000000000001101356743264500162630ustar00rootroot00000000000000version_info = (1, 9, 0) __version__ = '.'.join(map(str, version_info)) git-cola-3.6/qtpy/compat.py000066400000000000000000000170641356743264500157420ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Copyright © 2009- The Spyder Development Team # Licensed under the terms of the MIT License """ Compatibility functions """ from __future__ import print_function import sys import collections from . import PYQT4 from .QtWidgets import QFileDialog from .py3compat import is_text_string, to_text_string, TEXT_TYPES # ============================================================================= # QVariant conversion utilities # ============================================================================= PYQT_API_1 = False if PYQT4: import sip try: PYQT_API_1 = sip.getapi('QVariant') == 1 # PyQt API #1 except AttributeError: # PyQt =v4.4 (API #1 and #2) and PySide >=v1.0""" # Calling QFileDialog static method if sys.platform == "win32": # On Windows platforms: redirect standard outputs _temp1, _temp2 = sys.stdout, sys.stderr sys.stdout, sys.stderr = None, None try: result = QFileDialog.getExistingDirectory(parent, caption, basedir, options) finally: if sys.platform == "win32": # On Windows platforms: restore standard outputs sys.stdout, sys.stderr = _temp1, _temp2 if not is_text_string(result): # PyQt API #1 result = to_text_string(result) return result def _qfiledialog_wrapper(attr, parent=None, caption='', basedir='', filters='', selectedfilter='', options=None): if options is None: options = QFileDialog.Options(0) try: # PyQt =v4.6 QString = None # analysis:ignore tuple_returned = True try: # PyQt >=v4.6 func = getattr(QFileDialog, attr+'AndFilter') except AttributeError: # PySide or PyQt =v4.6 output, selectedfilter = result else: # PyQt =v4.4 (API #1 and #2) and PySide >=v1.0""" return _qfiledialog_wrapper('getOpenFileName', parent=parent, caption=caption, basedir=basedir, filters=filters, selectedfilter=selectedfilter, options=options) def getopenfilenames(parent=None, caption='', basedir='', filters='', selectedfilter='', options=None): """Wrapper around QtGui.QFileDialog.getOpenFileNames static method Returns a tuple (filenames, selectedfilter) -- when dialog box is canceled, returns a tuple (empty list, empty string) Compatible with PyQt >=v4.4 (API #1 and #2) and PySide >=v1.0""" return _qfiledialog_wrapper('getOpenFileNames', parent=parent, caption=caption, basedir=basedir, filters=filters, selectedfilter=selectedfilter, options=options) def getsavefilename(parent=None, caption='', basedir='', filters='', selectedfilter='', options=None): """Wrapper around QtGui.QFileDialog.getSaveFileName static method Returns a tuple (filename, selectedfilter) -- when dialog box is canceled, returns a tuple of empty strings Compatible with PyQt >=v4.4 (API #1 and #2) and PySide >=v1.0""" return _qfiledialog_wrapper('getSaveFileName', parent=parent, caption=caption, basedir=basedir, filters=filters, selectedfilter=selectedfilter, options=options) git-cola-3.6/qtpy/py3compat.py000066400000000000000000000144431356743264500163740ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Copyright © 2012-2013 Pierre Raybaut # Licensed under the terms of the MIT License # (see spyderlib/__init__.py for details) """ spyderlib.py3compat ------------------- Transitional module providing compatibility functions intended to help migrating from Python 2 to Python 3. This module should be fully compatible with: * Python >=v2.6 * Python 3 """ from __future__ import print_function import sys import os PY2 = sys.version_info[0] == 2 PY3 = sys.version_info[0] == 3 PY33 = PY3 and sys.version_info[1] >= 3 # ============================================================================= # Data types # ============================================================================= if PY2: # Python 2 TEXT_TYPES = (str, unicode) INT_TYPES = (int, long) else: # Python 3 TEXT_TYPES = (str,) INT_TYPES = (int,) NUMERIC_TYPES = tuple(list(INT_TYPES) + [float, complex]) # ============================================================================= # Renamed/Reorganized modules # ============================================================================= if PY2: # Python 2 import __builtin__ as builtins import ConfigParser as configparser try: import _winreg as winreg except ImportError: pass from sys import maxint as maxsize try: import CStringIO as io except ImportError: import StringIO as io try: import cPickle as pickle except ImportError: import pickle from UserDict import DictMixin as MutableMapping import thread as _thread import repr as reprlib else: # Python 3 import builtins import configparser try: import winreg except ImportError: pass from sys import maxsize import io import pickle if PY33: from collections.abc import MutableMapping else: from collections import MutableMapping import _thread import reprlib # ============================================================================= # Strings # ============================================================================= if PY2: # Python 2 import codecs def u(obj): """Make unicode object""" return codecs.unicode_escape_decode(obj)[0] else: # Python 3 def u(obj): """Return string as it is""" return obj def is_text_string(obj): """Return True if `obj` is a text string, False if it is anything else, like binary data (Python 3) or QString (Python 2, PyQt API #1)""" if PY2: # Python 2 return isinstance(obj, basestring) else: # Python 3 return isinstance(obj, str) def is_binary_string(obj): """Return True if `obj` is a binary string, False if it is anything else""" if PY2: # Python 2 return isinstance(obj, str) else: # Python 3 return isinstance(obj, bytes) def is_string(obj): """Return True if `obj` is a text or binary Python string object, False if it is anything else, like a QString (Python 2, PyQt API #1)""" return is_text_string(obj) or is_binary_string(obj) def is_unicode(obj): """Return True if `obj` is unicode""" if PY2: # Python 2 return isinstance(obj, unicode) else: # Python 3 return isinstance(obj, str) def to_text_string(obj, encoding=None): """Convert `obj` to (unicode) text string""" if PY2: # Python 2 if encoding is None: return unicode(obj) else: return unicode(obj, encoding) else: # Python 3 if encoding is None: return str(obj) elif isinstance(obj, str): # In case this function is not used properly, this could happen return obj else: return str(obj, encoding) def to_binary_string(obj, encoding=None): """Convert `obj` to binary string (bytes in Python 3, str in Python 2)""" if PY2: # Python 2 if encoding is None: return str(obj) else: return obj.encode(encoding) else: # Python 3 return bytes(obj, 'utf-8' if encoding is None else encoding) # ============================================================================= # Function attributes # ============================================================================= def get_func_code(func): """Return function code object""" if PY2: # Python 2 return func.func_code else: # Python 3 return func.__code__ def get_func_name(func): """Return function name""" if PY2: # Python 2 return func.func_name else: # Python 3 return func.__name__ def get_func_defaults(func): """Return function default argument values""" if PY2: # Python 2 return func.func_defaults else: # Python 3 return func.__defaults__ # ============================================================================= # Special method attributes # ============================================================================= def get_meth_func(obj): """Return method function object""" if PY2: # Python 2 return obj.im_func else: # Python 3 return obj.__func__ def get_meth_class_inst(obj): """Return method class instance""" if PY2: # Python 2 return obj.im_self else: # Python 3 return obj.__self__ def get_meth_class(obj): """Return method class""" if PY2: # Python 2 return obj.im_class else: # Python 3 return obj.__self__.__class__ # ============================================================================= # Misc. # ============================================================================= if PY2: # Python 2 input = raw_input getcwd = os.getcwdu cmp = cmp import string str_lower = string.lower from itertools import izip_longest as zip_longest else: # Python 3 input = input getcwd = os.getcwd def cmp(a, b): return (a > b) - (a < b) str_lower = str.lower from itertools import zip_longest def qbytearray_to_str(qba): """Convert QByteArray object to str in a way compatible with Python 2/3""" return str(bytes(qba.toHex().data()).decode()) git-cola-3.6/qtpy/uic.py000066400000000000000000000223561356743264500152370ustar00rootroot00000000000000import os from . import PYSIDE, PYSIDE2, PYQT4, PYQT5 from .QtWidgets import QComboBox if PYQT5: from PyQt5.uic import * elif PYQT4: from PyQt4.uic import * else: __all__ = ['loadUi'] # In PySide, loadUi does not exist, so we define it using QUiLoader, and # then make sure we expose that function. This is adapted from qt-helpers # which was released under a 3-clause BSD license: # qt-helpers - a common front-end to various Qt modules # # Copyright (c) 2015, Chris Beaumont and Thomas Robitaille # # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the # distribution. # * Neither the name of the Glue project nor the names of its contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # Which itself was based on the solution at # # https://gist.github.com/cpbotha/1b42a20c8f3eb9bb7cb8 # # which was released under the MIT license: # # Copyright (c) 2011 Sebastian Wiesner # Modifications by Charl Botha # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. if PYSIDE: from PySide.QtCore import QMetaObject from PySide.QtUiTools import QUiLoader elif PYSIDE2: from PySide2.QtCore import QMetaObject from PySide2.QtUiTools import QUiLoader class UiLoader(QUiLoader): """ Subclass of :class:`~PySide.QtUiTools.QUiLoader` to create the user interface in a base instance. Unlike :class:`~PySide.QtUiTools.QUiLoader` itself this class does not create a new instance of the top-level widget, but creates the user interface in an existing instance of the top-level class if needed. This mimics the behaviour of :func:`PyQt4.uic.loadUi`. """ def __init__(self, baseinstance, customWidgets=None): """ Create a loader for the given ``baseinstance``. The user interface is created in ``baseinstance``, which must be an instance of the top-level class in the user interface to load, or a subclass thereof. ``customWidgets`` is a dictionary mapping from class name to class object for custom widgets. Usually, this should be done by calling registerCustomWidget on the QUiLoader, but with PySide 1.1.2 on Ubuntu 12.04 x86_64 this causes a segfault. ``parent`` is the parent object of this loader. """ QUiLoader.__init__(self, baseinstance) self.baseinstance = baseinstance if customWidgets is None: self.customWidgets = {} else: self.customWidgets = customWidgets def createWidget(self, class_name, parent=None, name=''): """ Function that is called for each widget defined in ui file, overridden here to populate baseinstance instead. """ if parent is None and self.baseinstance: # supposed to create the top-level widget, return the base # instance instead return self.baseinstance else: # For some reason, Line is not in the list of available # widgets, but works fine, so we have to special case it here. if class_name in self.availableWidgets() or class_name == 'Line': # create a new widget for child widgets widget = QUiLoader.createWidget(self, class_name, parent, name) else: # If not in the list of availableWidgets, must be a custom # widget. This will raise KeyError if the user has not # supplied the relevant class_name in the dictionary or if # customWidgets is empty. try: widget = self.customWidgets[class_name](parent) except KeyError: raise Exception('No custom widget ' + class_name + ' ' 'found in customWidgets') if self.baseinstance: # set an attribute for the new child widget on the base # instance, just like PyQt4.uic.loadUi does. setattr(self.baseinstance, name, widget) return widget def _get_custom_widgets(ui_file): """ This function is used to parse a ui file and look for the section, then automatically load all the custom widget classes. """ import sys import importlib from xml.etree.ElementTree import ElementTree # Parse the UI file etree = ElementTree() ui = etree.parse(ui_file) # Get the customwidgets section custom_widgets = ui.find('customwidgets') if custom_widgets is None: return {} custom_widget_classes = {} for custom_widget in custom_widgets.getchildren(): cw_class = custom_widget.find('class').text cw_header = custom_widget.find('header').text module = importlib.import_module(cw_header) custom_widget_classes[cw_class] = getattr(module, cw_class) return custom_widget_classes def loadUi(uifile, baseinstance=None, workingDirectory=None): """ Dynamically load a user interface from the given ``uifile``. ``uifile`` is a string containing a file name of the UI file to load. If ``baseinstance`` is ``None``, the a new instance of the top-level widget will be created. Otherwise, the user interface is created within the given ``baseinstance``. In this case ``baseinstance`` must be an instance of the top-level widget class in the UI file to load, or a subclass thereof. In other words, if you've created a ``QMainWindow`` interface in the designer, ``baseinstance`` must be a ``QMainWindow`` or a subclass thereof, too. You cannot load a ``QMainWindow`` UI file with a plain :class:`~PySide.QtGui.QWidget` as ``baseinstance``. :method:`~PySide.QtCore.QMetaObject.connectSlotsByName()` is called on the created user interface, so you can implemented your slots according to its conventions in your widget class. Return ``baseinstance``, if ``baseinstance`` is not ``None``. Otherwise return the newly created instance of the user interface. """ # We parse the UI file and import any required custom widgets customWidgets = _get_custom_widgets(uifile) loader = UiLoader(baseinstance, customWidgets) if workingDirectory is not None: loader.setWorkingDirectory(workingDirectory) widget = loader.load(uifile) QMetaObject.connectSlotsByName(widget) return widget git-cola-3.6/requirements/000077500000000000000000000000001356743264500156235ustar00rootroot00000000000000git-cola-3.6/requirements/requirements-dev.txt000066400000000000000000000004301356743264500216600ustar00rootroot00000000000000# Documentation Sphinx # Test flake8 mock pbr # Check astroid==2.2.5; python_version >= '3.0' pylint==2.3.1; python_version >= '3.0' astroid==1.6.5; python_version < '3.0' enum34==1.1.6; python_version < '3.0' pylint==1.9.4; python_version < '3.0' PyYAML pytest>=3.6 pytest-cov git-cola-3.6/requirements/requirements-maint.txt000066400000000000000000000000641356743264500222150ustar00rootroot00000000000000# Maintainer packages ## Windows installer pynsist git-cola-3.6/requirements/requirements.txt000066400000000000000000000000051356743264500211020ustar00rootroot00000000000000qtpy git-cola-3.6/setup.cfg000066400000000000000000000004621356743264500147230ustar00rootroot00000000000000[bdist_rpm] release = 1 requires = python PyQt4 build_requires = python PyQt4 doc_files = COPYING COPYRIGHT README.md share/doc/git-cola/ [upload_sphinx] upload-dir = share/doc/git-cola/_build/html [build_sphinx] all_files = 1 build-dir = share/doc/git-cola/_build source-dir = share/doc/git-cola/ git-cola-3.6/setup.py000077500000000000000000000073421356743264500146230ustar00rootroot00000000000000#!/usr/bin/env python # git-cola installer # usage: use the Makefile instead of invoking this script directly. # pylint: disable=import-error,no-name-in-module from __future__ import absolute_import, division, unicode_literals from glob import glob from distutils.command import build_scripts from distutils.core import setup import os import re import sys from extras import cmdclass from extras import build_helpers # Hack: prevent python2's ascii default encoding from breaking inside # distutils when installing from utf-8 paths. if sys.version_info[0] < 3: # pylint: disable=reload-builtin,undefined-variable reload(sys) # noqa # pylint: disable=no-member sys.setdefaultencoding('utf-8') # Prevent distuils from changing "#!/usr/bin/env python" when # --use-env-python is specified. try: sys.argv.remove('--use-env-python') use_env_python = True except ValueError: use_env_python = False if use_env_python: build_scripts.first_line_re = re.compile(r'^should not match$') # Disable vendoring of qtpy and friends by passing --no-vendor-libs try: sys.argv.remove('--no-vendor-libs') vendor_libs = False except ValueError: vendor_libs = not os.getenv('GIT_COLA_NO_VENDOR_LIBS', '') here = os.path.dirname(__file__) version = os.path.join(here, 'cola', '_version.py') scope = {} exec(open(version).read(), scope) # pylint: disable=exec-used version = scope['VERSION'] def main(): """Runs distutils.setup()""" scripts = [ 'bin/git-cola', 'bin/git-dag', ] if sys.platform == 'win32': scripts.append('contrib/win32/cola') # Helper scripts are installed to share/git-cola/bin and are visible to # git-cola only. Adding scripts to build_helpers.scripts will make them # available for #! updating. build_helpers.helpers = [ 'share/git-cola/bin/git-xbase', ] setup(name='git-cola', version=version, description='The highly caffeinated git GUI', long_description='A sleek and powerful git GUI', license='GPLv2', author='David Aguilar', author_email='davvid@gmail.com', url='https://git-cola.github.io/', scripts=scripts, cmdclass=cmdclass, platforms='any', data_files=_data_files()) def _data_files(): """Return the list of data files""" data = [ _app_path('share/git-cola/bin', '*'), _app_path('share/git-cola/icons', '*.png'), _app_path('share/git-cola/icons', '*.svg'), _app_path('share/git-cola/icons/dark', '*.png'), _app_path('share/git-cola/icons/dark', '*.svg'), _app_path('share/appdata', '*.xml'), _app_path('share/applications', '*.desktop'), _app_path('share/doc/git-cola', '*.rst'), _app_path('share/doc/git-cola', '*.html'), _package('cola'), _package('cola.models'), _package('cola.widgets'), ] if vendor_libs: data.extend([ _package('qtpy'), _package('qtpy._patch'), ]) data.extend([_app_path(localedir, 'git-cola.mo') for localedir in glob('share/locale/*/LC_MESSAGES')]) return data def _package(package, subdirs=None): """Collect python files for a given python "package" name""" dirs = package.split('.') app_dir = _lib_path(*dirs) if subdirs: dirs = list(subdirs) + dirs src_dir = os.path.join(*dirs) return (app_dir, glob(os.path.join(src_dir, '*.py'))) def _lib_path(*dirs): return os.path.join('share', 'git-cola', 'lib', *dirs) def _app_path(dirname, entry): """Construct (dirname, [glob-expanded-entries relative to dirname])""" return (dirname, glob(os.path.join(dirname, entry))) if __name__ == '__main__': main() git-cola-3.6/share/000077500000000000000000000000001356743264500142025ustar00rootroot00000000000000git-cola-3.6/share/appdata/000077500000000000000000000000001356743264500156145ustar00rootroot00000000000000git-cola-3.6/share/appdata/git-cola.appdata.xml000066400000000000000000000012361356743264500214500ustar00rootroot00000000000000 git-cola.desktop CC0-1.0 GPL-2.0 Git Cola Sleek and powerful Git GUI

git-cola is a simple, powerful, and feature-rich GUI for git that provides an easy way to interact with Git repositories.

https://git-cola.github.io/images/screenshot-main-linux.png https://git-cola.github.io/
git-cola-3.6/share/appdata/git-dag.appdata.xml000066400000000000000000000003621356743264500212640ustar00rootroot00000000000000 CC0-1.0 git-dag.desktop git-cola.desktop git-cola-3.6/share/applications/000077500000000000000000000000001356743264500166705ustar00rootroot00000000000000git-cola-3.6/share/applications/git-cola-folder-handler.desktop000066400000000000000000000003311356743264500246430ustar00rootroot00000000000000[Desktop Entry] Name=Git Cola TryExec=git-cola Exec=git-cola --repo %f Icon=git-cola NoDisplay=true Terminal=false StartupNotify=true Type=Application Categories=Development;RevisionControl; MimeType=inode/directory; git-cola-3.6/share/applications/git-cola.desktop000066400000000000000000000005251356743264500217640ustar00rootroot00000000000000[Desktop Entry] Name=Git Cola Comment=The highly caffeinated Git GUI Comment[cs]=Git GUI s vysokým obsahem kofeinu Comment[zh_TW]=高咖啡因含量的 Git 圖形介面 TryExec=git-cola Exec=git-cola --prompt Icon=git-cola StartupNotify=true Terminal=false Type=Application Categories=Development;RevisionControl; X-KDE-SubstituteUID=false git-cola-3.6/share/applications/git-dag.desktop000066400000000000000000000003211356743264500215730ustar00rootroot00000000000000[Desktop Entry] Name=Git DAG Comment=Git DAG visualizer Exec=git-dag --prompt Icon=git-cola StartupNotify=true Terminal=false Type=Application Categories=Development;RevisionControl; X-KDE-SubstituteUID=false git-cola-3.6/share/doc/000077500000000000000000000000001356743264500147475ustar00rootroot00000000000000git-cola-3.6/share/doc/git-cola/000077500000000000000000000000001356743264500164465ustar00rootroot00000000000000git-cola-3.6/share/doc/git-cola/.gitignore000066400000000000000000000000101356743264500204250ustar00rootroot00000000000000/_build git-cola-3.6/share/doc/git-cola/Makefile000066400000000000000000000053731356743264500201160ustar00rootroot00000000000000prefix ?= $(CURDIR) docdir ?= $(prefix)/share/doc/git-cola htmldir ?= $(docdir)/html mandir ?= $(prefix)/share/man/man1 # DESTDIR = # External commands INSTALL ?= install MKDIR_P ?= mkdir -p RSYNC ?= rsync SED ?= sed RSYNC_FLAGS = -r --delete --delete-excluded RSYNC_FLAGS += --exclude=.buildinfo --exclude=.gitignore RSYNC_CMD = $(RSYNC) $(RSYNC_FLAGS) SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: all help clean html man dirhtml pickle json .PHONY: htmlhelp qthelp latex changes linkcheck doctest .PHONY: install install-files install-html install-man # The default target of this makefile is... all:: html man help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " man to make manual pages" @echo " dirhtml to make HTML files named index.html in directories" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf _build/doctrees _build/man _build/html/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) _build/man dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) _build/dirhtml pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) _build/json htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) _build/qthelp latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) _build/doctest install: install-files install-html install-man install-files: $(MKDIR_P) $(DESTDIR)$(docdir) $(INSTALL) -m 644 *.html $(DESTDIR)$(docdir) $(INSTALL) -m 644 *.rst $(DESTDIR)$(docdir) install-html: install-files html $(MKDIR_P) $(DESTDIR)$(htmldir) $(RSYNC_CMD) _build/html/ $(DESTDIR)$(htmldir)/ install-man: man $(MKDIR_P) $(DESTDIR)$(mandir) $(INSTALL) -m 644 _build/man/git-cola.1 $(DESTDIR)$(mandir) $(INSTALL) -m 644 _build/man/git-dag.1 $(DESTDIR)$(mandir) git-cola-3.6/share/doc/git-cola/_static/000077500000000000000000000000001356743264500200745ustar00rootroot00000000000000git-cola-3.6/share/doc/git-cola/_static/.gitignore000066400000000000000000000000001356743264500220520ustar00rootroot00000000000000git-cola-3.6/share/doc/git-cola/_templates/000077500000000000000000000000001356743264500206035ustar00rootroot00000000000000git-cola-3.6/share/doc/git-cola/_templates/.gitignore000066400000000000000000000000011356743264500225620ustar00rootroot00000000000000 git-cola-3.6/share/doc/git-cola/conf.py000066400000000000000000000027431356743264500177530ustar00rootroot00000000000000# -*- coding: utf-8 -*- import os import sys # Add the cola source directory to sys.path abspath = os.path.abspath(os.path.realpath(__file__)) docdir = os.path.dirname(os.path.dirname(abspath)) srcdir = os.path.dirname(os.path.dirname(docdir)) extrasdir = os.path.join(srcdir, 'extras') sys.path.insert(1, extrasdir) extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinxtogithub'] templates_path = ['_templates'] source_suffix = '.rst' source_encoding = 'utf-8' master_doc = 'index' project = 'git-cola' copyright = '2007-2017, David Aguilar and contributors' authors = 'David Aguilar and contributors' versionfile = os.path.join(srcdir, 'cola', '_version.py') scope = {} with open(versionfile) as f: exec(f.read(), scope) # The short X.Y version. version = scope['VERSION'] # The full version, including alpha/beta/rc tags. release = version exclude_trees = ['_build'] add_function_parentheses = True pygments_style = 'default' html_theme = 'default' html_theme_path = ['_themes'] html_static_path = ['_static'] html_show_sourcelink = True htmlhelp_basename = 'git-cola-doc' man_pages = [ ('git-cola', 'git-cola', 'The highly caffeinated Git GUI', authors, '1'), ('git-dag', 'git-dag', 'The sleek and powerful Git history browser', authors, '1'), ] latex_documents = [ ('index', 'git-cola.tex', 'git-cola Documentation', 'David Aguilar and contributors', 'manual'), ] git-cola-3.6/share/doc/git-cola/git-cola.rst000066400000000000000000000756131356743264500207130ustar00rootroot00000000000000=========== git-cola(1) =========== SYNOPSIS ======== git cola [options] [sub-command] DESCRIPTION =========== git cola is a sleek and powerful Git GUI. OPTIONS ======= --amend ------- Start `git cola` in amend mode. --prompt -------- Prompt for a Git repository. Defaults to the current directory. -r, --repo ----------------- Open the Git repository at ``. Defaults to the current directory. -s, --status-filter ---------------------------- Apply the path filter to the status widget. --version --------- Print the `git cola` version and exit. -h, --help ---------- Show usage and optional arguments. --help-commands --------------- Show available sub-commands. SUB-COMMANDS ============ am -- Apply patches. archive ------- Export tarballs from Git. branch ------ Create branches. browse ------ Browse tracked files. config ------ Configure settings. dag --- Start the `git dag` Git history browser. diff ---- Diff changed files. fetch ----- Fetch history from remote repositories. grep ---- Use `git grep` to search for content. merge ----- Merge branches. pull ---- Fetch and merge remote branches. push ---- Push branches to remotes. rebase ------ Start an interactive rebase. remote ------ Create and edit remotes. search ------ Search for commits. stash ----- Stash uncommitted modifications. tag --- Create tags. version ------- Print the `git cola` version. CONFIGURE YOUR EDITOR ===================== The editor used by `Ctrl-e` is configured from the Preferences screen. The environment variable `$VISUAL` is consulted when no editor has been configured. *ProTip*: Configuring your editor to `gvim -f -p` will open multiple tabs when editing files. `gvim -f -o` uses splits. `git cola` is {vim, emacs, textpad, notepad++}-aware. When you select a line in the `grep` screen and press any of `Enter`, `Ctrl-e`, or the `Edit` button, you are taken to that exact line. The editor preference is saved in the `gui.editor` variable using `git config `_. KEYBOARD SHORTCUTS ================== `git cola` has many useful keyboard shortcuts. You can see the available shortcuts by pressing the ``?`` key, choosing ``Help -> Keyboard shortcuts`` from the main menu, or by consulting the `git cola keyboard shortcuts reference `_. TOOLS ===== The `git cola` interface is composed of various cooperating tools. Double-clicking a tool opens it in its own subwindow. Dragging it around moves and places it within the window. Tools can be hidden and rearranged however you like. `git cola` carefully remembers your window layout and restores it the next time it is launched. The `Control-{1, 2, 3, ...}` hotkey gives focus to a specific tool. A hidden tool can be re-opened using the `Tools` menu or the `Shift+Control-{1, 2, 3, ...}` shortcut keys. The Diff editor can be focused with `Ctrl-j`. the Status tool can be focused with `Ctrl-k`. the Commit tool can be focused with `Ctrl-l`. .. _status: STATUS ====== The `Status` tool provides a visual analog to the `git status `_ command. `Status` displays files that are `modified` relative to the staging area, `staged` for the next commit, `unmerged` files from an in-progress merge, and files that are `untracked` to git. These are the same categories one sees when running `git status `_ on the command line. You can navigate through the list of files using keyboard arrows as well as the ergonomical and vim-like `j` and `k` shortcut keys. There are several convenient ways to interact with files in the `Status` tool. Selecting a file displays its diff in the :ref:`Diff` viewer. Double-clicking a file stages its contents, as does the the `Ctrl-s` shortcut key. `Ctrl-e` opens selected files in the conifgured editor, and `Ctrl-d` opens selected files using `git difftool `_ Additional actions can be performed using the right-click context menu. Actions ------- Clicking the `Staged` folder shows a diffstat for the index. Clicking the `Modified` folder shows a diffstat for the worktree. Clicking individual files sends diffs to the `Diff Display`. Double-clicking individual files adds and removes their content from the index. Various actions are available through the right-click context menu. Different actions are available depending a file's status. Stage Selected ~~~~~~~~~~~~~~ Add to the staging area using `git add `_ Marks unmerged files as resolved. Launch Editor ~~~~~~~~~~~~~ Launches the configured visual text editor Launch Difftool ~~~~~~~~~~~~~~~ Visualize changes using `git difftool`. Revert Unstaged Edits ~~~~~~~~~~~~~~~~~~~~~ Reverts unstaged content by checking out selected paths from the index/staging area Revert Uncommitted Edits ~~~~~~~~~~~~~~~~~~~~~~~~ Throws away uncommitted edits Unstage Selected ~~~~~~~~~~~~~~~~ Remove from the index/staging area with `git reset `_ Launch Merge Tool ~~~~~~~~~~~~~~~~~ Resolve conflicts using `git mergetool `_. Delete File(s) ~~~~~~~~~~~~~~ Delete untracked files from the filesystem. Add to .gitignore ~~~~~~~~~~~~~~~~~ Adds untracked files to to the .gitignore file. .. _diff: DIFF ==== The diff viewer/editor displays diffs for selected files. Additions are shown in green and removals are displayed in light red. Extraneous whitespace is shown with a pure-red background. Right-clicking in the diff provides access to additional actions that use either the cursor location or text selection. Staging content for commit -------------------------- The ``@@`` patterns denote a new diff hunk. Selecting lines of diff and using the `Stage Selected Lines` command will stage just the selected lines. Clicking within a diff hunk and selecting `Stage Diff Hunk` stages the entire patch diff hunk. The corresponding opposite commands can be performed on staged files as well, e.g. staged content can be selectively removed from the index when we are viewing diffs for staged content. COMMIT MESSAGE EDITOR ===================== The commit message editor is a simple text widget for entering commit messages. You can navigate between the `Subject` and `Extended description...` fields using the keyboard arrow keys. Pressing enter when inside the `Subject` field jumps down to the extended description field. The `Options` button menu to the left of the subject field provides access to the additional actions. The `Ctrl+i` keyboard shortcut adds a standard "Signed-off-by: " line, and `Ctrl+Enter` creates a new commit using the commit message and staged content. Sign Off -------- The `Sign Off` button adds a standard:: Signed-off-by: A. U. Thor line to the bottom of the commit message. Invoking this action is equivalent to passing the ``-s`` option to `git commit `_. Commit ------ The commit button runs `git commit `_. The contents of the commit message editor is provided as the commit message. Only staged files are included in the commit -- this is the same behavior as running ``git commit`` on the command-line. Line and Column Display ----------------------- The current line and column number is displayed by the editor. E.g. a ``5,0`` display means that the cursor is located at line five, column zero. The display changes colors when lines get too long. Yellow indicates the safe boundary for sending patches to a mailing list while keeping space for inline reply markers. Orange indicates that the line is starting to run a bit long and should break soon. Red indicates that the line is running up against the standard 80-column limit for commit messages. Keeping commit messages less than 76-characters wide is encouraged. `git log `_ is a great tool but long lines mess up its formatting for everyone else, so please be mindful when writing commit messages. Amend Last Commit ----------------- Clicking on `Amend Last Commit` makes `git cola` amend the previous commit instead of creating a new one. `git cola` loads the previous commit message into the commit message editor when this option is selected. The `Status` tool will display all of the changes for the amended commit. Create Signed Commit -------------------- Tell `git commit` and `git merge` to sign commits using GPG. Using this option is equivalent to passing the ``--gpg-sign`` option to `git commit `_ and `git merge `_. This option's default value can be configured using the `cola.signcommits` configuration variable. Prepare Commit Message ---------------------- The ``Commit -> Prepare Commit Message`` action or `Ctrl-Shift-Return` keyboard shortcut runs the `cola-prepare-commit-msg` hook if it is available in `.git/hooks/`. This is a `git cola`-specific hook that takes the same parameters as Git's `prepare-commit-msg hook `_ The hook is passed the path to `.git/GIT_COLA_MSG` as the first argument and the hook is expected to write an updated commit message to specified path. After running this action, the commit message editor is updated with the new commit message. To override the default path to this hook set the `cola.prepareCommitMessageHook` `git config` variable to the path to the hook script. This is useful if you would like to use a common hook across all repositories. BRANCHES ======== The `Branches` tool provides a visual tree to navigate through the branches. The tree has three main nodes `Local Branch`, `Remote Branch` and `Tags`. Branches are grouped by their name divided by the character '/'.Ex:: branch/feature/foo branch/feature/bar branch/doe Will produce:: branch - doe + feature - bar - foo Current branch will display a star icon. If current branch has commits ahead/behind it will display an up/down arrow with its number. Actions ------- Various actions are available through the right-click context menu. Different actions are available depending of selected branch status. Checkout ~~~~~~~~ The checkout action runs `git checkout [] `_. Merge in current branch ~~~~~~~~~~~~~~~~~~~~~~~ The merge action runs `git merge --no-commit [] `_. Pull ~~~~ The pull action runs `git pull --no-ff [] [] `_. Push ~~~~ The push action runs `git push [] [] `_. Rename Branch ~~~~~~~~~~~~~ The rename branch action runs `git branch -M [] `_. Delete Branch ~~~~~~~~~~~~~ The delete branch branch action runs `git branch -D [] `_. Delete Remote Branch ~~~~~~~~~~~~~~~~~~~~ The remote branch action runs `git push --delete [] [] `_. APPLY PATCHES ============= Use the ``File -> Apply Patches`` menu item to begin applying patches. Dragging and dropping patches onto the `git cola` interface adds the patches to the list of patches to apply using `git am `_. You can drag either a set of patches or a directory containing patches. Patches can be sorted using in the interface and are applied in the same order as is listed in the list. When a directory is dropped `git cola` walks the directory tree in search of patches. `git cola` sorts the list of patches after they have all been found. This allows you to control the order in which patchs are applied by placing patchsets into alphanumerically-sorted directories. CUSTOM WINDOW SETTINGS ====================== `git cola` remembers modifications to the layout and arrangement of tools within the `git cola` interface. Changes are saved and restored at application shutdown/startup. `git cola` can be configured to not save custom layouts by unsetting the `Save Window Settings` option in the `git cola` preferences. CONFIGURATION VARIABLES ======================= These variables can be set using `git config` or from the settings. cola.autocompletepaths ---------------------- Set to `false` to disable auto-completion of filenames in completion widgets. This can speed up operations when working in large repositories. Defaults to `true`. cola.autoloadCommitTemplate --------------------------- Set to `true` to automatically load the commit template in the commit message editor If the commit.template variable has not been configured, raise the corresponding error. Defaults to `false`. cola.blameviewer ---------------- The command used to blame files. Defaults to `git gui blame`. cola.browserdockable -------------------- Whether to create a dock widget with the `Browser` tool. Defaults to `false` to speedup startup time. cola.checkconflicts ------------------- Inspect unmerged files for conflict markers before staging them. This feature helps prevent accidental staging of unresolved merge conflicts. Defaults to `true`. cola.defaultrepo ---------------- `git cola`, when run outside of a Git repository, prompts the user for a repository. Set `cola.defaultrepo` to the path of a Git repository to make `git cola` attempt to use that repository before falling back to prompting the user for a repository. cola.dictionary --------------- Specifies an additional dictionary for `git cola` to use in its spell checker. This should be configured to the path of a newline-separated list of words. cola.expandtab -------------- Expand tabs into spaces in the commit message editor. When set to `true`, `git cola` will insert a configurable number of spaces when tab is pressed. The number of spaces is determined by `cola.tabwidth`. Defaults to `false`. cola.fileattributes ------------------- Enables per-file gitattributes encoding support when set to `true`. This tells `git cola` to honor the configured encoding when displaying and applying diffs. cola.fontdiff ------------- Specifies the font to use for `git cola`'s diff display. cola.hidpi ------------- Specifies the High DPI displays scale factor. Set `0` to automatically scaled. Setting value between 0 and 1 is undefined. This option requires at least Qt 5.6 to work. See `Qt QT_SCALE_FACTOR documentation `_ for more information. cola.icontheme -------------- Specifies the icon themes to use throughout `git cola`. The theme specified must be the name of the subdirectory containing the icons, which in turn must be placed in the inside the main "icons" directory in `git cola`'s installation prefix. If unset, or set either "light" or "default", then the default style will be used. If set to "dark" then the built-in "dark" icon theme, which is suitable for a dark window manager theme, will be used. If set to an absolute directory path then icons in that directory will be used. This value can be set to multiple values using, ``git config --add cola.icontheme $theme``. This setting can be overridden by the `GIT_COLA_ICON_THEME` environment variable, which can specify multiple themes using a colon-separated value. The icon theme can also be specified by passing ``--icon-theme=`` on the command line, once for each icon theme, in the order that they should be searched. This can be used to override a subset of the icons, and fallback to the built-in icons for the remainder. cola.inotify ------------ Set to `false` to disable file system change monitoring. Defaults to `true`, but also requires either Linux with inotify support or Windows with `pywin32` installed for file system change monitoring to actually function. cola.refreshonfocus ------------------- Set to `true` to automatically refresh when `git cola` gains focus. Defaults to `false` because this can cause a pause whenever switching to `git cola` from another application. cola.linebreak -------------- Whether to automatically break long lines while editing commit messages. Defaults to `true`. This setting is configured using the `Preferences` dialog, but it can be toggled for one-off usage using the commit message editor's options sub-menu. cola.maxrecent -------------- `git cola` caps the number of recent repositories to avoid cluttering the start and recent repositories menu. The maximum number of repositories to remember is controlled by `cola.maxrecent` and defaults to `8`. cola.dragencoding ----------------- `git cola` encodes paths dragged from its widgets into `utf-16` when adding them to the drag-and-drop mime data (specifically, the `text/x-moz-url` entry). `utf-16` is used to make `gnome-terminal` see the right paths, but other terminals may expect a different encoding. If you are using a terminal that expects a modern encoding, e.g. `terminator`, then set this value to `utf-8`. cola.readsize ------------- `git cola` avoids reading large binary untracked files. The maximum size to read is controlled by `cola.readsize` and defaults to `2048`. cola.safemode ------------- The "Stage" button in the `git cola` Actions panel stages all files when it is activated and no files are selected. This can be problematic if it is accidentally triggered after carefully preparing the index with staged changes. "Safe Mode" is enabled by setting `cola.safemode` to `true`. When enabled, `git cola` will do nothing when "Stage" is activated without a selection. Defaults to `false`. cola.savewindowsettings ----------------------- `git cola` will remember its window settings when set to `true`. Window settings and X11 sessions are saved in `$HOME/.config/git-cola`. cola.showpath ------------- `git cola` displays the absolute path of the repository in the window title. This can be disabled by setting `cola.showpath` to `false`. Defaults to `true`. cola.signcommits ---------------- `git cola` will sign commits by default when set `true`. Defaults to `false`. See the section below on setting up GPG for more details. cola.statusindent ----------------- Set to `true` to indent files in the Status widget. Files in the `Staged`, `Modified`, etc. categories will be grouped in a tree-like structure. Defaults to `false`. cola.statusshowtotals --------------------- Set to `true` to display files counts in the Status widget's category titles. Defaults to `false`. cola.tabwidth ------------- The number of columns occupied by a tab character. Defaults to 8. cola.terminal ------------- The command to use when launching commands within a graphical terminal. `cola.terminal` defaults to `xterm -e` when unset. e.g. when opening a shell, `git cola` will run `xterm -e $SHELL`. `git cola` has built-in support for `xterm`, `gnome-terminal`, `konsole`. If either `gnome-terminal`, `xfce4-terminal`, or `konsole` are installed then they will be preferred over `xterm` when `cola.terminal` is unset. The table below shows the built-in values that are used for the respective terminal. You can force the use of a specific terminal by configuring cola accordingly. cola.terminalshellquote ----------------------- Some terminal require that the command string get passed as a string. For example, ``xfce4-terminal -e "git difftool"`` requires shellquoting, whereas ``gnome-terminal -- git difftool`` does not. You should not need to set this variable for the built-in terminals cola knows about -- it will behave correctly without configuration. For example, when unconfigured, cola already knows that xfce4-terminal requires shellquoting. This configuration variable is for custom terminals outside of the builtin set. The table below shows the builtin configuration. Terminal cola.terminal cola.terminalshellquote -------- ------------- ----------------------- gnome-terminal gnome-terminal -- false konsole konsole -e false xfce4-terminal xfce4-terminal -e true xterm xterm -e false cola.textwidth -------------- The number of columns used for line wrapping. Tabs are counted according to `cola.tabwidth`. cola.theme -------------- Specifies the GUI theme to use throughout `git cola`. The theme specified must be one of the following values: * `default` – default Qt theme, may appear different on various systems * `flat-dark-blue` * `flat-dark-green` * `flat-dark-grey` * `flat-dark-red` * `flat-light-blue` * `flat-light-green` * `flat-light-grey` * `flat-light-red` If unset, or set wrong value, then the default style will be used. The `default` theme is generated by Qt internal engine and should look most native but may look noticeable differently on various systems. The flat themes on the other hand should look similar (but not identical) on various systems. The GUI theme can also be specified by passing ``--theme=`` on the command line. On Linux, you may want Qt to use the theme configured using the ``qt5ct`` Qt5 configuration tool. You can do this by exporting `QT_QPA_PLATFORMTHEME` in your `~/.bash_profile` to a value of ``qt5ct``:: # Use the style configured using the qt5ct tool QT_QPA_PLATFORMTHEME=qt5ct export QT_QPA_PLATFORMTHEME This only work with the `default` theme. The other themes replace the color palette with a specific configuration. cola.turbo ---------- Set to `true` to enables "turbo" mode. "Turbo" mode disables some features that can slow things down when operating on huge repositories. "Turbo" mode will skip loading Git commit messages, author details, status information, and commit date details in the `File Browser` tool. Defaults to `false`. cola.color.text --------------- The default diff text color, in hexadecimal #RRGGBB notation. Defaults to "#030303":: git config cola.color.text '#030303' cola.color.add -------------- The default diff "add" background color, in hexadecimal #RRGGBB notation. Defaults to "#d2ffe4":: git config cola.color.add '#d2ffe4' cola.color.remove ----------------- The default diff "remove" background color, in hexadecimal #RRGGBB notation. Defaults to "#fee0e4":: git config cola.color.remove '#fee0e4' cola.color.header ----------------- The default diff header text color, in hexadecimal #RRGGBB notation. Defaults to "#bbbbbb":: git config cola.color.header '#bbbbbb' gui.diffcontext --------------- The number of diff context lines to display. gui.displayuntracked -------------------- `git cola` avoids showing untracked files when set to `false`. gui.editor ---------- The default text editor to use is defined in `gui.editor`. The config variable overrides the VISUAL environment variable. e.g. `gvim -f -p`. gui.historybrowser ------------------ The history browser to use when visualizing history. Defaults to `gitk`. diff.tool --------- The default diff tool to use. merge.tool ---------- The default merge tool to use. user.email ---------- Your email address to be recorded in any newly created commits. Can be overridden by the 'GIT_AUTHOR_EMAIL', 'GIT_COMMITTER_EMAIL', and 'EMAIL' environment variables. user.name --------- Your full name to be recorded in any newly created commits. Can be overridden by the 'GIT_AUTHOR_NAME' and 'GIT_COMMITTER_NAME' environment variables. ENVIRONMENT VARIABLES ===================== GIT_COLA_ICON_THEME ------------------- When set in the environment, `GIT_COLA_ICON_THEME` overrides the theme specified in the `cola.icontheme` configuration. Read the section on `cola.icontheme` above for more details. GIT_COLA_SCALE -------------- .. Important:: `GIT_COLA_SCALE` should not be used with newer versions of Qt. Set `QT_AUTO_SCREEN_SCALE_FACTOR` to `1` and Qt will automatically scale the interface to the correct size based on the display DPI. This option is also available by setting `cola.hidpi` configuration. See the `Qt High DPI documentation `_ for more details. `git cola` can be made to scale its interface for HiDPI displays. When defined, `git cola` will scale icons, radioboxes, and checkboxes according to the scale factor. The default value is `1`. A good value is `2` for high-resolution displays. Fonts are not scaled, as their size can already be set in the settings. GIT_COLA_TRACE -------------- When defined, `git cola` logs `git` commands to stdout. When set to `full`, `git cola` also logs the exit status and output. When set to `trace`, `git cola` logs to the `Console` widget. VISUAL ------ Specifies the default editor to use. This is ignored when the `gui.editor` configuration variable is defined. LANGUAGE SETTINGS ================= `git cola` automatically detects your language and presents some translations when available. This may not be desired, or you may want `git cola` to use a specific language. You can make `git cola` use an alternative language by creating a `~/.config/git-cola/language` file containing the standard two-letter gettext language code, e.g. "en", "de", "ja", "zh", etc.:: mkdir -p ~/.config/git-cola && echo en >~/.config/git-cola/language Alternatively you may also use LANGUAGE environmental variable to temporarily change `git cola`'s language just like any other gettext-based program. For example to temporarily change `git cola`'s language to English:: LANGUAGE=en git cola To make `git cola` use the zh_TW translation with zh_HK, zh, and en as a fallback.:: LANGUAGE=zh_TW:zh_HK:zh:en git cola CUSTOM GUI ACTIONS ================== `git cola` allows you to define custom GUI actions by setting `git config` variables. The "name" of the command appears in the "Actions" menu. guitool..cmd ------------------ Specifies the shell command line to execute when the corresponding item of the Tools menu is invoked. This option is mandatory for every tool. The command is executed from the root of the working directory, and in the environment it receives the name of the tool as GIT_GUITOOL, the name of the currently selected file as FILENAME, and the name of the current branch as CUR_BRANCH (if the head is detached, CUR_BRANCH is empty). guitool..background ------------------------- Run the command in the background (similar to editing and difftool actions). This avoids blocking the GUI. Setting `background` to `true` implies `noconsole` and `norescan`. guitool..needsfile ------------------------ Run the tool only if a diff is selected in the GUI. It guarantees that FILENAME is not empty. guitool..noconsole ------------------------ Run the command silently, without creating a window to display its output. guitool..norescan ----------------------- Don’t rescan the working directory for changes after the tool finishes execution. guitool..confirm ---------------------- Show a confirmation dialog before actually running the tool. guitool..argprompt ------------------------ Request a string argument from the user, and pass it to the tool through the ARGS environment variable. Since requesting an argument implies confirmation, the confirm option has no effect if this is enabled. If the option is set to true, yes, or 1, the dialog uses a built-in generic prompt; otherwise the exact value of the variable is used. guitool..revprompt ------------------------ Request a single valid revision from the user, and set the REVISION environment variable. In other aspects this option is similar to argprompt, and can be used together with it. guitool..revunmerged -------------------------- Show only unmerged branches in the revprompt subdialog. This is useful for tools similar to merge or rebase, but not for things like checkout or reset. guitool..title -------------------- Specifies the title to use for the prompt dialog. Defaults to the tool name. guitool..prompt --------------------- Specifies the general prompt string to display at the top of the dialog, before subsections for argprompt and revprompt. The default value includes the actual command. guitool..shortcut ----------------------- Specifies a keyboard shortcut for the custom tool. The value must be a valid string understood by the `QAction::setShortcut()` API. See http://qt-project.org/doc/qt-4.8/qkeysequence.html#QKeySequence-2 for more details about the supported values. Avoid creating shortcuts that conflict with existing built-in `git cola` shortcuts. Creating a conflict will result in no action when the shortcut is used. SETTING UP GPG FOR SIGNED COMMITS ================================= When creating signed commits `gpg` will attempt to read your password from the terminal from which `git cola` was launched. The way to make this work smoothly is to use a GPG agent so that you can avoid needing to re-enter your password every time you commit. This also gets you a graphical passphrase prompt instead of getting prompted for your password in the terminal. Install gpg-agent and friends ----------------------------- On Mac OS X, you may need to `brew install gpg-agent` and install the `Mac GPG Suite `_. On Linux use your package manager to install gnupg2, gnupg-agent and pinentry-qt, e.g.:: sudo apt-get install gnupg2 gnupg-agent pinentry-qt On Linux, you should also configure Git so that it uses gpg2 (gnupg2), otherwise you will get errors mentioning, "unable to open /dev/tty". Set Git's `gpg.program` to `gpg2`:: git config --global gpg.program gpg2 Configure gpg-agent and a pin-entry program ------------------------------------------- On Mac OS X, edit `~/.gnupg/gpg.conf` to include the line,:: use-agent This is typically not needed on Linux, where `gpg2` is used, as this is the default value when using `gpg2`. Next, edit `~/.gnupg/gpg-agent.conf` to contain a pinentry-program line pointing to the pinentry program for your platform. The following example `~/.gnupg/gpg-agent.conf` shows how to use pinentry-gtk-2 on Linux:: pinentry-program /usr/bin/pinentry-gtk-2 default-cache-ttl 3600 This following example `.gnupg/gpg-agent.conf` shows how to use MacGPG2's pinentry app on On Mac OS X:: pinentry-program /usr/local/MacGPG2/libexec/pinentry-mac.app/Contents/MacOS/pinentry-mac default-cache-ttl 3600 enable-ssh-support use-standard-socket Once this has been setup then you will need to reload your gpg-agent config.:: echo RELOADAGENT | gpg-connect-agent If you see the following output:: OK Then the daemon is already running, and you do not need to start it yourself. If it is not running, eval the output of ``gpg-agent --daemon`` in your shell prior to launching `git cola`.:: eval $(gpg-agent --daemon) git cola WINDOWS NOTES ============= Git Installation ---------------- If Git is installed in a custom location, e.g. not installed in `C:/Git` or Program Files, then the path to Git must be configured by creating a file in your home directory `~/.config/git-cola/git-bindir` that points to your git installation. e.g.:: C:/Tools/Git/bin LINKS ===== Git Cola's Git Repository ------------------------- https://github.com/git-cola/git-cola/ Git Cola Homepage ----------------- https://git-cola.github.io/ Mailing List ------------ https://groups.google.com/group/git-cola git-cola-3.6/share/doc/git-cola/git-dag.rst000066400000000000000000000036171356743264500205230ustar00rootroot00000000000000========== git-dag(1) ========== SYNOPSIS ======== git dag [options] [..] [[--] [...]] DESCRIPTION =========== `git-dag` is a powerful Git history visualizer. `git-dag` presents powerful `git log` features in a simple-to-use graphical interface. OPTIONS ======= --prompt -------- Prompt for a Git repository instead of using the current directory. -r, --repo ----------------- Run `git dag` on the git repository in ``. Defaults to the current directory. --version --------- Print the `git dag` version and exit. -h, --help ---------- Show usage and optional arguments. Log Options =========== The `Log` prompt allows you to pass arguments to `git log`. This can be used to filter the displayed history, for example entering `master -- Makefile` will display only commits on the `master` branch that touch the `Makefile`. CONTEXT-MENU ACTIONS ==================== The right-click menu can be used to perform various actions. All actions operate on the selected commit. You can create branches and tags, cherry-pick commits, save patches, export tarballs, and grab files from older commits using the context menu. DIFF COMMITS ============ You can diff arbitrary commits. Select a single commit in either the list view or the graph view and then right-click on a second commit. A menu will appear allowing you to diff the two commits. SHORTCUTS ========= You can run commands using dedicated shortcuts. Select a single commit and then press `Ctrl-Alt-c` to copy sha1 or `Ctrl-d` to run diff tool. You can read more about hotkeys from 'keyboard shortcuts' window or context menu. CONFIGURATION VARIABLES ======================= log.date -------- Set the default date-time format for the 'Date' field. Setting a value for log.date is similar to using `git log`'s `--date` option. Possible values are `relative`, `local`, `default`, `iso`, `rfc`, and `short`; see git-log(1) for details. git-cola-3.6/share/doc/git-cola/hotkeys.html000066400000000000000000000140711356743264500210250ustar00rootroot00000000000000 Keyboard shortcuts
    Commit
Ctrl + Return : Commit staged changes
Ctrl + Shift + Return : Prepare commit message hook
Ctrl + S : Stage / unstage selected files
Alt + A : Stage modified files
Alt + U : Stage untracked files
Ctrl + U : Revert unstaged edits
Ctrl + Z : Revert uncommitted changes
Ctrl + Shift + M : Merge branches
Ctrl + m : Amend last commit
Ctrl + Shift + C : Cherry pick
    Actions
Ctrl + B : Create branch
Alt + B : Checkout branch
T / Ctrl + T : Find files
Ctrl + G : Grep
Alt + D : Show diffstat
Alt + E : Export patches
Alt + Shift + S : Stash
Ctrl + Backspace : Delete untracked files
Ctrl + Shift + F : Toggle paths filter
Alt + R : Start/continue interactive rebase
Ctrl + R : Refresh
? : Keyboard shortcuts
    Editing
Enter / Ctrl + E : Launch editor
Space : Open using default application
Shift + Space : Open parent directory
Ctrl + Shift + E : View / edit recently modified files
Ctrl + # : Focus tools
Ctrl + Shift + # : Show and hide tools
# is 1 for commit, 2 for status, 3 for diff, etc.
    Remotes
Ctrl + P : Launch the Push dialog
Ctrl + Shift + P : Launch the Pull dialog
    Diff
S : Stage the selected lines, or the diff hunk beneath the text cursor when nothing is selected
Ctrl + D : View diff using `git difftool`
Ctrl + Shift + D : View directory diff using `git difftool --dir-diff`
    Browser actions
Ctrl + Shift + H : View history
Ctrl + Shift + D : View diff against predecessor
Ctrl + Alt + C : Copy SHA-1
    Navigation
H : Move left/collapse
J / Alt + J : Move down
K / Alt + K : Move up
L : Move right/expand
Ctrl + J : Focus the Diff Editor
Ctrl + K : Focus the Status tool
Ctrl + L : Focus the Commit tool
git-cola-3.6/share/doc/git-cola/hotkeys_de.html000066400000000000000000000135231356743264500214760ustar00rootroot00000000000000 Tastenkürzel
    Version
Ctrl + Return : Vorgemerkte Änderungen versionieren
Ctrl + Shift + Return : Prepare commit message hook
Ctrl + S : Ausgewählte Dateien vormerken
Alt + A : Geänderte Dateien vormerken
Alt + U : Alle neuen Dateien vormerken
Ctrl + U : Revert unstaged edits
Ctrl + Z : Nicht versionierte Änderungen verwerfen
Ctrl + Shift + M : Merge branches
Ctrl + M : Letzte Version nachbessern
Ctrl + Shift + C : Einzelne Version übernehmen
    Befehle
Ctrl + B : Neuen Zweig erstellen
Alt + B : Zweig wechseln
T / Ctrl + T : Find files
Ctrl + G : Suchen
Alt + D : Vergleichsstatistik anzeigen
Alt + Shift + E : Patches exportieren
Alt + Shift + S : Weglegen und zurückholen
Ctrl + Backspace : Delete untracked files
Ctrl + Shift + F : Toggle paths filter
Ctrl + R : Ansicht aktualisieren
? : Tastenkürzel
    Bearbeiten
Enter / Ctrl + E : Im Editor bearbeiten
Space : Mit der Standardanwendung öffnen
Shift + Space : Übergeordnetes Verzeichnis öffnen
Ctrl + Shift + E : Kürzlich geänderte Dateien anzeigen/bearbeiten
Ctrl + # : Werkzeuge fokussieren
Ctrl + Shift + # : Werkzeuge anzeigen und verstecken
    Vergleichsansicht
S : Auswahl vormerken; falls nichts ausgewählt ist, siehe H
Ctrl + D : Mithilfe von `git difftool` ansehen
Ctrl + Shift + D : View directory diff using `git difftool --dir-diff`
    Browser-Befehle
Ctrl + Shift + H : Verlauf anzeigen
Ctrl + Shift + D : Mit Vorgänger vergleichen
Ctrl + Alt + C : SHA-1 kopieren
    Navigation
H : Nach links/einklappen
J / Alt + J : Nach unten
K / Alt + K : Nach oben
L : Nach rechts/ausklappen
Ctrl + J : Focus the Diff Editor
Ctrl + K : Focus the Status tool
Ctrl + L : Focus the Commit tool
git-cola-3.6/share/doc/git-cola/hotkeys_zh_CN.html000066400000000000000000000133101356743264500221010ustar00rootroot00000000000000 键盘快捷键
    提交
Ctrl + Return : 提交已缓存变更
Ctrl + Shift + Return : Prepare commit message hook
Ctrl + S : 缓存所选项目
Alt + A : 缓存已更改项目
Alt + U : 缓存未追踪项目
Ctrl + U : 还原缓存改动
Ctrl + Z : 撤销未缓存变更
Ctrl + Shift + M : Merge branches
Ctrl + M : 修正前一次提交
Ctrl + Shift + C : Cherry pick
    操作
Ctrl + B : 建立新分支
Alt + B : 取出分支內容
T / Ctrl + T : Find files
Ctrl + G : 搜索
Alt + D : 显示内容差异
Alt + Shift + E : 导出差异
Alt + Shift + S : 缓存
Ctrl + Backspace : Delete untracked files
Ctrl + Shift + f : Toggle paths filter
Ctrl + R : 重新整理
? : 显示键盘快捷键列表
    编辑
Enter / Ctrl + E : 启动文本编辑器
空白鍵 : 用默认程序打开
Shift + 空白鍵 : 打开上级目录
Ctrl + Shift + E : 查看 / 编辑最近修改的文件
Ctrl + # : 聚焦于工具
Ctrl + Shift + # : 显示/隐藏工具
    差异查看器
S : 缓存所选项目,未选择项目时与H作用相同
Ctrl + D : 使用「git difftool」命令查看内容差异
Ctrl + Shift + D : View directory diff using `git difftool --dir-diff`
    「浏览器」窗口操作
Ctrl + Shift + H : 查看变更历史
Ctrl + Shift + D : 与之前版本比较差异
Ctrl + Alt + C : Copy SHA-1
    导航键
H : 左移/折叠
J / Alt + J : 下移
K / Alt + K : 上移
L : 右移/展开
Ctrl + J : Focus the Diff Editor
Ctrl + K : Focus the Status tool
Ctrl + L : 聚焦在 DAG 输入框
git-cola-3.6/share/doc/git-cola/hotkeys_zh_TW.html000066400000000000000000000144461356743264500221460ustar00rootroot00000000000000 鍵盤快捷鍵
    提交版本
Ctrl + Return : 提交版本提交準備區域中的變更
Ctrl + Shift + Return : Prepare commit message hook
Ctrl + S : 將被選取的項目移入版本提交準備區域
Alt + A : 將已變更的項目移入版本提交準備區域
Alt + U : 將尚未追蹤其版本的項目移動到版本提交準備區域
Ctrl + U : 還原尚未移入版本提交準備區域的內容變動
Ctrl + Z : 撤銷尚未建立版本提交的內容變動
Ctrl + Shift + M : 合併分支
Ctrl + M : 修正前一次的版本提交
Ctrl + Shift + C : 挑取(cherry pick)
    操作
Ctrl + B : 建立一個新的分支
Alt + B : 取出分支內容
T / Ctrl + T : 尋找檔案
Ctrl + G : 搜尋
Alt + D : 顯示內容差異
Alt + Shift + E : 匯出修正
Alt + Shift + S : 珍藏
Ctrl + Backspace : 刪除未納入版本追蹤的檔案
Ctrl + Shift + F : 開啟/關閉路徑過濾器
Ctrl + R : 重新整理
? : 顯示鍵盤快捷鍵列表
    編輯
Enter / Ctrl + E : 啟動文字編輯器
空白鍵 : 以系統預設的軟體開啟
Shift + 空白鍵 : 開啟上一層目錄
Ctrl + Shift + E : 檢視/編輯最近修改過的檔案
Ctrl + # : 將焦點移至指定工具
Ctrl + Shift + # : 顯示或隱藏指定工具
對提交版本工具來說 # 為 1、對版控庫狀態工具來說 # 為 2、對內容差異工具來說 # 為 3,依此類推
    內容差異檢視器
S : 將選取的行移入版本提交準備區域,或是當沒有選取任何行時跟 H 效果相同
Ctrl + D : 使用「git difftool」命令檢視內容差異
Ctrl + Shift + D : 使用「git difftool --dir-diff」命令檢視目錄內容差異
    瀏覽器工具內可進行的操作
Ctrl + Shift + H : 檢視變更紀錄
Ctrl + Shift + D : 與過去版本比較內容差異
Ctrl + Alt + C : 複製修訂版的SHA-1雜湊值
    導覽按鍵
H : 向左移動/折疊
J / Alt + J : 向下移動
K / Alt + K : 向下移動
L : 向下移動/展開
Ctrl + J : 將焦點移至內容差異編輯器
Ctrl + K : 將焦點移至板控庫狀態工具
Ctrl + L : 將焦點移至提交變更工具
git-cola-3.6/share/doc/git-cola/index.rst000066400000000000000000000004331356743264500203070ustar00rootroot00000000000000====================== Git Cola Documentation ====================== .. toctree:: :maxdepth: 3 git-cola git-dag thanks Release Notes ============= .. toctree:: :maxdepth: 2 relnotes Indices and tables ================== * :ref:`genindex` * :ref:`search` git-cola-3.6/share/doc/git-cola/make.bat000066400000000000000000000056231356743264500200610ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation set SPHINXBUILD=sphinx-build set ALLSPHINXOPTS=-d _build/doctrees %SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (_build\*) do rmdir /q /s %%i del /q /s _build\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% _build/html echo. echo.Build finished. The HTML pages are in _build/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% _build/dirhtml echo. echo.Build finished. The HTML pages are in _build/dirhtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% _build/pickle echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% _build/json echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% _build/htmlhelp echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in _build/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% _build/qthelp echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in _build/qthelp, like this: echo.^> qcollectiongenerator _build\qthelp\git-cola.qhcp echo.To view the help file: echo.^> assistant -collectionFile _build\qthelp\git-cola.ghc goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% _build/latex echo. echo.Build finished; the LaTeX files are in _build/latex. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% _build/changes echo. echo.The overview file is in _build/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% _build/linkcheck echo. echo.Link check complete; look for any errors in the above output ^ or in _build/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% _build/doctest echo. echo.Testing of doctests in the sources finished, look at the ^ results in _build/doctest/output.txt. goto end ) :end git-cola-3.6/share/doc/git-cola/relnotes.rst000066400000000000000000003352411356743264500210430ustar00rootroot00000000000000======== Releases ======== Latest Release ============== :ref:`v3.6 ` is the latest stable release. Development version =================== Clone the git-cola repo to get the latest development version: ``git clone git://github.com/git-cola/git-cola.git`` .. _v3.6: Usability, bells and whistles ----------------------------- * The remote editor is much faster since it no longer queries remotes, and uses the cached information instead. (`#986 `_) * Commit message templates can now be loaded automatically by setting ``git config cola.autoloadcommittemplate true``. (`#1013 `_) (`#735 `_) * The UI layout can now be reset back to its initial state by selecting the "Reset Layout" action. This reverts the layout to the same state as when the app first launched. (`#1008 `_) (`#994 `_) * Files can now be ignored in either the project's `.gitignore`, or in the repository's private local `.git/info/exclude` ignore file. (`#1006 `_) (`#1000 `_) * New remotes are now selected when they are added in the "Edit Remotes" tool. (`#1002 `_) * The "Recent" repositories list is now saved to disk when opening a repository. Previously, this list was only updated when exiting the app. (`#1001 `_) * The bookmarks tool now has a "Delete" option in its right-click menu. (`#999 `_) * The current repository is no longer listed in the "File/Open Recent" menu. (`#998 `_) Translations ------------ * Updated Hungarian translation. (`#1005 `_) (`#1018 `_) * Updated Turkish translation. (`#1003 `_) (`#1011 `_) Fixes ----- * Better support for Python 3.8's line buffering modes. (`#1014 `_) * The default `ssh-askpass` script now uses a more generic `#!` shebang line. (`#1012 `_) * Fetch, push, and pull operations will now refresh the model and display when operations complete. (`#996 `_) * The branches widget now refreshes its display when changing branches. (`#992 `_) Packaging --------- * The `share/git-cola/bin/git-xbase` script will now have its `#!` lines updated during installation. (`#991 `_) Development ----------- * The unit tests were made more platform-independent. (`#993 `_) .. _v3.5: Usability, bells and whistles ----------------------------- * Auto-completion for filenames can now be disabled. This speeds up revision completion when working in large repositories with many files. (`#981 `_) * The Stash dialog now shows the stash date as a tooltip when hovering over a stashed change. (`#982 `_) * Qt HiDPI settings are overriden by the `git cola` HiDPI appearance settings. These overrides can now be disabled by selecting the "Disable" mode. This allows users to control Qt's HiDPI settings through environment variables. Additionally, the "Auto" mode now detects the presence of the Qt HiDPI variables and no longer overrides them when the user has configured their environment explicitly. (`#963 `_) * Confirmation dialogs can now focus buttons using the Tab key. Previously, the "Y" and "N" keys could be used to confirm or deny using the keyboard, but "Tab" is more familiar. (`#965 `_) * Error dialogs (for example, when a commit hook fails) will now always show the details. The details were previously hidden behind a toggle. (`#968 `_) Translations ------------ * Updated Japanese translation. (`#973 `_) (`#974 `_) * Updated Simplified Chinese translation. (`#950 `_) Fixes ----- * The filesystem monitor no longer logs that it has been enabled after the inotify watch limit is reached on Linux. (`#984 `_) * Better unicode robustness. (`#990 `_) (`#910 `_) * The "Branches" widget did not always update itself when deleting branches (for example, when inotify is disabled or unavailable). (`#978 `_) * Non-ascii unicode byte strings are more robustly handled by the log widget. (`#977 `_) * Non-unicode results from the `gettext` library are more robustly handled. (`#969 `_) * Launching `git cola` from within a directory that has since been deleted would previously result in a traceback, and is now robustly handled. (`#961 `_) Packaging --------- * The vendored `qtpy` library was updated to `v1.9`. .. _v3.4: git-cola v3.4 ============= Usability, bells and whistles ----------------------------- * The file browser now includes "Blame" in its context menu. (`#953 `_) * The "Push" action now uses "git push --force-with-lease" when using the "Force" option with Git v1.8.5 and newer. (`#946 `_) * Updated German translation. (`#936 `_) * The `Status` widget learned to optionally display file counts in its category headers, and indent the files displayed in each category. (`#931 `_) * The `Branches` widget can now sort branches by their most recent commit. (`#930 `_) * `git cola` now includes configurable GUI themes that can be used to style the user interface. Enable the new themes by configuring `cola.theme` in the preferences window. See the `cola.theme documentation `_ for more details. (`#924 `_) * `git cola` now has built-in support for HiDPI displays by enabling Qt's 5.6's `QT_AUTO_SCREEN_SCALE_FACTOR` feature. (`#938 `_) * `git cola` now uses HiDPI pixmaps when rendering icons, and the builtin icons have been updated to look sharp when displayed in HiDPI. (`#932 `_) Fixes ----- * `git cola`'s "Revert Unstaged Edits" previously checked out from "HEAD^", when in "Amend" mode, and removing staged changes. This behavior has been changed to always checkout from the index, which avoids data loss. (`#947 `_) * `git cola` has been updated to work with newer versions of `gnome-terminal` and no longer shell-quotes its arguments when launching `gnome-terminal`. The `cola.terminalshellquote` configuration variable can be set to `true` to get the old behavior, or to handle other terminals that take the command to run as a single string instead of as arguments to `execv()`. (`#935 `_) * `git dag` now properly handles arbitrary input on Python3. Previously, an exception would be raised when entering `--grep=xxx` where `xxx` is a quoted string with a missing end-quote. (`#941 `_) Development ----------- * The contribution guidelines for contributors has been updated to mention how to regenerate the `*.mo` message files. (`#934 `_) .. _v3.3: git-cola v3.3 ============= Usability, bells and whistles ----------------------------- * `git dag` improved how it renders parent commits. (`#921 `_) * The `Branches` widget now checks out branches when double-clicked. (`#920 `_) * The new `Submodules` widget makes it easy to interact with submodules. Additionally, submodules can now be updated using the `Status` widget. (`#916 `_) * Updated Japanese translation. (`#914 `_) * The "Open Terminal" action now launches a Git Bash shell on Windows. (`#913 `_) * New menu actions for updating all submodules. (`#911 `_) * The status widget can now update submodules. (`#911 `_) * The "Apply Patch" `git cola am` dialog now includes a diff viewer to display the contents of the selected patch. * The "Alt+D" diffstat hotkey now selects the staged/modified/etc. header in the Status widget, which shows the totality of everything that will be committed. (`#771 `_) * Running "Launch Editor" from the diff editor now opens the editor at the current line. (`#898 `_) * The textwidth and tabwidth configuration values can now be set per-repository, rather than globally only. * Text entry widgets switched to using a block cursor in `v3.2`. This has been reverted to the original line cursor for consistency with other applications and user expectations. (`#889 `_) * The "edit at line" feature, used by the "Grep" tool, now supports the Sublime text editor. (`#894 `_) Fixes ----- * Launching external programs has been improved on Windows. (`#925 `_) * Improve compatibility when using PySide2. (`#912 `_) * The Diff Editor was not honoring the configured tab width on startup. (`#900 `_) * The "Delete Files" feature was creating an unreadable display when many files were selected. Word-wrap the list of files so that the display stays within a sensible size. (`#895 `_) * Spelling and grammar fixes. (`#915 `_) (`#891 `_) Development ----------- * The logo was run through `tidy` to give it a consistent style. Some technical issues with the logo were improved. (`#877 `_) * The entire codebase is now checked by `flake8`, rather than just the module and test directories. This catches things like the pynsist installer scripts. (`#884 `_) (`#882 `_) (`#879 `_) Packaging --------- * The vendored `qtpy` library was updated to `v1.6`. * The Windows installer's wrapper scripts were missing an import. (`#878 `_) .. _v3.2: git-cola v3.2 ============= Usability, bells and whistles ----------------------------- * The `git cola dag` DAG window now supports `git revert`. (`#843 `_) * `git stash pop` is now supported by the stash dialog. (`#844 `_) * The status widget now ensures that each item is visible when selection changes. Previously, if you scrolled to the right to see the name of a long filename, and then selected a short filename above it, the widget may not have shown the short filename in the viewport. We now ensure that the filenames are visible when the selection changes. (`#828 `_) * The `git xbase` rebase editor no longer displays an error when cancelling an interactive rebase. (`#814 `_) * The dialog shown when renaming remotes has been simplified. (`#840 `_) (`#838 `_) * The help dialog in the `git-xbase` Rebase editor is now scrollable. (`#855 `_) Translations ------------ * Updated Brazilian translation. (`#845 `_) * Updated Czech translation. (`#854 `_) (`#853 `_) (`#835 `_) (`#813 `_) * Update Spanish translation. (`#862 `_) (`#867 `_) Packaging --------- * The original `#!/usr/bin/env python` shebang lines can now be retained by passing `USE_ENV_PYTHON=1` to `make` when installing. (`#850 `_) * The Makefile is now resilient to DESTDIR and prefix containing whitespace. (`#858 `_) * The vendored `qtpy` library was updated to `v1.4.2`. * `python3-distutils` is needed to build cola on Debian. (`#837 `_) Fixes ----- * The "C" key no longer closes the message dialogs, for example the one that is shown when a commit fails its pre-commit hooks. This allows "Ctrl+C" copy to work, rather than closing the dialog. (`#734 `_) * Dock widgets sizes are now properly saved and restored when the main window is maximized. (`#848 `_) * The spellcheck feature was broken under Python3. (`#857 `_) * A regression when saving stashes was fixed. (`#847 `_) * Diffing image files was not updating the available context menus, which prevented the "Stage" action from being present in the menu. (`#841 `_) * `git cola` now detects when `git lfs uninstall` has been run. This allows you to re-initialize "Git LFS" in an existing repository where it had been previously uninstalled. (`#842 `_) * Custom color values that did not contain any hexadecimal digits in the `a-f` range were being converted into integers by the config reader. This then caused the configured colors to be ignored. These color values are now interpreted correctly. Additionally, color values can now use an optional HTML-like `#` prefix. Example `.gitconfig` snippet:: [cola "color"] text = "#0a0303" (`#836 `_) (`#849 `_) * We now display an error message graphically when `Git` is not installed. Previously, the message went to stderr only. (`#830 `_) * Changing diff options was causing resulting in an exception. (`#833 `_) (`#834 `_) * The DAG window now updates itself when branches and tags are created. (`#814 `_) * The user's `$PATH` environment variable can now contain utf-8 encoded paths. Previously, launching external commands could lead to tracebacks. (`#807 `_) * Git Cola development sandboxes can now be stored on utf-8 encoded filesystem paths. Previously, the interactive rebase feature could be broken when running in that environment. (`#825 `_) * The log window now uses an ISO-8601 timestamp, which avoids localized output in the log window. (`#817 `_) Development ----------- * The code base has been thoroughly sanitized using `pylint`, and travis is now running pylint over the entire project. * Miscellaneous improvements and code improvements. (`#874 `_) .. _v3.1: git-cola v3.1 ============= Usability, bells and whistles ----------------------------- * The "Browser" widget learned to rename files using "git mv". (`#239 `_) * The "Diff" widget learned to diff images. Side-by-side and pixel diff modes allow you to inspect changes to common images formats. (`#444 `_) (`#803 `_) * Git LFS and Git Annex are natively supported by the image diff viewer. * Git Annex operations are now included. `git annex init` can be performed on repositories, and `git annex add` can be run on untracked files from the status widget. Install `git-annex` to activate this feature. * Git LFS operations are now included. `git lfs install` can be performed on repositories, and `git lfs track` can be run on untracked files from the status widget. Install `git-lfs` to activate this feature. * The "Stash" tool learned to stash staged changes only. Select the "Stage Index" option and only staged changes will be stashed away. (`#413 `_) * The "Stash" tool learned to use vim-like navigation keyboard shortcuts, shows error messages when things go wrong, and now saves the "Stash Index" and "Keep Index" options across sessions. * The Edit menu's "Copy" and "Select All" actions now forward to either the diff, status, recent, or favorites widgets, based on which widget has focus. * The "File" and "Edit" menu can now be activated using `Alt-{f,e}` hotkeys. (`#759 `_) * It was easy to accidentally trigger the first action in the `Status` tool's context menu when using a quick right-click to bring up the menu. A short sub-second delay was added to ensure that the top-most action is not triggered unless enough time has passed. This prevents accidental activation of the first item (typically "Stage" or "Unstage") without burdening common use cases. (`#755 `_) (`#643 `_) * The "Ctrl+S" hotkey now works for the header items in the Status tool. Selected the "Modified" header item and activating the "Stage" hotkey, for example, will stage all modified files. This works for the "Staged", "Modified", and "Untracked" headers. This is not enabled for the "Unmerged" header by design. (`#772 `_) * The list of "Recent" repositories previously capped the number of repositories shown to 8 repositories. This can be set to a higher value by setting the `cola.maxrecent` configuration variable. (`#752 `_) * The "Create Branch" dialog now prevents invalid branch names. (`#765 `_) * Updated Turkish translation. (`#756 `_) * Updated Ukrainian translation. (`#753 `_) * Updated German translation. (`#802 `_) * Updated Czech translation (`#792 `_) (`#806 `_) * The window title can be configured to not display the absolute path of the repository. (`#775 `_) * The "Edit Remotes" editor learned to edit remote URLS. * Bare repositories can now be created by selecting the "New Bare Repository..." action from the `File` menu. * The "Branches" widget learned to configure upstream branches. * A new `git cola clone` sub-command was added for cloning repositories. Packaging --------- * The vendored `qtpy` library was updated to `v1.3.1`. * The macOS installation was made simpler for better compatibility with Homebrew. (`#636 `_) * The Windows installer is now much simpler. Git Cola now bundles Python and PyQt5, so users need only install the "Git for Windows" and "Git Cola" installers to get things working. Fixes ----- * Uninitialized difftool errors will now be displayed graphically. They were previously going to the shell. (`#457 `_) * Translations marked "fuzzy" will no longer be used when translating strings. (`#782 `_) * Deleted unmerged files will now correctly use a deleted icon. (`#479 `_) * The `Ctrl+C` "Copy" hotkey on the diff viewer has been fixed. (`#767 `_) * The "Create Tag" dialog did not correctly handle the case when a signed tag is requested, but no message is provided, and the user chooses to create an unannotated tag instead. This convenience fallback will now properly create an unsigned, unannotated tag. (`#696 `_) * `.gitconfig` and `.git/config` values editable by the Preferences dialog (aka `git cola config`) will now get unset when set to an empty value. For example, setting a different `user.email` in the current repository, followed by a subsequent emptying of that field, would previously result in an empty string getting stored in the config. This has been fixed so that the value will now get unset in the config instead. (`#406 `_) * Spelling and typofixes. (`#748 `_) * `core.commentChar` is now honored when set in the local repository `.git/config`. (`#766 `_) * The log window was using a format string that did not display correctly in all locales. A locale-aware format is now used. (`#800 `_) * The dialog displayed when prompting for a reference could sometimes lose focus. (`#804 `_) .. _v3.0: git-cola v3.0 ============= Usability, bells and whistles ----------------------------- * Updated Simplified Chinese translation. (`#726 `_) * Updated Ukrainian translation. (`#723 `_) * New Czech translation. (`#736 `_) (`#737 `_) (`#740 `_) (`#743 `_) * The "name" field in the "Create Tag" dialog now includes autocompletion, which makes it easy to see which tags currently exist. * `git cola` now has configurable toolbars. Use the `View -> Add toolbar` menu item to add a toolbar. * Setting `cola.expandtab` to `true` will now expand tabs into spaces in the commit message editor. The number of spaces to insert is determined by consulting `cola.tabwidth`, which defaults to `8`. * The "Copy SHA-1" hotkey is now `Alt + Ctrl + C`, to avoid clobbering the ability to copy text from the DAG window. (`#705 `_) * The "Prepare Commit Message" action can now be invoked via the `Ctrl+Shift+Return` shortcut. (`#707 `_) * The `Branches` pane now has a filter field that highlights branches whose names match the string entered into its text field. (`#713 `_) * Actions that are triggered in response to button presses were being triggered when the button was pressed, rather than when it was released, which was a usability flaw. All buttons now respond when clicked rather than when pressed. (`#715 `_) * The DAG window will now only refresh when object IDs change. Previously, the DAG would redraw itself in response to inotify events, such as filesystem operations, which was disruptive when inspecting a large diff in its diff viewer. The DAG will now only redraw when the object IDs corresponding to its query input changes. Furthermore, when redrawing, the scrollbar positions are retained to minimize disruption to the viewport contents. (`#620 `_) (`#724 `_) * The "About" dialog now includes the SHA-1 where Git Cola was built. (`#530 `_) * The "Status" widget now has "Copy Leading Path to Clipboard" and "Copy Basename to Clipboard" actions. (`#435 `_) (`#436 `_) * The "Status" widget now supports custom "Copy ... to Clipboard" actions. (`#437 `_) * The main menu now has an "Edit" menu. (`#725 `_) * `git dag` learned to checkout commits into a detached HEAD state. (`#698 `_) * The `status` widget's context menus now omit actions selection-dependent actions when no file is selected. (`#731 `_) * The startup dialog now focuses the repository list so that repositories can be selected with the keyboard without mouse intervention. (`#741 `_) Fixes ----- * `git dag` now prevents nodes from overlapping in more situations. (`#689 `_) * Adding untracked Git submodule repo directories previously ran `git add submodule/` but we now call `git add submodule` without the trailing slash (`/`) to avoid staging files that belong to the submodule (which is possibly a `git` bug). By working around the buggy behavior we allow users to recover by issuing the appropriate `git submodule add` command to properly register the submodule. (`#681 `_) * We now avoid `git for-each-ref --sort=version:refname` on versions of `git` older than `v2.7.0`. Previously we only avoided it for versions older than `v2.0.0`, which was a mistake. (`#686 `_) * The error message displayed when `git` is not installed has been fixed. (`#686 `_) * Adding new remotes was silently broken. (`#684 `_) (`#685 `_) * The repo selection dialog had errors during startup when the `cola.refreshonfocus` feature was enabled, as reported on Ubuntu 16.04. (`#690 `_) * Restored support for PyQt 4.6 (Centos 6.8) (`#692 `_) * Switching repositories now resets the "Amend Mode" and other settings when switching. (`#710 `_) * `git rebase` error messages now displayed when rebasing fails or stops via the standalone `git cola rebase` front-end. (`#721 `_) * `git cola` learned to stage broken symlinks. (`#727 `_) * The "View History" feature in the `Browser` tool was fixed, and now disambiguates between refs and paths. (`#732 `_) * The diff editor now has better support for files with CRLF `\r\n` line endings. (`#730 `_) * `cola.inotify` in a repo-local config is now honored when `git cola` is launched from a desktop entry (`git cola --prompt`). (`#695 `_) .. _v2.11: git-cola v2.11 ============== Usability, bells and whistles ----------------------------- * New Ukrainian translation. (`#670 `_) (`#672 `_) * New and improved French translations. * The new `Branches` widget makes it easier to checkout, merge, push, and pull branches from a single interface. * `git cola` now includes a dark icon theme. The dark icon theme can be activated either by setting the `GIT_COLA_ICON_THEME` environment variable to `dark`, by configuring `cola.icontheme` to `dark`, or by specifying `--icon-theme=dark` on the command line. (`#638 `_) * Autocompletion was added to the `Fetch`, `Push`, and `Pull` dialogs. * The commit message editor now remembers the "Spellcheck" setting after exiting. (`#645 `_) * `git dag` now uses an improved algorithm for laying out the graph, which avoids collisions under certain graph configurations, and avoids overlapping tag with commits. (`#648 `_) (`#651 `_) (`#654 `_) (`#656 `_) (`#659 `_) * `git dag` now remembers its column sizes across sessions. (`#674 `_) * `Grep` now shows a preview of the selected file's content in a split window below the grep results. * `Grep` now includes line numbers in the preview pane's output. * `Edit Remotes` now remembers its window settings after exiting. * `Diff` now has an option to display line numbers in the editor. (`#136 `_) * `Amend Last Commit` can now be triggered via the `Commit` menu in addition to the commit message editor's options. (`#640 `_) * The `File Browser` tool was made much faster and can now operate on much larger repositories. (`#499 `_) * A new "turbo" mode was added that allows you to opt-out of operations that can slow `git cola` on large repositories. The turbo mode is enabled by configuring `git config cola.turbo true`. Turbo mode disables the background loading of Git commit messages and other details in the `File Browser` widget. * A new GitIgnore dialog allows adding custom gitignore patterns. (`#653 `_) * The spellchecker in `git cola` can now use an additional dictionary by configuring `cola.dictionary` to the path to a file containing a newline-separated list of words. (`#663 `_) * The stash, export patches, diff, and gitignore dialogs now remember their window sizes. * A new `git cola recent` sub-command was added for finding recently edited files. * The `Fetch` dialog now allows pruning remote branches. (`#639 `_) (`#680 `_) Fixes ----- * `git cola`'s spellchecker now supports the new `dict-common` filesystem layout, and prefers the `/usr/share/dict/cracklib-small` file over the `/usr/share/dict/words` provided on older distributions. This makes the spellchecker compatible with Arch, which does not provide a `words` symlink like Debian. (`#663 `_) * Properly handle the case where an existing file is untracked using the File Browser. * Fix a quirk where the "Create Branch" dialog sometimes required clicking twice on the radio buttons. (`#662 `_) * Fixed a focus issue to ensure that "Push", "Fetch", and "Pull" can be executed with the press of a single enter key after being shown. (`#661 `_) * Committing is now allowed in when resolving a merge results in no changes. This state was previously prevented by the commit message editor, which prevented users from resolving merges that result in no changes. (`#679 `_) * The filesystem monitor would sometimes emit backtraces when directories are modified. This has been fixed. (`bz #1438522 `_) * Absolute paths are now returned when querying for `.git`-relative paths from within a submodule, which uses `.git`-files. This fixes launching `git cola` from within a subdirectory of a submodule. (`#675 `_) .. _v2.10: git-cola v2.10 ============== Usability, bells and whistles ----------------------------- * `git cola` can now invoke the `.git/hooks/cola-prepare-commit-msg` hook to update the commit message. This hook takes the same parameters as Git's `prepare-commit-message` hook. The default path to this hook can be overridden by setting the `cola.prepareCommitMessageHook` configuration variable. (`Documentation `_) * `git cola diff` (and the corresponding `Diff` menu actions) can now launch difftool with the standard `Ctrl+D` hotkey. The `Ctrl+E` hotkey was also added for launching an editor. * Traditional Chinese (Taiwan) translation updates. Fixes ----- * `git cola` now works when installed in non-ascii, utf8-encoded paths. (`#629 `_) * Styling issues that caused black backgrounds in various widgets when using PyQ5 on Mac OS X have been fixed. (`#624 `_) * The "Open Recent" menu action was broken and has been fixed. (`#634 `_) * Exiting `git cola` with a maximized main window would hang when reopened on Linux. (`#641 `_) Packaging --------- * `appdata.xml` files are now provided at `share/appdata/git-cola.xml` and `share/appdata/git-dag.xml` for use by the Linux software gallery. (`#627 `_) (`Appdata `_) .. _v2.9.1: git-cola v2.9.1 =============== Fixes ----- * The "Open Recent" menu was updated to new bookmarks format. (`#628 `_) .. _v2.9: git-cola v2.9 ============= Usability, bells and whistles ----------------------------- * New Polish translation thanks to Łukasz Wojniłowicz (`#598 `_) * The `Bypass Commit Hooks` feature now disables itself automatically when a new commit is created. The new behavior turns the option into a single-use flag, which helps prevent users from accidentally leaving it active longer than intended. (`#595 `_) * `git dag` learned to launch an external diff viewer on selected commits. The standard `Ctrl+D` shortcut can be used to view diffs. (`#468 `_) * `git dag` learned to launch directory diffs via `git difftool --dir-diff`. The `Ctrl+Shift+D` shortcut launches difftool in directory-diff mode. (`#468 `_) * Items in the "Favorites" list can now be renamed, which makes it easier to differentiate between several checkouts of the same repository. (`#599 `_) (`#601 `_) * The startup screen now includes a logo and `git cola` version information. (`#526 `_) * The `About` page was revamped to contain multiple tabs. A new tab was added that provides details about `git cola`''s dependencies. New tabs were also added for giving credit to `git cola`'s authors and translators. * The `About` page can now be accessed via `git cola about`. * The "Fast-forward only" and "No fast-forward" options supported by `git pull` are now accessible via `git cola pull`. * Doing a forced push no longer requires selecting the remote branch. (`#618 `_) * `git cola push` now has an option to suppress the prompt that is shown when pushing would create new remote branches. (`#605 `_) * `git dag` now shows commit messages in a more readable color. (`#574 `_) * `git cola browse` and the `status` widget learned to launch the OS-specified default action for a file. When used on directories via `git cola browse`, or when "Open Parent Directory" is used on files, the OS-specified file browser will typically be used. * `git cola browse` and the `status` widget learned to launch terminals. Fixes ----- * `git cola browse` was not updating when expanding items. (`#588 `_) * Typofixes in comments, naming, and strings have been applied. (`#593 `_) * The inotify and win32 filesystem monitoring no longer refreshes when updates are made to ignored files. (`#517 `_) (`#516 `_) * The `Refresh` button on the actions panel no longer raises an exception when using PyQt5. (`#604 `_) * Fixed a typo in the inotify backend that is triggered when files are removed. (`#607 `_) * Fixed a typo when recovering from a failed attempt to open a repository. (`#606 `_) * `git dag` now properly updates itself when launched from the menubar. (`#613 `_) * If git-cola is invoked on Windows using `start pythonw git-cola`, a console window will briefly flash on the screen each time `git cola` invokes `git`. The console window is now suppressed. * We now avoid some problematic Popen flags on Windows which were breaking the `git rebase` feature on Windows. * The `Save` button in `git dag`'s "Grab File..." feature now properly prompts for a filename when saving files. (`#617 `_) Development ----------- * The `qtpy` symlink in the source tree has been removed to allow for easier development on Windows. (`#626 `_) .. _v2.8: git-cola v2.8 ============= Usability, bells and whistles ----------------------------- * `git cola push` learned to configure upstream branches. (`#563 `_) Fixes ----- * The diffstat view is now properly updated when notifications are received via inotify filesystem monitoring. (`#577 `_) * Python3 with PyQt5 had a bug that prevented `git cola` from starting. (`#589 `_) .. _v2.7: git-cola v2.7 ============= Fixes ----- * When repositories stored in non-ASCII, UTF-8-encoded filesystem paths were operated upon with `LC_ALL=C` set in the environment, unicode errors would occur when using `python2`. `git cola` was made more robust and will now operate correctly within this environment. (`#581 `_) * Support for the `GIT_WORK_TREE` environment variable was fixed. (`#582 `_) Development ----------- * The `unittest.mock` module is now used instead of the original `mock` module when running the `git cola` test suite using Python3. (`#569 `_) Packaging --------- * `git cola` is now compatible with *PyQt5*, *PyQt4*, and *Pyside*. `git cola` previously supported *PyQt4* only, but will now use whichever library is available. Users are not required to upgrade at this time, but *PyQt5* support can be enabled anytime by making its python modules available. (`#232 `_) *NOTE*: We do not yet recommend using *PyQt5* because there are known exit-on-segfault bugs in *Qt5* that have not yet been addressed. `git cola` is sensitive to this bug and is known to crash on exit when using `git dag` or the interactive rebase feature on *PyQt5*. https://bugreports.qt.io/browse/QTBUG-52988 *PyQt4* is stable and there are no known issues when using it so we recommend using it until the Qt5 bugs have been resolved. * `git cola` now depends on *QtPy* and includes a bundled copy of the `qtpy` library. If you are packaging `git cola` and would prefer to use `qtpy` from your distribution instead of the built-in version then use `make NO_VENDOR_LIBS=1` when building `git cola`. This will prevent vendored libraries from being installed. .. _v2.6: git-cola v2.6 ============= Usability, bells and whistles ----------------------------- * A new "Reset" sub-menu provides access to running "git reset --mixed" when resetting branch heads and "git reset --merge" when resetting worktrees. (`#542 `_) * `git cola` now supports linked worktrees, i.e. worktrees created by `git worktree`. (`#554 `_) Fixes ----- * Diff highlighting is now robust to the user having diff.supressBlankEmpty=true in their git config. (`#541 `_) * The filesystem monitor now properly handles repositories that use `.git`-files, e.g. when using submodules. (`#545 `_) (`#546 `_) * Per-repository git configuration is now properly detected when launching `git cola` from an application launcher. (`#548 `_) * `git cola` now cleans up after itself immediately to avoid leaving behind empty `/tmp/git-cola-XXXXXX` directories when the user uses `Ctrl+C` to quit the app. (`#566 `_) Packaging --------- * It is now possible to install `git cola` to and from utf8-encoded filesystem paths. Previously, Python's stdlib would throw an encoding error during installation. We workaround the stdlib by forcing python2 to use utf-8, thus fixing assumptions in the stdlib library code. (`#551 `_) .. _v2.5: git-cola v2.5 ============= Usability, bells and whistles ----------------------------- * The icon for untracked files was adjusted to better differentiate between files and the "Untracked" header. (`#509 `_) * Ctrl+O was added as a hotkey for opening repositories. (`#507 `_) * `git dag` now uses consistent edge colors across updates. (`#512 `_) * `git cola`'s Bookmarks widget can now be used to set a "Default Repository". Under the hood, we set the `cola.defaultrepo` configuration variable. The default repository is used whenever `git cola` is launched outside of a Git repository. When unset, or when set to a bogus value, `git cola` will prompt for a repository, as it previously did. (`#513 `_) * `git cola`'s Russian and Spanish translations were improved thanks to Vaiz and Zeioth. (`#514 `_) (`#515 `_) (`#523 `_) * `git cola` was translated to Turkish thanks to Barış ÇELİK. (`#520 `_) * The status view now supports launching `git gui blame`. It can be configured to use a different command by setting `cola.blameviewer`. (`#521 `_) * `git dag` now allows selecting non-contiguous ranges in the log widget. (`#468 `_) * Any font can now be chosen for the diff editor, not just monospace fonts. (`#525 `_) Fixes ----- * `xfce4-terminal` and `gnome-terminal` are now supported when launching `git mergetool` to resolve merges. These terminals require that the command to execute is shell-quoted and passed as a single string argument to `-e` rather than as additional command line arguments. (`#524 `_) * Fixed a unicode problem when formatting the error message that is shown when `gitk` is not installed. We now handle unicode data in tracebacks generated by python itself. (`#528 `_) * The `New repository` feature was fixed. (`#533 `_) * We now use omit the extended description when creating "fixup!" commits, for consistency with the Git CLI. We now include only the one-line summary in the final commit message. (`#522 `_) .. _v2.4: git-cola v2.4 ============= Usability, bells and whistles ----------------------------- * The user interface is now HiDPI-capable. git-cola now uses SVG icons, and its interface can be scaled by setting the `GIT_COLA_SCALE` environment variable. * `git dag` now supports the standard editor, difftool, and history hotkeys. It is now possible to invoke these actions from file widget's context menu and through the standard hotkeys. (`#473 `_) * The `Status` tool also learned about the history hotkey. Additionally, the `Alt-{j,k}` aliases are also supported in the `Status` tool for consistency with the other tools where the non-Alt hotkeys are not available. (`#488 `_) * The `File Browser` tool now has better default column sizes, and remembers its window size and placement. * The `File Browser` now supports the refresh hotkey, and has better behavior when refreshing. The selection is now retained, and new and removed files are found when refreshing. * A new `git-cola-completion.bash` completion script is provided in the `contrib/` directory. It must be used alongside Git's completion script. Source it from your `~/.bashrc` (or `~/.zshrc`, etc) after sourcing the `git-completion.bash` script and you will have command-line completion support for the `git cola` and `git dag` sub-commands. * The "checkout" dialog now offers completion for remote branches and other git refs. This makes it easier to checkout remote branches in a detached head state. Additionally, the checkout dialog also offers completion for remote branches that have not yet been checked out, which makes it easier to create a local tracking branch by just completing for that potential name. (`#390 `_) * The "create branch" and "create tag" dialogs now save and restore their window settings. * The "status" widget can now be configured to use a bold font with a darker background for the header items. (`#506 `_) * The "status" widget now remembers its horizontol scrollbar position across updates. This is helpful when working on projects with long paths. (`#494 `_) Fixes ----- * When using *Git for Windows*, a `git` window would appear when running *Windows 8*. We now pass additional flags to `subprocess.Popen` to prevent a `git` window from appearing. (`#477 `_) (`#486 `_) * Launching difftool with `.PY` in `$PATHEXT` on Windows was fixed. (`#492 `_) * Creating a local branch tracking a remote branch that contains slashes in its name is now properly handled. (`#496 `_) * The "Browse Other Branch" feature was broken by Python3, and is now fixed. (`#501 `_) * We now avoid `long` for better Python3 compatibility. (`#502 `_) * We now use Git's default merge message when merging branches. (`#508 `_) * Miscellaneous fixes (`#485 `_) Packaging --------- * git-cola's documentation no longer uses an intersphinx link mapping to docs.python.org. This fixes warnings when building rpms using koji, where network access is prevented. https://bugzilla.redhat.com/show_bug.cgi?id=1231812 .. _v2.3: git-cola v2.3 ============= Usability, bells and whistles ----------------------------- * The Interactive Rebase feature now works on Windows! (`#463 `_) * The `diff` editor now understands vim-style `hjkl` navigation hotkeys. (`#476 `_) * `Alt-{j,k}` navigation hotkeys were added to allow changing to the next/previous file from the diff and commit editors. * The `Rename branch` menu action is now disabled in empty repositories. (`#475 `_) (`#459 `_) * `git cola` now checks unmerged files for conflict markers before staging them. This feature can be disabled in the preferences. (`#464 `_) * `git dag` now remembers which commits were selected when refreshing so that it can restore the selection afterwards. (`#480 `_) * "Launch Editor", "Launch Difftool", "Stage/Unstage", and "Move Up/Down" hotkeys now work when the commit message editor has focus. (`#453 `_) * The diff editor now supports the `Ctrl+u` hotkey for reverting diff hunks and selected lines. * The `core.commentChar` Git configuration value is now honored. Commit messages and rebase instruction sheets will now use the configured character for comments. This allows having commit messages that start with `#` when `core.commentChar` is configured to its non-default value. (`#446 `_) Fixes ----- * Diff syntax highlighting was improved to handle more edge cases and false positives. (`#467 `_) * Setting commands in the interactive rebase editor was fixed. (`#472 `_) * git-cola no longer clobbers the Ctrl+Backspace text editing shortcut in the commit message editor. (`#453 `_) * The copy/paste clipboard now persists after `git cola` exits. (`#484 `_) .. _v2.2.1: git-cola v2.2.1 =============== Fixes ----- * Fixed the "Sign off" feature in the commit message editor. .. _v2.2: git-cola v2.2 ============= Usability, bells and whistles ----------------------------- * Double-click will now choose a commit in the "Select commit" dialog. * `git cola` has a feature that reads `.git/MERGE_MSG` and friends for the commit message when a merge is in-progress. Upon refresh, `git cola` will now detect when a merge has completed and reset the commit message back to its previous state. It is only reset if the editor contains a message that was read from the file and has not been manually edited by the user. * The commit message editor's context menu now has a "Clear..." action for clearing the message across both the summary and description fields. * Traditional Chinese (Taiwan) translation updates. * The system theme's icons are now used wherever possible. (`#458 `_) Fixes ----- * The stash viewer now uses ``git show --no-ext-diff`` to avoid running user-configured diff tools. * `git cola` now uses the `setsid()` system call to ensure that the `GIT_ASKPASS` and `SSH_ASKPASS` helper programs are used when pushing changes using `git`. The askpass helpers will now be used even when `git cola` is launched from a terminal. The behavior without `setsid()` is that `git cola` can appear to hang while pushing changes. The hang happens when `git` prompts the user for a password using the terminal, but the user never sees the prompt. `setsid()` detaches the terminal, which ensures that the askpass helpers are used. (`#218 `_) (`#262 `_) (`#377 `_) * `git dag`'s file list tool was updated to properly handle unicode paths. * `gnome-terminal` is no longer used by default when `cola.terminal` is unset. It is broken, as was detailed in #456. (`#456 `_) * The interactive rebase feature was not always setting `$GIT_EDITOR` to the value of `gui.editor`, thus there could be instances where rebase will seem to not stop, or hang, when performing "reword" actions. We now set the `$GIT_EDITOR` environment variable when performing the "Continue", "Skip", and "Edit Todo" rebase actions so that the correct editor is used during the rebase. (`#445 `_) Packaging --------- * `git cola` moved from a 3-part version number to a simpler 2-part "vX.Y" version number. Most of our releases tend to contain new features. .. _v2.1.2: git-cola v2.1.2 =============== Usability, bells and whistles ----------------------------- * Updated zh_TW translations. * `git cola rebase` now defaults to `@{upstream}`, and generally uses the same CLI syntax as `git rebase`. * The commit message editor now allows you to bypass commit hooks by selecting the "Bypass Commit Hooks" option. This is equivalent to passing the `--no-verify` option to `git commit`. (`#357 `_) * We now prevent the "Delete Files" action from creating a dialog that does not fit on screen. (`#378 `_) * `git xbase` learned to edit rebase instruction sheets that contain `exec` commands. * The diff colors are now configurable. `cola.color.{text,add,remove,header}` can now be set with 6-digit hexadecimal colors. See the `git cola manual _` for more details. * Improved hotkey documentation. Fixes ----- * `git cola` will now allow starting an interactive rebase with a dirty worktree when `rebase.autostash` is set. (`#360 `_) .. _v2.1.1: git-cola v2.1.1 =============== Usability, bells and whistles ----------------------------- * A new "Find files" widget was added, and can be activated by using the `Ctrl+t` or `t` hotkeys. * A new `git cola find` sub-command was added for finding files. * `git cola` now remembers the text cursor's position when staging interactively with the keyboard. This makes it easier to use the keyboard arrows to select and stage lines. * The completion widgets will now select the top completion item when `Enter` or `Return` are pressed. * You can now refresh using `F5` in addition to the existing `Ctrl+R` hotkey. Fixes ----- * `git cola` now passes `--no-abbrev-commit` to `git log` to override having `log.abbrevCommit = true` set in `.gitconfig`. .. _v2.1.0: git-cola v2.1.0 =============== Usability, bells and whistles ----------------------------- * `git dag` now forwards all unknown arguments along to `git log`. (`#389 `_) * Line-by-line interactive staging was made more robust. (`#399 `_) * "Bookmarks" was renamed to "Favorites". (`#392 `_) * Untracked files are now displayed using a unique icon. (`#388 `_) Fixes ----- * `git dag` was triggering a traceback on Fedora when parsing Git logs. (`bz #181676 `_) * inotify expects unicode paths on Python3. (`#393 `_) * Untracked files are now assumed to be utf-8 encoded. (`#401 `_) .. _v2.0.8: git-cola v2.0.8 =============== Usability, bells and whistles ----------------------------- * `git cola` can now create GPG-signed commits and merges. See the documentation for details about setting up a GPG agent. (`#149 `_) * The status widget learned to copy relative paths when `Ctrl+x` is pressed. (`#358 `_) * Custom GUI actions can now define their own keyboard shortcuts by setting `guitool.$name.shortcut` to a string understood by Qt's `QAction::setShortcut()` API, e.g. `Alt+X`. See the `Qt docs `_ for more details about the supported values. * `git cola` learned to rename branches. (`#364 `_) (`#278 `_) * `git dag` now has a "Show history" context menu which can be used to filter history using the selected paths. Fixes ----- * `sphinxtogithub.py` was fixed for Python3. (`#353 `_) * The commit that changed how we read remotes from `git remote` to parsing `git config` was reverted since it created problems for some users. * Fixed a crash when using the `rebase edit` feature. (`#351 `_) * Better drag-and-drop behavior when dropping into gnome-terminal. (`#373 `_) Packaging --------- * The `git-cola-folder-handler.desktop` file handler was fixed to pass validation by `desktop-file-validate`. (`#356 `_) * The `git.svg` icon was renamed to `git-cola.svg`, and `git cola` was taught to prefer icons from the desktop theme when available. .. _v2.0.7: git-cola v2.0.7 =============== Usability, bells and whistles ----------------------------- * New hotkey: `Ctrl+Shift+M` merges branches. * New hotkey: `Ctrl+R` refreshes the DAG viewer. (`#347 `_) Fixes ----- * We now use `git config` to parse the list of remotes instead of parsing the output of `git remote`, which is a Git porcelain and should not be used by scripts. * Avoid "C++ object has been deleted" errors from PyQt4. (`#346 `_) Packaging --------- * The `make install` target now uses `install` instead of `cp`. .. _v2.0.6: git-cola v2.0.6 =============== Usability, bells and whistles ----------------------------- * Updated Brazillian Portuguese translation. * The status and browse widgets now allow drag-and-drop into external applications. (`#335 `_) * We now show a progress bar when cloning repositories. (`#312 `_) * The bookmarks widget was simplified to not need a separate dialog. (`#289 `_) * Updated Traditional Chinese translation. * We now display a warning when trying to rebase with uncommitted changes. (`#338 `_) * The status widget learned to filter paths. `Ctrl+Shift+S` toggles the filter widget. (`#337 `_) (`#339 `_) * The status widget learned to move files to the trash when the `send2trash `_ module is installed. (`#341 `_) * "Recent repositories" is now a dedicated widget. (`#342 `_) * New Spanish translation thanks to Pilar Molina Lopez. (`#344 `_) Fixes ----- * Newly added remotes are now properly seen by the fetch/push/pull dialogs. (`#343 `_) .. _v2.0.5: git-cola v2.0.5 =============== Usability, bells and whistles ----------------------------- * New Brazillian Portuguese translation thanks to Vitor Lobo. * New Indonesian translation thanks to Samsul Ma'arif. * Updated Simplified Chinese translation thanks to Zhang Han. * `Ctrl+Backspace` is now a hotkey for "delete untracked files" in the status widget. * Fetch/Push/Pull dialogs now use the configured remote of the current branch by default. (`#324 `_) Fixes ----- * We now use `os.getcwd()` on Python3. (`#316 `_) (`#326 `_) * The `Ctrl+P` hotkey was overloaded to both "push" and "cherry-pick", so "cherry-pick" was moved to `Ctrl+Shift+C`. * Custom GUI tools with mixed-case names are now properly supported. * "Diff Region" is now referred to as "Diff Hunk" for consistency with common terminology from diff/patch tools. (`#328 `_) * git-cola's test suite is now portable to MS Windows. (`#332 `_) .. _v2.0.4: git-cola v2.0.4 =============== Usability, bells and whistles ----------------------------- * We now handle the case when inotify `add_watch()` fails and display instructions on how to increase the number of watches. (`#263 `_) * New and improved zh_TW localization thanks to V字龍(Vdragon). (`#265 `_) (`#267 `_) (`#268 `_) (`#269 `_) (`#270 `_) (`#271 `_) (`#272 `_) * New hotkeys: `Ctrl+F` for fetch, `Ctrl+P` for push, and `Ctrl+Shift+P` for pull. * The bookmarks widget's context menu actions were made clearer. (`#281 `_) * The term "Staging Area" is used consistently in the UI to allow for better localization. (`#283 `_) * The "Section" term is now referred to as "Diff Region" in the UI. (`#297 `_) * The localization documentation related to the LANGUAGE environment variable was improved. (`#293 `_) * The "Actions" panel now contains tooltips for each button in case the button labels gets truncated by Qt. (`#292 `_) * Custom `git config`-defined actions can now be run in the background by setting `guitool..background` to `true`. Fixes ----- * We now use bold fonts instead of SmallCaps to avoid artifacts on several configurations. * We now pickup `user.email`, `cola.tabwidth`, and similar settings when defined in /etc/gitconfig. (`#259 `_) * Better support for unicode paths when using inotify. (`bz #1104181 `_) * Unicode fixes for non-ascii locales. (`#266 `_) (`#273 `_) (`#276 `_) (`#282 `_) (`#298 `_) (`#302 `_) (`#303 `_) (`#305 `_) * Viewing history from the file browser was fixed for Python3. (`#274 `_) * setup.py was fixed to install the `*.rst` documentation. (`#279 `_) * Patch export was fixed for Python3. (`#290 `_) * Fixed adding a bookmark with trailing slashes. (`#295 `_) * The default `git dag` layout is now setup so that its widgets can be freely resized on Linux. (`#299 `_) * Invalid tag names are now reported when creating tags. (`#296 `_) .. _v2.0.3: git-cola v2.0.3 =============== Usability, bells and whistles ----------------------------- * `git cola` no longer prompts after successfully creating a new branch. (`#251 `_) * Hitting enter on simple dialogs now accepts them. (`#255 `_) Fixes ----- * `git dag` no longer relies on `sys.maxint`, which is not available in Python3. (`#249 `_) * Python3-related fixes. (`#254 `_) * Python3-on-Windows-related fixes. (`#250 `_) (`#252 `_) (`#253 `_) * Switching repositories using the bookmarks widget was not refreshing the inotify watcher. (`#256 `_) * Special commit messages trailers (e.g. "Acked-by:") are now special-cased to fix word wrapping lines that start with "foo:". (`#257 `_) * `git dag` sometimes left behind selection artifacts. We now refresh the view to avoid them. (`#204 `_) .. _v2.0.2: git-cola v2.0.2 =============== Usability, bells and whistles ----------------------------- * Better inotify support for file creation and deletion. (`#240 `_) * `git cola` now supports the X11 Session Management Protocol and remembers its state across logout/reboot. (`#164 `_) * `git cola` has a new icon. (`#190 `_) Packaging --------- * Building the documentation no longer requires `asciidoc`. We now use `Sphinx `_ for building html documentation and man pages. Fixes ----- * Reworked the git-dag gravatar icon code to avoid a unicode error in Python 2. * Commit message line-wrapping was made to better match the GUI editor. (`#242 `_) * Better support for Python3 on Windows (`#246 `_) Packaging --------- * git-cola no longer depends on Asciidoc for building its documentation and man-pages. We now depend on [Sphinx](http://sphinx-doc.org/) only. .. _v2.0.1: git-cola v2.0.1 =============== Usability, bells and whistles ----------------------------- * Some context menu actions are now hidden when selected files do not exist. (`#238 `_) Fixes ----- * The build-git-cola.sh contrib script was improved. (`#235 `_) * Non-ascii worktrees work properly again. (`#234 `_) * The browser now guards itself against missing files. (`bz #1041378 `_) * Saving widget state now works under Python3. (`#236 `_) .. _v2.0.0: git-cola v2.0.0 =============== Portability ----------- * git-cola now runs on Python 3 thanks to Virgil Dupras. (`#233 `_) * Python 2.6, 2.7, and 3.2+ are now supported. Python 2.5 is no longer supported. Fixes ----- * i18n test fixes thanks to Virgil Dupras. (`#231 `_) * git-cola.app build fixes thanks to Maicon D. Filippsen. (`#230 `_) * Lots of pylint improvements thanks to Alex Chernetz. (`#229 `_) .. _v1.9.4: git-cola v1.9.4 =============== Usability, bells and whistles ----------------------------- * The new `Bookmarks` tool makes it really easy to switch between repositories. * There is now a dedicated dialog for applying patches. See the ``File -> Apply Patches`` menu item. (`#215 `_) * A new `git cola am` sub-command was added for applying patches. Fixes ----- * Fixed a typo that caused inotify events to be silently ignored. * Fixed the sys.path setup for Mac OS X (Homebrew). (`#221 `_) * Lots of pylint fixes thanks to Alex Chernetz. .. _v1.9.3: git-cola v1.9.3 =============== Usability, bells and whistles ----------------------------- * `git cola --amend` now starts the editor in `amend` mode. (`#187 `_) * Multiple lines of text can now be pasted into the `summary` field. All text beyond the first newline will be automatically moved to the `extended description` field. (`#212 `_) Fixes ----- * Stray whitespace in `.git` files is now ignored. (`#213 `_) * Fix "known incorrect sRGB profile" in `staged-item.png`. (`gentoo-devel message #85066 `_) .. _v1.9.2: git-cola v1.9.2 =============== Fixes ----- * Fix a traceback when `git push` fails. (`bz #1034778 `_) Packaging --------- * Most of the git-cola sub-packages have been removed. The only remaining packages are `cola`, `cola.models`, and `cola.widgets`. * The translation file for Simplified Chinese was renamed to `zh_CN.po`. (`#209 `_) .. _v1.9.1: git-cola v1.9.1 =============== Packaging --------- * `git cola version --brief` now prints the brief version number. Fixes ----- * Resurrected the "make dist" target, for those that prefer to create their own tarballs. * Fixed the typo that broke the preferences dialog. .. _v1.9.0: git-cola v1.9.0 =============== Usability, bells and whistles ----------------------------- * We now ship a full-featured interactive `git rebase` editor. The rebase todo file is edited using the `git xbase` script which is provided at `$prefix/share/git-cola/bin/git-xbase`. This script can be used standalone by setting the `$GIT_SEQUENCE_EDITOR` before running `git rebase --interactive`. (`#1 `_) * Fixup commit messages can now be loaded from the commit message editor. * Tool widgets can be locked in place by using the "Tools/Lock Layout" menu action. (`#202 `_) * You can now push to several remotes simultaneously by selecting multiple remotes in the "Push" dialog. (`#148 `_) * The `grep` tool learned to search using three different modes: basic regular expressions (default), extended regular expressions, and fixed strings. Packaging --------- * `git cola` now depends on the `argparse` Python module. This module is part of the stdlib in Python 2.7 and must be installed separately when using Python 2.6 and below. Fixes ----- * Support unicode in the output from `fetch`, `push`, and `pull`. .. _v1.8.5: git-cola v1.8.5 =============== Usability, bells and whistles ----------------------------- * We now detect when the editor or history browser are misconfigured. (`#197 `_) (`bz #886826 `_) * Display of untracked files can be disabled from the Preferences dialog or by setting the `gui.displayuntracked` configuration variable to `false`. (`Git Mailing List on 2013-08-21 `_) Fixes ----- * Unicode stash names are now supported (`#198 `_) * The diffs produced when reverting workspace changes were made more robust. .. _v1.8.4: git-cola v1.8.4 ======================= Usability, bells and whistles ----------------------------- * Brand new German translation thanks to Sven Claussner. * The "File" menu now provides a "New Repository..." menu action. * `git dag` now uses a dock-widget interface so that its widgets can be laid-out and arranged. Customizations are saved and restored the next time `git dag` is launched. * `git dag` now has a "Zoom Best Fit" button next alongside the "Zoom In" and "Zoom Out" buttons. * `Ctrl+L` now focuses the "Search" field in the `git dag` tool. * Right-clicking in the "diff" viewer now updates the cursor position before performing actions, which makes it much easier to click around and selectively stage sections. Previously, the current cursor position was used which meant that it required two clicks (left-click to update the position followed by right-click to get the context menu) for the desired section to be used. This is now a single right-click operation. * The `Ctrl+D` "Launch Diff Tool" action learned to automatically choose between `git difftool` and `git mergetool`. If the file is unmerged then we automatically launch `git mergetool` on the path, otherwise we use `git difftool`. We do this because `git difftool` is not intended to be used on unmerged paths. Automatically using `git mergetool` when appropriate is the most intuitive and muscle-memory-friendly thing to do. * You can now right-click on folders in your standard file browser and choose "Open With -> Git Cola" (Linux-only). Fixes ----- * Python 2.6 on Mac OS X Snow Leopard does not provide a namedtuple at `sys.version_info`. We now avoid using that variable for better portability. * We now read the user's Git configuration from `~/.config/git/config` if that file is available, otherwise we use the traditional `~/.gitconfig` path, just like Git itself. * Some edge cases were fixed when applying partial/selected diffs. * The diff viewer is now properly cleared when refreshing. (`#194 `_) .. _v1.8.3: git-cola v1.8.3 =============== Usability, bells and whistles ----------------------------- * The diff viewer now has an "Options" menu which can be used to set "git diff" options. This can be used to ignore whitespace changes or to show a change with its surrounding function as context. (`#150 `_) * `git cola` now remembers your commit message and will restore it when `git cola` is restarted. (`#175 `_) * `Ctrl+M` can now be used to toggle the "Amend last commit" checkbox in the commit message editor. (`#161 `_) * Deleting remote branches can now be done from the "Branch" menu. (`#152 `_) * The commit message editor now has a built-in spell checker. Fixes ----- * We now avoid invoking external diffs when showing diffstats. (`#163 `_) * The `Status` tool learned to reselect files when refreshing. (`#165 `_) * `git cola` now remembers whether it has been maximized and will restore the maximized state when `git cola` is restarted. (`#172 `_) * Performance is now vastly improved when staging hundreds or thousands of files. * `git cola` was not correctly saving repo-specific configuration. (`#174 `_) * Fix a UnicodeDecode in sphinxtogithub when building from source. .. _v1.8.2: git-cola v1.8.2 =============== Usability, bells and whistles ----------------------------- * We now automatically remove missing repositories from the "Select Repository" dialog. (`#145 `_) * A new `git cola diff` sub-command was added for diffing changed files. Fixes ----- * The inotify auto-refresh feature makes it difficult to select text in the "diff" editor when files are being continually modified by another process. The auto-refresh causes it to lose the currently selected text, which is not wanted. We now avoid this problem by saving and restoring the selection when refreshing the editor. (`#155 `_) * More strings have been marked for l10n. (`#157 `_) * Fixed the Alt+D Diffstat shortcut. (`#159 `_) Fixes ----- * Better error handling when cloning repositories. We were not handling the case where a git URL has no basename, e.g. `https://git.example.com/`. `git cola` originally rejected these URLs instead of allowing users to clone them. It now allows these URLs when they point to valid git repositories. Additionally, `git cola` learned to echo the errors reported by `git clone` when it fails. (`#156 `_) .. _v1.8.1: git-cola v1.8.1 =============== Usability, bells and whistles ----------------------------- * `git dag` got a big visual upgrade. * `Ctrl+G` now launches the "Grep" tool. * `Ctrl+D` launches difftool and `Ctrl+E` launches your editor when in the diff panel. * git-cola can now be told to use an alternative language. For example, if the native language is German and we want git-cola to use English then we can create a `~/.config/git-cola/language` file with "en" as its contents: ``echo en >~/.config/git-cola/language`` (`#140 `_) * A new `git cola merge` sub-command was added for merging branches. * Less blocking in the main UI Fixes ----- * Autocomplete issues on KDE (`#144 `_) * The "recently opened repositories" startup dialog did not display itself in the absence of bookmarks. (`#139 `_) .. _v1.8.0: git-cola v1.8.0 =============== Usability, bells and whistles ----------------------------- * `git cola` learned to honor `.gitattributes` when showing and interactively applying diffs. This makes it possible to store files in git using a non-utf-8 encoding and `git cola` will properly accept them. This must be enabled by settings `cola.fileattributes` to true, as it incurs a small performance penalty. (`#96 `_) * `git cola` now wraps commit messages at 72 columns automatically. This is configurable using the `cola.linebreak` variable to enable/disable the feature, and `cola.textwidth` to configure the limit. (`#133 `_) * A new "Open Recent" sub-menu was added to the "File" menu. This makes it easy to open a recently-edited repository. (`#135 `_) * We now show a preview for untracked files when they are clicked using the `Status` tool. * A new "Open Using Default Application" action was added to the `Status` tool. It is activated using either `Spacebar` or through the context menu. This action uses `xdg-open` on Linux and `open` on Mac OS X. * A new "Open Parent Directory" action was added to the `Status` tool. It is activated using either `Shift+Spacebar` or through the context menu. * `git dag` learned to honor the `log.date` git configuration variable. This makes the date display follow whatever format the user has configured. * A new `git cola config` sub-command was added for quickly tweaking `git cola`'s git configuration settings. * Some small usability tweaks -- some user confirmation prompts were defaulting to "Cancel" when they should have been defaulting to the affirmative option instead. Fixes ----- * Properly handle arbitrarily-named branches. * We went back to launching `git mergetool` using an xterm. The reason is that there are a couple of places where `git mergetool` requires a terminal for user interaction not covered by `--no-prompt`. * We now properly handle an edge case when applying short diffs at the start of a file. .. _v1.7.7: git-cola v1.7.7 =============== Usability, bells and whistles ----------------------------- * New and improved `grep` mode lets you instantly find and edit files. * New `git cola grep` standalone mode. * Support for passing arguments to the configured editors, e.g. `gvim -p` This makes it possible to select multiple files in the status window and use `Ctrl-e` to edit them all at once. * Remote operations now prompt on errors only. * The `Tab` key now jumps to the extended description when editing the summary. * More shortcut key labels and misc. UX improvements. Fixes ----- * Selecting an item no longer copies its filename to the copy/paste buffer. `Ctrl-c` or the "Copy" context-menu action can be used instead. * The repository monitoring feature on Windows learned to ignore changes within the ".git" directory. Thanks to Andreas Sommer. (`#120 `_) .. _v1.7.6: git-cola v1.7.6 =============== Usability, bells and whistles ----------------------------- * `git dag` learned to color-code branchy edges. The edge colors change when a new branch is detected, which makes the history much easier to follow. A huge thanks to Uri Okrent for making it happen. * New GUI for editing remote repositories. * New `git cola archive` and `git cola remote` sub-commands. * `git cola browser` learned an 'Untrack' command. * The diff editor learned to staged/unstaged while amending. * The status tool can now scroll horizontally. * New git repositories can be created by clicking 'New' on the `git cola --prompt` startup screen. .. _v1.7.5: git-cola v1.7.5 =============== Usability, bells and whistles ----------------------------- * Auto-completion was added to more tools. * `git dag` is easier to use on smaller displays -- the author field elides its text which allows for a more compact display. * Selected commits in `git dag` were made more prominent and easier to see. * 'Create Branch' learned to fetch remote branches and uses a background thread to do so. * User-configured GUI tools are listed alphabetically in the 'Actions' menu. * The 'Pull' dialog remembers the value of the 'Rebase' checkbox between invocations. .. _v1.7.4.1: git-cola v1.7.4.1 ================= Fixes ----- * Detect Homebrew so that OS X users do not need to set PYTHONPATH. * `git dag` can export patches again. .. _v1.7.4: git-cola v1.7.4 =============== Usability, bells and whistles ----------------------------- * The 'Classic' tool was renamed to 'Browser' and learned to limit history to the current branch. * `git dag` learned about gravatar and uses it to show images for commit authors. * `git dag` learned to use OpenGL for rendering resulting in much faster rendering. * More dialogs learned vim-style keyboard shortcuts. * The commit message editor learned better arrow key navigation. .. _v1.7.3: git-cola v1.7.3 =============== Usability, bells and whistles ----------------------------- * `git cola` learned a few new sub commands: .. sourcecode:: sh git cola dag git cola branch git cola search * `Return` in the summary field jumps to the extended description. * `Ctrl+Return` is now a shortcut for 'Commit'. * Better French translation for 'Sign-off'. * The 'Search' widget now has a much simpler and streamlined user interface. * vim-style `h,j,k,l` navigation shortcuts were added to the DAG widget. * `git dag` no longer prompts for files when diffing commits if the text field contains paths. * General user interface and performance improvements. Fixes ----- * The diff viewer no longer changes font size when holding `Control` while scrolling with the mouse wheel. * Files with a typechange (e.g. symlinks that become files, etc.) are now correctly identified as being modified. Packaging --------- * The `cola.controllers` and `cola.views` packages were removed. .. _v1.7.2: git-cola v1.7.2 =============== Usability, bells and whistles ----------------------------- * `git cola` can now launch sub commands, e.g.: .. sourcecode:: sh git cola classic git cola stash git cola fetch git cola push git cola pull git cola tag * `git dag` is more responsive when gathering auto-completions. * Keyboard shortcuts are displayed when the '?' key is pressed. * Various keyboard shortcuts were added for improved usability. * The status widget now lists unmerged files before modified files. * vim-style `h,j,k,l` navigation shortcuts were added to the status widget. * A 'Recently Modified Files...' tool was added. * Tools can now be hidden with `Alt + #` (where `#` is a keyboard number) and focused with `Alt + Shift + #`. * The syntax highlighting colors for diffs was made less intrusive. * The commit message editor was redesigned to have a more compact and keyboard-convenient user interface. * Keyboard shortcuts for adding a Signed-off-by (`Ctrl + i`) and creating a commit (`Ctrl + m`) were added. * The status widget was adjusted to use less screen real-estate. Fixes ----- * Avoid updating the index when responding to inotify events. This avoids interfering with operations such as `git rebase --interactive`. (`#99 `_) Packaging --------- * Create `git-dag.pyw` in the win32 installer. * win32 shortcuts now contain explicit calls to `pythonw.exe` instead of calling the `.pyw` file directly. Deprecated Features ------------------- * The 'Apply Changes from Branch...' feature was removed. `git dag`'s 'Grab File...' feature used alongside the index/worktree editor is a simpler alternative. .. _v1.7.1.1: git-cola v1.7.1.1 ================= Fixes ----- * Further enhanced the staging/unstaging behavior in the status widget. (`#97 `_) * Unmerged files are no longer listed as modified. Packaging --------- The `cola-$version` tarballs on github were originally setup to have the same contents as the old tarballs hosted on tuxfamily. The `make dist` target was changed to write files to a `git-cola-$version` subdirectory and tarball. This makes the filenames consistent for the source tarball, the darwin .app tarball, and the win32 .exe installer. .. _v1.7.1: git-cola v1.7.1 =============== Usability, bells and whistles ----------------------------- * Refined the staging/unstaging behavior for code reviews. (`#97 `_) * Added more styling and icons to menus and buttons. * Adjusted some terminology to more closely match the git CLI. Fixes ----- * Boolean `git config` settings with no value are now supported (these are not created by git these days but exist in legacy repositories). * Unicode branches and tags are supported in the "branch diff" tool. * Guard against low-memory conditions and more interrupted system calls. Packaging --------- * Added desktop launchers for git-cola.desktop and git-dag.desktop. This replaces the old cola.desktop, so some adjustments to RPM .spec and debian/ files will be needed. * Fixed the darwin app-tarball Makefile target to create relative paths. Cleanup ------- * The `--style` option was removed. `git cola` follows the system theme so there's no need for this option these days. .. _v1.7.0: git-cola v1.7.0 =============== Usability, bells and whistles ----------------------------- * Export a patch series from `git dag` into a `patches/` directory. * `git dag` learned to diff commits, slice history along paths, etc. * Added instant-preview to the `git stash` widget. * A simpler preferences editor is used to edit `git config` values. (`#90 `_) (`#89 `_) * Previous commit messages can be re-loaded from the message editor. (`#33 `_) Fixes ----- * Display commits with no file changes. (`#82 `_) * Improved the diff editor's copy/paste behavior (`#90 `_) Packaging --------- * Bumped version number to ceil(minimum git version). `git cola` now requires `git` >= 1.6.3. * Simplified git-cola's versioning when building from tarballs outside of git. We no longer check for a 'version' file at the root of the repository. We instead keep a default version in `cola/version.py` and use it when `git cola`'s `.git` repository is not available. .. _v1.4.3.5: git-cola v1.4.3.5 ================= Usability, bells and whistles ----------------------------- * inotify is much snappier and available on Windows thanks to Karl Bielefeldt. * New right-click command to add untracked files to .gitignore thanks to Audrius Karabanovas. * Stash, fetch, push, and pull usability improvements * General usability improvements * stderr is logged when applying partial diffs. Fixes ----- * Files can be unstaged when amending. (`#82 `_) * Show the configured remote.$remote.pushurl in the GUI (`#83 `_) * Removed usage of the "user" module. (`#86 `_) * Avoids an extra `git update-index` call during startup. .. _v1.4.3.4: git-cola v1.4.3.4 ================= Usability, bells and whistles ----------------------------- * We now provide better feedback when `git push` fails. (`#69 `_) * The Fetch, Push, and Pull dialogs now give better feedback when interacting with remotes. The dialogs are modal and a progress dialog is used. Fixes ----- * More unicode fixes, again. It is now possible to have unicode branch names, repository paths, home directories, etc. This continued the work initiated by Redhat's bugzilla #694806. https://bugzilla.redhat.com/show_bug.cgi?id=694806 .. _v1.4.3.3: git-cola v1.4.3.3 ================= Usability, bells and whistles ----------------------------- * The `git cola` desktop launchers now prompt for a repo by default. This is done by using the new `--prompt` flag which tells `git cola` to ignore any git repositories in the current directory and prompt for one instead. Fixes ----- * More Unicode fixes for repositories and home directories with embedded unicode characters. Thanks to Christian Jann for patience and helpful bug reports. * Fix the 'Clone' button in the startup dialog. .. _v1.4.3.2: git-cola v1.4.3.2 ================= Usability, bells and whistles ----------------------------- * Faster startup time! `git cola` now offloads initialization to a background thread so that the GUI appears almost instantly. * Specialized diff options for p4merge, vimdiff, araxis, emerge, and ecmerge in difftool (backported from git.git). Fixes ----- * Fix launching commands in the background on Windows (e.g. when launching `git difftool`). * Fix unicode errors when home or repository directories contain unicode characters. (`#74 `_) (`bz #694806 `_) .. _v1.4.3.1: git-cola v1.4.3.1 ================= Usability, bells and whistles ----------------------------- * The `cola classic` tool can be now configured to be dockable. (`#56 `_) * The `cola classic` tool now uses visual sigils to indicate a file's status. The idea and icons were provided by Uri Okrent. * Include the 'Rescan' button in the 'Actions' widget regardless of whether inotify is installed. Packaging --------- * Fix installation of translations per Fedora This incorporates Fedora's fix for the translations path which originally appeared in cola-1.4.3-translations.patch. * Mac OS X git-cola developers can now generate git-cola.app application bundles using 'make app-bundle'. Fixes ----- * Fixed a stacktrace when trying to use "Get Commit Message Template" with an unconfigured "commit.template" git config variable. (`bz #67521 `_) (`#72 `_) * Properly raise the main window on Mac OS X. * Properly handle staging a huge numbers of files at once. * Speed up 'git config' usage by fixing cola's caching proxy. * Guard against damaged ~/.cola files. .. _v1.4.3: git-cola v1.4.3 =============== Usability, bells and whistles ----------------------------- * `git dag` now has a separate display area for displaying commit metadata. This area will soon grow additional functionality such as cherry-picking, branching, etc. Fixes ----- * Fixed tests from a previous refactoring. * Guard against 'diff.external' configuration by always calling 'git diff' with the '--no-ext-diff' option. (`#67 `_) * Respect 'gui.diffcontext' so that cola's diff display shows the correct number of context lines. * Raise the GUI so that it is in the foreground on OS X. Packaging --------- * We now allow distutils to rewrite cola's shebang line. This allows us to run on systems where "which python" is Python3k. This is exposed by setting the `PYTHON` Makefile variable to the location of python2.x. * git-cola.app is now a tiny download because it no longer contains Qt and PyQt. These libraries are provided as a separate download. (`Link `_) .. _v1.4.2.5: git-cola v1.4.2.5 ================= Usability, bells and whistles ----------------------------- * Clicking on paths in the status widget copies them into the copy/paste buffer for easy middle-clicking into terminals. * `Ctrl+C` in diff viewer copies the selected diff to the clipboard. Fixes ----- * Fixed the disappearing actions buttons on PyQt 4.7.4 as reported by Arch and Ubuntu 10.10. (`#62 `_) * Fixed mouse interaction with the status widget where some items could not be de-selected. Packaging --------- * Removed hard-coded reference to lib/ when calculating Python's site-packages directory. .. _v1.4.2.4: git-cola v1.4.2.4 ================= Usability, bells and whistles ----------------------------- * Removed "single-click to (un)stage" in the status view. This is a usability improvement since we no longer perform different actions depending on where a row is clicked. * Added ability to create unsigned, annotated tags. Fixes ----- * Updated documentation to use `cola.git` instead of `cola.gitcmd`. .. _v1.4.2.3: git-cola v1.4.2.3 ================= Usability, bells and whistles ----------------------------- * Allow un/staging by right-clicking top-level items (`#57 `_) * Running 'commit' with no staged changes prompts to allow staging all files. (`#55 `_) * Fetch, Push, and Pull are now available via the menus (`#58 `_) Fixes ----- * Simplified the actions widget to work around a regression in PyQt4 4.7.4. (`#62 `_) .. _v1.4.2.2: git-cola v1.4.2.2 ================= Usability, bells and whistles ----------------------------- * `git dag` interaction was made faster. Fixes ----- * Added '...' indicators to the buttons for 'Fetch...', 'Push...', 'Pull...', and 'Stash...'. (`#51 `_) * Fixed a hang-on-exit bug in the cola-provided 'ssh-askpass' implementation. .. _v1.4.2.1: git-cola v1.4.2.1 ================= Usability, bells and whistles ----------------------------- * Staging and unstaging is faster. (`#48 `_) * `git dag` reads history in a background thread. Portability ----------- * Added :data:`cola.compat.hashlib` for `Python 2.4` compatibility * Improved `PyQt 4.1.x` compatibility. Fixes ----- * Configured menu actions use ``sh -c`` for Windows portability. .. _v1.4.2: git-cola v1.4.2 =============== Usability, bells and whistles ----------------------------- * Added support for the configurable ``guitool..*`` actions as described in the ``git config`` documentation. (`git-config(1) `_) (`#44 `_) This makes it possible to add new actions to `git cola` by simply editing ``~/.gitconfig``. This implements the same guitool support as `git gui`. * Introduced a stat cache to speed up `git config` and repository status checks. * Added Alt-key shortcuts to the main `git cola` interface. * The `Actions` dock widget switches between a horizontal and vertical layout when resized. * We now use ``git diff --submodule`` for submodules (used when git >= 1.6.6). * The context menu for modified submodules includes an option to launch `git cola`. (`#17 `_) * Prefer ``$VISUAL`` over ``$EDITOR`` when both are defined. These are used to set a default editor in lieu of `core.editor` configuration. * Force the editor to be ``gvim`` when we see ``vim``. This prevents us from launching an editor in the (typically unattached) parent terminal and creating zombie editors that cannot be easily killed. * Selections are remembered and restored across updates. This makes the `partial-staging` workflow easier since the diff view will show the updated diff after staging. * Show the path to the current repository in a tooltip over the commit message editor. (`#45 `_) * Log internal ``git`` commands when ``GIT_COLA_TRACE`` is defined. (`#39 `_) Fixes ----- * Improved backwards compatibility for Python 2.4. * `Review mode` can now review the current branch; it no longer requires you to checkout the branch into which the reviewed branch will be merged. * Guard against `color.ui = always` configuration when using `git log` by passing ``--no-color``. * ``yes`` and ``no`` are now supported as valid booleans by the `git config` parser. * Better defaults are used for `fetch`, `push`, and `pull`.. (`#43 `_) Packaging --------- * Removed colon (`:`) from the applilcation name on Windows (`#41 `_) * Fixed bugs with the Windows installer (`#40 `_) * Added a more standard i18n infrastructure. The install tree now has the common ``share/locale/$lang/LC_MESSAGES/git-cola.mo`` layout in use by several projects. * Started trying to accommodate Mac OSX 10.6 (Snow Leopard) in the ``darwin/`` build scripts but our tester is yet to report success building a `.app` bundle. * Replaced use of ``perl`` in Sphinx/documentation Makefile with more-portable ``sed`` constructs. Thanks to Stefan Naewe for discovering the portability issues and providing msysgit-friendly patches. .. _v1.4.1.2: git-cola v1.4.1.2 ================= Usability, bells and whistles ----------------------------- * It is now possible to checkout from the index as well as from `HEAD`. This corresponds to the `Removed Unstaged Changes` action in the `Repository Status` tool. * The `remote` dialogs (fetch, push, pull) are now slightly larger by default. * Bookmarks can be selected when `git cola` is run outside of a git repository. * Added more user documentation. We now include many links to external git resources. * Added `git dag` to the available tools. `git dag` is a node-based DAG history browser. It doesn't do much yet, but it's been merged so that we can start building and improving upon it. Fixes ----- * Fixed a missing ``import`` when showing `right-click` actions for unmerged files in the `Repository Status` tool. * ``git update-index --refresh`` is no longer run every time ``git cola version`` is run. * Don't try to watch non-existent directories when using `inotify`. * Use ``git rev-parse --symbolic-full-name`` plumbing to find the name of the current branch. Packaging --------- * The ``Makefile`` will now conditionally include a ``config.mak`` file located at the root of the project. This allows for user customizations such as changes to the `prefix` variable to be stored in a file so that custom settings do not need to be specified every time on the command-line. * The build scripts no longer require a ``.git`` directory to generate the ``builtin_version.py`` module. The release tarballs now include a ``version`` file at the root of the project which is used in lieu of having the git repository available. This allows for ``make clean && make`` to function outside of a git repository. * Added maintainer's ``make dist`` target to the ``Makefile``. * The built-in `simplejson` and `jsonpickle` libraries can be excluded from ``make install`` by specifying the ``standalone=true`` `make` variable. For example, ``make standalone=true install``. This corresponds to the ``--standalone`` option to ``setup.py``. .. _v1.4.1.1: git-cola v1.4.1.1 ================= Usability, bells and whistles ----------------------------- * We now use patience diff by default when it is available via `git diff --patience`. * Allow closing the `cola classic` tool with `Ctrl+W`. Fixes ----- * Fixed an unbound variable error in the `push` dialog. Packaging --------- * Don't include `simplejson` in MANIFEST.in. * Update desktop entry to read `Cola Git GUI`. .. _v1.4.1: git-cola v1.4.1 =============== This feature release adds two new features directly from `git cola`'s github issues backlog. On the developer front, further work was done towards modularizing the code base. Usability, bells and whistles ----------------------------- * Dragging and dropping patches invokes `git am` (`#3 `_) * A dialog to allow opening or cloning a repository is presented when `git cola` is launched outside of a git repository. (`#22 `_) * Warn when `push` is used to create a new branch (`#35 `_) * Optimized startup time by removing several calls to `git`. Portability ----------- * `git cola` is once again compatible with PyQt 4.3.x. Developer --------- * `cola.gitcmds` was added to factor out git command-line utilities * `cola.gitcfg` was added for interacting with `git config` * `cola.models.browser` was added to factor out repobrowser data * Added more tests .. _v1.4.0.5: git-cola v1.4.0.5 ================= Fixes ----- * Fix launching external applications on Windows * Ensure that the `amend` checkbox is unchecked when switching modes * Update the status tree when amending commits .. _v1.4.0.4: git-cola v1.4.0.4 ================= Packaging --------- * Fix Lintian warnings .. _v1.4.0.3: git-cola v1.4.0.3 ================= Fixes ----- * Fix X11 warnings on application startup .. _v1.4.0.2: git-cola v1.4.0.2 ================= Fixes ----- * Added missing 'Exit Diff Mode' button for 'Diff Expression' mode (`#31 `_) * Fix a bug when initializing fonts on Windows (`#32 `_) .. _v1.4.0.1: git-cola v1.4.0.1 ================= Fixes ----- * Keep entries in sorted order in the `cola classic` tool * Fix staging untracked files (`#27 `_) * Fix the `show` command in the Stash dialog (`#29 `_) * Fix a typo when loading merge commit messages (`#30 `_) .. _v1.4.0: git-cola v1.4.0 =============== This release focuses on a redesign of the git-cola user interface, a tags interface, and better integration of the `cola classic` tool. A flexible interface based on configurable docks is used to manage the various cola widgets. Usability, bells and whistles ----------------------------- * New GUI is flexible and user-configurable * Individual widgets can be detached and rearranged arbitrarily * Add an interface for creating tags * Provide a fallback `SSH_ASKPASS` implementation to prompt for SSH passwords on fetch/push/pull * The commit message editor displays the current row/column and warns when lines get too long * The `cola classic` tool displays upstream changes * `git cola --classic` launches `cola classic` in standalone mode * Provide more information in log messages Fixes ----- * Inherit the window manager's font settings * Miscellaneous PyQt4 bug fixes and workarounds Developer --------- * Removed all usage of Qt Designer `.ui` files * Simpler model/view architecture * Selection is now shared across tools * Centralized notifications are used to keep views in sync * The `cola.git` command class was made thread-safe * Less coupling between model and view actions * The status view was rewritten to use the MVC architecture * Added more documentation and tests .. _v1.3.9: git-cola v1.3.9 =============== Usability, bells and whistles ----------------------------- * Added a `cola classic` tool for browsing the entire repository * Handle diff expressions with spaces * Handle renamed files Portability ----------- * Handle carat `^` characters in diff expressions on Windows * Worked around a PyQt 4.5/4.6 QThreadPool bug Documentation ------------- * Added a keyboard shortcuts reference page * Added developer API documentation Fixes ----- * Fix the diff expression used when reviewing branches * Fix a bug when pushing branches * Fix X11 warnings at startup * Fix more interrupted system calls on Mac OS X .. _v1.3.8: git-cola v1.3.8 =============== Usability, bells and whistles ----------------------------- * Fresh and tasty SVG logos * Added `Branch Review` mode for reviewing topic branches * Added diff modes for diffing between tags, branches, or arbitrary `git diff` expressions * The push dialog selects the current branch by default. This is in preparation for `git 1.7.0` where unconfigured `git push` will refuse to push when run without specifying the remote name and branch. See the `git` release notes for more information * Support `open` and `clone` commands on Windows * Allow saving cola UI layouts * Re-enabled `double-click-to-stage` for unmerged entries. Disabling it for unmerged items was inconsistent, though safer. * Show diffs when navigating the status tree with the keyboard Packaging --------- * Worked around `pyuic4` bugs in the `setup.py` build script * Added Mac OSX application bundles to the download page .. _v1.3.7: git-cola v1.3.7 =============== Subsystems ---------- * `git difftool` became an official git command in `git 1.6.3`. * `git difftool` learned `--no-prompt` / `-y` and a corresponding `difftool.prompt` configuration variable Usability, bells and whistles ----------------------------- * Warn when `non-fast-forward` is used with fetch, push or pull * Allow `Ctrl+C` to exit cola when run from the command line Fixes ----- * Support Unicode font names * Handle interrupted system calls Developer --------- * `PEP-8`-ified more of the cola code base * Added more tests Packaging --------- * All resources are now installed into `$prefix/share/git-cola`. Closed Debian bug #519972 http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=519972 .. _v1.3.6: git-cola v1.3.6 =============== Subsystems ---------- * Added support for Kompare in `git difftool` * Added a separate configuration namespace for `git difftool` * Added the `diff.tool` configuration variable to define the default diff tool Usability, bells and whistles ----------------------------- * The stash dialog allows passing the `--keep-index` option to `git stash` * Amending a published commit warns at commit time * Simplified the file-across-revisions comparison dialog * `origin` is selected by default in fetch/push/pull * Removed the search field from the log widget * The log window moved into a drawer widget at the bottom of the UI * Log window display can be configured with `cola.showoutput` = `{never, always, errors}`. `errors` is the default. * `NOTE` -- `cola.showoutput` was removed with the GUI rewrite in 1.4.0. Developer --------- * Improved nose unittest usage Packaging --------- * Added a Windows/msysGit installer * Included private versions of `simplejson` and `jsonpickle` for ease of installation and development git-cola-3.6/share/doc/git-cola/thanks.rst000066400000000000000000000074751356743264500205050ustar00rootroot00000000000000Thanks ====== `git-cola` was made possible thanks to the contributions of the following people: * Aaron Cook * Aaron Wolf * Adam Lesperance * Adrien be * Adil * AJ Bagwell * akontsevich * Aleksey Kontsevich * Alex Chernetz * Alex Gulyás * Alexander Kozienko * Alf Eaton * anderben * Andreas Schnederle-Wagner * Andreas Sommer * Andrej Kvasnica * Andrew Chen * Andrew Hemming * armandg * Arthur Coelho * Audrius Karabanovas * Balázs Meskó * balping * Barış ÇELİK * Barry Roberts * Boris W * Ben Boeckel * Ben Cole * Benedict Lee * Benjamin Somers * Benoît Nouyrigat * Bert Jacobs * Birger Skogeng Pedersen * Björn Ketelaars * 林博仁 (Buo-ren Lin) * cclaus * Charles 101 * Christian Jann * Christopher Meng * Clément Pit--Claudel * Constantine Grantcharov * Daniel Fahlke * Daniel Jay Haskin * Daniel Harding * Daniel King * Dave Thomas * David Aguilar * David Fernandez * David LeGare * David Martínez Martí * Dawid Drozd * Dennis Gilmore * deniz1a * Dmitry Kann * Dmitry Pashkevich * Doug Hoskisson * Drugoy * Efimov Vasily * Eric Drechsel * Erop @EgZvor * Erwan Bousse * Fabio Coatti * Felipe Morales * Filip Danilović * fu7mu4 * Garoe Dorta * Geoffrey van Wyk * geotavros * `Git Hackers `_ * green-eyed-bear * Glen Mailer * Guillaume de Bure * Guo Yunhe * Gyuris Gellért * Harro Verton * Hannes @kannes * Igor Galarraga * Igor Kopach * Ilya Tumaykin * Ingo Weinhold * Ismael Juma * Iulian Udrea * Ivar Smolin * Jan @hanksoff * Jan Šilhan * Jan Tumanov * jakubklos77 * Jakub Szymański * Jakub Wilk * James Geiger * Javier Rodriguez Cuevas * Jeff Dagenais * Jérôme Carretero * jfessard * JiCiT * Jimmy M. Coleman * Joachim Jablon * Joachim Lusiardi * Johannes Löhnert * Johann Schmitz * Jordan Bedwell * Josh Noe * Josh Taylor * Justin Lecher * Kai Krakow * Karl Bielefeldt * Karthik Manamcheri * Kelvie Wong * Kerrick Staley * Kevin Kofler * Kirit Sælensminde * Kyle Slane * László Böszörményi * Leho Kraav * Lev Zlotin * Louis Rousseau * Libor Jelinek * Liviu Cristian Mirea-Ghiban * Luca Ottaviano * Łukasz Wojniłowicz * Luke Bakken * Maarten Nieber * Maaaks * Maciej Filipiak * Mahmoud Hossam * Mateusz Kedzior * Maicon D. Filippsen * Marcin Mielniczuk * Marco Costalba * Mariusz Jaskółka * Markus Heidelberg * Martin Konecny * Matěj Šmíd * Matthew Levine * Matthias Mailänder * Micha Rosenbaum * Michael Geddes * Michael Homer * Mickael Albertus * Mike Hanson * MikHulk * Mikołaj Milej * Minarto Margoliono * Mosaab Alzoubi * Muhammad Bashir Al-Noimi * Myz * Naraesk * Niel Buys * Nick Todd * Nicolas Dietrich * Nikos Roussos * Noel Grandin * NotSqrt * ochristi * Oliver Haessler * OmegaPhil (Omega Weapon) * Owen Healy * Pamela Strucker * Paolo G. Giarrusso * Parashurama Rhagdamaziel * Patrick Browne * Paul Hildebrandt * Paul Weingardt * Paulo Fidalgo * Pavel Borecki * Pavel Rehak * Peter Dave Hello * Peter Júnoš * Petr Gladkikh * Philip Stark * Pilar Molina Lopez * Radek Novacek * Radek Postołowicz * Rafael Nascimento * Rafael Reuber * Raghavendra Karunanidhi * Rainer Müller * Ricardo J. Barberis * Robbert Korving * Robert Pollak * Rolando Espinoza La fuente * Rustam Safin * Sabri Ünal * Samsul Ma'arif * Sebastian Brass * Sebastian Oliva * Sergey Leschina * Shun Sakai * Simon Peeters * Srinivasa Nallapati * Stan Angeloff * Stanisław Halik * Stefan Naewe * Steffen Prohaska * Stéphane Cerveau * Stephen Groat * Sven Claussner * Szymon Judasz * Taylor Braun-Jones * Thiemo van Engelen * Thomas Kiley * Thomas Kluyver * Thomas Thorne * Tom Dobbelaere * Tim Brown * Tim Schumacher * Trevor Alexander * Ugo Riboni * Uri Okrent * Utku Karatas * V字龍 (Vdragon) * Vaibhav Sagar * Vaiz * Ved Vyas * Victor Nepveu * Victorhck * Ville Skyttä * Virgil Dupras * Vitor Lobo * v.paritskiy * waterzch * Wolfgang Ocker * wsdfhjxc * Xie Hua Liang (xieofxie) * Yi EungJun * Zauber Paracelsus * Zeioth * Zhang Han * 0xflotus git-cola-3.6/share/git-cola/000077500000000000000000000000001356743264500157015ustar00rootroot00000000000000git-cola-3.6/share/git-cola/bin/000077500000000000000000000000001356743264500164515ustar00rootroot00000000000000git-cola-3.6/share/git-cola/bin/git-xbase000077500000000000000000000512221356743264500202640ustar00rootroot00000000000000#!/usr/bin/env python # flake8: noqa from __future__ import absolute_import, division, unicode_literals import os import sys import re from argparse import ArgumentParser from functools import partial def setup_environment(): path = os.path dirname = path.dirname # / share/git-cola/ bin/git-xbase prefix = dirname(dirname(dirname(dirname(path.abspath(__file__))))) # str() avoids unicode on python2 by staying in bytes source_tree = path.join(prefix, str('cola'), str('__init__.py')) unixpkgs = path.join(prefix, str('share'), str('git-cola'), str('lib')) winpkgs = path.join(prefix, str('pkgs')) if path.exists(source_tree): modules = prefix elif path.exists(unixpkgs): modules = unixpkgs elif path.exists(winpkgs): modules = winpkgs else: modules = None if modules: sys.path.insert(1, modules) setup_environment() from cola import app # prints a message if Qt cannot be found from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from qtpy.QtCore import Qt from qtpy.QtCore import Signal # pylint: disable=ungrouped-imports from cola import core from cola import difftool from cola import hotkeys from cola import icons from cola import observable from cola import qtutils from cola import utils from cola.i18n import N_ from cola.models import dag from cola.models import prefs from cola.widgets import defs from cola.widgets import diff from cola.widgets import standard from cola.widgets import text PICK = 'pick' REWORD = 'reword' EDIT = 'edit' FIXUP = 'fixup' SQUASH = 'squash' EXEC = 'exec' COMMANDS = (PICK, REWORD, EDIT, FIXUP, SQUASH,) COMMAND_IDX = dict([(cmd_, idx_) for idx_, cmd_ in enumerate(COMMANDS)]) ABBREV = { 'p': PICK, 'r': REWORD, 'e': EDIT, 'f': FIXUP, 's': SQUASH, 'x': EXEC, } def main(): """Start a git-xbase session""" args = parse_args() context = app.application_init(args) view = new_window(context, args.filename) app.application_run(context, view, start=view.start, stop=stop) return view.status def stop(_context, _view): """All done, cleanup""" QtCore.QThreadPool.globalInstance().waitForDone() def parse_args(): parser = ArgumentParser() parser.add_argument('filename', metavar='', help='git-rebase-todo file to edit') app.add_common_arguments(parser) return parser.parse_args() def new_window(context, filename): window = XBaseWindow(context) editor = Editor(context, filename, parent=window) window.set_editor(editor) return window def unabbrev(cmd): """Expand shorthand commands into their full name""" return ABBREV.get(cmd, cmd) class XBaseWindow(standard.MainWindow): def __init__(self, context, settings=None, parent=None): super(XBaseWindow, self).__init__(parent) self.context = context self.status = 1 self.editor = None default_title = '%s - git xbase' % core.getcwd() title = core.getenv('GIT_XBASE_TITLE', default_title) self.setWindowTitle(title) self.show_help_action = qtutils.add_action( self, N_('Show Help'), partial(show_help, context), hotkeys.QUESTION) self.menubar = QtWidgets.QMenuBar(self) self.help_menu = self.menubar.addMenu(N_('Help')) self.help_menu.addAction(self.show_help_action) self.setMenuBar(self.menubar) qtutils.add_close_action(self) self.init_state(settings, self.init_window_size) def init_window_size(self): """Set the window size on the first initial view""" context = self.context if utils.is_darwin(): desktop = context.app.desktop() self.resize(desktop.width(), desktop.height()) else: self.showMaximized() def set_editor(self, editor): self.editor = editor self.setCentralWidget(editor) editor.exit.connect(self.exit) editor.setFocus() def start(self, _context, _view): self.editor.start() def exit(self, status): self.status = status self.close() class Editor(QtWidgets.QWidget): exit = Signal(int) def __init__(self, context, filename, parent=None): super(Editor, self).__init__(parent) self.widget_version = 1 self.status = 1 self.context = context self.filename = filename self.comment_char = comment_char = prefs.comment_char(context) self.cancel_action = core.getenv('GIT_XBASE_CANCEL_ACTION', 'abort') self.notifier = notifier = observable.Observable() self.diff = diff.DiffWidget(context, notifier, self) self.tree = RebaseTreeWidget(context, notifier, comment_char, self) self.setFocusProxy(self.tree) self.rebase_button = qtutils.create_button( text=core.getenv('GIT_XBASE_ACTION', N_('Rebase')), tooltip=N_('Accept changes and rebase\n' 'Shortcut: Ctrl+Enter'), icon=icons.ok(), default=True) self.extdiff_button = qtutils.create_button( text=N_('Launch Diff Tool'), tooltip=N_('Launch external diff tool\n' 'Shortcut: Ctrl+D')) self.extdiff_button.setEnabled(False) self.help_button = qtutils.create_button( text=N_('Help'), tooltip=N_('Show help\nShortcut: ?'), icon=icons.question()) self.cancel_button = qtutils.create_button( text=N_('Cancel'), tooltip=N_('Cancel rebase\nShortcut: Ctrl+Q'), icon=icons.close()) splitter = qtutils.splitter(Qt.Vertical, self.tree, self.diff) controls_layout = qtutils.hbox(defs.no_margin, defs.button_spacing, self.cancel_button, qtutils.STRETCH, self.help_button, self.extdiff_button, self.rebase_button) layout = qtutils.vbox(defs.no_margin, defs.spacing, splitter, controls_layout) self.setLayout(layout) self.action_rebase = qtutils.add_action( self, N_('Rebase'), self.rebase, hotkeys.CTRL_RETURN, hotkeys.CTRL_ENTER) notifier.add_observer(diff.COMMITS_SELECTED, self.commits_selected) self.tree.external_diff.connect(self.external_diff) qtutils.connect_button(self.rebase_button, self.rebase) qtutils.connect_button(self.extdiff_button, self.external_diff) qtutils.connect_button(self.help_button, partial(show_help, context)) qtutils.connect_button(self.cancel_button, self.cancel) def start(self): insns = core.read(self.filename) self.parse_sequencer_instructions(insns) # notifier callbacks def commits_selected(self, commits): self.extdiff_button.setEnabled(bool(commits)) # helpers def parse_sequencer_instructions(self, insns): idx = 1 re_comment_char = re.escape(self.comment_char) exec_rgx = re.compile(r'^\s*(%s)?\s*(x|exec)\s+(.+)$' % re_comment_char) # The upper bound of 40 below must match git.OID_LENGTH. # We'll have to update this to the new hash length when that happens. pick_rgx = re.compile((r'^\s*(%s)?\s*' r'(p|pick|r|reword|e|edit|f|fixup|s|squash)' r'\s+([0-9a-f]{7,40})' r'\s+(.+)$') % re_comment_char) for line in insns.splitlines(): match = pick_rgx.match(line) if match: enabled = match.group(1) is None command = unabbrev(match.group(2)) oid = match.group(3) summary = match.group(4) self.tree.add_item(idx, enabled, command, oid=oid, summary=summary) idx += 1 continue match = exec_rgx.match(line) if match: enabled = match.group(1) is None command = unabbrev(match.group(2)) cmdexec = match.group(3) self.tree.add_item(idx, enabled, command, cmdexec=cmdexec) idx += 1 continue self.tree.decorate(self.tree.items()) self.tree.refit() self.tree.select_first() # actions def cancel(self): if self.cancel_action == 'save': status = self.save('') else: status = 1 self.status = status self.exit.emit(status) def rebase(self): lines = [item.value() for item in self.tree.items()] sequencer_instructions = '\n'.join(lines) + '\n' status = self.save(sequencer_instructions) self.status = status self.exit.emit(status) def save(self, string): """Save the instruction sheet""" try: core.write(self.filename, string) status = 0 except (OSError, IOError, ValueError) as e: msg, details = utils.format_exception(e) sys.stderr.write(msg + '\n\n' + details) status = 128 return status def external_diff(self): items = self.tree.selected_items() if not items: return item = items[0] difftool.diff_expression(self.context, self, item.oid + '^!', hide_expr=True) # pylint: disable=too-many-ancestors class RebaseTreeWidget(standard.DraggableTreeWidget): external_diff = Signal() move_rows = Signal(object, object) def __init__(self, context, notifier, comment_char, parent=None): super(RebaseTreeWidget, self).__init__(parent=parent) self.context = context self.notifier = notifier self.comment_char = comment_char # header self.setHeaderLabels([ N_('#'), N_('Enabled'), N_('Command'), N_('SHA-1'), N_('Summary'), ]) self.header().setStretchLastSection(True) self.setColumnCount(5) # actions self.copy_oid_action = qtutils.add_action( self, N_('Copy SHA-1'), self.copy_oid, QtGui.QKeySequence.Copy) self.external_diff_action = qtutils.add_action( self, N_('Launch Diff Tool'), self.external_diff.emit, hotkeys.DIFF) self.toggle_enabled_action = qtutils.add_action( self, N_('Toggle Enabled'), self.toggle_enabled, hotkeys.PRIMARY_ACTION) self.action_pick = qtutils.add_action( self, N_('Pick'), lambda: self.set_selected_to(PICK), *hotkeys.REBASE_PICK) self.action_reword = qtutils.add_action( self, N_('Reword'), lambda: self.set_selected_to(REWORD), *hotkeys.REBASE_REWORD) self.action_edit = qtutils.add_action( self, N_('Edit'), lambda: self.set_selected_to(EDIT), *hotkeys.REBASE_EDIT) self.action_fixup = qtutils.add_action( self, N_('Fixup'), lambda: self.set_selected_to(FIXUP), *hotkeys.REBASE_FIXUP) self.action_squash = qtutils.add_action( self, N_('Squash'), lambda: self.set_selected_to(SQUASH), *hotkeys.REBASE_SQUASH) self.action_shift_down = qtutils.add_action( self, N_('Shift Down'), self.shift_down, hotkeys.MOVE_DOWN_TERTIARY) self.action_shift_up = qtutils.add_action( self, N_('Shift Up'), self.shift_up, hotkeys.MOVE_UP_TERTIARY) # pylint: disable=no-member self.itemChanged.connect(self.item_changed) self.itemSelectionChanged.connect(self.selection_changed) self.move_rows.connect(self.move) self.items_moved.connect(self.decorate) def add_item(self, idx, enabled, command, oid='', summary='', cmdexec=''): comment_char = self.comment_char item = RebaseTreeWidgetItem(idx, enabled, command, oid=oid, summary=summary, cmdexec=cmdexec, comment_char=comment_char) self.invisibleRootItem().addChild(item) def decorate(self, items): for item in items: item.decorate(self) def refit(self): self.resizeColumnToContents(0) self.resizeColumnToContents(1) self.resizeColumnToContents(2) self.resizeColumnToContents(3) self.resizeColumnToContents(4) # actions def item_changed(self, item, column): if column == item.ENABLED_COLUMN: self.validate() def validate(self): invalid_first_choice = set([FIXUP, SQUASH]) for item in self.items(): if item.is_enabled() and item.is_commit(): if item.command in invalid_first_choice: item.reset_command(PICK) break def set_selected_to(self, command): for i in self.selected_items(): i.reset_command(command) self.validate() def set_command(self, item, command): item.reset_command(command) self.validate() def copy_oid(self): item = self.selected_item() if item is None: return clipboard = item.oid or item.cmdexec qtutils.set_clipboard(clipboard) def selection_changed(self): item = self.selected_item() if item is None or not item.is_commit(): return context = self.context oid = item.oid params = dag.DAG(oid, 2) repo = dag.RepoReader(context, params) commits = [] for c in repo.get(): commits.append(c) if commits: commits = commits[-1:] self.notifier.notify_observers(diff.COMMITS_SELECTED, commits) def toggle_enabled(self): item = self.selected_item() if item is None: return item.toggle_enabled() def select_first(self): items = self.items() if not items: return idx = self.model().index(0, 0) if idx.isValid(): self.setCurrentIndex(idx) def shift_down(self): item = self.selected_item() if item is None: return items = self.items() idx = items.index(item) if idx < len(items) - 1: self.move_rows.emit([idx], idx + 1) def shift_up(self): item = self.selected_item() if item is None: return items = self.items() idx = items.index(item) if idx > 0: self.move_rows.emit([idx], idx - 1) def move(self, src_idxs, dst_idx): new_items = [] items = self.items() for idx in reversed(sorted(src_idxs)): item = items[idx].copy() self.invisibleRootItem().takeChild(idx) new_items.insert(0, item) if new_items: self.invisibleRootItem().insertChildren(dst_idx, new_items) self.setCurrentItem(new_items[0]) # If we've moved to the top then we need to re-decorate all items. # Otherwise, we can decorate just the new items. if dst_idx == 0: self.decorate(self.items()) else: self.decorate(new_items) self.validate() # Qt events def dropEvent(self, event): super(RebaseTreeWidget, self).dropEvent(event) self.validate() def contextMenuEvent(self, event): menu = qtutils.create_menu(N_('Actions'), self) menu.addAction(self.action_pick) menu.addAction(self.action_reword) menu.addAction(self.action_edit) menu.addAction(self.action_fixup) menu.addAction(self.action_squash) menu.addSeparator() menu.addAction(self.toggle_enabled_action) menu.addSeparator() menu.addAction(self.copy_oid_action) menu.addAction(self.external_diff_action) menu.exec_(self.mapToGlobal(event.pos())) class ComboBox(QtWidgets.QComboBox): validate = Signal() class RebaseTreeWidgetItem(QtWidgets.QTreeWidgetItem): ENABLED_COLUMN = 1 COMMAND_COLUMN = 2 OID_LENGTH = 7 def __init__(self, idx, enabled, command, oid='', summary='', cmdexec='', comment_char='#', parent=None): QtWidgets.QTreeWidgetItem.__init__(self, parent) self.combo = None self.command = command self.idx = idx self.oid = oid self.summary = summary self.cmdexec = cmdexec self.comment_char = comment_char # if core.abbrev is set to a higher value then we will notice by # simply tracking the longest oid we've seen oid_len = self.__class__.OID_LENGTH self.__class__.OID_LENGTH = max(len(oid), oid_len) self.setText(0, '%02d' % idx) self.set_enabled(enabled) # checkbox on 1 # combo box on 2 if self.is_exec(): self.setText(3, '') self.setText(4, cmdexec) else: self.setText(3, oid) self.setText(4, summary) flags = self.flags() | Qt.ItemIsUserCheckable flags = flags | Qt.ItemIsDragEnabled flags = flags & ~Qt.ItemIsDropEnabled self.setFlags(flags) def __eq__(self, other): return self is other def __hash__(self): return self.oid def copy(self): return self.__class__(self.idx, self.is_enabled(), self.command, oid=self.oid, summary=self.summary, cmdexec=self.cmdexec) def decorate(self, parent): if self.is_exec(): items = [EXEC] idx = 0 else: items = COMMANDS idx = COMMAND_IDX[self.command] combo = self.combo = ComboBox() combo.setEditable(False) combo.addItems(items) combo.setCurrentIndex(idx) combo.setEnabled(self.is_commit()) signal = combo.currentIndexChanged # pylint: disable=no-member signal.connect(lambda x: self.set_command_and_validate(combo)) combo.validate.connect(parent.validate) parent.setItemWidget(self, self.COMMAND_COLUMN, combo) def is_exec(self): return self.command == EXEC def is_commit(self): return bool(self.command != EXEC and self.oid and self.summary) def value(self): """Return the serialized representation of an item""" if self.is_enabled(): comment = '' else: comment = self.comment_char + ' ' if self.is_exec(): return '%s%s %s' % (comment, self.command, self.cmdexec) return ('%s%s %s %s' % (comment, self.command, self.oid, self.summary)) def is_enabled(self): return self.checkState(self.ENABLED_COLUMN) == Qt.Checked def set_enabled(self, enabled): self.setCheckState(self.ENABLED_COLUMN, enabled and Qt.Checked or Qt.Unchecked) def toggle_enabled(self): self.set_enabled(not self.is_enabled()) def set_command(self, command): """Set the item to a different command, no-op for exec items""" if self.is_exec(): return self.command = command def refresh(self): """Update the view to match the updated state""" if self.is_commit(): command = self.command self.combo.setCurrentIndex(COMMAND_IDX[command]) def reset_command(self, command): """Set and refresh the item in one shot""" self.set_command(command) self.refresh() def set_command_and_validate(self, combo): command = COMMANDS[combo.currentIndex()] self.set_command(command) self.combo.validate.emit() def show_help(context): help_text = N_(""" Commands -------- pick = use commit reword = use commit, but edit the commit message edit = use commit, but stop for amending squash = use commit, but meld into previous commit fixup = like "squash", but discard this commit's log message exec = run command (the rest of the line) using shell These lines can be re-ordered; they are executed from top to bottom. If you disable a line here THAT COMMIT WILL BE LOST. However, if you disable everything, the rebase will be aborted. Keyboard Shortcuts ------------------ ? = show help j = move down k = move up J = shift row down K = shift row up 1, p = pick 2, r = reword 3, e = edit 4, f = fixup 5, s = squash spacebar = toggle enabled ctrl+enter = accept changes and rebase ctrl+q = cancel and abort the rebase ctrl+d = launch difftool """) title = N_('Help - git-xbase') return text.text_dialog(context, help_text, title) if __name__ == '__main__': sys.exit(main()) git-cola-3.6/share/git-cola/bin/ssh-askpass000077500000000000000000000026031356743264500206400ustar00rootroot00000000000000#!/usr/bin/env tclsh # Tcl ignores the next line -*- tcl -*- \ exec wish "$0" -- "$@" # This is a trivial implementation of an GIT_ASKPASS / SSH_ASKPASS handler. # Git-gui uses this script if none are already configured. package require Tk set answer {} set yesno 0 set rc 255 if {$argc < 1} { set prompt "Enter your password / passphrase:" } else { set prompt [join $argv " "] if {[regexp -nocase {\(yes\/no\)\?\s*$} $prompt]} { set yesno 1 } } message .m -text $prompt -justify center -aspect 4000 pack .m -side top -fill x -padx 20 -pady 20 -expand 1 entry .e -textvariable answer -width 50 pack .e -side top -fill x -padx 10 -pady 10 if {!$yesno} { .e configure -show "*" } frame .b button .b.ok -text OK -command finish button .b.cancel -text Cancel -command cancel pack .b.ok -side left -expand 1 pack .b.cancel -side right -expand 1 pack .b -side bottom -fill x -padx 10 -pady 10 bind . {focus -force .e} bind . [list .b.ok invoke] bind . [list .b.cancel invoke] bind . {set rc $rc} proc cancel {} { set ::rc 255 } proc finish {} { if {$::yesno} { if {$::answer ne "yes" && $::answer ne "no"} { tk_messageBox -icon error -title "Error" -type ok \ -message "Only 'yes' or 'no' input allowed." return } } puts $::answer set ::rc 0 } wm title . "Git Authentication" tk::PlaceWindow . vwait rc exit $rc git-cola-3.6/share/git-cola/bin/ssh-askpass-darwin000077500000000000000000000014311356743264500221200ustar00rootroot00000000000000#! /bin/sh TITLE=${MACOS_ASKPASS_TITLE:-"SSH"} DIALOG="display dialog \"$@\" default answer \"\" with title \"$TITLE\"" DIALOG="$DIALOG with icon caution" yesno= if echo "$1" | grep "'yes'" 2>&1 >/dev/null || echo "$1" | grep "yes/no" 2>&1 >/dev/null then yesno=true fi if test -z "$yesno" then DIALOG="$DIALOG with hidden answer" fi result=$(osascript \ -e 'tell application "Finder"' \ -e "activate" \ -e "$DIALOG" \ -e 'end tell' 2>/dev/null) if test -z "$result" then exit 1 fi # The beginning of the output can be either "text returned:" # or "button returned:", and is Mac OS X version-dependent. # Account for both output styles. printf '%s\n' "$result" | sed -e 's/^text returned://' -e 's/, button returned:.*$//' \ -e 's/^button returned:OK, text returned://' exit 0 git-cola-3.6/share/git-cola/icons/000077500000000000000000000000001356743264500170145ustar00rootroot00000000000000git-cola-3.6/share/git-cola/icons/README.md000066400000000000000000000055331356743264500203010ustar00rootroot00000000000000# Git Cola Icons ## Guidelines 1. Size: 22x22px (the default action icon size of KDE and GNOME) 2. Margin: 1px (20x20px drawing area) 3. Colors: #000000 black, #ffffff white, #cc0000 red, #00dd26 green, #1961ff blue ## Copyright ### New icons The following icons are created/re-created by [Guo Yunhe](https://guoyunhe.me/): - a-z-order.svg - check.svg - circle-slash-red.svg - circle-slash.svg - desktop-download.svg - diff.svg ### Original icons The following icons are based on the based on the original .png icon designs for git-cola's File Browser by Uri Okrent. staged.svg modified.svg partial.svg upstream.svg Copyright (C) 2011 Uri Okrent Copyright (C) 2015-2017 David Aguilar and contributors License: MIT ### Git Logo Git Logo by [Jason Long](https://twitter.com/jasonlong) is licensed under the [Creative Commons Attribution 3.0 Unported License](https://creativecommons.org/licenses/by/3.0/). This license lets others distribute, remix, tweak, and build upon your work, even commercially, as long as they credit you for the original creation. This is the most accommodating of the CC licenses offered. Recommended for maximum dissemination and use of licensed materials. https://git-scm.com/downloads/logos git-cola.svg is based on the Git Logo. ### Octicons The following files are from Github's [octicons](https://github.com/github/octicons) icon set: check.svg circle-slash.svg desktop-download.svg diff.svg ellipsis.svg eye.svg file-binary.svg file-code.svg file-directory.svg file-media.svg file-text.svg file-zip.svg fold.svg gear.svg git-branch.svg git-compare.svg git-merge.svg link-external.svg pencil.svg plus.svg primitive-dot.svg question.svg question-plain.svg repo-pull.svg repo-push.svg repo.svg screen-full.svg search.svg star.svg sync.svg tag.svg telescope.svg trashcan.svg unfold.svg x.svg Copyright (C) 2012-2015 GitHub License: [MIT](http://choosealicense.com/licenses/mit/) ### Gnome Adwaita Icons The following files are from the Gnome project's [Adwaita icon theme](https://github.com/GNOME/adwaita-icon-theme): document-save-symbolic.svg Copyright (C) The Gnome Project License: [LGPL](https://github.com/GNOME/adwaita-icon-theme/blob/master/COPYING_LGPL) ### Gnome High Contrast Icons The following files are from the Gnome High Contrast Icon set: zoom-fit-best.svg zoom-in.svg zoom-out.svg License: LGPL v2+ ### Flaticon.com Icons The following files are designed by Freepik from http://www.flaticons.com/ edit-undo.svg License: [Flatpik Basic License](http://cdn.flaticon.com/license/license.pdf) The following files are by Linh Pham from http://flaticons.com/ edit-copy.svg License: [Creative Commons BY 3.0](http://creativecommons.org/licenses/by/3.0/) ### Google Icons The following files are by Google: edit-select-all.svg file-download.svg License: [Creative Commons BY 3.0](http://creativecommons.org/licenses/by/3.0/) git-cola-3.6/share/git-cola/icons/a-z-order.svg000066400000000000000000000025071356743264500213410ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/check.svg000066400000000000000000000003151356743264500206110ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/circle-slash-red.svg000066400000000000000000000007501356743264500226600ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/circle-slash.svg000066400000000000000000000007511356743264500221110ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/000077500000000000000000000000001356743264500177355ustar00rootroot00000000000000git-cola-3.6/share/git-cola/icons/dark/README.md000066400000000000000000000041431356743264500212160ustar00rootroot00000000000000Git Cola Dark Icons -------------- All icons in this directory, besides color inversion, are unmodified original ones. All kudos and copyrights go to their respective authors ( see original readme bellow ). 2017 Filip Danilovic -------------------- Git Cola Icons -------------- The following icons are based on the based on the original .png icon designs for git-cola's File Browser by Uri Okrent. staged.svg modified.svg partial.svg upstream.svg Copyright (C) 2011 Uri Okrent Copyright (C) 2015-2017 David Aguilar and contributors License: MIT Git Logo -------- Git Logo by Jason Long is licensed under the Creative Commons Attribution 3.0 Unported License. http://git-scm.com/downloads/logos git-cola.svg is based on the original Git Logo. Octicons -------- The following files are from Github's [octicons](https://github.com/github/octicons) icon set: check.svg circle-slash.svg desktop-download.svg diff.svg ellipsis.svg eye.svg file-binary.svg file-code.svg file-directory.svg file-media.svg file-text.svg file-zip.svg fold.svg gear.svg git-branch.svg git-compare.svg git-merge.svg link-external.svg pencil.svg plus.svg primitive-dot.svg question.svg question-plain.svg repo-pull.svg repo-push.svg repo.svg screen-full.svg search.svg star.svg sync.svg tag.svg telescope.svg trashcan.svg unfold.svg x.svg Copyright (C) 2012-2015 GitHub License: [MIT](http://choosealicense.com/licenses/mit/) Gnome High Contrast Icons ------------------------- The following files are from the Gnome High Contrast Icon set: zoom-fit-best.svg zoom-in.svg zoom-out.svg License: LGPL v2+ Flaticon.com Icons ------------------ The following files are designed by Freepik from http://www.flaticons.com/ edit-undo.svg License: [Flatpik Basic License](http://cdn.flaticon.com/license/license.pdf) The following files are by Linh Pham from http://flaticons.com/ edit-copy.svg License: [Creative Commons BY 3.0](http://creativecommons.org/licenses/by/3.0/) Google Icons ------------ The following files are by Google: edit-select-all.svg file-download.svg License: [Creative Commons BY 3.0](http://creativecommons.org/licenses/by/3.0/) git-cola-3.6/share/git-cola/icons/dark/a-z-order.svg000066400000000000000000000025071356743264500222620ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/check.svg000066400000000000000000000003151356743264500215320ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/circle-slash-red.svg000066400000000000000000000007501356743264500236010ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/circle-slash.svg000066400000000000000000000007501356743264500230310ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/desktop-download.svg000066400000000000000000000003401356743264500237310ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/diff.svg000066400000000000000000000003741356743264500213720ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/document-save-symbolic.svg000066400000000000000000000020331356743264500250450ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/edit-copy.svg000066400000000000000000000010041356743264500223460ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/edit-select-all.svg000066400000000000000000000104211356743264500234240ustar00rootroot00000000000000 image/svg+xml git-cola-3.6/share/git-cola/icons/dark/edit-undo.svg000066400000000000000000000015121356743264500223450ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/ellipsis.svg000066400000000000000000000007171356743264500223070ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/eye.svg000066400000000000000000000010651356743264500212420ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/file-binary.svg000066400000000000000000000011121356743264500226520ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/file-code.svg000066400000000000000000000010271356743264500223050ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/file-directory.svg000066400000000000000000000006651356743264500234060ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/file-download.svg000066400000000000000000000011621356743264500232020ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/file-media.svg000066400000000000000000000006671356743264500224630ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/file-text.svg000066400000000000000000000007511356743264500223620ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/file-zip.svg000066400000000000000000000014341356743264500221770ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/fold.svg000066400000000000000000000012541356743264500214040ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/folder-new.svg000066400000000000000000000023521356743264500225220ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/folder.svg000066400000000000000000000013441356743264500217330ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/gear.svg000066400000000000000000000014571356743264500214030ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/git-branch.svg000066400000000000000000000030721356743264500224760ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/git-cola.ico000066400000000000000000013226261356743264500221440ustar00rootroot00000000000000 ( f ( @@ (B(00 %j   h.( 999 FFF!BBB:DDDDFFF3BBB333DDD"DDDqDDDCCDDDDDDDDDDDDDDDDCCDDDDDDD^KKKDDD"DDDDDEDDDDDI@Hv=J;K:L;K=JAGgCDDDDDCCDDDDIII333DDDDDEDDD?Ht8M4Q3Q3Q3Q3Q3Q3Q3Q5P9LAF^DDDDEFCCC[GGGDDEDDDAGh7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9LCFVDDDCCCUUUEEEDDEDDD=J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4P@GoDDDDDDUUUEEEDDEDDE:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>IDDDCCCUUUFFFCCEDDD;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P?H|DDDDDDUUUFFFCCEDDDH}DDDCCC333CCCDDEDDD;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>H}DDDDDD333CCCDDEDDE;L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>H~DDDDDD333CCCDDEDDE;L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>H~DDDDDDUUUCCCDDEDDE:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>H~DDDDDDUUUCCCDDEDDE:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>H~DDDDDDUUUCCCDDEDDE:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDDDDUUUCCCDDEDDE:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDDDDUUU@@@DDEDDE:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q?IDDDDDDUUU@@@CCDDDE:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q?IDDDDDDUUU@@@CCDDDE:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q?IDDDDDDUUU@@@CCDDDE:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q?IDDDDDDUUU@@@CCDDDE;L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=HDDDDDDUUU@@@CCDDDE;L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=IDDDDDDUUU@@@CCDDDE:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=IDDDCCCUUUFFFCCDDDE:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=IDDDCCCUUUFFFDDEDDE:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>IDDDCCCUUUFFFDDEDDE:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>IDDDDDDUUUFFFDDEDDE:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>IDDDDDDUUUFFFDDEDDE:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>IDDDDDDIIIFFFDDEDDE:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>IDDDDDDIIIFFFDDEDDE:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>IDDDDDDIIIDDDDDEDDE:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=IDDDDDDIIIDDDDDECCD:M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=IDDDDDDIIIDDDDDECCD9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=IDDDEEE999 DDDCEFCCD9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=IDDDDDD999 DDDCEFCCD9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=IDDDDDD999 DDDCDECDE9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=IDDDDDD999 DDDCDECDE9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=IDDDDDDMMM BBBCDECDE9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=IDDDDDDMMM BBBCDECDE9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=IDDDDDDMMM BBBCDECDE9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>JDDDDDDMMM BBBCDECDE:M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>JDDDDDDMMM BBBCDECDE:M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QGwCDEDDDDDDDDDDDDDDDDDDDDDCCCDDDDDEDDDDDDAF`9L3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QI3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;JDDDDDE@@@FFF,CDECDG8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4PCFSCCDHHH EEEDDD9N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QFI7Bc3P3P6Ds7?B~QX[7?C4J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q?HxDDE@@@EEECDH4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:KDDDCCD@@@BBB2CCEDEK7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4J7?B>FI7Cd3P3Q3P6D{7?Bw|~RY]7?C5I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9NDDDEEECCC5DDD>I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:KDDDCCD@@@FFF3CDECDJ7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5J7?B7?B5I3Q3Q3Q5E}7?Bw|~T[^7?C5I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAF`DEFEEEDDDCCD6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:KDDDCCD@@@FFF3CDECDJ7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4L7?BY_c7@C5J3Q3Q3Q5E}7?Bw}U\`7?C5I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q8MDDDDDDDDDZDDD=I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;KDDEDDE@@@FFF3CDEDEK8N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4P8AIlqtOVZ7?D4I3Q3Q3Q6E~7?BX^b7?C5I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q?I}DDDCCCjEEE%CCDCER5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;LDDEDDEIIIEEE4CDEDEL8N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P5I4L3Q3Q3Q3Q6Ey9AEPWZ7?B5H3Q3Q3Q7B`PX`Y`c7?C5I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4PBFZDDEDDDKFFFDDECCD8N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;LDDEDDEIIIEEE4CDEDEL7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3M8BR7?B7?C4J3Q3Q3Q4L7?B[ae7?B6Dx4L5I7@Cotw[ae7@C5I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6ODFQDDEDDDKFFF!DDEDDD:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:KDDEDDEIIICCC5DEFDEL7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4K8@I>GKY`c7@C4J3Q3Q3Q6Er8@Cz7?B7?B7?BNUXZad7@C5I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q7NDFQCCDDDDmDDDGw;L4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LCCDDDEEEEDDDDEFCEO6N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5F7?B7?B4J3Q3Q4L8AP9AC7?B6E{3Q3P5F7?Buz}\bf7?B5I3Q3Q3Q3O3O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5PAF`DDDDDD999 @@@DDDDDDCFV6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9LCDEDDEBBBFFF>DEFCEO6N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6D{8@CCDECFP6N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5E7?B7?B5F3Q3Q3Q3Q5Dv7?Bhnpqwy7?B5G3Q3Q5F7?Btz|\bf7?B4I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q@GmDDDCCCcFFFBDDECFX4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9LCDEDDE@@@EEE?CDECFP6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5H7?Bntv7?B4J3Q3Q3Q3Q5G7?B\cffln7?B4K3Q3Q5F7?Btz|\bf7?B5H3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QFI8BP3N3Q3Q3Q3Q5I7?B^dh7?B6G3Q3Q3Q6G7?Bsy{\cf7?B5H3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q8NDDDDDDDDDmDDD:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QFI9AD6Dv3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5H7?Bekn7?B6Dq3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q?HvDDE@@@DDDAE[3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAGcDDEDDDDDD6P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q8B]NUY8AD6Dk3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4M9BP;CGw|~7?B4M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5H7?Bkpt7?B7C^4O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QI3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3M7?BX^b7@E4L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3N7C^7?Bz?FJ8AO3N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5H7?BY`cdkm7?B6Dn4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4PDEIDDDDDDDDD6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;KDDDFFFBDDECET3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6Dp8@CELQ8AH4M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P5E}7?BQX[KRV8@H4M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5I8@C7?B7?B8@C5G3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4QBF_DDDGGGFFF DDEAF_3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAFaCCD333CCCyDDD9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4N7?Dcil=EI8BR4N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4I8AI8ADCJN8AF4L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4N5F6F4M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?HxDDDCCCUUUDDDmDDD:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9LDDDDDD@@@ CDDCFW3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5G7?B;CF8BT3O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3N6Dq7?B;CFv{}8@C8BN5L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?HwDDDDDDUUUKKKCDECFS3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3PAEXCDE@@@EEEoDDD=J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P7Ce9AC9AC8BU4N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4L7Ci7?B7?BMTWqwyzLSW7?B7?C6E3N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?HwDDDDDDUUUDDDDDD9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QJ6P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:KDDEDDEEEEFFF(CDECDG8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5H7?BX^bz7?B4N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3P?HtDDDEEEEEEFDEFCFS>H~BEQDDDDDDDDDDDDDDDDDDDDDDEI?Hu:K4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;LDDEDDEEEEAAA'CDECDH8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5I8@CHPT8@C6Dv3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3P?GsDDDDDDDDDGDDECFR6O3Q3Q5P7N9L:L:L9N5O4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;LDDEDEFGGGDDD-CDEDEK8N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4K8AH;CG?FJ8BS3O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q4Q?HyDDDDDDCCC=DEFCEN7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LCCDDDEHHH DDD-CDEDDI7M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4M8C[7?Bw}FMQ8AF4M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q4Q?HyDDDDDDCCC=DEFCEN7O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LCCDCDDHHH FFF,CDEDDI7M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P6E7?B?GK;CF9AM4L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q4Q?HxDDDDDDFFF>DEFCEN7O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LCCDCDDHHH FFF,CDEDDI7M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4L7C^7?BFMQbhl7?B8C\3N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q4Q?HxDDDEEEFFF>DEFCEN7O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LDDECDF@@@FFF,CDEDDI8N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P5J8BX7?B8@C[aeU\`7?B7?D5H3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q4Q?HxDDDCCCCCCEDDECEQ6N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LDDECDFBBBFFF,CDEDDI8N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4L6F7BT7?B7?B7?B7?B8AR6G4O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q4Q?HxDDDCCCCCCEDDECEQ6N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LDDECDFBBBAAA+CDECDH8N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P4N4M3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q4Q>GwDDDDDDEEEFDDECEQ6N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LDDECCDBBBAAA+CDECDH8N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M4Q>GwDDDDDDEEEFDDECEQ6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KDDEDDEBBBAAA+DEFCDH8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD9M>GwDDDDDDEEEFDDECEQ6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KDDEDDEEEEBBB#DDFCDG8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDDBERDDDDDDCCCPCCDCET6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;KDDDCEEIIIBBB#DDFDDG9M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDDDDDDDDEEEQDDECET5O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;KDDDDEEIIIDDD"CEFDDG9M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QBF[CCCEEE]DDDDDDDDDRDDECET5O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;KDDDDDE@@@DDD"CEFDDG9M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q7O@GlDDDCCCEEE]DDDDDDSDDECFU5O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;KDDDCCD@@@FFF!DEFDDG8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=IDDECCDEEEAAA+CCCCCCTDDECFU5O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QHzDDEDDD"CCCWDDECFV6P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;JDDDDDE@@@DDDCEFCDE9M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3PCDIDDDCCCnDDD9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QIDDDGGGCCCBDO3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:KDDDCCECCC@@@CDECDE:M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q@HsDDEEEEDDD3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;JDDDDDEDDD@@@CDFCDE:M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAGlCCDEEEDDD4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QGwCCDEEECDE4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q@@@DDEAFb3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QGwDDDDDDFFFCDEAEX4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=JDDDDDDFFF @@@CDFCCD9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?HxDDDDDDEEEDDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=JDDDCCEFFF @@@DDECCD:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?HxDDDDDDEEEDDD>I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QJBF^CDIDDDDDDDDDDDDBET?GqGwDDDEEECCCHDDECEN7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=JDDDCCCFFF GGGCCDCCD:L3Q3Q3Q3Q3Q3Q3Q3Q4Q>GwDDDEEEBBBIDDECEN7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=JDDDDDF999 GGGCCDCCD:L3Q3Q3Q3Q3Q3Q4Q>GwDDDEEEBBBIDDECEN7O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=JDDDDDF999 GGGCCDCCD:L3Q3Q3Q3Q4Q?HwDDDDDDBBBIDDECEN7O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=JDDDCCE999 @@@CCDCCD:L3Q3Q4Q?HwDDDDDDBBBIDDECEQ6N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=JDDDCCE999 @@@DDECCD:L4Q?HwDDDDDDBBBIDDECEQ6N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=IDDDCCE999 KKKCCDDDDAE\DDDCCCDDDVDDECFS6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=IDDDDDEUUUKKKCCDDDDDDDDDDVDDECET6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=HDDDDDDUUUKKKCCCjCCCWDDECET6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=HDDDCCD333DDDKDDECEQ6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QHDDDEEE@@@GGGCEFDDD;J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>HDDDDDDUUU@@@DDEDDD;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=HDDDDDD333@@@DDEDDD;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>IDDDDDD333@@@CCDDDD;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>IDDDDDD333@@@CCDDDD;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>IDDDEEE333@@@CCEDDD;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDEEE333CCCCCEDDD:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDEEE@@@CCCCCEDDD:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDDDD@@@CCCDDEDDD:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDDDD@@@CCCDDEDDD;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDDDD@@@GGGDDEDDD;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDDDD@@@GGGDDEDDD;J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=HDDDDDD@@@GGGCCDDDD;J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=HDDDDDD@@@KKKCCDDDD;J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=HDDDDDD@@@IIIDDEDDD;J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDDDD@@@IIIDDFDDD;J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDEEE@@@IIIDDFDDD;J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDEEE@@@;;; CCEDDD;J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDEEEUUU;;; CCEDDDIDDDCCC999 DDFDDD=J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?HxDDDDDD999 CCEDDD>I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q@GoDDDDDD999 DDDDDD@Gl6P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6NAE[DDDDDD@@@CCCDDDDDG=I5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6N?HxDDEDDECCCjEEE;CCCDDDCDE@Gm;K7N5O3P3P5O7MIBDSBBMYEEHCCET7M3Q3Q3Q3Q3Q3Q5O@GqDETEEHCBF\5P3Q3Q3Q3Q3Q3Q3Q3Q3Q=JCFQDDHBE\5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=ICERBFJ>BE\5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>JCEQEEI?BE\5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QH~?Gs=I9L4O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LBEQ999 CCOj@Hm3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q8MAE]CEUFFIbDDDICFQCCCCEQ7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LBDQFFF CCPo@Hn4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:MBEQEEECES5O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;LCER@@@ CENo@Go4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4PBETGGGBBM]>I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9MCFQ@@@ CERs?Hr4Q3Q3Q3Q3Q3Q3Q3Q3P4K3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9MBDOCEQ3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:MBEQ;;; DFSu?Gr4Q3Q3Q3Q3Q3Q3Q3Q;OFO_xCMi3O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q?HtBBB6DFT9M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9LBDQIIIACMjAGm3P3Q3Q3Q3Q3Q3Q3OBMjDNb3O3Q3Q3Q3Q3Q3Q3Q3Q3Q3QBEY@@@CCC_;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LBEQMMM CETz?Ht3P3Q3Q3Q3Q3Q3Q4OFOcFOa4O3Q3Q3Q3Q3Q3Q3Q3Q3QBESCCCL=J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9MBEQDDDCFQn@Gn3P3Q3Q3Q3Q3Q3Q3OENcFOa3N3Q3Q3Q3Q3Q3Q3Q3QBEYIIICCC_;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KBEQFFF CET}?Hv3Q3Q3Q3Q3Q3Q3Q3QCQdkyGP`4N3Q3Q3Q3Q3Q3Q3Q?GuFFF7CDS9M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q8MCEQ@@@BDR?Iw3Q3Q3Q3Q3Q3Q3Q3Q4POXfGP\4MEPdGQ`4N3Q3Q3Q3Q3Q3Q9LCGSCDQ3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q8KBEQKKKADQq@Go4Q3Q3Q3Q3Q3Q3Q3Q3Q4MjsV^m4N4OCNdIRb4M3Q3Q3Q3Q3Q4QBEU@@@EEHY?I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LCEPIIIBFT?Iz3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3PKTbFO_4N3ODNfJSd3N3Q3Q3Q3Q3Q9LBEQEEECFS5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9NBDPGGGCGT>G{3Q3Q3Q3Q3Q3Q3Q3QIBFOUUUFFFBDQ6N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q8MCEQCCCDES>G|3Q3Q3Q3Q3Q3Q3Q3Q>NxIRa4M3OIRbJSb4N3Q3Q3Q3Q3QG~4Q3Q3Q3Q3Q3Q3Q3NIQaZbn>P3PDOhIQa4M3Q4NNV_JSa6N3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9NBEOFFFDES>I3Q3Q3Q3Q3Q3Q3Q3PDNaANv3ODOhJRa5N3QDOlEPd4N3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4O:K@FdBEWBEVBEY=G|9N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q7MBDPBBBBFS=I3Q3Q3Q3Q3Q3Q3Q3Q;NGP\iq~BNk3MDNiJRa5N3OFP`KTc?O3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P=HCESDFMqHHH UUUFFF EEE?BFUAFY8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q7NCEP@@@CFP>I3Q3Q3Q3Q3Q3Q3Q3Q3QFPlw~4L5MGPaBLj4ODNiJRa5M4O4K3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5O@FcAFSuFFFBDS;J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q8MCEPFFFBDR=I3Q3Q3Q3Q3Q3Q3Q3Q3Q3QFPgBNk3P4ODNgAMq3PEQnJSa5M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3PBF[CCGA333CEQ:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6NCEPDDDBDR=I3Q3Q3Q3Q3Q3Q3Q3P4L:M4N@P?O3Q4PBMn>P3PEPoJSa4M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>ICFMn999 DER5N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6NBDPKKKCEPs?Hy3Q3Q3Q3Q3Q3Q3Q4NFPgMVb5KR\iz?P3Q3PAMt`ht6M3PEPnJSa4M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6PDERۀBBEF?Hs3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:MCER@@@BFV3P3Q3Q3Q3Q3Q3Q5NIR`DM_?Pt{>O3Q3PCOpEPe3Q3PDOnKUc5M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q3Q3Q3QO3Q3QCNjx4L3Q3PCOnLUc5L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAGbCCCBFR9M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q7NCEUBEU6O3Q3Q3Q3Q3Q3QCRKTb4M3Q3Q4OGPcy@N3Q3OFP`?P3Q3Q4PDOoLUc5L3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q3Q3Q3QBEUDDFf:J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QCEQCER4Q3Q3Q3Q3Q3Q3QFP]H~4Q3Q3Q3Q3Q3Q4MKSaKT`7M3Q3Q3Q9Npxbjv>P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q:LCDP@@@ CFFECFV5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3PAHoBDR|DFT?H}4Q3Q3Q3Q3Q3Q6MNWcckxBQ4M8MNVdYap4N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q:KCFQFFF FFFCEPBGb5O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3PAGmBDP|CER?H{3Q3Q3Q3Q3Q3Q7NNVdyfm|4N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q:LDEPFFF DDI8DFOBDUDFPCCCgBFUBETBG]:M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P?GlCERzCFU?I{3Q3Q3Q3Q3Q3Q4NISbEPk3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q:LBDRMMM CCH9CFV6O7N8L:L8M6P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P@HmACTyCFT>H3Q3Q3Q3Q3Q3Q4ODOiEO_4O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q:LCFQ;;; BBG2CFU5N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?GqCERAEQ>H}4Q3Q3Q3Q3Q3Q3Q=OJScEPl4O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q:MCDO;;; AAF3CFU6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>GpDFSAES?I~3Q3Q3Q3Q3Q3Q3Q4P:OGSHSpGRw7L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q:LCDO;;; AAF3ADW6P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q@GqBDPCET>H}3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv:LCDO@@@ EEJ4AEW5O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q@GqBDS{CEW?Hu3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.DENCFR@@@DDH@BEX4O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4P@FhAFSqBDQ{?Gr4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QI~4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4PAF[DDJOBEM]AFb5Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=JBESUUUDDKKBEQCERBFXADSCFWCER>Hz6N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4OAFZFFIMBGR]AGb5Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=JBEUUUUDDGKAF_4P4Q5P7O4O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5PAE[BBLMAFPfAFc4P3Q3Q3Q3Q3Q3Q3Q3Q3QHDGWEEKUBF`5Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5OBEZDDKDCCMPCEPCFNXAFa5Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5OBEWCCGABBLMAG_4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4OBF[BEEFEENNAG_4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4OCFYCFFEDDMOAG_4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5PBFXCFFEDDMVAE^4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5PBFXDGGD@@@DEI5O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6PCEUBBB:EEKUBF`5Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5OBFWBBFBFFLTAF\5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5OBEWBBFBDDJSAF\5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5OBEUCCGADDJSAF\5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5OBEUDDD@FFIPAF\5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6PBFWCCC9DGGOBFZ4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6OCEUDDD8EHHNBFZ4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6OCETDDD8BFFMBEZ4O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5OBETFFF7BEEFCFX4O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5OBEUFFF7DDDHz@MYCCQ>H~5Q3Q3Q4Q=JDIc1@@P?I|4P3Q3Q3Q3Q4Q=JCI[*@@P?I}4P3Q3Q3Q3Q3Q3Q4Q=JAG_+<H3P3Q3Q3Q3Q3Q3Q3Q3Q3Q=J@F],<H3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=JAG\/<I3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QH4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=KDIc1FFQ>I4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QI3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;IFF]7BBZ=I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4P;K>J=HFaBBBZ>J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6O?GoFFF BIhe9K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:JAHcC@HX >J4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?IzBGih5N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;K?FdEFM]!EbFDKZ">J4Q3Q3QBYE[3Q3Q3Q3Q;K߀=I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:JAHeG@G\$D])MMM >Hx4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:KBIcM@F`(GuoFFF ?J4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:KBFcMFM]!>J4Q3Q3Q3Q@XFYan\j@Wmz3Q3Q3Q=I@@@8L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;KAHaGDKZ"Gw?Iv=I8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;L@FdTAG\/;J3Q3Q3Q3QJ\>SfqFYEZ3O3Q3Q3Q3Q3Q3Q=I@@@8L3Q3Q3Q3Q3Q6NAGh}@G`H:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LBHfUFFXI;I3Q3Q3Q}4P3Q`n=Sxv3Q?VJ^3Q3Q3Q3Q=I@@@8L3Q3Q3Q3Q;K=I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QJ3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;J?Hy3Q3Q3QTdht3P3Q3QTceq3P3Q3Q3Q9SK]3Q3Q3Q3Q3Q=I@@@8L3Q3Q3Q3Q;JEES%CI[*9M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q?I|BBUI3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=J@JUDKZ"Fcb@F`P?HoGoZ8L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QD])BIf#;I4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=I@@@AGjBFc>@Gid7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>JEnk7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDUBBZ=I4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q8M@Ekk@Iql8N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IFFXDD^=J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P?Gp?Hrn8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P>III[FFX=I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9M@GN$=J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P=I;ENII[=I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;K>I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P>I;ENII[>I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9NBBI#=I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>G=GRBBU>I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QFm@Fjx?Hy:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?I~FFQEEb>I3P3Q3Q3Q3QJ3Q3Q3Q;JAEa?@Gol9M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P?IBLUDD^>J3Q;JAEa?@Iql8L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?IBLUCNY@HlDIc1>Fp{7M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P>I|GGG?Hlq7M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?JFFQ?Hlq7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>I==I333?H{3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>Hz@@@;EN>I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?HCCC;EN>I3P3Q3Q3Q3Q3Q3Q3Q3Q4Q?HCCC==I>I4Q3Q3Q3Q3Q3Q3Q3P>I|CCC==I>H4Q3Q3Q3Q3Q4Q>IzGGG@@@>Gz5P3Q3Q5P?Hw;;; @@@AGlv?J>H@GloUUU????~?π?>|?(0` $333@@@;;N =H8N8N;K>Fa999 J4Q3Q3Q3Q3Q3Q;JGG\MMM =J3P3Q3Q3Q3Q3Q3Q3Q;JGG\MMM =J3P3Q3Q3Q3Q3Q3Q3Q3Q3QDj)CQ^:J3Q3QKa=W3Q3Q7M@@@;M3Q3Q3Q3Q3Q3Q3Q3Q3Q:L>Dj)@MY;K3Q3Q3QapAY3Q5PAHjR=IU9M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;M=Im*@MY;K3Q3QAYQf{AY3Q9LFMf(FFF =I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9MCIs*FF];K3Q3Q3PUhbn3Q3Q:KUUUHyg5P3Q3Q3Q3Q3Q3Q3Q:MGGf?J3P3QK`QcRfguwMbQc3Q3Q3Q7MIII;J3Q3Q3Q8N=IU:L3Q3Q3Q3Q3Q3Q3Q3Q=KIt6O3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q;K7I[@MYJ999 =Gv5O3Q3Q3Q3Q3Q3Q3Q3Q3Q4QFd!8N3Q3Q3Q3Q3Q3Q3Q4Q;JFF] DDUHz:K:K8M3Q3Q3Q3Q3Q3Q3Q3QG|w6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;L77I@P`;K7O=G{O>F}x6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:K77IFFF BFj:>I|5O3Q3Q3Q3Q3Q3Q3Q3Q3Q3QH}x5N3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q;J@@@ @@@=I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;I@@@DDUIUUU????<?x?( @ Dj)99U 8N3Q3Q3Q3Q3Q3Q7MCQy@@`8L3QShdu7S9MBJ{;J3Q3Q3Q3Q3Q3Q3Q3Q7LCQyIIm:L3Q4O]ojyOcSh3Q;Jh@@@ 6N3Q3Q3Q3Q3Q3Q3Q3Q3Q9MIIm3Mf 9M3QYlq^pz3Q3Q;Jh@@@ 6N3Q3Q4Q9N8N4Q3Q3Q3Q3Q7L=Iy333:L3QF^uo~_r3Q3Q3Q;Jh@@@ 6N3Q4Q;JY/Mu(G2P3Q3U:U-I:X.Eʀ4LW0Q3Q3Q3U;W3OYn@[/K֣7Nu3Q8P̊7Nu4Q3V>XGTGf{Sj2P֡7Nx5P5O3Q3YCT6S寓(G(I-M6Pک7NƆ6N\8NR6Oؼ3Q3Q6U7W.Q/Q3Q3Q8Lq8Mg3Q3Q3V=V?[3W3Q4P4P3Q3XAZ@Z8X6MU8NK5P3Q3XBZFU8Xl@Wh?a?git-cola-3.6/share/git-cola/icons/dark/git-cola.svg000066400000000000000000000146231356743264500221630ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/git-commit.svg000066400000000000000000000005421356743264500225300ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/git-compare.svg000066400000000000000000000027571356743264500227000ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/git-merge.svg000066400000000000000000000027011356743264500223360ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/last-first-order.svg000066400000000000000000000112501356743264500236560ustar00rootroot00000000000000 image/svg+xml git-cola-3.6/share/git-cola/icons/dark/link-external.svg000066400000000000000000000006201356743264500232310ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/modified.svg000066400000000000000000000002341356743264500222350ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/partial.svg000066400000000000000000000002341356743264500221110ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/pencil.svg000066400000000000000000000006771356743264500217420ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/plus.svg000066400000000000000000000003001356743264500214320ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/primitive-dot.svg000066400000000000000000000003761356743264500232600ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/question-plain.svg000066400000000000000000000007261356743264500234330ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/question.svg000066400000000000000000000015641356743264500223330ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/repo-pull.svg000066400000000000000000000011431356743264500223740ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/repo-push.svg000066400000000000000000000010741356743264500224020ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/repo.svg000066400000000000000000000011031356743264500214160ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/screen-full.svg000066400000000000000000000011331356743264500226730ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/search.svg000066400000000000000000000012771356743264500217320ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/staged.svg000066400000000000000000000002321356743264500217220ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/star.svg000066400000000000000000000004101356743264500214220ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/sync.svg000066400000000000000000000013601356743264500214320ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/tag.svg000066400000000000000000000012301356743264500212250ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/telescope.svg000066400000000000000000000015041356743264500224410ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/trashcan.svg000066400000000000000000000014471356743264500222670ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/unfold.svg000066400000000000000000000012321356743264500217430ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/upstream.svg000066400000000000000000000002411356743264500223130ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/x.svg000066400000000000000000000004711356743264500207270ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/zoom-fit-best.svg000066400000000000000000000015261356743264500231610ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/zoom-in.svg000066400000000000000000000022441356743264500220500ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/dark/zoom-out.svg000066400000000000000000000023121356743264500222450ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/desktop-download.svg000066400000000000000000000003401356743264500230100ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/diff.svg000066400000000000000000000003741356743264500204510ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/document-save-symbolic.svg000066400000000000000000000020071356743264500241250ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/edit-copy.svg000066400000000000000000000010041356743264500214250ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/edit-select-all.svg000066400000000000000000000022151356743264500225050ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/edit-undo.svg000066400000000000000000000006711356743264500214310ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/ellipsis.svg000066400000000000000000000004001356743264500213530ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/eye.svg000066400000000000000000000005341356743264500203210ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/file-binary.svg000066400000000000000000000005241356743264500217370ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/file-code.svg000066400000000000000000000010271356743264500213640ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/file-directory.svg000066400000000000000000000006651356743264500224650ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/file-download.svg000066400000000000000000000011621356743264500222610ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/file-media.svg000066400000000000000000000006671356743264500215420ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/file-text.svg000066400000000000000000000007511356743264500214410ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/file-zip.svg000066400000000000000000000014341356743264500212560ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/fold.svg000066400000000000000000000012541356743264500204630ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/folder-new.svg000066400000000000000000000023521356743264500216010ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/folder.svg000066400000000000000000000013441356743264500210120ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/gear.svg000066400000000000000000000014571356743264500204620ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/git-branch.svg000066400000000000000000000030721356743264500215550ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/git-cola.ico000066400000000000000000013226261356743264500212230ustar00rootroot00000000000000 ( f ( @@ (B(00 %j   h.( 999 FFF!BBB:DDDDFFF3BBB333DDD"DDDqDDDCCDDDDDDDDDDDDDDDDCCDDDDDDD^KKKDDD"DDDDDEDDDDDI@Hv=J;K:L;K=JAGgCDDDDDCCDDDDIII333DDDDDEDDD?Ht8M4Q3Q3Q3Q3Q3Q3Q3Q5P9LAF^DDDDEFCCC[GGGDDEDDDAGh7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9LCFVDDDCCCUUUEEEDDEDDD=J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4P@GoDDDDDDUUUEEEDDEDDE:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>IDDDCCCUUUFFFCCEDDD;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P?H|DDDDDDUUUFFFCCEDDDH}DDDCCC333CCCDDEDDD;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>H}DDDDDD333CCCDDEDDE;L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>H~DDDDDD333CCCDDEDDE;L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>H~DDDDDDUUUCCCDDEDDE:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>H~DDDDDDUUUCCCDDEDDE:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>H~DDDDDDUUUCCCDDEDDE:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDDDDUUUCCCDDEDDE:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDDDDUUU@@@DDEDDE:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q?IDDDDDDUUU@@@CCDDDE:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q?IDDDDDDUUU@@@CCDDDE:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q?IDDDDDDUUU@@@CCDDDE:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q?IDDDDDDUUU@@@CCDDDE;L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=HDDDDDDUUU@@@CCDDDE;L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=IDDDDDDUUU@@@CCDDDE:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=IDDDCCCUUUFFFCCDDDE:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=IDDDCCCUUUFFFDDEDDE:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>IDDDCCCUUUFFFDDEDDE:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>IDDDDDDUUUFFFDDEDDE:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>IDDDDDDUUUFFFDDEDDE:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>IDDDDDDIIIFFFDDEDDE:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>IDDDDDDIIIFFFDDEDDE:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>IDDDDDDIIIDDDDDEDDE:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=IDDDDDDIIIDDDDDECCD:M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=IDDDDDDIIIDDDDDECCD9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=IDDDEEE999 DDDCEFCCD9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=IDDDDDD999 DDDCEFCCD9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=IDDDDDD999 DDDCDECDE9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=IDDDDDD999 DDDCDECDE9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=IDDDDDDMMM BBBCDECDE9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=IDDDDDDMMM BBBCDECDE9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=IDDDDDDMMM BBBCDECDE9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>JDDDDDDMMM BBBCDECDE:M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>JDDDDDDMMM BBBCDECDE:M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QGwCDEDDDDDDDDDDDDDDDDDDDDDCCCDDDDDEDDDDDDAF`9L3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QI3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;JDDDDDE@@@FFF,CDECDG8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4PCFSCCDHHH EEEDDD9N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QFI7Bc3P3P6Ds7?B~QX[7?C4J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q?HxDDE@@@EEECDH4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:KDDDCCD@@@BBB2CCEDEK7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4J7?B>FI7Cd3P3Q3P6D{7?Bw|~RY]7?C5I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9NDDDEEECCC5DDD>I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:KDDDCCD@@@FFF3CDECDJ7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5J7?B7?B5I3Q3Q3Q5E}7?Bw|~T[^7?C5I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAF`DEFEEEDDDCCD6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:KDDDCCD@@@FFF3CDECDJ7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4L7?BY_c7@C5J3Q3Q3Q5E}7?Bw}U\`7?C5I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q8MDDDDDDDDDZDDD=I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;KDDEDDE@@@FFF3CDEDEK8N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4P8AIlqtOVZ7?D4I3Q3Q3Q6E~7?BX^b7?C5I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q?I}DDDCCCjEEE%CCDCER5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;LDDEDDEIIIEEE4CDEDEL8N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P5I4L3Q3Q3Q3Q6Ey9AEPWZ7?B5H3Q3Q3Q7B`PX`Y`c7?C5I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4PBFZDDEDDDKFFFDDECCD8N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;LDDEDDEIIIEEE4CDEDEL7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3M8BR7?B7?C4J3Q3Q3Q4L7?B[ae7?B6Dx4L5I7@Cotw[ae7@C5I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6ODFQDDEDDDKFFF!DDEDDD:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:KDDEDDEIIICCC5DEFDEL7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4K8@I>GKY`c7@C4J3Q3Q3Q6Er8@Cz7?B7?B7?BNUXZad7@C5I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q7NDFQCCDDDDmDDDGw;L4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LCCDDDEEEEDDDDEFCEO6N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5F7?B7?B4J3Q3Q4L8AP9AC7?B6E{3Q3P5F7?Buz}\bf7?B5I3Q3Q3Q3O3O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5PAF`DDDDDD999 @@@DDDDDDCFV6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9LCDEDDEBBBFFF>DEFCEO6N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6D{8@CCDECFP6N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5E7?B7?B5F3Q3Q3Q3Q5Dv7?Bhnpqwy7?B5G3Q3Q5F7?Btz|\bf7?B4I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q@GmDDDCCCcFFFBDDECFX4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9LCDEDDE@@@EEE?CDECFP6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5H7?Bntv7?B4J3Q3Q3Q3Q5G7?B\cffln7?B4K3Q3Q5F7?Btz|\bf7?B5H3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QFI8BP3N3Q3Q3Q3Q5I7?B^dh7?B6G3Q3Q3Q6G7?Bsy{\cf7?B5H3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q8NDDDDDDDDDmDDD:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QFI9AD6Dv3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5H7?Bekn7?B6Dq3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q?HvDDE@@@DDDAE[3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAGcDDEDDDDDD6P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q8B]NUY8AD6Dk3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4M9BP;CGw|~7?B4M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5H7?Bkpt7?B7C^4O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QI3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3M7?BX^b7@E4L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3N7C^7?Bz?FJ8AO3N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5H7?BY`cdkm7?B6Dn4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4PDEIDDDDDDDDD6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;KDDDFFFBDDECET3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6Dp8@CELQ8AH4M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P5E}7?BQX[KRV8@H4M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5I8@C7?B7?B8@C5G3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4QBF_DDDGGGFFF DDEAF_3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAFaCCD333CCCyDDD9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4N7?Dcil=EI8BR4N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4I8AI8ADCJN8AF4L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4N5F6F4M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?HxDDDCCCUUUDDDmDDD:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9LDDDDDD@@@ CDDCFW3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5G7?B;CF8BT3O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3N6Dq7?B;CFv{}8@C8BN5L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?HwDDDDDDUUUKKKCDECFS3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3PAEXCDE@@@EEEoDDD=J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P7Ce9AC9AC8BU4N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4L7Ci7?B7?BMTWqwyzLSW7?B7?C6E3N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?HwDDDDDDUUUDDDDDD9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QJ6P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:KDDEDDEEEEFFF(CDECDG8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5H7?BX^bz7?B4N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3P?HtDDDEEEEEEFDEFCFS>H~BEQDDDDDDDDDDDDDDDDDDDDDDEI?Hu:K4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;LDDEDDEEEEAAA'CDECDH8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5I8@CHPT8@C6Dv3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q3Q3P?GsDDDDDDDDDGDDECFR6O3Q3Q5P7N9L:L:L9N5O4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;LDDEDEFGGGDDD-CDEDEK8N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4K8AH;CG?FJ8BS3O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q3Q4Q?HyDDDDDDCCC=DEFCEN7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LCCDDDEHHH DDD-CDEDDI7M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4M8C[7?Bw}FMQ8AF4M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q3Q4Q?HyDDDDDDCCC=DEFCEN7O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LCCDCDDHHH FFF,CDEDDI7M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P6E7?B?GK;CF9AM4L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q3Q4Q?HxDDDDDDFFF>DEFCEN7O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LCCDCDDHHH FFF,CDEDDI7M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4L7C^7?BFMQbhl7?B8C\3N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q3Q4Q?HxDDDEEEFFF>DEFCEN7O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LDDECDF@@@FFF,CDEDDI8N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P5J8BX7?B8@C[aeU\`7?B7?D5H3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q3Q4Q?HxDDDCCCCCCEDDECEQ6N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LDDECDFBBBFFF,CDEDDI8N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4L6F7BT7?B7?B7?B7?B8AR6G4O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q3Q4Q?HxDDDCCCCCCEDDECEQ6N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LDDECDFBBBAAA+CDECDH8N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P4N4M3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M3Q4Q>GwDDDDDDEEEFDDECEQ6N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LDDECCDBBBAAA+CDECDH8N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD8M4Q>GwDDDDDDEEEFDDECEQ6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KDDEDDEBBBAAA+DEFCDH8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDD9M>GwDDDDDDEEEFDDECEQ6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KDDEDDEEEEBBB#DDFCDG8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDDBERDDDDDDCCCPCCDCET6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;KDDDCEEIIIBBB#DDFDDG9M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAE\CCCEEE]DDDDDDDDDEEEQDDECET5O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;KDDDDEEIIIDDD"CEFDDG9M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QBF[CCCEEE]DDDDDDDDDRDDECET5O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;KDDDDDE@@@DDD"CEFDDG9M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q7O@GlDDDCCCEEE]DDDDDDSDDECFU5O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;KDDDCCD@@@FFF!DEFDDG8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=IDDECCDEEEAAA+CCCCCCTDDECFU5O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QHzDDEDDD"CCCWDDECFV6P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;JDDDDDE@@@DDDCEFCDE9M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3PCDIDDDCCCnDDD9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QIDDDGGGCCCBDO3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:KDDDCCECCC@@@CDECDE:M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q@HsDDEEEEDDD3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;JDDDDDEDDD@@@CDFCDE:M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAGlCCDEEEDDD4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QGwCCDEEECDE4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q@@@DDEAFb3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QGwDDDDDDFFFCDEAEX4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=JDDDDDDFFF @@@CDFCCD9L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?HxDDDDDDEEEDDD8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=JDDDCCEFFF @@@DDECCD:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?HxDDDDDDEEEDDD>I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QJBF^CDIDDDDDDDDDDDDBET?GqGwDDDEEECCCHDDECEN7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=JDDDCCCFFF GGGCCDCCD:L3Q3Q3Q3Q3Q3Q3Q3Q4Q>GwDDDEEEBBBIDDECEN7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=JDDDDDF999 GGGCCDCCD:L3Q3Q3Q3Q3Q3Q4Q>GwDDDEEEBBBIDDECEN7O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=JDDDDDF999 GGGCCDCCD:L3Q3Q3Q3Q4Q?HwDDDDDDBBBIDDECEN7O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=JDDDCCE999 @@@CCDCCD:L3Q3Q4Q?HwDDDDDDBBBIDDECEQ6N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=JDDDCCE999 @@@DDECCD:L4Q?HwDDDDDDBBBIDDECEQ6N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=IDDDCCE999 KKKCCDDDDAE\DDDCCCDDDVDDECFS6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=IDDDDDEUUUKKKCCDDDDDDDDDDVDDECET6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=HDDDDDDUUUKKKCCCjCCCWDDECET6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=HDDDCCD333DDDKDDECEQ6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QHDDDEEE@@@GGGCEFDDD;J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>HDDDDDDUUU@@@DDEDDD;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q=HDDDDDD333@@@DDEDDD;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>IDDDDDD333@@@CCDDDD;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>IDDDDDD333@@@CCDDDD;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>IDDDEEE333@@@CCEDDD;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDEEE333CCCCCEDDD:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDEEE@@@CCCCCEDDD:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDDDD@@@CCCDDEDDD:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDDDD@@@CCCDDEDDD;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDDDD@@@GGGDDEDDD;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDDDD@@@GGGDDEDDD;J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=HDDDDDD@@@GGGCCDDDD;J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=HDDDDDD@@@KKKCCDDDD;J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=HDDDDDD@@@IIIDDEDDD;J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDDDD@@@IIIDDFDDD;J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDEEE@@@IIIDDFDDD;J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDEEE@@@;;; CCEDDD;J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDDEEEUUU;;; CCEDDDIDDDCCC999 DDFDDD=J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?HxDDDDDD999 CCEDDD>I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q@GoDDDDDD999 DDDDDD@Gl6P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6NAE[DDDDDD@@@CCCDDDDDG=I5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6N?HxDDEDDECCCjEEE;CCCDDDCDE@Gm;K7N5O3P3P5O7MIBDSBBMYEEHCCET7M3Q3Q3Q3Q3Q3Q5O@GqDETEEHCBF\5P3Q3Q3Q3Q3Q3Q3Q3Q3Q=JCFQDDHBE\5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=ICERBFJ>BE\5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>JCEQEEI?BE\5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QH~?Gs=I9L4O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LBEQ999 CCOj@Hm3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q8MAE]CEUFFIbDDDICFQCCCCEQ7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LBDQFFF CCPo@Hn4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:MBEQEEECES5O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;LCER@@@ CENo@Go4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4PBETGGGBBM]>I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9MCFQ@@@ CERs?Hr4Q3Q3Q3Q3Q3Q3Q3Q3P4K3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9MBDOCEQ3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:MBEQ;;; DFSu?Gr4Q3Q3Q3Q3Q3Q3Q3Q;OFO_xCMi3O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q?HtBBB6DFT9M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9LBDQIIIACMjAGm3P3Q3Q3Q3Q3Q3Q3OBMjDNb3O3Q3Q3Q3Q3Q3Q3Q3Q3Q3QBEY@@@CCC_;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LBEQMMM CETz?Ht3P3Q3Q3Q3Q3Q3Q4OFOcFOa4O3Q3Q3Q3Q3Q3Q3Q3Q3QBESCCCL=J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9MBEQDDDCFQn@Gn3P3Q3Q3Q3Q3Q3Q3OENcFOa3N3Q3Q3Q3Q3Q3Q3Q3QBEYIIICCC_;K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KBEQFFF CET}?Hv3Q3Q3Q3Q3Q3Q3Q3QCQdkyGP`4N3Q3Q3Q3Q3Q3Q3Q?GuFFF7CDS9M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q8MCEQ@@@BDR?Iw3Q3Q3Q3Q3Q3Q3Q3Q4POXfGP\4MEPdGQ`4N3Q3Q3Q3Q3Q3Q9LCGSCDQ3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q8KBEQKKKADQq@Go4Q3Q3Q3Q3Q3Q3Q3Q3Q4MjsV^m4N4OCNdIRb4M3Q3Q3Q3Q3Q4QBEU@@@EEHY?I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LCEPIIIBFT?Iz3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3PKTbFO_4N3ODNfJSd3N3Q3Q3Q3Q3Q9LBEQEEECFS5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9NBDPGGGCGT>G{3Q3Q3Q3Q3Q3Q3Q3QIBFOUUUFFFBDQ6N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q8MCEQCCCDES>G|3Q3Q3Q3Q3Q3Q3Q3Q>NxIRa4M3OIRbJSb4N3Q3Q3Q3Q3QG~4Q3Q3Q3Q3Q3Q3Q3NIQaZbn>P3PDOhIQa4M3Q4NNV_JSa6N3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9NBEOFFFDES>I3Q3Q3Q3Q3Q3Q3Q3PDNaANv3ODOhJRa5N3QDOlEPd4N3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4O:K@FdBEWBEVBEY=G|9N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q7MBDPBBBBFS=I3Q3Q3Q3Q3Q3Q3Q3Q;NGP\iq~BNk3MDNiJRa5N3OFP`KTc?O3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P=HCESDFMqHHH UUUFFF EEE?BFUAFY8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q7NCEP@@@CFP>I3Q3Q3Q3Q3Q3Q3Q3Q3QFPlw~4L5MGPaBLj4ODNiJRa5M4O4K3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5O@FcAFSuFFFBDS;J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q8MCEPFFFBDR=I3Q3Q3Q3Q3Q3Q3Q3Q3Q3QFPgBNk3P4ODNgAMq3PEQnJSa5M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3PBF[CCGA333CEQ:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6NCEPDDDBDR=I3Q3Q3Q3Q3Q3Q3Q3P4L:M4N@P?O3Q4PBMn>P3PEPoJSa4M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>ICFMn999 DER5N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6NBDPKKKCEPs?Hy3Q3Q3Q3Q3Q3Q3Q4NFPgMVb5KR\iz?P3Q3PAMt`ht6M3PEPnJSa4M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6PDERۀBBEF?Hs3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:MCER@@@BFV3P3Q3Q3Q3Q3Q3Q5NIR`DM_?Pt{>O3Q3PCOpEPe3Q3PDOnKUc5M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q3Q3Q3QO3Q3QCNjx4L3Q3PCOnLUc5L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q3Q3Q3QAGbCCCBFR9M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q7NCEUBEU6O3Q3Q3Q3Q3Q3QCRKTb4M3Q3Q4OGPcy@N3Q3OFP`?P3Q3Q4PDOoLUc5L3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q3Q3Q3QBEUDDFf:J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QCEQCER4Q3Q3Q3Q3Q3Q3QFP]H~4Q3Q3Q3Q3Q3Q4MKSaKT`7M3Q3Q3Q9Npxbjv>P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q3Q:LCDP@@@ CFFECFV5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3PAHoBDR|DFT?H}4Q3Q3Q3Q3Q3Q6MNWcckxBQ4M8MNVdYap4N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q3Q:KCFQFFF FFFCEPBGb5O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3PAGmBDP|CER?H{3Q3Q3Q3Q3Q3Q7NNVdyfm|4N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q3Q:LDEPFFF DDI8DFOBDUDFPCCCgBFUBETBG]:M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P?GlCERzCFU?I{3Q3Q3Q3Q3Q3Q4NISbEPk3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q3Q:LBDRMMM CCH9CFV6O7N8L:L8M6P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P@HmACTyCFT>H3Q3Q3Q3Q3Q3Q4ODOiEO_4O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q3Q:LCFQ;;; BBG2CFU5N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?GqCERAEQ>H}4Q3Q3Q3Q3Q3Q3Q=OJScEPl4O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q3Q:MCDO;;; AAF3CFU6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>GpDFSAES?I~3Q3Q3Q3Q3Q3Q3Q4P:OGSHSpGRw7L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv3Q:LCDO;;; AAF3ADW6P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q@GqBDPCET>H}3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.?Hv:LCDO@@@ EEJ4AEW5O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q@GqBDS{CEW?Hu3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9KEEEhCCC.DENCFR@@@DDH@BEX4O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4P@FhAFSqBDQ{?Gr4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QI~4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4PAF[DDJOBEM]AFb5Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=JBESUUUDDKKBEQCERBFXADSCFWCER>Hz6N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4OAFZFFIMBGR]AGb5Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=JBEUUUUDDGKAF_4P4Q5P7O4O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5PAE[BBLMAFPfAFc4P3Q3Q3Q3Q3Q3Q3Q3Q3QHDGWEEKUBF`5Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5OBEZDDKDCCMPCEPCFNXAFa5Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5OBEWCCGABBLMAG_4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4OBF[BEEFEENNAG_4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4OCFYCFFEDDMOAG_4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5PBFXCFFEDDMVAE^4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5PBFXDGGD@@@DEI5O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6PCEUBBB:EEKUBF`5Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5OBFWBBFBFFLTAF\5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5OBEWBBFBDDJSAF\5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5OBEUCCGADDJSAF\5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5OBEUDDD@FFIPAF\5P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6PBFWCCC9DGGOBFZ4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6OCEUDDD8EHHNBFZ4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6OCETDDD8BFFMBEZ4O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5OBETFFF7BEEFCFX4O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q5OBEUFFF7DDDHz@MYCCQ>H~5Q3Q3Q4Q=JDIc1@@P?I|4P3Q3Q3Q3Q4Q=JCI[*@@P?I}4P3Q3Q3Q3Q3Q3Q4Q=JAG_+<H3P3Q3Q3Q3Q3Q3Q3Q3Q3Q=J@F],<H3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=JAG\/<I3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QH4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=KDIc1FFQ>I4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QI3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;IFF]7BBZ=I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4P;K>J=HFaBBBZ>J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q6O?GoFFF BIhe9K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:JAHcC@HX >J4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?IzBGih5N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;K?FdEFM]!EbFDKZ">J4Q3Q3QBYE[3Q3Q3Q3Q;K߀=I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:JAHeG@G\$D])MMM >Hx4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:KBIcM@F`(GuoFFF ?J4P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:KBFcMFM]!>J4Q3Q3Q3Q@XFYan\j@Wmz3Q3Q3Q=I@@@8L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;KAHaGDKZ"Gw?Iv=I8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;L@FdTAG\/;J3Q3Q3Q3QJ\>SfqFYEZ3O3Q3Q3Q3Q3Q3Q=I@@@8L3Q3Q3Q3Q3Q6NAGh}@G`H:K3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:LBHfUFFXI;I3Q3Q3Q}4P3Q`n=Sxv3Q?VJ^3Q3Q3Q3Q=I@@@8L3Q3Q3Q3Q;K=I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QJ3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;J?Hy3Q3Q3QTdht3P3Q3QTceq3P3Q3Q3Q9SK]3Q3Q3Q3Q3Q=I@@@8L3Q3Q3Q3Q;JEES%CI[*9M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q?I|BBUI3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=J@JUDKZ"Fcb@F`P?HoGoZ8L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QD])BIf#;I4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q=I@@@AGjBFc>@Gid7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>JEnk7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IDDUBBZ=I4Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q8M@Ekk@Iql8N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q>IFFXDD^=J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P?Gp?Hrn8M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P>III[FFX=I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9M@GN$=J3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P=I;ENII[=I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;K>I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P>I;ENII[>I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9NBBI#=I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>G=GRBBU>I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3QFm@Fjx?Hy:L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?I~FFQEEb>I3P3Q3Q3Q3QJ3Q3Q3Q;JAEa?@Gol9M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P?IBLUDD^>J3Q;JAEa?@Iql8L3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?IBLUCNY@HlDIc1>Fp{7M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3P>I|GGG?Hlq7M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?JFFQ?Hlq7N3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>I==I333?H{3P3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q>Hz@@@;EN>I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q?HCCC;EN>I3P3Q3Q3Q3Q3Q3Q3Q3Q4Q?HCCC==I>I4Q3Q3Q3Q3Q3Q3Q3P>I|CCC==I>H4Q3Q3Q3Q3Q4Q>IzGGG@@@>Gz5P3Q3Q5P?Hw;;; @@@AGlv?J>H@GloUUU????~?π?>|?(0` $333@@@;;N =H8N8N;K>Fa999 J4Q3Q3Q3Q3Q3Q;JGG\MMM =J3P3Q3Q3Q3Q3Q3Q3Q;JGG\MMM =J3P3Q3Q3Q3Q3Q3Q3Q3Q3QDj)CQ^:J3Q3QKa=W3Q3Q7M@@@;M3Q3Q3Q3Q3Q3Q3Q3Q3Q:L>Dj)@MY;K3Q3Q3QapAY3Q5PAHjR=IU9M3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;M=Im*@MY;K3Q3QAYQf{AY3Q9LFMf(FFF =I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q9MCIs*FF];K3Q3Q3PUhbn3Q3Q:KUUUHyg5P3Q3Q3Q3Q3Q3Q3Q:MGGf?J3P3QK`QcRfguwMbQc3Q3Q3Q7MIII;J3Q3Q3Q8N=IU:L3Q3Q3Q3Q3Q3Q3Q3Q=KIt6O3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q;K7I[@MYJ999 =Gv5O3Q3Q3Q3Q3Q3Q3Q3Q3Q4QFd!8N3Q3Q3Q3Q3Q3Q3Q4Q;JFF] DDUHz:K:K8M3Q3Q3Q3Q3Q3Q3Q3QG|w6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;L77I@P`;K7O=G{O>F}x6O3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q:K77IFFF BFj:>I|5O3Q3Q3Q3Q3Q3Q3Q3Q3Q3QH}x5N3Q3Q3Q3Q3Q3Q3Q3Q3Q4Q;J@@@ @@@=I3Q3Q3Q3Q3Q3Q3Q3Q3Q3Q;I@@@DDUIUUU????<?x?( @ Dj)99U 8N3Q3Q3Q3Q3Q3Q7MCQy@@`8L3QShdu7S9MBJ{;J3Q3Q3Q3Q3Q3Q3Q3Q7LCQyIIm:L3Q4O]ojyOcSh3Q;Jh@@@ 6N3Q3Q3Q3Q3Q3Q3Q3Q3Q9MIIm3Mf 9M3QYlq^pz3Q3Q;Jh@@@ 6N3Q3Q4Q9N8N4Q3Q3Q3Q3Q7L=Iy333:L3QF^uo~_r3Q3Q3Q;Jh@@@ 6N3Q4Q;JY/Mu(G2P3Q3U:U-I:X.Eʀ4LW0Q3Q3Q3U;W3OYn@[/K֣7Nu3Q8P̊7Nu4Q3V>XGTGf{Sj2P֡7Nx5P5O3Q3YCT6S寓(G(I-M6Pک7NƆ6N\8NR6Oؼ3Q3Q6U7W.Q/Q3Q3Q8Lq8Mg3Q3Q3V=V?[3W3Q4P4P3Q3XAZ@Z8X6MU8NK5P3Q3XBZFU8Xl@Wh?a?git-cola-3.6/share/git-cola/icons/git-cola.svg000066400000000000000000000146231356743264500212420ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/git-commit.svg000066400000000000000000000005461356743264500216130ustar00rootroot00000000000000git-cola-3.6/share/git-cola/icons/git-compare.svg000066400000000000000000000027571356743264500217570ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/git-merge.svg000066400000000000000000000027011356743264500214150ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/last-first-order.svg000066400000000000000000000112501356743264500227350ustar00rootroot00000000000000 image/svg+xml git-cola-3.6/share/git-cola/icons/link-external.svg000066400000000000000000000006201356743264500223100ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/modified.svg000066400000000000000000000034441356743264500213220ustar00rootroot00000000000000 image/svg+xml git-cola-3.6/share/git-cola/icons/partial.svg000066400000000000000000000002341356743264500211700ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/pencil.svg000066400000000000000000000006771356743264500210210ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/plus.svg000066400000000000000000000003001356743264500205110ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/primitive-dot.svg000066400000000000000000000003761356743264500223370ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/question-plain.svg000066400000000000000000000007261356743264500225120ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/question.svg000066400000000000000000000015641356743264500214120ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/repo-pull.svg000066400000000000000000000011431356743264500214530ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/repo-push.svg000066400000000000000000000010741356743264500214610ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/repo.svg000066400000000000000000000011031356743264500204750ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/screen-full.svg000066400000000000000000000011331356743264500217520ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/search.svg000066400000000000000000000012771356743264500210110ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/staged.svg000066400000000000000000000002321356743264500210010ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/star.svg000066400000000000000000000004101356743264500205010ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/sync.svg000066400000000000000000000013601356743264500205110ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/tag.svg000066400000000000000000000012301356743264500203040ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/telescope.svg000066400000000000000000000015041356743264500215200ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/trashcan.svg000066400000000000000000000014471356743264500213460ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/unfold.svg000066400000000000000000000012261356743264500210250ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/upstream.svg000066400000000000000000000005541356743264500214010ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/x.svg000066400000000000000000000030661356743264500200110ustar00rootroot00000000000000 image/svg+xml git-cola-3.6/share/git-cola/icons/zoom-fit-best.svg000066400000000000000000000015511356743264500222360ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/zoom-in.svg000066400000000000000000000022441356743264500211270ustar00rootroot00000000000000 git-cola-3.6/share/git-cola/icons/zoom-out.svg000066400000000000000000000023121356743264500213240ustar00rootroot00000000000000 git-cola-3.6/test/000077500000000000000000000000001356743264500140575ustar00rootroot00000000000000git-cola-3.6/test/__init__.py000066400000000000000000000000001356743264500161560ustar00rootroot00000000000000git-cola-3.6/test/app_test.py000066400000000000000000000014301356743264500162460ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import absolute_import, division, unicode_literals import argparse import unittest from cola import app from .helper import run_unittest class AppTestCase(unittest.TestCase): def test_setup_environment(self): # If the function doesn't throw an exception we are happy. self.assertTrue(hasattr(app, 'setup_environment')) app.setup_environment() def test_add_common_arguments(self): # If the function doesn't throw an exception we are happy. parser = argparse.ArgumentParser() self.assertTrue(hasattr(app, 'add_common_arguments')) app.add_common_arguments(parser) def test_suite(): return unittest.makeSuite(AppTestCase) if __name__ == "__main__": run_unittest(test_suite()) git-cola-3.6/test/branch_test.py000066400000000000000000000131631356743264500167310ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import absolute_import, division, unicode_literals import unittest try: from unittest.mock import MagicMock except ImportError: from mock import MagicMock from cola.widgets import branch class BranchesTestCase(unittest.TestCase): """Tests related to the branches widget""" def test_create_tree_entries(self): names = [ 'abc', 'cat/abc', 'cat/def', 'xyz/xyz', ] root = branch.create_tree_entries(names) self.assertEqual(3, len(root.children)) # 'abc' abc = root.children[0] self.assertEqual('abc', abc.basename) self.assertEqual('abc', abc.refname) self.assertEqual([], abc.children) # 'cat' cat = root.children[1] self.assertEqual('cat', cat.basename) self.assertEqual(None, cat.refname) self.assertEqual(2, len(cat.children)) # 'cat/abc' cat_abc = cat.children[0] self.assertEqual('abc', cat_abc.basename) self.assertEqual('cat/abc', cat_abc.refname) self.assertEqual([], cat_abc.children) # 'cat/def' cat_def = cat.children[1] self.assertEqual('def', cat_def.basename) self.assertEqual('cat/def', cat_def.refname) self.assertEqual([], cat_def.children) # 'xyz' xyz = root.children[2] self.assertEqual('xyz', xyz.basename) self.assertEqual(None, xyz.refname) self.assertEqual(1, len(xyz.children)) # 'xyz/xyz' xyz_xyz = xyz.children[0] self.assertEqual('xyz', xyz_xyz.basename) self.assertEqual('xyz/xyz', xyz_xyz.refname) self.assertEqual([], xyz_xyz.children) def test_create_name_dict(self): """Test transforming unix path-like names into a nested dict""" branches = ['top_1/child_1/child_1_1', 'top_1/child_1/child_1_2', 'top_1/child_2/child_2_1/child_2_1_1', 'top_1/child_2/child_2_1/child_2_1_2'] result = branch.create_name_dict(branches) inner_child = {'child_2_1_2': {}, 'child_2_1_1': {}} self.assertEqual( {'top_1': { 'child_1': {'child_1_2': {}, 'child_1_1': {}}, 'child_2': {'child_2_1': inner_child}}}, result) def test_create_toplevel_item(self): names = [ 'child_1', 'child_2/child_2_1', 'child_2/child_2_2', ] tree = branch.create_tree_entries(names) tree.basename = 'top' result = branch.create_toplevel_item(tree) self.assertEqual('top', result.name) self.assertEqual(2, result.childCount()) self.assertEqual('child_1', result.child(0).name) self.assertEqual('child_1', result.child(0).refname) self.assertEqual('child_2', result.child(1).name) self.assertEqual(None, result.child(1).refname) self.assertEqual(2, result.child(1).childCount()) self.assertEqual('child_2_1', result.child(1).child(0).name) self.assertEqual('child_2_2', result.child(1).child(1).name) self.assertEqual('child_2/child_2_1', result.child(1).child(0).refname) self.assertEqual('child_2/child_2_2', result.child(1).child(1).refname) def test_get_toplevel_item(self): items = _create_top_item() result = branch.get_toplevel_item(items['child_1']) self.assertTrue(items['top'] is result) result = branch.get_toplevel_item(items['sub_child_2_1']) self.assertTrue(items['top'] is result) def test_refname_attribute(self): items = _create_top_item() result = items['child_1'].refname self.assertEqual('child_1', result) result = items['sub_child_2_2'].refname self.assertEqual('child_2/sub_child_2_2', result) def test_should_return_a_valid_child_on_find_child(self): """Test the find_child function.""" items = _create_top_item() child = branch.find_by_refname(items['top'], 'child_1') self.assertEqual('child_1', child.refname) child = branch.find_by_refname(items['top'], 'child_2/sub_child_2_2') self.assertEqual('sub_child_2_2', child.name) def test_should_return_empty_state_on_save_state(self): """Test the save_state function.""" top = _create_item('top', None, False) tree_helper = branch.BranchesTreeHelper() result = tree_helper.save_state(top) self.assertEqual({'top': {}}, result) def test_should_return_a_valid_state_on_save_state(self): """Test the save_state function.""" items = _create_top_item() tree_helper = branch.BranchesTreeHelper() result = tree_helper.save_state(items['top']) self.assertEqual({'top': {'child_1': {}, 'child_2': { 'sub_child_2_1': {}, 'sub_child_2_2': {}}}}, result) def _create_top_item(): top = _create_item('top', None, True) child_1 = _create_item('child_1', 'child_1', False) child_2 = _create_item('child_2', None, True) sub_child_2_1 = _create_item( 'sub_child_2_1', 'child_2/sub_child_2_1', False) sub_child_2_2 = _create_item( 'sub_child_2_2', 'child_2/sub_child_2_2', False) child_2.addChildren([sub_child_2_1, sub_child_2_2]) top.addChildren([child_1, child_2]) return {'top': top, 'child_1': child_1, 'sub_child_2_1': sub_child_2_1, 'sub_child_2_2': sub_child_2_2} def _create_item(name, refname, expanded): item = branch.BranchTreeWidgetItem(name, refname=refname) item.isExpanded = MagicMock(return_value=expanded) return item if __name__ == '__main__': unittest.main() git-cola-3.6/test/browse_model_test.py000066400000000000000000000035741356743264500201620ustar00rootroot00000000000000"""Covers interfaces used by the browser (git cola browse)""" from __future__ import absolute_import, division, unicode_literals from cola import core from cola import gitcmds from . import helper class ClassicModelTestCase(helper.GitRepositoryTestCase): """Tests interfaces used by the browser (git cola browse)""" def test_stage_paths_untracked(self): """Test stage_paths() with an untracked file.""" core.makedirs('foo/bar') self.touch('foo/bar/baz') gitcmds.add(self.context, ['foo']) self.model.update_file_status() self.assertTrue('foo/bar/baz' in self.model.staged) self.assertTrue('foo/bar/baz' not in self.model.modified) self.assertTrue('foo/bar/baz' not in self.model.untracked) def test_unstage_paths(self): """Test a simple usage of unstage_paths().""" self.commit_files() self.write_file('A', 'change') self.run_git('add', 'A') gitcmds.unstage_paths(self.context, ['A']) self.model.update_status() self.assertTrue('A' not in self.model.staged) self.assertTrue('A' in self.model.modified) def test_unstage_paths_init(self): """Test unstage_paths() on the root commit.""" gitcmds.unstage_paths(self.context, ['A']) self.model.update_status() self.assertTrue('A' not in self.model.staged) self.assertTrue('A' in self.model.untracked) def test_unstage_paths_subdir(self): """Test unstage_paths() in a subdirectory.""" self.run_git('commit', '-m', 'initial commit') core.makedirs('foo/bar') self.touch('foo/bar/baz') self.run_git('add', 'foo/bar/baz') gitcmds.unstage_paths(self.context, ['foo']) self.model.update_status() self.assertTrue('foo/bar/baz' in self.model.untracked) self.assertTrue('foo/bar/baz' not in self.model.staged) git-cola-3.6/test/cmds_test.py000066400000000000000000000045121356743264500164200ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import absolute_import, division, unicode_literals import unittest try: from unittest import mock except ImportError: import mock from cola import cmds from cola.compat import uchr class CmdsTestCase(unittest.TestCase): """Tests the cola.core module's unicode handling """ def test_Commit_strip_comments(self): """Ensure that commit messages are stripped of comments""" msg = 'subject\n\n#comment\nbody' expect = 'subject\n\nbody\n' actual = cmds.Commit.strip_comments(msg) self.assertEqual(expect, actual) def test_Commit_strip_comments_unicode(self): """Ensure that unicode is preserved in stripped commit messages""" msg = uchr(0x1234) + '\n\n#comment\nbody' expect = uchr(0x1234) + '\n\nbody\n' actual = cmds.Commit.strip_comments(msg) self.assertEqual(expect, actual) def test_unix_path_win32(self): path = r'Z:\Program Files\git-cola\bin\git-dag' expect = '/Z/Program Files/git-cola/bin/git-dag' actual = cmds.unix_path(path, is_win32=lambda: True) self.assertEqual(expect, actual) def test_unix_path_network_win32(self): path = r'\\Z\Program Files\git-cola\bin\git-dag' expect = '//Z/Program Files/git-cola/bin/git-dag' actual = cmds.unix_path(path, is_win32=lambda: True) self.assertEqual(expect, actual) def test_unix_path_is_a_noop_on_sane_platforms(self): path = r'/:we/don\t/need/no/stinking/badgers!' expect = path actual = cmds.unix_path(path, is_win32=lambda: False) self.assertEqual(expect, actual) def test_context_edit_command(self): context = mock.Mock() model = context.model cmd = cmds.EditModel(context) cmd.new_diff_text = 'test_diff_text' cmd.new_diff_type = 'test_diff_type' cmd.new_mode = 'test_mode' cmd.new_filename = 'test_filename' cmd.do() model.set_diff_text.assert_called_once_with('test_diff_text') model.set_diff_type.assert_called_once_with('test_diff_type') model.set_mode.assert_called_once_with('test_mode') model.set_filename.assert_called_once_with('test_filename') self.assertEqual(model.set_filename.call_count, 1) if __name__ == '__main__': unittest.main() git-cola-3.6/test/compat_test.py000066400000000000000000000012201356743264500167460ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 from __future__ import absolute_import, division, unicode_literals import os import unittest from cola import compat class CompatTestCase(unittest.TestCase): """Tests the compat module""" def test_setenv(self): """Test the core.decode function """ key = 'COLA_UNICODE_TEST' value = '字龍' compat.setenv(key, value) self.assertTrue(key in os.environ) self.assertTrue(os.getenv(key)) compat.unsetenv(key) self.assertFalse(key in os.environ) self.assertFalse(os.getenv(key)) if __name__ == '__main__': unittest.main() git-cola-3.6/test/core_test.py000066400000000000000000000037541356743264500164310ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 from __future__ import absolute_import, division, unicode_literals import unittest from cola import core from . import helper class CoreColaUnicodeTestCase(unittest.TestCase): """Tests the cola.core module's unicode handling """ def test_core_decode(self): """Test the core.decode function """ filename = helper.fixture('unicode.txt') expect = core.decode(core.encode('unicøde')) actual = core.read(filename).strip() self.assertEqual(expect, actual) def test_core_encode(self): """Test the core.encode function """ filename = helper.fixture('unicode.txt') expect = core.encode('unicøde') actual = core.encode(core.read(filename).strip()) self.assertEqual(expect, actual) def test_decode_None(self): """Ensure that decode(None) returns None""" expect = None actual = core.decode(None) self.assertEqual(expect, actual) def test_decode_utf8(self): filename = helper.fixture('cyrillic-utf-8.txt') actual = core.read(filename) self.assertEqual(actual.encoding, 'utf-8') def test_decode_non_utf8(self): filename = helper.fixture('cyrillic-cp1251.txt') actual = core.read(filename) self.assertEqual(actual.encoding, 'iso-8859-15') def test_decode_non_utf8_string(self): filename = helper.fixture('cyrillic-cp1251.txt') with open(filename, 'rb') as f: content = f.read() actual = core.decode(content) self.assertEqual(actual.encoding, 'iso-8859-15') def test_guess_mimetype(self): value = '字龍.txt' expect = 'text/plain' actual = core.guess_mimetype(value) self.assertEqual(expect, actual) # This function is robust to bytes vs. unicode actual = core.guess_mimetype(core.encode(value)) self.assertEqual(expect, actual) if __name__ == '__main__': unittest.main() git-cola-3.6/test/dag_test.py000066400000000000000000000077201356743264500162310ustar00rootroot00000000000000#!/usr/bin/env python """Tests DAG functionality""" from __future__ import absolute_import, division, unicode_literals import mock from cola.models import dag from . import helper LOG_LINES = """ ad454b189fe5785af397fd6067cf103268b6626e^A^A (tag: refs/tags/v0.0)^ADavid Aguilar^AFri Nov 30 00:03:28 2007 -0800^Adavvid@gmail.com^Afirst cut of ugit 1ba04ad185cf9f04c56c8482e9a73ef1bd35c695^Aad454b189fe5785af397fd6067cf103268b6626e^A^ADavid Aguilar^AFri Nov 30 05:07:47 2007 -0800^Adavvid@gmail.com^Aupdated model/view/controller api fa5ad6c38be603e2ffd1f9b722a3a5c675f63de2^A1ba04ad185cf9f04c56c8482e9a73ef1bd35c695^A^ADavid Aguilar^AFri Nov 30 05:19:05 2007 -0800^Adavvid@gmail.com^AAvoid multiple signoffs 103766573cd4e6799d3ee792bcd632b92cf7c6c0^Afa5ad6c38be603e2ffd1f9b722a3a5c675f63de2^A^ADavid Aguilar^ATue Dec 11 05:13:21 2007 -0800^Adavvid@gmail.com^AAdded TODO e3f5a2d0248de6197d6e0e63c901810b8a9af2f8^Afa5ad6c38be603e2ffd1f9b722a3a5c675f63de2^A^ADavid Aguilar^AMon Dec 3 02:36:06 2007 -0800^Adavvid@gmail.com^AMerged qlistwidgets into master. f4fb8fd5baaa55d9b41faca79be289bb4407281e^Ae3f5a2d0248de6197d6e0e63c901810b8a9af2f8^A^ADavid Aguilar^ATue Dec 4 03:14:56 2007 -0800^Adavvid@gmail.com^ASquashed commit of the following: 23e7eab4ba2c94e3155f5d261c693ccac1342eb9^Af4fb8fd5baaa55d9b41faca79be289bb4407281e^A^ADavid Aguilar^AThu Dec 6 18:59:20 2007 -0800^Adavvid@gmail.com^AMerged diffdisplay into master """.strip().replace('^A', chr(0x01)).split('\n') + [''] # noqa class DAGTestCase(helper.GitRepositoryTestCase): def setUp(self): helper.GitRepositoryTestCase.setUp(self) self.params = dag.DAG('HEAD', 1000) self.reader = dag.RepoReader(self.context, self.params) @mock.patch('cola.models.dag.core') def test_repo_reader(self, core): expect = len(LOG_LINES) - 1 actual = 0 core.readline.return_value = LOG_LINES[0] for idx, _ in enumerate(self.reader.get()): core.readline.return_value = LOG_LINES[idx+1] actual += 1 self.assertEqual(expect, actual) @mock.patch('cola.models.dag.core') def test_repo_reader_order(self, core): commits = [ 'ad454b189fe5785af397fd6067cf103268b6626e', '1ba04ad185cf9f04c56c8482e9a73ef1bd35c695', 'fa5ad6c38be603e2ffd1f9b722a3a5c675f63de2', '103766573cd4e6799d3ee792bcd632b92cf7c6c0', 'e3f5a2d0248de6197d6e0e63c901810b8a9af2f8', 'f4fb8fd5baaa55d9b41faca79be289bb4407281e', '23e7eab4ba2c94e3155f5d261c693ccac1342eb9', ] core.readline.return_value = LOG_LINES[0] for idx, commit in enumerate(self.reader.get()): core.readline.return_value = LOG_LINES[idx+1] self.assertEqual(commits[idx], commit.oid) @mock.patch('cola.models.dag.core') def test_repo_reader_parents(self, core): parents = [ [], ['ad454b189fe5785af397fd6067cf103268b6626e'], ['1ba04ad185cf9f04c56c8482e9a73ef1bd35c695'], ['fa5ad6c38be603e2ffd1f9b722a3a5c675f63de2'], ['fa5ad6c38be603e2ffd1f9b722a3a5c675f63de2'], ['e3f5a2d0248de6197d6e0e63c901810b8a9af2f8'], ['f4fb8fd5baaa55d9b41faca79be289bb4407281e'], ] core.readline.return_value = LOG_LINES[0] for idx, commit in enumerate(self.reader.get()): core.readline.return_value = LOG_LINES[idx+1] self.assertEqual(parents[idx], [p.oid for p in commit.parents]) @mock.patch('cola.models.dag.core') def test_repo_reader_contract(self, core): core.exists.return_value = True core.readline.return_value = LOG_LINES[0] for idx, _ in enumerate(self.reader.get()): core.readline.return_value = LOG_LINES[idx+1] core.start_command.assert_called() call_args = core.start_command.call_args self.assertTrue('log.abbrevCommit=false' in call_args[0][0]) self.assertTrue('log.showSignature=false' in call_args[0][0]) git-cola-3.6/test/diffparse_test.py000066400000000000000000000301701356743264500174340ustar00rootroot00000000000000from __future__ import absolute_import, division, unicode_literals import unittest from cola import core from cola import diffparse from . import helper class ParseDiffTestCase(unittest.TestCase): def test_diff(self): fixture_path = helper.fixture('diff.txt') parser = diffparse.DiffParser( 'cola/diffparse.py', core.read(fixture_path)) hunks = parser.hunks self.assertEqual(len(hunks), 3) self.assertEqual(hunks[0].first_line_idx, 0) self.assertEqual(len(hunks[0].lines), 23) self.assertEqual( hunks[0].lines[0], '@@ -6,10 +6,21 @@ from cola import gitcmds\n') self.assertEqual( hunks[0].lines[1], ' from cola import gitcfg\n') self.assertEqual(hunks[0].lines[2], ' \n') self.assertEqual(hunks[0].lines[3], ' \n') self.assertEqual(hunks[0].lines[4], '+class DiffSource(object):\n') self.assertEqual( hunks[0].lines[-1], r" self._header_start_re = re.compile('^@@ -(\d+)" r" \+(\d+),(\d+) @@.*')" '\n') self.assertEqual(hunks[1].first_line_idx, 23) self.assertEqual(len(hunks[1].lines), 18) self.assertEqual( hunks[1].lines[0], '@@ -29,13 +40,11 @@ class DiffParser(object):\n') self.assertEqual( hunks[1].lines[1], ' self.diff_sel = []\n') self.assertEqual( hunks[1].lines[2], ' self.selected = []\n') self.assertEqual( hunks[1].lines[3], ' self.filename = filename\n') self.assertEqual( hunks[1].lines[4], '+ self.diff_source = diff_source or DiffSource()\n') self.assertEqual( hunks[1].lines[-1], ' self.header = header\n') self.assertEqual(hunks[2].first_line_idx, 41) self.assertEqual(len(hunks[2].lines), 16) self.assertEqual( hunks[2].lines[0], '@@ -43,11 +52,10 @@ class DiffParser(object):\n') self.assertEqual( hunks[2].lines[-1], ' """Writes a new diff corresponding to the user\'s' ' selection."""\n') def test_diff_at_start(self): fixture_path = helper.fixture('diff-start.txt') parser = diffparse.DiffParser('foo bar/a', core.read(fixture_path)) hunks = parser.hunks self.assertEqual(hunks[0].lines[0], '@@ -1 +1,4 @@\n') self.assertEqual(hunks[-1].lines[-1], '+c\n') self.assertEqual(hunks[0].old_start, 1) self.assertEqual(hunks[0].old_count, 1) self.assertEqual(hunks[0].new_start, 1) self.assertEqual(hunks[0].new_count, 4) self.assertEqual(parser.generate_patch(1, 3), '--- a/foo bar/a\n' '+++ b/foo bar/a\n' '@@ -1 +1,3 @@\n' ' bar\n' '+a\n' '+b\n') self.assertEqual(parser.generate_patch(0, 4), '--- a/foo bar/a\n' '+++ b/foo bar/a\n' '@@ -1 +1,4 @@\n' ' bar\n' '+a\n' '+b\n' '+c\n') def test_diff_at_end(self): fixture_path = helper.fixture('diff-end.txt') parser = diffparse.DiffParser('rijndael.js', core.read(fixture_path)) hunks = parser.hunks self.assertEqual(hunks[0].lines[0], '@@ -1,39 +1 @@\n') self.assertEqual( hunks[-1].lines[-1], "+module.exports = require('./build/Release/rijndael');\n") self.assertEqual(hunks[0].old_start, 1) self.assertEqual(hunks[0].old_count, 39) self.assertEqual(hunks[0].new_start, 1) self.assertEqual(hunks[0].new_count, 1) def test_diff_that_empties_file(self): fixture_path = helper.fixture('diff-empty.txt') parser = diffparse.DiffParser('filename', core.read(fixture_path)) hunks = parser.hunks self.assertEqual(hunks[0].lines[0], '@@ -1,2 +0,0 @@\n') self.assertEqual(hunks[-1].lines[-1], '-second\n') self.assertEqual(hunks[0].old_start, 1) self.assertEqual(hunks[0].old_count, 2) self.assertEqual(hunks[0].new_start, 0) self.assertEqual(hunks[0].new_count, 0) self.assertEqual(parser.generate_patch(1, 1), '--- a/filename\n' '+++ b/filename\n' '@@ -1,2 +1 @@\n' '-first\n' ' second\n') self.assertEqual(parser.generate_patch(0, 2), '--- a/filename\n' '+++ b/filename\n' '@@ -1,2 +0,0 @@\n' '-first\n' '-second\n') def test_diff_file_removal(self): diff_text = """\ deleted file mode 100755 @@ -1,1 +0,0 @@ -#!/bin/sh """ parser = diffparse.DiffParser('deleted.txt', diff_text) self.assertEqual(1, len(parser.hunks)) # Selecting the first two lines generate no diff expect = None actual = parser.generate_patch(0, 1) self.assertEqual(expect, actual) # Selecting the last line should generate a line removal expect = """\ --- a/deleted.txt +++ b/deleted.txt @@ -1 +0,0 @@ -#!/bin/sh """ actual = parser.generate_patch(1, 2) self.assertEqual(expect, actual) # All three lines should map to the same hunk diff actual = parser.generate_hunk_patch(0) self.assertEqual(expect, actual) actual = parser.generate_hunk_patch(1) self.assertEqual(expect, actual) actual = parser.generate_hunk_patch(2) self.assertEqual(expect, actual) class DiffLinesTestCase(unittest.TestCase): def setUp(self): self.parser = diffparse.DiffLines() fixture_path = helper.fixture('diff.txt') self.text = core.read(fixture_path) def test_basic_diff_line_count(self): """Verify the basic line counts""" lines = self.parser.parse(self.text) expect = len(self.text.splitlines()) actual = len(lines) self.assertEqual(expect, actual) def test_diff_line_count_ranges(self): parser = self.parser lines = parser.parse(self.text) # Diff header line = 0 count = 1 self.assertEqual(lines[line][0], parser.DASH) self.assertEqual(lines[line][1], parser.DASH) line += count # 3 lines of context count = 3 current_old = 6 current_new = 6 for i in range(count): self.assertEqual(lines[line+i][0], current_old+i) self.assertEqual(lines[line+i][1], current_new+i) line += count current_old += count current_new += count # 10 lines of new text count = 10 for i in range(count): self.assertEqual(lines[line+i][0], parser.EMPTY) self.assertEqual(lines[line+i][1], current_new+i) line += count current_new += count # 3 more lines of context count = 3 for i in range(count): self.assertEqual(lines[line+i][0], current_old+i) self.assertEqual(lines[line+i][1], current_new+i) line += count current_new += count current_old += count # 1 line of removal count = 1 for i in range(count): self.assertEqual(lines[line+i][0], current_old+i) self.assertEqual(lines[line+i][1], parser.EMPTY) line += count current_old += count # 2 lines of addition count = 2 for i in range(count): self.assertEqual(lines[line+i][0], parser.EMPTY) self.assertEqual(lines[line+i][1], current_new+i) line += count current_new += count # 3 more lines of context count = 3 for i in range(count): self.assertEqual(lines[line+i][0], current_old+i) self.assertEqual(lines[line+i][1], current_new+i) line += count current_new += count current_old += count # 1 line of header count = 1 for i in range(count): self.assertEqual(lines[line+i][0], parser.DASH) self.assertEqual(lines[line+i][1], parser.DASH) line += count # 3 more lines of context current_old = 29 current_new = 40 count = 3 for i in range(count): self.assertEqual(lines[line+i][0], current_old+i) self.assertEqual(lines[line+i][1], current_new+i) line += count current_new += count current_old += count expect_max_old = 54 self.assertEqual(expect_max_old, parser.old.max_value) expect_max_new = 62 self.assertEqual(expect_max_new, parser.new.max_value) self.assertEqual(parser.digits(), 2) def test_diff_line_for_merge(self): """Verify the basic line counts""" text = """@@@ -1,23 -1,33 +1,75 @@@ ++<<<<<<< upstream + +Ok """ parser = self.parser lines = parser.parse(text) self.assertEqual(len(lines), 4) self.assertEqual(len(lines[0]), 3) self.assertEqual(len(lines[1]), 3) self.assertEqual(len(lines[2]), 3) self.assertEqual(len(lines[3]), 3) self.assertEqual(lines[0][0], parser.DASH) self.assertEqual(lines[0][1], parser.DASH) self.assertEqual(lines[0][2], parser.DASH) self.assertEqual(lines[1][0], parser.EMPTY) self.assertEqual(lines[1][1], parser.EMPTY) self.assertEqual(lines[1][2], 1) self.assertEqual(lines[2][0], 1) self.assertEqual(lines[2][1], parser.EMPTY) self.assertEqual(lines[2][2], 2) self.assertEqual(lines[3][0], 2) self.assertEqual(lines[3][1], parser.EMPTY) self.assertEqual(lines[3][2], 3) class FormatDiffLinesTestCase(unittest.TestCase): def test_format_basic(self): fmt = diffparse.FormatDigits() fmt.set_digits(2) expect = '01 99' actual = fmt.value(1, 99) self.assertEqual(expect, actual) def test_format_reuse(self): fmt = diffparse.FormatDigits() fmt.set_digits(3) expect = '001 099' actual = fmt.value(1, 99) self.assertEqual(expect, actual) fmt.set_digits(4) expect = '0001 0099' actual = fmt.value(1, 99) self.assertEqual(expect, actual) def test_format_special_values(self): fmt = diffparse.FormatDigits(dash='-') fmt.set_digits(3) expect = ' 099' actual = fmt.value(fmt.EMPTY, 99) self.assertEqual(expect, actual) expect = '001 ' actual = fmt.value(1, fmt.EMPTY) self.assertEqual(expect, actual) expect = ' ' actual = fmt.value(fmt.EMPTY, fmt.EMPTY) self.assertEqual(expect, actual) expect = '--- 001' actual = fmt.value(fmt.DASH, 1) self.assertEqual(expect, actual) expect = '099 ---' actual = fmt.value(99, fmt.DASH) self.assertEqual(expect, actual) expect = '--- ---' actual = fmt.value(fmt.DASH, fmt.DASH) self.assertEqual(expect, actual) expect = ' ---' actual = fmt.value(fmt.EMPTY, fmt.DASH) self.assertEqual(expect, actual) expect = '--- ' actual = fmt.value(fmt.DASH, fmt.EMPTY) self.assertEqual(expect, actual) class ParseRangeStrTestCase(unittest.TestCase): def test_parse_range_str(self): start, count = diffparse.parse_range_str('1,2') self.assertEqual(start, 1) self.assertEqual(count, 2) def test_parse_range_str_single_line(self): start, count = diffparse.parse_range_str('2') self.assertEqual(start, 2) self.assertEqual(count, 1) def test_parse_range_str_empty(self): start, count = diffparse.parse_range_str('0,0') self.assertEqual(start, 0) self.assertEqual(count, 0) if __name__ == '__main__': unittest.main() git-cola-3.6/test/fixtures/000077500000000000000000000000001356743264500157305ustar00rootroot00000000000000git-cola-3.6/test/fixtures/.gitattributes000066400000000000000000000002401356743264500206170ustar00rootroot00000000000000# The fixtures must be treated as binary to make sure we don't ever mess with # their line endings during checkout. Otherwise the tests may break. *.txt -text git-cola-3.6/test/fixtures/cyrillic-cp1251.txt000066400000000000000000000010051356743264500212100ustar00rootroot00000000000000 Git Git ? , , Git, , . Git, , , Subversion Perforce. Git' , . Git'. git-cola-3.6/test/fixtures/cyrillic-utf-8.txt000066400000000000000000000015751356743264500212540ustar00rootroot00000000000000Основы Git Так что же такое Git в двух словах? Эту часть важно усвоить, поскольку если вы поймёте, что такое Git, и каковы принципы его работы, вам будет гораздо проще пользоваться им эффективно. Изучая Git, постарайтесь освободиться от всего, что вы знали о других СКВ, таких как Subversion или Perforce. В Git'е совсем не такие понятия об информации и работе с ней как в других системах, хотя пользовательский интерфейс очень похож. Знание этих различий защитит вас от путаницы при использовании Git'а. git-cola-3.6/test/fixtures/diff-empty.txt000066400000000000000000000000371356743264500205350ustar00rootroot00000000000000@@ -1,2 +0,0 @@ -first -second git-cola-3.6/test/fixtures/diff-end.txt000066400000000000000000000021301356743264500201410ustar00rootroot00000000000000@@ -1,39 +1 @@ -var lib = require('./build/Release/rijndael'); - -var Rijndael = function(key, encoding) { - if (!(this instanceof Rijndael)) - return new Rijndael(key); - - if (!Buffer.isBuffer(key)) - key = new Buffer(key, encoding); - - this._key = key; -}; - -Rijndael.prototype.encrypt = function(plaintext) { - if (!Buffer.isBuffer(plaintext)) - throw new TypeError('plaintext must be a buffer'); - return lib.rijndael(plaintext, this._key, true); -}; - -Rijndael.prototype.decrypt = function(ciphertext) { - if (!Buffer.isBuffer(ciphertext)) - throw new TypeError('ciphertext must be a buffer'); - return lib.rijndael(ciphertext, this._key, false); -}; - -var createRijndael = function(key, encoding) { - return new Rijndael(key, encoding); -}; - -createRijndael.encrypt = function(plaintext, key) { - return lib.rijndael(plaintext, key, true); -}; - -createRijndael.decrypt = function(ciphertext, key) { - return lib.rijndael(ciphertext, key, false); -}; - -createRijndael.version = "0.0.2"; - -module.exports = createRijndael; +module.exports = require('./build/Release/rijndael'); git-cola-3.6/test/fixtures/diff-start.txt000066400000000000000000000000341356743264500205310ustar00rootroot00000000000000@@ -1 +1,4 @@ bar +a +b +c git-cola-3.6/test/fixtures/diff.txt000066400000000000000000000047641356743264500174140ustar00rootroot00000000000000@@ -6,10 +6,21 @@ from cola import gitcmds from cola import gitcfg +class DiffSource(object): + def get(self, head, amending, filename, cached, reverse): + return gitcmds.diff_helper(head=head, + amending=amending, + filename=filename, + with_diff_header=True, + cached=cached, + reverse=reverse) + + class DiffParser(object): """Handles parsing diff for use by the interactive index editor.""" def __init__(self, model, filename='', - cached=True, reverse=False): + cached=True, reverse=False, + diff_source=None): self._header_re = re.compile('^@@ -(\d+),(\d+) \+(\d+),(\d+) @@.*') self._header_start_re = re.compile('^@@ -(\d+) \+(\d+),(\d+) @@.*') @@ -29,13 +40,11 @@ class DiffParser(object): self.diff_sel = [] self.selected = [] self.filename = filename + self.diff_source = diff_source or DiffSource() - (header, diff) = gitcmds.diff_helper(head=self.head, - amending=self.amending, - filename=filename, - with_diff_header=True, - cached=cached, - reverse=cached or reverse) + (header, diff) = self.diff_source.get(self.head, self.amending, + filename, cached, + cached or reverse) self.model = model self.diff = diff self.header = header @@ -43,11 +52,10 @@ class DiffParser(object): # Always index into the non-reversed diff self.fwd_header, self.fwd_diff = \ - gitcmds.diff_helper(head=self.head, - amending=self.amending, - filename=filename, - with_diff_header=True, - cached=cached) + self.diff_source.get(self.head, + self.amending, + filename, + cached, False) def write_diff(self,filename,which,selected=False,noop=False): """Writes a new diff corresponding to the user's selection.""" git-cola-3.6/test/fixtures/unicode.txt000066400000000000000000000000111356743264500201070ustar00rootroot00000000000000unicøde git-cola-3.6/test/git_test.py000066400000000000000000000305741356743264500162640ustar00rootroot00000000000000#!/usr/bin/env python """Tests various operations using the cola.git module """ from __future__ import absolute_import, division, unicode_literals import unittest try: from unittest.mock import patch except ImportError: from mock import patch from cola import git from cola.git import STDOUT class GitModuleTestCase(unittest.TestCase): @patch('cola.git.is_git_dir') def test_find_git_dir_None(self, is_git_dir): paths = git.find_git_directory(None) self.assertFalse(is_git_dir.called) self.assertEqual(None, paths.git_dir) self.assertEqual(None, paths.git_file) self.assertEqual(None, paths.worktree) @patch('cola.git.is_git_dir') def test_find_git_dir_empty_string(self, is_git_dir): paths = git.find_git_directory('') self.assertFalse(is_git_dir.called) self.assertEqual(None, paths.git_dir) self.assertEqual(None, paths.git_file) self.assertEqual(None, paths.worktree) @patch('cola.git.is_git_dir') def test_find_git_dir_never_found(self, is_git_dir): is_git_dir.return_value = False paths = git.find_git_directory('/does/not/exist') self.assertTrue(is_git_dir.called) self.assertEqual(None, paths.git_dir) self.assertEqual(None, paths.git_file) self.assertEqual(None, paths.worktree) self.assertEqual(8, is_git_dir.call_count) kwargs = {} is_git_dir.assert_has_calls([ (('/does/not/exist',), kwargs), (('/does/not/exist/.git',), kwargs), (('/does/not',), kwargs), (('/does/not/.git',), kwargs), (('/does',), kwargs), (('/does/.git',), kwargs), (('/',), kwargs), (('/.git',), kwargs), ]) @patch('cola.git.is_git_dir') def test_find_git_dir_found_right_away(self, is_git_dir): git_dir = '/seems/to/exist/.git' worktree = '/seems/to/exist' is_git_dir.return_value = True paths = git.find_git_directory(git_dir) self.assertTrue(is_git_dir.called) self.assertEqual(git_dir, paths.git_dir) self.assertEqual(None, paths.git_file) self.assertEqual(worktree, paths.worktree) @patch('cola.git.is_git_dir') def test_find_git_does_discovery(self, is_git_dir): git_dir = '/the/root/.git' worktree = '/the/root' is_git_dir.side_effect = lambda x: x == git_dir paths = git.find_git_directory('/the/root/sub/dir') self.assertEqual(git_dir, paths.git_dir) self.assertEqual(None, paths.git_file) self.assertEqual(worktree, paths.worktree) @patch('cola.git.read_git_file') @patch('cola.git.is_git_file') @patch('cola.git.is_git_dir') def test_find_git_honors_git_files(self, is_git_dir, is_git_file, read_git_file): git_file = '/the/root/.git' worktree = '/the/root' git_dir = '/super/module/.git/modules/root' is_git_dir.side_effect = lambda x: x == git_file is_git_file.side_effect = lambda x: x == git_file read_git_file.return_value = git_dir paths = git.find_git_directory('/the/root/sub/dir') self.assertEqual(git_dir, paths.git_dir) self.assertEqual(git_file, paths.git_file) self.assertEqual(worktree, paths.worktree) kwargs = {} self.assertEqual(6, is_git_dir.call_count) is_git_dir.assert_has_calls([ (('/the/root/sub/dir',), kwargs), (('/the/root/sub/dir/.git',), kwargs), (('/the/root/sub',), kwargs), (('/the/root/sub/.git',), kwargs), (('/the/root',), kwargs), (('/the/root/.git',), kwargs), ]) read_git_file.assert_called_once_with('/the/root/.git') @patch('cola.core.getenv') @patch('cola.git.is_git_dir') def test_find_git_honors_ceiling_dirs(self, is_git_dir, getenv): git_dir = '/ceiling/.git' ceiling = '/tmp:/ceiling:/other/ceiling' is_git_dir.side_effect = lambda x: x == git_dir def mock_getenv(k, v=None): if k == 'GIT_CEILING_DIRECTORIES': return ceiling return v getenv.side_effect = mock_getenv paths = git.find_git_directory('/ceiling/sub/dir') self.assertEqual(None, paths.git_dir) self.assertEqual(None, paths.git_file) self.assertEqual(None, paths.worktree) self.assertEqual(4, is_git_dir.call_count) kwargs = {} is_git_dir.assert_has_calls([ (('/ceiling/sub/dir',), kwargs), (('/ceiling/sub/dir/.git',), kwargs), (('/ceiling/sub',), kwargs), (('/ceiling/sub/.git',), kwargs), ]) @patch('cola.core.islink') @patch('cola.core.isdir') @patch('cola.core.isfile') def test_is_git_dir_finds_linked_repository(self, isfile, isdir, islink): dirs = set([ '/foo', '/foo/.git', '/foo/.git/refs', '/foo/.git/objects', '/foo/.git/worktrees', '/foo/.git/worktrees/foo', ]) files = set([ '/foo/.git/HEAD', '/foo/.git/worktrees/foo/HEAD', '/foo/.git/worktrees/foo/index', '/foo/.git/worktrees/foo/commondir', '/foo/.git/worktrees/foo/gitdir', ]) islink.return_value = False isfile.side_effect = lambda x: x in files isdir.side_effect = lambda x: x in dirs self.assertTrue(git.is_git_dir('/foo/.git/worktrees/foo')) self.assertTrue(git.is_git_dir('/foo/.git')) @patch('cola.core.getenv') @patch('cola.git.is_git_dir') def test_find_git_worktree_from_GIT_DIR(self, is_git_dir, getenv): git_dir = '/repo/.git' worktree = '/repo' is_git_dir.return_value = True getenv.side_effect = lambda x: x == 'GIT_DIR' and '/repo/.git' or None paths = git.find_git_directory(git_dir) self.assertTrue(is_git_dir.called) self.assertEqual(git_dir, paths.git_dir) self.assertEqual(None, paths.git_file) self.assertEqual(worktree, paths.worktree) @patch('cola.git.is_git_dir') def test_finds_no_worktree_from_bare_repo(self, is_git_dir): git_dir = '/repos/bare.git' worktree = None is_git_dir.return_value = True paths = git.find_git_directory(git_dir) self.assertTrue(is_git_dir.called) self.assertEqual(git_dir, paths.git_dir) self.assertEqual(None, paths.git_file) self.assertEqual(worktree, paths.worktree) @patch('cola.core.getenv') @patch('cola.git.is_git_dir') def test_find_git_directory_uses_GIT_WORK_TREE(self, is_git_dir, getenv): git_dir = '/repo/worktree/.git' worktree = '/repo/worktree' def is_git_dir_fn(path): return path == git_dir is_git_dir.side_effect = is_git_dir_fn def getenv_fn(name): if name == 'GIT_WORK_TREE': return worktree return None getenv.side_effect = getenv_fn paths = git.find_git_directory(worktree) self.assertTrue(is_git_dir.called) self.assertEqual(git_dir, paths.git_dir) self.assertEqual(None, paths.git_file) self.assertEqual(worktree, paths.worktree) @patch('cola.core.getenv') @patch('cola.git.is_git_dir') def test_uses_cwd_for_worktree_with_GIT_DIR(self, is_git_dir, getenv): git_dir = '/repo/.yadm/repo.git' worktree = '/repo' def getenv_fn(name): if name == 'GIT_DIR': return git_dir return None getenv.side_effect = getenv_fn def is_git_dir_fn(path): return path == git_dir is_git_dir.side_effect = is_git_dir_fn paths = git.find_git_directory(worktree) self.assertTrue(is_git_dir.called) self.assertTrue(getenv.called) self.assertEqual(git_dir, paths.git_dir) self.assertEqual(None, paths.git_file) self.assertEqual(worktree, paths.worktree) class GitCommandTest(unittest.TestCase): """Runs tests using a git.Git instance""" def setUp(self): """Creates a git.Git instance for later use""" self.git = git.Git() def test_transform_kwargs_empty(self): expect = [] actual = git.transform_kwargs(foo=None, bar=False) self.assertEqual(expect, actual) def test_transform_kwargs_single_dash_from_True(self): """Single dash for one-character True""" expect = ['-a'] actual = git.transform_kwargs(a=True) self.assertEqual(expect, actual) def test_transform_kwargs_no_single_dash_from_False(self): """No single-dash for False""" expect = [] actual = git.transform_kwargs(a=False) self.assertEqual(expect, actual) def test_transform_kwargs_double_dash_from_True(self): """Double-dash for longer True""" expect = ['--abc'] actual = git.transform_kwargs(abc=True) self.assertEqual(expect, actual) def test_transform_kwargs_no_double_dash_from_True(self): """No double-dash for False""" expect = [] actual = git.transform_kwargs(abc=False) self.assertEqual(expect, actual) def test_transform_kwargs_single_dash_int(self): expect = ['-a1'] actual = git.transform_kwargs(a=1) self.assertEqual(expect, actual) def test_transform_kwargs_double_dash_int(self): expect = ['--abc=1'] actual = git.transform_kwargs(abc=1) self.assertEqual(expect, actual) def test_transform_kwargs_single_dash_float(self): expect = ['-a1.5'] actual = git.transform_kwargs(a=1.5) self.assertEqual(expect, actual) def test_transform_kwargs_double_dash_float(self): expect = ['--abc=1.5'] actual = git.transform_kwargs(abc=1.5) self.assertEqual(expect, actual) def test_transform_kwargs_single_dash_string(self): expect = ['-abc'] actual = git.transform_kwargs(a='bc') self.assertEqual(expect, actual) def test_transform_double_single_dash_string(self): expect = ['--abc=def'] actual = git.transform_kwargs(abc='def') self.assertEqual(expect, actual) def test_version(self): """Test running 'git version'""" version = self.git.version()[STDOUT] self.assertTrue(version.startswith('git version')) def test_stdout(self): """Test overflowing the stdout buffer""" # Write to stdout only code = ('import sys;' 's = "\\0" * (1024 * 16 + 1);' 'sys.stdout.write(s);') status, out, err = git.Git.execute(['python', '-c', code], _raw=True) self.assertEqual(status, 0) self.assertEqual(len(out), 1024 * 16 + 1) self.assertEqual(len(err), 0) def test_stderr(self): """Test that stderr is seen""" # Write to stderr and capture it code = ('import sys;' 's = "\\0" * (1024 * 16 + 1);' 'sys.stderr.write(s);') status, out, err = git.Git.execute(['python', '-c', code], _raw=True) self.assertEqual(status, 0) self.assertEqual(len(out), 0) self.assertEqual(len(err), 1024 * 16 + 1) def test_stdout_and_stderr(self): """Test ignoring stderr when stdout+stderr are provided (v2)""" # Write to stdout and stderr but only capture stdout code = ('import sys;' 's = "\\0" * (1024 * 16 + 1);' 'sys.stdout.write(s);' 'sys.stderr.write(s);') status, out, err = git.Git.execute(['python', '-c', code], _raw=True) self.assertEqual(status, 0) self.assertEqual(len(out), 1024 * 16 + 1) self.assertEqual(len(err), 1024 * 16 + 1) def test_it_doesnt_deadlock(self): """Test that we don't deadlock with both stderr and stdout""" # 16k+1 bytes to exhaust any output buffers code = ('import sys;' 's = "\\0" * (1024 * 16 + 1);' 'sys.stderr.write(s);' 'sys.stdout.write(s);') status, out, err = git.Git.execute(['python', '-c', code], _raw=True) self.assertEqual(status, 0) self.assertEqual(out, '\0' * (1024 * 16 + 1)) self.assertEqual(err, '\0' * (1024 * 16 + 1)) if __name__ == '__main__': unittest.main() git-cola-3.6/test/gitcfg_test.py000066400000000000000000000072421356743264500167400ustar00rootroot00000000000000from __future__ import absolute_import, division, unicode_literals import unittest from . import helper class GitConfigTestCase(helper.GitRepositoryTestCase): """Tests the cola.gitcmds module.""" def test_string(self): """Test string values in get().""" self.run_git('config', 'test.value', 'test') self.assertEqual(self.cfg.get('test.value'), 'test') def test_int(self): """Test int values in get().""" self.run_git('config', 'test.int', '42') self.assertEqual(self.cfg.get('test.int'), 42) def test_true(self): """Test bool values in get().""" self.run_git('config', 'test.bool', 'true') self.assertEqual(self.cfg.get('test.bool'), True) def test_false(self): self.run_git('config', 'test.bool', 'false') self.assertEqual(self.cfg.get('test.bool'), False) def test_yes(self): self.run_git('config', 'test.bool', 'yes') self.assertEqual(self.cfg.get('test.bool'), True) def test_no(self): self.run_git('config', 'test.bool', 'no') self.assertEqual(self.cfg.get('test.bool'), False) def test_bool_no_value(self): self.append_file('.git/config', '[test]\n') self.append_file('.git/config', '\tbool\n') self.assertEqual(self.cfg.get('test.bool'), True) def test_empty_value(self): self.append_file('.git/config', '[test]\n') self.append_file('.git/config', '\tvalue = \n') self.assertEqual(self.cfg.get('test.value'), '') def test_default(self): """Test default values in get().""" self.assertEqual(self.cfg.get('does.not.exist'), None) self.assertEqual(self.cfg.get('does.not.exist', default=42), 42) def test_get_all(self): """Test getting multiple values in get_all()""" self.run_git('config', '--add', 'test.value', 'abc') self.run_git('config', '--add', 'test.value', 'def') expect = ['abc', 'def'] self.assertEqual(expect, self.cfg.get_all('test.value')) def assert_color(self, expect, git_value, key='test', default=None): self.run_git('config', 'cola.color.%s' % key, git_value) self.cfg.reset() actual = self.cfg.color(key, default) self.assertEqual(expect, actual) def test_color_rrggbb(self): self.assert_color((0xaa, 0xbb, 0xcc), 'aabbcc') self.assert_color((0xaa, 0xbb, 0xcc), '#aabbcc') def test_color_int(self): self.assert_color((0x10, 0x20, 0x30), '102030') self.assert_color((0x10, 0x20, 0x30), '#102030') def test_guitool_opts(self): self.run_git('config', 'guitool.hello world.cmd', 'hello world') opts = self.cfg.get_guitool_opts('hello world') expect = 'hello world' actual = opts['cmd'] self.assertEqual(expect, actual) def test_guitool_names(self): self.run_git('config', 'guitool.hello meow.cmd', 'hello meow') names = self.cfg.get_guitool_names() self.assertTrue('hello meow' in names) def test_guitool_names_mixed_case(self): self.run_git('config', 'guitool.Meow Cat.cmd', 'cat hello') names = self.cfg.get_guitool_names() self.assertTrue('Meow Cat' in names) def test_find_mixed_case(self): self.run_git('config', 'guitool.Meow Cat.cmd', 'cat hello') opts = self.cfg.find('guitool.Meow Cat.*') self.assertEqual(opts['guitool.Meow Cat.cmd'], 'cat hello') def test_guitool_opts_mixed_case(self): self.run_git('config', 'guitool.Meow Cat.cmd', 'cat hello') opts = self.cfg.get_guitool_opts('Meow Cat') self.assertEqual(opts['cmd'], 'cat hello') if __name__ == '__main__': unittest.main() git-cola-3.6/test/gitcmds_test.py000066400000000000000000000123651356743264500171310ustar00rootroot00000000000000from __future__ import absolute_import, division, unicode_literals import os import unittest from cola import gitcmds from . import helper class GitCmdsTestCase(helper.GitRepositoryTestCase): """Tests the cola.gitcmds module.""" def test_currentbranch(self): """Test current_branch().""" self.assertEqual(gitcmds.current_branch(self.context), 'master') def test_branch_list_local(self): """Test branch_list(remote=False).""" context = self.context self.commit_files() expect = ['master'] actual = gitcmds.branch_list(context, remote=False) self.assertEqual(expect, actual) def test_branch_list_remote(self): """Test branch_list(remote=False).""" context = self.context expect = [] actual = gitcmds.branch_list(context, remote=True) self.assertEqual(expect, actual) self.commit_files() self.run_git('remote', 'add', 'origin', '.') self.run_git('fetch', 'origin') expect = ['origin/master'] actual = gitcmds.branch_list(context, remote=True) self.assertEqual(expect, actual) self.run_git('remote', 'rm', 'origin') expect = [] actual = gitcmds.branch_list(context, remote=True) self.assertEqual(expect, actual) def test_upstream_remote(self): """Test getting the configured upstream remote""" context = self.context self.assertEqual(gitcmds.upstream_remote(context), None) self.run_git('config', 'branch.master.remote', 'test') self.cfg.reset() self.assertEqual(gitcmds.upstream_remote(context), 'test') def test_tracked_branch(self): """Test tracked_branch().""" context = self.context self.assertEqual(gitcmds.tracked_branch(context), None) self.run_git('config', 'branch.master.remote', 'test') self.run_git('config', 'branch.master.merge', 'refs/heads/master') self.cfg.reset() self.assertEqual(gitcmds.tracked_branch(context), 'test/master') def test_tracked_branch_other(self): """Test tracked_branch('other').""" context = self.context self.assertEqual(gitcmds.tracked_branch(context, 'other'), None) self.run_git('config', 'branch.other.remote', 'test') self.run_git('config', 'branch.other.merge', 'refs/heads/other/branch') self.cfg.reset() self.assertEqual(gitcmds.tracked_branch(context, 'other'), 'test/other/branch') def test_untracked_files(self): """Test untracked_files().""" context = self.context self.touch('C', 'D', 'E') self.assertEqual(gitcmds.untracked_files(context), ['C', 'D', 'E']) def test_all_files(self): context = self.context self.touch('other-file') all_files = gitcmds.all_files(context) self.assertTrue('A' in all_files) self.assertTrue('B' in all_files) self.assertTrue('other-file' in all_files) def test_tag_list(self): """Test tag_list().""" context = self.context self.commit_files() self.run_git('tag', 'a') self.run_git('tag', 'b') self.run_git('tag', 'c') self.assertEqual(gitcmds.tag_list(context), ['c', 'b', 'a']) def test_merge_message_path(self): """Test merge_message_path().""" context = self.context self.touch('.git/SQUASH_MSG') self.assertEqual(gitcmds.merge_message_path(context), os.path.abspath('.git/SQUASH_MSG')) self.touch('.git/MERGE_MSG') self.assertEqual(gitcmds.merge_message_path(context), os.path.abspath('.git/MERGE_MSG')) os.unlink(gitcmds.merge_message_path(context)) self.assertEqual(gitcmds.merge_message_path(context), os.path.abspath('.git/SQUASH_MSG')) os.unlink(gitcmds.merge_message_path(context)) self.assertEqual(gitcmds.merge_message_path(context), None) def test_all_refs(self): self.commit_files() self.run_git('branch', 'a') self.run_git('branch', 'b') self.run_git('branch', 'c') self.run_git('tag', 'd') self.run_git('tag', 'e') self.run_git('tag', 'f') self.run_git('remote', 'add', 'origin', '.') self.run_git('fetch', 'origin') refs = gitcmds.all_refs(self.context) self.assertEqual(refs, ['a', 'b', 'c', 'master', 'origin/a', 'origin/b', 'origin/c', 'origin/master', 'f', 'e', 'd']) def test_all_refs_split(self): self.commit_files() self.run_git('branch', 'a') self.run_git('branch', 'b') self.run_git('branch', 'c') self.run_git('tag', 'd') self.run_git('tag', 'e') self.run_git('tag', 'f') self.run_git('remote', 'add', 'origin', '.') self.run_git('fetch', 'origin') local, remote, tags = gitcmds.all_refs(self.context, split=True) self.assertEqual(local, ['a', 'b', 'c', 'master']) self.assertEqual(remote, ['origin/a', 'origin/b', 'origin/c', 'origin/master']) self.assertEqual(tags, ['f', 'e', 'd']) if __name__ == '__main__': unittest.main() git-cola-3.6/test/gitops_test.py000066400000000000000000000015371356743264500170030ustar00rootroot00000000000000#!/usr/bin/env python """Tests basic git operations: commit, log, config""" from __future__ import absolute_import, division, unicode_literals import unittest from . import helper class ColaBasicGitTestCase(helper.GitRepositoryTestCase): def test_git_commit(self): """Test running 'git commit' via cola.git""" self.write_file('A', 'A') self.write_file('B', 'B') self.run_git('add', 'A', 'B') self.git.commit(m='initial commit') log = self.run_git('log', '--pretty=oneline') self.assertEqual(len(log.splitlines()), 1) def test_git_config(self): """Test cola.git.config()""" self.run_git('config', 'section.key', 'value') value = self.git.config('section.key', get=True) self.assertEqual(value, (0, 'value', '')) if __name__ == '__main__': unittest.main() git-cola-3.6/test/gravatar_test.py000066400000000000000000000013121356743264500172740ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import absolute_import, division, unicode_literals import unittest from cola import gravatar from cola.compat import ustr class GravatarTestCase(unittest.TestCase): def test_url_for_email_(self): email = 'email@example.com' expect = (r'https://gravatar.com/avatar/' r'5658ffccee7f0ebfda2b226238b1eb6e' r'?s=64' r'&d=https%3A%2F%2Fgit-cola.github.io' r'%2Fimages%2Fgit-64x64.jpg') actual = gravatar.Gravatar.url_for_email(email, 64) self.assertEqual(expect, actual) self.assertTrue(isinstance(actual, ustr)) if __name__ == '__main__': unittest.main() git-cola-3.6/test/helper.py000066400000000000000000000056011356743264500157120ustar00rootroot00000000000000from __future__ import absolute_import, division, unicode_literals import os import shutil import stat import unittest import tempfile import mock from cola import core from cola import git from cola import gitcfg from cola import gitcmds from cola.models import main def tmp_path(*paths): """Returns a path relative to the test/tmp directory""" dirname = core.decode(os.path.dirname(__file__)) return os.path.join(dirname, 'tmp', *paths) def fixture(*paths): dirname = core.decode(os.path.dirname(__file__)) return os.path.join(dirname, 'fixtures', *paths) def run_unittest(suite): return unittest.TextTestRunner(verbosity=2).run(suite) # shutil.rmtree() can't remove read-only files on Windows. This onerror # handler, adapted from , works # around this by changing such files to be writable and then re-trying. def remove_readonly(func, path, _exc_info): if func is os.remove and not os.access(path, os.W_OK): os.chmod(path, stat.S_IWRITE) func(path) else: raise AssertionError('Should not happen') class TmpPathTestCase(unittest.TestCase): def setUp(self): self._testdir = tempfile.mkdtemp('_cola_test') os.chdir(self._testdir) def tearDown(self): """Remove the test directory and return to the tmp root.""" path = self._testdir os.chdir(tmp_path()) shutil.rmtree(path, onerror=remove_readonly) @staticmethod def touch(*paths): for path in paths: open(path, 'a').close() @staticmethod def write_file(path, content): with open(path, 'w') as f: f.write(content) @staticmethod def append_file(path, content): with open(path, 'a') as f: f.write(content) def test_path(self, *paths): return os.path.join(self._testdir, *paths) class GitRepositoryTestCase(TmpPathTestCase): """Tests that operate on temporary git repositories.""" def setUp(self): TmpPathTestCase.setUp(self) self.initialize_repo() self.context = context = mock.Mock() context.git = git.create() context.git.set_worktree(core.getcwd()) context.cfg = gitcfg.create(context) context.model = self.model = main.create(self.context) self.git = context.git self.cfg = context.cfg self.cfg.reset() gitcmds.reset() def run_git(self, *args): status, out, _ = core.run_command(['git'] + list(args)) self.assertEqual(status, 0) return out def initialize_repo(self): self.run_git('init') self.run_git('config', '--local', 'user.name', 'Your Name') self.run_git('config', '--local', 'user.email', 'you@example.com') self.touch('A', 'B') self.run_git('add', 'A', 'B') def commit_files(self): self.run_git('commit', '-m', 'initial commit') git-cola-3.6/test/i18n_test.py000066400000000000000000000032471356743264500162550ustar00rootroot00000000000000from __future__ import absolute_import, division, unicode_literals import unittest from cola import i18n from cola.i18n import N_ from cola.compat import uchr class ColaI18nTestCase(unittest.TestCase): """Test cases for the ColaApplication class""" def tearDown(self): i18n.uninstall() def test_translates_noun(self): """Test that strings with @@noun are translated """ i18n.install('ja_JP') expect = (uchr(0x30b3) + uchr(0x30df) + uchr(0x30c3) + uchr(0x30c8)) actual = N_('Commit@@verb') self.assertEqual(expect, actual) def test_translates_verb(self): """Test that strings with @@verb are translated """ i18n.install('de_DE') expect = 'Commit aufnehmen' actual = N_('Commit@@verb') self.assertEqual(expect, actual) def test_translates_english_noun(self): """Test that English strings with @@noun are properly handled """ i18n.install('en_US.UTF-8') expect = 'Commit' actual = N_('Commit@@noun') self.assertEqual(expect, actual) def test_translates_english_verb(self): """Test that English strings with @@verb are properly handled """ i18n.install('en_US.UTF-8') expect = 'Commit' actual = N_('Commit@@verb') self.assertEqual(expect, actual) def test_translates_random_english(self): """Test that random English strings are passed through as-is """ i18n.install('en_US.UTF-8') expect = 'Random' actual = N_('Random') self.assertEqual(expect, actual) if __name__ == '__main__': unittest.main() git-cola-3.6/test/icons_test.py000066400000000000000000000010641356743264500166040ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 from __future__ import absolute_import, division, unicode_literals import unittest from cola import compat from cola import core from cola import icons class IconTestCase(unittest.TestCase): def test_from_filename_unicode(self): filename = compat.uchr(0x400) + '.py' expect = 'file-code.svg' actual = icons.basename_from_filename(filename) self.assertEqual(expect, actual) actual = icons.basename_from_filename(core.encode(filename)) self.assertEqual(expect, actual) git-cola-3.6/test/main_model_test.py000066400000000000000000000171431356743264500176020ustar00rootroot00000000000000from __future__ import absolute_import, division, unicode_literals import os import unittest import mock from cola import core from cola import git from cola.models import main from . import helper class MainModelTestCase(helper.GitRepositoryTestCase): """Tests the MainModel class.""" def test_project(self): """Test the 'project' attribute.""" project = os.path.basename(self.test_path()) self.model.set_worktree(core.getcwd()) self.assertEqual(self.model.project, project) def test_local_branches(self): """Test the 'local_branches' attribute.""" self.commit_files() self.model.update_status() self.assertEqual(self.model.local_branches, ['master']) def test_remote_branches(self): """Test the 'remote_branches' attribute.""" self.model.update_status() self.assertEqual(self.model.remote_branches, []) self.commit_files() self.run_git('remote', 'add', 'origin', '.') self.run_git('fetch', 'origin') self.model.update_status() self.assertEqual(self.model.remote_branches, ['origin/master']) def test_modified(self): """Test the 'modified' attribute.""" self.write_file('A', 'change') self.model.update_status() self.assertEqual(self.model.modified, ['A']) def test_unstaged(self): """Test the 'unstaged' attribute.""" self.write_file('A', 'change') self.write_file('C', 'C') self.model.update_status() self.assertEqual(self.model.unstaged, ['A', 'C']) def test_untracked(self): """Test the 'untracked' attribute.""" self.write_file('C', 'C') self.model.update_status() self.assertEqual(self.model.untracked, ['C']) def test_remotes(self): """Test the 'remote' attribute.""" self.run_git('remote', 'add', 'origin', '.') self.model.update_status() self.assertEqual(self.model.remotes, ['origin']) def test_currentbranch(self): """Test the 'currentbranch' attribute.""" self.run_git('checkout', '-b', 'test') self.model.update_status() self.assertEqual(self.model.currentbranch, 'test') def test_tags(self): """Test the 'tags' attribute.""" self.commit_files() self.run_git('tag', 'test') self.model.update_status() self.assertEqual(self.model.tags, ['test']) class RemoteArgsTestCase(unittest.TestCase): def setUp(self): self.context = context = mock.Mock() context.git = git.create() self.remote = 'server' self.local_branch = 'local' self.remote_branch = 'remote' def test_remote_args_fetch(self): # Fetch (args, kwargs) = \ main.remote_args(self.context, self.remote, local_branch=self.local_branch, remote_branch=self.remote_branch) self.assertEqual(args, [self.remote, 'remote:local']) self.assertTrue(kwargs['verbose']) self.assertFalse('tags' in kwargs) self.assertFalse('rebase' in kwargs) def test_remote_args_fetch_tags(self): # Fetch tags (args, kwargs) = \ main.remote_args(self.context, self.remote, tags=True, local_branch=self.local_branch, remote_branch=self.remote_branch) self.assertEqual(args, [self.remote, 'remote:local']) self.assertTrue(kwargs['verbose']) self.assertTrue(kwargs['tags']) self.assertFalse('rebase' in kwargs) def test_remote_args_pull(self): # Pull (args, kwargs) = \ main.remote_args(self.context, self.remote, pull=True, local_branch='', remote_branch=self.remote_branch) self.assertEqual(args, [self.remote, 'remote']) self.assertTrue(kwargs['verbose']) self.assertFalse('rebase' in kwargs) self.assertFalse('tags' in kwargs) def test_remote_args_pull_rebase(self): # Rebasing pull (args, kwargs) = \ main.remote_args(self.context, self.remote, pull=True, rebase=True, local_branch='', remote_branch=self.remote_branch) self.assertEqual(args, [self.remote, 'remote']) self.assertTrue(kwargs['verbose']) self.assertTrue(kwargs['rebase']) self.assertFalse('tags' in kwargs) def test_remote_args_push(self): # Push, swap local and remote (args, kwargs) = \ main.remote_args(self.context, self.remote, local_branch=self.remote_branch, remote_branch=self.local_branch) self.assertEqual(args, [self.remote, 'local:remote']) self.assertTrue(kwargs['verbose']) self.assertFalse('tags' in kwargs) self.assertFalse('rebase' in kwargs) def test_remote_args_push_tags(self): # Push, swap local and remote (args, kwargs) = \ main.remote_args(self.context, self.remote, tags=True, local_branch=self.remote_branch, remote_branch=self.local_branch) self.assertEqual(args, [self.remote, 'local:remote']) self.assertTrue(kwargs['verbose']) self.assertTrue(kwargs['tags']) self.assertFalse('rebase' in kwargs) def test_remote_args_push_same_remote_and_local(self): (args, kwargs) = \ main.remote_args(self.context, self.remote, tags=True, local_branch=self.local_branch, remote_branch=self.local_branch, push=True) self.assertEqual(args, [self.remote, 'local']) self.assertTrue(kwargs['verbose']) self.assertTrue(kwargs['tags']) self.assertFalse('rebase' in kwargs) def test_remote_args_push_set_upstream(self): (args, kwargs) = \ main.remote_args(self.context, self.remote, tags=True, local_branch=self.local_branch, remote_branch=self.local_branch, push=True, set_upstream=True) self.assertEqual(args, [self.remote, 'local']) self.assertTrue(kwargs['verbose']) self.assertTrue(kwargs['tags']) self.assertTrue(kwargs['set_upstream']) self.assertFalse('rebase' in kwargs) def test_remote_args_rebase_only(self): (_, kwargs) = \ main.remote_args(self.context, self.remote, pull=True, rebase=True, ff_only=True) self.assertTrue(kwargs['rebase']) self.assertFalse('ff_only' in kwargs) def test_run_remote_action(self): def passthrough(*args, **kwargs): return (args, kwargs) (args, kwargs) = \ main.run_remote_action(self.context, passthrough, self.remote, local_branch=self.local_branch, remote_branch=self.remote_branch) self.assertEqual(args, (self.remote, 'remote:local')) self.assertTrue(kwargs['verbose']) self.assertFalse('tags' in kwargs) self.assertFalse('rebase' in kwargs) if __name__ == '__main__': unittest.main() git-cola-3.6/test/models_selection_test.py000066400000000000000000000010031356743264500210120ustar00rootroot00000000000000from __future__ import absolute_import, division, unicode_literals import unittest import mock from cola.models import selection class SelectionTestCase(unittest.TestCase): def test_union(self): t = mock.Mock() t.staged = ['a'] t.unmerged = ['a', 'b'] t.modified = ['b', 'a', 'c'] t.untracked = ['d'] expect = ['a', 'b', 'c', 'd'] actual = selection.union(t) self.assertEqual(expect, actual) if __name__ == '__main__': unittest.main() git-cola-3.6/test/settings_test.py000066400000000000000000000054141356743264500173340ustar00rootroot00000000000000from __future__ import absolute_import, division, unicode_literals import unittest import os from cola.settings import Settings from . import helper def new_settings(**kwargs): settings = Settings(**kwargs) settings.load() return settings class SettingsTestCase(unittest.TestCase): """Tests the cola.settings module""" def setUp(self): Settings.config_path = self._file = helper.tmp_path('settings') self.settings = new_settings() def tearDown(self): if os.path.exists(self._file): os.remove(self._file) def test_gui_save_restore(self): """Test saving and restoring gui state""" settings = new_settings() settings.gui_state['test-gui'] = {'foo': 'bar'} settings.save() settings = new_settings() state = settings.gui_state.get('test-gui', {}) self.assertTrue('foo' in state) self.assertEqual(state['foo'], 'bar') def test_bookmarks_save_restore(self): """Test the bookmark save/restore feature""" # We automatically purge missing entries so we mock-out # git.is_git_worktree() so that this bookmark is kept. bookmark = {'path': '/tmp/python/thinks/this/exists', 'name': 'exists'} def mock_verify(path): return path == bookmark['path'] settings = new_settings() settings.add_bookmark(bookmark['path'], bookmark['name']) settings.save() settings = new_settings(verify=mock_verify) bookmarks = settings.bookmarks self.assertEqual(len(settings.bookmarks), 1) self.assertTrue(bookmark in bookmarks) settings.remove_bookmark(bookmark['path'], bookmark['name']) bookmarks = settings.bookmarks self.assertEqual(len(bookmarks), 0) self.assertFalse(bookmark in bookmarks) def test_bookmarks_removes_missing_entries(self): """Test that missing entries are removed after a reload""" bookmark = {'path': '/tmp/this/does/not/exist', 'name': 'notexist'} settings = new_settings() settings.add_bookmark(bookmark['path'], bookmark['name']) settings.save() settings = new_settings() bookmarks = settings.bookmarks self.assertEqual(len(settings.bookmarks), 0) self.assertFalse(bookmark in bookmarks) def test_rename_bookmark(self): settings = new_settings() settings.add_bookmark('/tmp/repo', 'a') settings.add_bookmark('/tmp/repo', 'b') settings.add_bookmark('/tmp/repo', 'c') settings.rename_bookmark('/tmp/repo', 'b', 'test') expect = ['a', 'test', 'c'] actual = [i['name'] for i in settings.bookmarks] self.assertEqual(expect, actual) if __name__ == '__main__': unittest.main() git-cola-3.6/test/short_branch_overlapping.sh000077500000000000000000000036601356743264500215050ustar00rootroot00000000000000#!/bin/bash folder=tmp/a_repo nodeI=0 function node() { n=$nodeI nodeI=$((nodeI+1)) touch $n >> /dev/null git add $n >> /dev/null if ! [ "$1" == "" ] ; then n=$1 fi git commit -m node-$n- >> /dev/null if ! [ "$1" == "" ] ; then git tag -m "" $n >> /dev/null fi } function get_SHA1() { git log --all --grep node-$1- | grep commit | sed -e 's/commit //' } function goto() { SHA1=$(get_SHA1 $1) git checkout $SHA1 -b $2 >> /dev/null } function merge() { n=$nodeI nodeI=$((nodeI+1)) SHA1=$(get_SHA1 $1) git merge --no-ff $SHA1 -m node-$n- >> /dev/null } function range() { i=$1 I=$2 res=$i while [[ i -lt I ]] ; do i=$((i+1)) res="$res $i" done echo $res } function nodes() { I=$(($1-1)) for i in $(range 0 $I) ; do node done } rm -rf "$folder" mkdir "$folder" cd "$folder" git init # Tags are used to get difference between row and generation values. # Branches master & b2 occupied 2 rows per generation because of tags. # Branches b0 is at the left of tags. Therefore, b0 uses 1 row per generation. # The same is for b1 too. The b1 is short but tag 'b1' cannot be placed # right at the row the branch ends, because the tags at the right were already # placed (they have less generation value). Hence, a gap between last two # commits of b1 is big. Let b0 forks at a row inside the gap. The fork commit # have greater generation than last commit of b1. Hence, it is placed after. # Because of the bug, making many enough branches starting from the fork will # manage to overlapping of last commit of b1 and a commit of a branch. node tag0 node tag1 node tag2 node tag3 node tag4 nodes 1 goto tag0 b0 nodes 8 b0_head=$n goto tag0 b1 nodes 5 goto tag0 b2 nodes 10 git checkout b0 nodes 5 goto $b0_head b5 nodes 5 goto $b0_head b6 nodes 5 goto $b0_head b7 nodes 5 git checkout b2 ../../../bin/git-dag --all & git-cola-3.6/test/spellcheck_test.py000066400000000000000000000013621356743264500176070ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import absolute_import, division, unicode_literals import unittest from cola import compat from cola import spellcheck from . import helper class TestCase(unittest.TestCase): def test_spellcheck_generator(self): check = spellcheck.NorvigSpellCheck() self.assert_spellcheck(check) def test_spellcheck_unicode(self): path = helper.fixture('unicode.txt') check = spellcheck.NorvigSpellCheck(cracklib=path) self.assert_spellcheck(check) def assert_spellcheck(self, check): for word in check.read(): self.assertTrue(word is not None) self.assertTrue(isinstance(word, compat.ustr)) if __name__ == '__main__': unittest.main() git-cola-3.6/test/textwrap_test.py000066400000000000000000000123371356743264500173540ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import absolute_import, division, unicode_literals import unittest from cola import textwrap class WordWrapTestCase(unittest.TestCase): def setUp(self): self.tabwidth = 8 self.limit = None def wrap(self, text, break_on_hyphens=True): return textwrap.word_wrap(text, self.tabwidth, self.limit, break_on_hyphens=break_on_hyphens) def test_word_wrap(self): self.limit = 16 text = """ 12345678901 3 56 8 01 3 5 7 1 3 5""" expect = """ 12345678901 3 56 8 01 3 5 7 1 3 5""" self.assertEqual(expect, self.wrap(text)) def test_word_wrap_dashes(self): self.limit = 4 text = '123-5' expect = '123-5' self.assertEqual(expect, self.wrap(text)) def test_word_wrap_leading_spaces(self): self.limit = 4 expect = '1234\n5' self.assertEqual(expect, self.wrap('1234 5')) self.assertEqual(expect, self.wrap('1234 5')) self.assertEqual(expect, self.wrap('1234 5')) self.assertEqual(expect, self.wrap('1234 5')) self.assertEqual(expect, self.wrap('1234 5')) expect = '123\n4' self.assertEqual(expect, self.wrap('123 4')) self.assertEqual(expect, self.wrap('123 4')) self.assertEqual(expect, self.wrap('123 4')) self.assertEqual(expect, self.wrap('123 4')) self.assertEqual(expect, self.wrap('123 4')) def test_word_wrap_double_dashes(self): self.limit = 4 text = '12--5' expect = '12--\n5' self.assertEqual(expect, self.wrap(text, break_on_hyphens=True)) expect = '12--5' self.assertEqual(expect, self.wrap(text, break_on_hyphens=False)) def test_word_wrap_many_lines(self): self.limit = 2 text = """ aa bb cc dd""" expect = """ aa bb cc dd""" self.assertEqual(expect, self.wrap(text)) def test_word_python_code(self): self.limit = 78 text = """ if True: print "hello world" else: print "hello world" """ self.assertEqual(text, self.wrap(text)) def test_word_wrap_spaces(self): self.limit = 2 text = ' ' * 6 self.assertEqual('', self.wrap(text)) def test_word_wrap_special_tag(self): self.limit = 2 text = """ This test is so meta, even this sentence Cheered-on-by: Avoids word-wrap C.f. This also avoids word-wrap References: This also avoids word-wrap See-also: This also avoids word-wrap Related-to: This also avoids word-wrap Link: This also avoids word-wrap """ expect = """ This test is so meta, even this sentence Cheered-on-by: Avoids word-wrap C.f. This also avoids word-wrap References: This also avoids word-wrap See-also: This also avoids word-wrap Related-to: This also avoids word-wrap Link: This also avoids word-wrap """ self.assertEqual(self.wrap(text), expect) def test_word_wrap_space_at_start_of_wrap(self): inputs = """0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 """ expect = """0 1 2 3 4 5 6 7 8 9\n0 1 2 3 4 5 6 7 8""" self.limit = 20 actual = self.wrap(inputs) self.assertEqual(expect, actual) def test_word_wrap_keeps_tabs_at_start(self): inputs = """\tfirst line\n\n\tsecond line""" expect = """\tfirst line\n\n\tsecond line""" self.limit = 20 actual = self.wrap(inputs) self.assertEqual(expect, actual) def test_word_wrap_keeps_twospace_indents(self): inputs = """first line\n\n* branch:\n line1\n line2\n""" expect = """first line\n\n* branch:\n line1\n line2\n""" self.limit = 20 actual = self.wrap(inputs) self.assertEqual(expect, actual) def test_word_wrap_ranges(self): text = 'a bb ccc dddd\neeeee' expect = 'a\nbb\nccc\ndddd\neeeee' actual = textwrap.word_wrap(text, 8, 2) self.assertEqual(expect, actual) expect = 'a bb\nccc\ndddd\neeeee' actual = textwrap.word_wrap(text, 8, 4) self.assertEqual(expect, actual) text = 'a bb ccc dddd\n\teeeee' expect = 'a bb\nccc\ndddd\n\t\neeeee' actual = textwrap.word_wrap(text, 8, 4) self.assertEqual(expect, actual) def test_triplets(self): text = 'xx0 xx1 xx2 xx3 xx4 xx5 xx6 xx7 xx8 xx9 xxa xxb' expect = ( 'xx0 xx1 xx2 xx3 xx4 xx5 xx6\n' 'xx7 xx8 xx9 xxa xxb' ) actual = textwrap.word_wrap(text, 8, 27) self.assertEqual(expect, actual) expect = ( 'xx0 xx1 xx2 xx3 xx4 xx5\n' 'xx6 xx7 xx8 xx9 xxa xxb' ) actual = textwrap.word_wrap(text, 8, 26) self.assertEqual(expect, actual) actual = textwrap.word_wrap(text, 8, 25) self.assertEqual(expect, actual) actual = textwrap.word_wrap(text, 8, 24) self.assertEqual(expect, actual) actual = textwrap.word_wrap(text, 8, 23) self.assertEqual(expect, actual) expect = ( 'xx0 xx1 xx2 xx3 xx4\n' 'xx5 xx6 xx7 xx8 xx9\n' 'xxa xxb' ) actual = textwrap.word_wrap(text, 8, 22) self.assertEqual(expect, actual) if __name__ == '__main__': unittest.main() git-cola-3.6/test/tmp/000077500000000000000000000000001356743264500146575ustar00rootroot00000000000000git-cola-3.6/test/tmp/.gitignore000066400000000000000000000000001356743264500166350ustar00rootroot00000000000000git-cola-3.6/test/utils_test.py000066400000000000000000000070471356743264500166400ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import absolute_import, division, unicode_literals import os import unittest from cola import core from cola import utils class ColaUtilsTestCase(unittest.TestCase): """Tests the cola.utils module.""" def test_basename(self): """Test the utils.basename function.""" self.assertEqual(utils.basename('bar'), 'bar') self.assertEqual(utils.basename('/bar'), 'bar') self.assertEqual(utils.basename('/bar '), 'bar ') self.assertEqual(utils.basename('foo/bar'), 'bar') self.assertEqual(utils.basename('/foo/bar'), 'bar') self.assertEqual(utils.basename('foo/foo/bar'), 'bar') self.assertEqual(utils.basename('/foo/foo/bar'), 'bar') self.assertEqual(utils.basename('/foo/foo//bar'), 'bar') self.assertEqual(utils.basename('////foo //foo//bar'), 'bar') def test_dirname(self): """Test the utils.dirname function.""" self.assertEqual(utils.dirname('bar'), '') self.assertEqual(utils.dirname('/bar'), '') self.assertEqual(utils.dirname('//bar'), '') self.assertEqual(utils.dirname('///bar'), '') self.assertEqual(utils.dirname('foo/bar'), 'foo') self.assertEqual(utils.dirname('foo//bar'), 'foo') self.assertEqual(utils.dirname('foo /bar'), 'foo ') self.assertEqual(utils.dirname('/foo//bar'), '/foo') self.assertEqual(utils.dirname('/foo /bar'), '/foo ') self.assertEqual(utils.dirname('//foo//bar'), '/foo') self.assertEqual(utils.dirname('///foo///bar'), '/foo') def test_add_parents(self): """Test the utils.add_parents() function.""" paths = set(['foo///bar///baz']) path_set = utils.add_parents(paths) self.assertTrue('foo/bar/baz' in path_set) self.assertTrue('foo/bar' in path_set) self.assertTrue('foo' in path_set) self.assertFalse('foo///bar///baz' in path_set) # Ensure that the original set is unchanged expect = set(['foo///bar///baz']) self.assertEqual(expect, paths) def test_tmp_filename_gives_good_file(self): first = utils.tmp_filename('test') second = utils.tmp_filename('test') self.assertFalse(core.exists(first)) self.assertFalse(core.exists(second)) self.assertNotEqual(first, second) self.assertTrue(os.path.basename(first).startswith('git-cola-test')) self.assertTrue(os.path.basename(second).startswith('git-cola-test')) def test_strip_one_abspath(self): expect = 'bin/git' actual = utils.strip_one('/usr/bin/git') self.assertEqual(expect, actual) def test_strip_one_relpath(self): expect = 'git' actual = utils.strip_one('bin/git') self.assertEqual(expect, actual) def test_strip_one_nested_relpath(self): expect = 'bin/git' actual = utils.strip_one('local/bin/git') self.assertEqual(expect, actual) def test_strip_one_basename(self): expect = 'git' actual = utils.strip_one('git') self.assertEqual(expect, actual) def test_select_directory(self): filename = utils.tmp_filename('test') expect = os.path.dirname(filename) actual = utils.select_directory([filename]) self.assertEqual(expect, actual) def test_select_directory_prefers_directories(self): filename = utils.tmp_filename('test') expect = '.' actual = utils.select_directory([filename, '.']) self.assertEqual(expect, actual) if __name__ == '__main__': unittest.main() git-cola-3.6/tox.ini000066400000000000000000000003561356743264500144170ustar00rootroot00000000000000[tox] minversion = 1.8 envlist = py{27,34,35,36,37} [testenv] sitepackages = true deps = -rrequirements/requirements.txt -rrequirements/requirements-dev.txt whitelist_externals = make commands = make test make flake8