pax_global_header00006660000000000000000000000064141722250420014511gustar00rootroot0000000000000052 comment=699cdec67a7195c7f6bd6cf5e4354c168aed0d44 git-cola-3.12.0/000077500000000000000000000000001417222504200132735ustar00rootroot00000000000000git-cola-3.12.0/.flake8000066400000000000000000000004061417222504200144460ustar00rootroot00000000000000[flake8] doctests = true max-line-length = 88 ignore = # W503 violates spec https://github.com/PyCQA/pycodestyle/issues/513 W503 # W504 has issues https://github.com/OCA/maintainer-quality-tools/issues/545 W504 # Black creates whitespace before colon E203 git-cola-3.12.0/.github/000077500000000000000000000000001417222504200146335ustar00rootroot00000000000000git-cola-3.12.0/.github/FUNDING.yml000066400000000000000000000000471417222504200164510ustar00rootroot00000000000000github: [davvid] patreon: daveinthesky git-cola-3.12.0/.github/workflows/000077500000000000000000000000001417222504200166705ustar00rootroot00000000000000git-cola-3.12.0/.github/workflows/main.yml000066400000000000000000000100031417222504200203310ustar00rootroot00000000000000name: CI on: [push, pull_request] jobs: build: name: 'Build' runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v2 # Repository checked out under $GITHUB_WORKSPACE - name: Install Dependencies run: | sudo apt-get update sudo apt-get install \ gettext \ python3-sphinx - name: Build run: make prefix="build" install - name: Upload Artifact uses: actions/upload-artifact@v2 with: name: git-cola-run${{github.run_number}}-${{runner.os}} path: build/ test: name: 'Test' runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v2 # Repository checked out under $GITHUB_WORKSPACE - name: Install Dependencies run: | sudo apt-get update sudo apt-get install \ black \ gettext \ flake8 \ pylint \ python-pytest \ python3-pytest \ python3-pytest-flake8 # Runtime dependencies (required) sudo apt-get install \ python3-pyqt5 # Runtime dependencies (optional) sudo apt-get install \ python3-qtpy \ python3-send2trash - name: Build Translations run: make i18n - name: Run Unit Tests run: | git config --global user.name "Git Cola" git config --global user.email git-cola@localhost make test - name: Run Linter run: make pylint color=0 - name: Check Code Style run: make flake8 - name: Check Code Formatting # For strict adherence to formatting, run 'black' with --check run: make format win32: name: 'Build / win32' runs-on: windows-latest steps: - name: Checkout uses: actions/checkout@v2 # Repository checked out under $GITHUB_WORKSPACE - name: Setup Python uses: actions/setup-python@v2 with: python-version: '3.x' architecture: 'x64' - name: Pip Cache uses: actions/cache@v2 with: path: ~\AppData\Local\pip\Cache key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements/requirements*.txt') }} - name: Install Dependencies run: | pip install -r requirements/requirements.txt pip install -r requirements/requirements-optional.txt pip install -r requirements/requirements-maint.txt pip install -r requirements/requirements-dev.txt pip install PyQt5 # Based on: contrib/win32/run-pynsist.sh - name: Build Installer run: | make all make doc make htmldir="$PWD/share/doc/git-cola/html" install-doc pynsist pynsist.cfg rm -r share/doc/git-cola/html # Rename executable output cd build\nsis mv git-cola*.exe git-cola-run${{github.run_number}}.exe - name: Upload Artifact uses: actions/upload-artifact@v2 with: name: git-cola-run${{github.run_number}}-${{runner.os}} path: build\nsis\git-cola*.exe darwin: name: 'Build / darwin' runs-on: macos-latest steps: - name: Checkout uses: actions/checkout@v2 # Repository checked out under $GITHUB_WORKSPACE - name: Install Dependencies run: | brew install sphinx-doc brew install git-cola - name: Build Bundle run: | mkdir build 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 mv git-cola.app build/ - name: Upload Artifact uses: actions/upload-artifact@v2 with: name: git-cola-run${{github.run_number}}-${{runner.os}} path: build/ git-cola-3.12.0/.gitignore000066400000000000000000000004171417222504200152650ustar00rootroot00000000000000/.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.12.0/.mailmap000066400000000000000000000014411417222504200147140ustar00rootroot00000000000000AJ 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.12.0/.pylintrc000066400000000000000000000263151417222504200151470ustar00rootroot00000000000000[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,qtpy,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=4 # 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=binascii,math,PyQt4,PyQt5,PyQt6,PySide,PySide2,select,struct,struct.pack,struct.unpack # 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,bad-option-value,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,super-with-arguments,raise-missing-from,duplicate-code [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=88 # 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.12.0/CHANGES.rst000066400000000000000000003614651417222504200151140ustar00rootroot00000000000000.. _v3.12.0: v3.12.0 ======= Usability, bells and whistles ----------------------------- * The git config guitool action can now be grouped under user-defined menus. This is done by using slash (``/``) delimiters in the action name. Entries before the final slash are treated like submenus inside the top-level ``Actions`` menu. (`#1150 `_) * Toolbars now have a full set of icons. The icons follow the system theme and can be configured to display text, just icons, or text and icons. (`#1171 `_) * The startup dialog will now open the selected repository when the "enter" key is pressed. (`#1162 `_) * ``S`` is stages selected lines (in addition to ``s``). (`#1187 `_) Fixes ----- * The vendored qtpy library was patched to retain Python2 compatibility. * The "Unstage" toolbar action was fixed. (`#1178 `_) * We now avoid `setWidth(float)` for compatibility with newer Qt versions. (`#1183 `_) * Documentation typofixes. (`#1185 `_) Translations ------------ * Updated Polish translation. (`#1184 `_) Development ----------- * Git Cola now uses Github Actions for running its continuous integration tests. (`#1179 `_) .. _v3.11.0: v3.11.0 ======= Usability, bells and whistles ----------------------------- * The Status tool was improved to better retain selected files when the state changes and the display is refreshed. (`#1130 `_) (`#1131 `_) * The Diff editor can now stage selected lines for untracked files. Git Cola will detect when a file is untracked and will allow you to partially stage it, just like existing tracked files. (`#1146 `_) (`#1084 `_) * Diffing of staged files has been implemented for repositories that contain no commits. (`#1149 `_) (`#1110 `_) * Documentation improvements and typofixes. (`#1163 `_) (`#1164 `_) Security -------- * The `FIPS security mode `_ is now supported by Git Cola when running on FIPS-enabled Python (Python 3.9+ or centos8/rhel8's patched Python 3.6). (`#1157 `_) Fixes ----- * The `argparse` usage was adjusted to remain compatible with older Pythons. (`#1155 `_) * The window restoration logic was fixed to properly save/restore settings when different languages are used. (`#1071 `_) (`#1161 `_) (`#382 `_) * `git dag` no longer passes floats to `QPen::setWidth()` for better compatibility. (`bz #2014950 `_) Packaging --------- * The Windows installer was slimmed down by removing unused Qt DLLs. (`#1152 `_) .. _v3.10.1: v3.10.1 ======= Fixes ----- * Patch release to fix a typo in the Interactive Rebase feature. .. _v3.10: v3.10 ===== Usability, bells and whistles ----------------------------- * The git config reader now supports the `include.path` directive for including config files. (`#1136 `_) (`#1137 `_) * The dialog for selecting commits now support filtering. (`#1121 `_) * The diff editor now wraps long lines by default. The diff options menu can be used to enable/disable line wrapping. (`#1123 `_) * Git Cola now honors `core.hooksPath` for configuring custom Git hooks, which was introduced in Git v2.9. (`#1118 `_) * A new `Ctrl + Shift + S` hotkey was added for staging/unstaging all files, both modified and untracked. * The `Status` tool now supports `Ctrl + A` for selecting all files and it behaves more predictably when performing operations when multiple categories of files are selected (eg. when both modified and untracked header items are selected). (`#1117 `_) Translations ------------ * Updated Hungarian translation. (`#1135 `_) Fixes ----- * The "Interactive Rebase" feature was updated to work with Windows. * `make install-man` was updated to support Sphinx 4.0. (`#1141 `_) * `git cola --help-commands` was updated for newer versions of argparse. (`#1133 `_) Development ----------- * Git Cola can now be started as a Python module. (`#1119 `_) .. _v3.9: v3.9 ==== Usability, bells and whistles ----------------------------- * The startup dialog now detects when Recent and Favorite repositories no longer exist on disk, and offers to remove these entries when selected. (`#1089 `_) * The startup dialog now includes a simpler and more condensed folder view that can be used for selecting Favorites and Recent repositories. (`#1086 `_) * The "Commit" menu now includes an "Undo Last Commit" action. (`#890 `_) * The "Reset" menu was revamped to expose all of Git's reset modes alongside a new "Restore Worktree" action that updates the worktree using "git read-tree". (`#890 `_) Translations ------------ * Updated Polish translation. (`#1107 `_) * Updated Japanese translation. (`#1098 `_) * Updated Brazilian translation. (`#1091 `_) Packaging --------- * The ``--use-env-python`` option for ``setup.py`` is now Python3 compatible. (`#1102 `_) .. _v3.8: v3.8 ==== Usability, bells and whistles ----------------------------- * The submodules widget can now be used to add submodules. Submodules are now updated recursively. (`#534 `_) * The image diff viewer can now be toggled between text and image modes. This is helpful when, for example, diffing .svg files where it can be useful to see diffs in both an image and text representation. (`#859 `_) (`#1035 `_) * The default `ssh-askpass` username + password dialog included with Git Cola can now toggle between showing and masking the password input field. (`#1069 `_) Translations ------------ * Updated Polish translation. (`#1076 `_) * Updated Hungarian translation. (`#1067 `_) Packaging --------- * The `share/appdata` AppStream data was renamed to `share/metainfo` in accordance with `AppStream standard changes from 2016 `_. (`#1079 `_) * The ``cola`` modules are now installed into the Python ``site-packages`` directory by default. This allows distributions to package ``git-cola`` for multiple versions of Python. See the PACKAGING NOTES section in the README for details about suppressing the installation of the private ``share/git-cola/lib/cola`` modules when building cola. (`#181 `_) * Git Cola's rebase / sequence editor, formerly known as ``git-xbase`` and installed as ``share/git-cola/bin/git-xbase``, has been renamed to ``git-cola-sequence-editor`` and is now installed into the default ``bin/git-cola-sequence-editor`` executable location to enable external reuse of this general-purpose tool. * A workaround used by the pynsist installer preamble script was obsoleted by `takluyver/pynsist#149 `_ and has now been removed. (`#1073 `_) Fixes ----- * `git dag` now uses integer widths when initializing its brushes. (`#1080 `_) .. _v3.7: v3.7 ==== Usability, bells and whistles ----------------------------- * The ``git-xbase`` rebase editor now includes a file list for filtering the changes displayed in the diff view. (`#1051 `_) * The fallback `ssh-askpass` script, which provides the Username/Password login dialog when performing remote operations, previously presented both the username and password input fields with ``***`` asterisks. The dialog now uses asterisks for the password field only. (`#1026 `_) * Stashes can now be applied using the `Ctrl + Enter` hotkey, popped with the `Ctrl + Backspace` hotkey, and dropped with the `Ctrl + Shift + Backspace` hotkey when inside the stash dialog. This enables a keyboard-centric mouse-free workflow when using the stash dialog. * When amending a commit, `git cola` will check whether the commit has been published to a remote branch using ``git branch -r --contains HEAD``. This command can be slow when operating on a repository with many remote branches. The new `cola.checkpublishedcommits` configuration variable allows you to opt-out of this check, which improves performance when amending a commit. The settings widget exposes this variable as, "Check Published Commits when Amending". (`#1021 `_) (`#1027 `_) Translations ------------ * Updated Polish translation. (`#1033 `_) Fixes ----- * ``git-dag.appdata.xml`` was updated to allow network access for author icons. (`#1050 `_) * The inotify filesystem monitor now handles `OSError: [Errno 24] Too many open files` errors by disabling inotify. (`#1015 `_) * Typos in various documentation files have been fixed. (`#1025 `_) * The "Recent Repositories" limit was off by one, and now correctly remembers the configured number of repositories in the menu. (`#1024 `_) * The "revert" action in the DAG and other tools now uses ``git revert --no-edit``, which avoids launching an editor when reverting the commit. Use `Ctrl+m` in the commit message editor after reverting a commit to rewrite its commit message. (`#1020 `_) .. _v3.6: 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: 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 overridden 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: 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: 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: 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: 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: 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: 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: 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: v2.9.1 ====== Fixes ----- * The "Open Recent" menu was updated to new bookmarks format. (`#628 `_) .. _v2.9: 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: 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: 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: 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: 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: 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: 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: v2.2.1 ====== Fixes ----- * Fixed the "Sign off" feature in the commit message editor. .. _v2.2: 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: 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: 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: 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: 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: 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: v2.0.6 ====== Usability, bells and whistles ----------------------------- * Updated Brazilian 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: v2.0.5 ====== Usability, bells and whistles ----------------------------- * New Brazilian 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: v1.4.0.4 ======== Packaging --------- * Fix Lintian warnings .. _v1.4.0.3: v1.4.0.3 ======== Fixes ----- * Fix X11 warnings on application startup .. _v1.4.0.2: 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: 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: 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: 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: 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: 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: 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.12.0/CONTRIBUTING.md000066400000000000000000000160311417222504200155250ustar00rootroot00000000000000# 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` ## Write tests When adding new features or fixing defects, extend the unit tests to cover the new behavior. See the `tests/` directory for examples. Find an appropriate test suite and extend it whenever possible. ## 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/ * Use the `make format` command to format the source code using `black`. * 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`. Untranslated 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.12.0/COPYING000066400000000000000000000431031417222504200143270ustar00rootroot00000000000000 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.12.0/COPYRIGHT000066400000000000000000000000671417222504200145710ustar00rootroot00000000000000Copyright (C) 2007-2020 David Aguilar and contributors git-cola-3.12.0/Makefile000066400000000000000000000216741417222504200147450ustar00rootroot00000000000000# 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, --ff failed first # 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 # run the black python formatter # 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... BLACK = black CTAGS = ctags CP = cp FIND = find FLAKE8 = flake8 GREP = grep GIT = git GZIP = gzip LN = ln LN_S = $(LN) -s -f MARKDOWN = markdown MKDIR_P = mkdir -p PIP = pip PYTHON ?= python PYLINT = $(PYTHON) -B -m pylint PYTEST = $(PYTHON) -B -m pytest RM = rm -f RM_R = rm -fr RMDIR = rmdir TAR = tar TOX = tox XARGS = xargs # 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) PYTEST_FLAGS = $(QUIET) $(TEST_VERBOSE) uname_S := $(shell uname -s) ifneq ($(uname_S),Linux) PYTEST_FLAGS += --ignore=cola/inotify.py endif TOX_FLAGS = $(VERBOSE_SHORT) --develop --skip-missing-interpreters TOX_ENVS ?= py{27,36,37,38,39,lint} PYLINT_SCORE_FLAG := $(shell sh -c '$(PYLINT) --score=no --help >/dev/null 2>&1 && echo " --score=no" || true') PYLINT_FLAGS = --rcfile=.pylintrc ifdef color PYLINT_FLAGS += --output-format=colorized endif ifneq ($(PYLINT_SCORE_FLAGSCORE),) PYLINT_FLAGS += $(PYLINT_SCORE_FLAG) endif # These values can be overridden on the command-line or via config.mak prefix = $(HOME) bindir = $(prefix)/bin datadir = $(prefix)/share/git-cola python_lib := $(shell $(PYTHON) -c \ 'import distutils.sysconfig as sc; print(sc.get_python_lib(prefix=""))') pythondir = $(prefix)/$(python_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) # Read $(VERSION) from cola/_version.py and strip quotes. include cola/_version.py cola_version := $(subst ',,$(VERSION)) 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 ifdef DESTDIR install_args += --root="$(DESTDIR)" export DESTDIR endif export prefix ifdef NO_PRIVATE_LIBS install_args += --no-private-libs endif 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-cola-sequence-editor PYTHON_SOURCES += bin/git-dag PYTHON_SOURCES += setup.py # User customizations -include config.mak .PHONY: all all:: build .PHONY: build_version build_version: @GIT=$(GIT) ./extras/generate-build-version.sh 2>/dev/null || true .PHONY: build build: build_version $(SETUP) $(QUIET) $(VERBOSE) $(build_args) .PHONY: install 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" .PHONY: doc doc: $(MAKE) -C share/doc/git-cola all .PHONY: html html: $(MAKE) -C share/doc/git-cola html .PHONY: man man: $(MAKE) -C share/doc/git-cola man .PHONY: install-doc install-doc: $(MAKE) -C share/doc/git-cola install .PHONY: install-html install-html: $(MAKE) -C share/doc/git-cola install-html .PHONY: install-man install-man: $(MAKE) -C share/doc/git-cola install-man .PHONY: uninstall uninstall: $(RM) "$(DESTDIR)$(prefix)"/bin/git-cola $(RM) "$(DESTDIR)$(prefix)"/bin/git-cola-sequence-editor $(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/metainfo/git-dag.appdata.xml $(RM) "$(DESTDIR)$(prefix)"/share/metainfo/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 $(RM_R) "$(DESTDIR)$(pythondir)"/git_cola-* $(RM_R) "$(DESTDIR)$(pythondir)"/cola $(RMDIR) -p "$(DESTDIR)$(pythondir)" 2>/dev/null || true $(RMDIR) "$(DESTDIR)$(prefix)"/share/applications 2>/dev/null || true $(RMDIR) "$(DESTDIR)$(prefix)"/share/metainfo 2>/dev/null || true $(RMDIR) "$(DESTDIR)$(prefix)"/share/doc 2>/dev/null || true $(RMDIR) "$(DESTDIR)$(prefix)"/share/locale/*/LC_MESSAGES 2>/dev/null || true $(RMDIR) "$(DESTDIR)$(prefix)"/share/locale/* 2>/dev/null || true $(RMDIR) "$(DESTDIR)$(prefix)"/share/locale 2>/dev/null || true $(RMDIR) "$(DESTDIR)$(prefix)"/share/icons/hicolor/scalable/apps 2>/dev/null || true $(RMDIR) "$(DESTDIR)$(prefix)"/share/icons/hicolor/scalable 2>/dev/null || true $(RMDIR) "$(DESTDIR)$(prefix)"/share/icons/hicolor 2>/dev/null || true $(RMDIR) "$(DESTDIR)$(prefix)"/share/icons 2>/dev/null || true $(RMDIR) "$(DESTDIR)$(prefix)"/share 2>/dev/null || true $(RMDIR) "$(DESTDIR)$(prefix)"/bin 2>/dev/null || true $(RMDIR) "$(DESTDIR)$(prefix)" 2>/dev/null || true .PHONY: test test: all $(PYTEST) $(PYTEST_FLAGS) $(flags) $(PYTHON_DIRS) .PHONY: coverage coverage: $(PYTEST) $(PYTEST_FLAGS) --cov=cola $(flags) $(PYTHON_DIRS) .PHONY: clean clean: $(FIND) $(ALL_PYTHON_DIRS) -name '*.py[cod]' -print0 | $(XARGS) -0 $(RM) $(FIND) $(ALL_PYTHON_DIRS) -name __pycache__ -print0 | $(XARGS) -0 $(RM_R) $(RM_R) build dist tags git-cola.app $(RM_R) share/locale $(MAKE) -C share/doc/git-cola clean .PHONY: tags tags: $(FIND) $(ALL_PYTHON_DIRS) -name '*.py' -print0 | $($XARGS) -0 $(CTAGS) -f tags # Update i18n files .PHONY: i18n i18n:: pot i18n:: po i18n:: mo .PHONY: pot pot: $(SETUP) build_pot --build-dir=po --no-lang .PHONY: po po: $(SETUP) build_pot --build-dir=po .PHONY: mo mo: $(SETUP) build_mo --force .PHONY: git-cola.app 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: app-tarball app-tarball: git-cola.app $(TAR) czf $(cola_dist).app.tar.gz $(cola_app_base) # Preview the markdown using "make README.html" %.html: %.md $(MARKDOWN) $< >$@ .PHONY: flake8 flake8: $(FLAKE8) --version $(FLAKE8) $(FLAKE8_FLAGS) $(flags) \ $(PYTHON_SOURCES) $(ALL_PYTHON_DIRS) contrib .PHONY: pylint3k pylint3k: $(PYLINT) --version $(PYLINT) $(PYLINT_FLAGS) --py3k $(flags) \ $(PYTHON_SOURCES) $(ALL_PYTHON_DIRS) .PHONY: pylint pylint: $(PYLINT) --version $(PYLINT) $(PYLINT_FLAGS) $(flags) \ $(PYTHON_SOURCES) $(ALL_PYTHON_DIRS) # Pre-commit checks .PHONY: check 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 # NOTE: flake8 is not part of "make check" because the pytest-flake8 plugin runs flake8 # checks during "make test" via pytest. check:: all check:: test check:: doc check:: pylint3k check:: pylint endif .PHONY: format format: $(GIT) ls-files -- '*.py' | \ $(GREP) -v ^qtpy | \ $(XARGS) $(BLACK) --skip-string-normalization --target-version=py27 $(BLACK) --skip-string-normalization --target-version=py27 $(PYTHON_SOURCES) .PHONY: requirements requirements: $(PIP) install --requirement requirements/requirements.txt .PHONY: requirements-dev requirements-dev: $(PIP) install --requirement requirements/requirements-dev.txt .PHONY: tox tox: $(TOX) $(TOX_FLAGS) $(flags) .PHONY: tox-check tox-check: $(TOX) $(TOX_FLAGS) --parallel auto -e "$(TOX_ENVS)" $(flags) git-cola-3.12.0/README.md000066400000000000000000000355761417222504200145720ustar00rootroot00000000000000# git-cola: The highly caffeinated Git GUI git-cola is a powerful Git GUI with a slick and intuitive user interface. Copyright (C) 2007-2020, 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://github.com/git-cola/git-cola/actions/workflows/main.yml/badge.svg?branch=main&event=push)](https://github.com/git-cola/git-cola/actions/workflows/main.yml) [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. ## 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 You can also start `cola` as a Python module if Python can find it. cd git-cola python -m cola python -m cola 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). ### FreeBSD # install from official binary packages pkg install -r FreeBSD devel/git-cola # build from source cd /usr/ports/devel/git-cola && make clean install ## Ubuntu [See here](https://packages.ubuntu.com/search?keywords=git-cola) for the versions that are available in Ubuntu's repositories. There was a [PPA by @pavreh](https://launchpad.net/~pavreh/+archive/ubuntu/git-cola) but it has not been updated for a while. ## 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 set up. A quick fix when upgrading to newer versions of XCode or macOS is to reinstall pyqt5. brew reinstall pyqt@5 You may also need to relink your pyqt installation: brew link pyqt@5 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. If the "brew reinstall" command above does not work then re-installing from scratch using the instructions below should get things back in shape. # 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-cola-sequence-editor`. `git-cola-sequence-editor` 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 use the `git-cola-sequence-editor`: git cola rebase origin/main git-cola-sequence-editor can be launched independently of git cola by telling `git rebase` to use it as its editor through the `GIT_SEQUENCE_EDITOR` environment variable: env GIT_SEQUENCE_EDITOR="$PWD/bin/git-cola-sequence-editor" \ git rebase -i origin/main # 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. Commits and pull requests are automatically tested for code quality using [GitHub Actions](https://github.com/git-cola/git-cola/actions/workflows/main.yml). 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. ## PACKAGING NOTES Git Cola installs its modules into the default Python site-packages directory (eg. `lib/python2.7/site-packages`), and in its own private `share/git-cola/lib` area by default. The private modules are redundant and not needed when cola's modules have been installed into the site-packages directory. Git Cola will prefer its private modules when the `share/git-cola/lib` directory exists, but they are not required to exist. This directory is optional, and can be safely removed if the cola modules have been installed into site-packages and are importable through the default `sys.path`. To suppress the installation of the private (redundant) `share/git-cola/lib/cola` package, specify `make NO_PRIVATE_LIBS=1 ...` when invoking `make`, or export `GIT_COLA_NO_PRIVATE_LIBS=1` into the build environment. make NO_PRIVATE_LIBS=1 ... Git Cola installs a vendored copy of its QtPy dependency by default. Git Cola provides a copy of the `qtpy` module in its private modules area 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 specify `make NO_VENDOR_LIBS=1 ...` when invoking `make`, or export `GIT_COLA_NO_VENDOR_LIBS=1` into the build environment. make NO_VENDOR_LIBS=1 ... 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. # 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.12.0/bin/000077500000000000000000000000001417222504200140435ustar00rootroot00000000000000git-cola-3.12.0/bin/cola000077700000000000000000000000001417222504200157532../colaustar00rootroot00000000000000git-cola-3.12.0/bin/git-cola000077500000000000000000000026701417222504200154750ustar00rootroot00000000000000#!/usr/bin/env python """git-cola: The highly caffeinated Git GUI""" from __future__ import absolute_import, division, print_function, unicode_literals import os import sys __copyright__ = """ Copyright (C) 2007-2020 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(): """Provide access to the cola modules""" abspath = os.path.abspath(__file__) prefix = os.path.dirname(os.path.dirname(os.path.realpath(abspath))) install_lib = os.path.join(prefix, str('share'), str('git-cola'), str('lib')) win_pkgs = os.path.join(prefix, str('pkgs')) # Use the private modules from share/git-cola/lib when they exist. # It is assumed that that our modules to be present in sys.path through python's # site-packages directory when the private modules do not exist. if os.path.exists(install_lib): sys.path.insert(1, install_lib) elif os.path.exists(win_pkgs): sys.path.insert(1, win_pkgs) if __name__ == '__main__': setup_environment() from cola.main import main sys.exit(main()) git-cola-3.12.0/bin/git-cola-sequence-editor000077500000000000000000000026541417222504200205710ustar00rootroot00000000000000#!/usr/bin/env python # flake8: noqa from __future__ import absolute_import, division, print_function, unicode_literals import os import sys __copyright__ = """ Copyright (C) 2007-2020 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(): """Provide access to the cola modules""" abspath = os.path.abspath(__file__) prefix = os.path.dirname(os.path.dirname(os.path.realpath(abspath))) install_lib = os.path.join(prefix, str('share'), str('git-cola'), str('lib')) win_pkgs = os.path.join(prefix, str('pkgs')) # Use the private modules from share/git-cola/lib when they exist. # It is assumed that that our modules to be present in sys.path through python's # site-packages directory when the private modules do not exist. if os.path.exists(install_lib): sys.path.insert(1, install_lib) elif os.path.exists(win_pkgs): sys.path.insert(1, win_pkgs) if __name__ == '__main__': setup_environment() from cola import sequenceeditor sys.exit(sequenceeditor.main()) git-cola-3.12.0/bin/git-dag000077500000000000000000000026751417222504200153170ustar00rootroot00000000000000#!/usr/bin/env python """git-dag: An advanced Git DAG history visualizer""" from __future__ import absolute_import, division, print_function, unicode_literals import os import sys __copyright__ = """ Copyright (C) 2007-2020 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(): """Provide access to the cola modules""" abspath = os.path.abspath(__file__) prefix = os.path.dirname(os.path.dirname(os.path.realpath(abspath))) install_lib = os.path.join(prefix, str('share'), str('git-cola'), str('lib')) win_pkgs = os.path.join(prefix, str('pkgs')) # Use the private modules from share/git-cola/lib when they exist. # It is assumed that that our modules to be present in sys.path through python's # site-packages directory when the private modules do not exist. if os.path.exists(install_lib): sys.path.insert(1, install_lib) elif os.path.exists(win_pkgs): sys.path.insert(1, win_pkgs) if __name__ == '__main__': setup_environment() from cola import dag sys.exit(dag.main()) git-cola-3.12.0/bin/qtpy000077700000000000000000000000001417222504200161112../qtpyustar00rootroot00000000000000git-cola-3.12.0/cola/000077500000000000000000000000001417222504200142115ustar00rootroot00000000000000git-cola-3.12.0/cola/__init__.py000066400000000000000000000000001417222504200163100ustar00rootroot00000000000000git-cola-3.12.0/cola/__main__.py000066400000000000000000000004251417222504200163040ustar00rootroot00000000000000"""Run cola as a Python module. Usage: python -m cola """ from __future__ import absolute_import, division, print_function, unicode_literals from cola import main def run(): """Start the command-line interface.""" main.main() if __name__ == '__main__': run() git-cola-3.12.0/cola/_version.py000066400000000000000000000000231417222504200164020ustar00rootroot00000000000000VERSION = '3.12.0' git-cola-3.12.0/cola/actions.py000066400000000000000000000036701417222504200162310ustar00rootroot00000000000000"""QAction creator functions""" from __future__ import absolute_import, division, print_function, 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 at the current line""" 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""" action = qtutils.add_action( widget, N_('Next File'), widget.down.emit, hotkeys.MOVE_DOWN_SECONDARY ) action.setIcon(icons.move_down()) return action def move_up(widget): """Create a QAction to select the previous/above item""" action = qtutils.add_action( widget, N_('Previous File'), widget.up.emit, hotkeys.MOVE_UP_SECONDARY ) action.setIcon(icons.move_up()) return action git-cola-3.12.0/cola/app.py000066400000000000000000000500721417222504200153470ustar00rootroot00000000000000"""Provides the main() routine and ColaApplication""" # pylint: disable=unused-import from __future__ import absolute_import, division, print_function, 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 .settings import Settings 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()) session.update() 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) 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.settings = args.settings or Settings.read() 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""" initialize_view(context, view) # 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 initialize_view(context, view): """Register the main widget and display it""" context.set_view(view) view.show() if sys.platform == 'darwin': view.raise_() 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): """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) gitdir = startup_dlg.find_git_repo() if not gitdir: sys.exit(core.EXIT_NOINPUT) if not core.exists(os.path.join(gitdir, '.git')): offer_to_create_repo(context, gitdir) valid = model.set_worktree(gitdir) continue valid = model.set_worktree(gitdir) if not valid: standard.critical( N_('Error Opening Repository'), N_('Could not open %s.' % gitdir) ) def offer_to_create_repo(context, gitdir): """Offer to create a new repo""" title = N_('Repository Not Found') text = N_('%s is not a Git repository.') % gitdir informative_text = N_('Create a new repository at that location?') if standard.confirm(title, text, informative_text, N_('Create')): status, out, err = context.git.init(gitdir) title = N_('Error Creating Repository') if status != 0: Interaction.command_error(title, 'git init', status, out, err) 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.settings = None # settings.Settings 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.12.0/cola/cmd.py000066400000000000000000000016641417222504200153350ustar00rootroot00000000000000"""Base Command class""" from __future__ import absolute_import, division, print_function, 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.12.0/cola/cmds.py000066400000000000000000002655521417222504200155300ustar00rootroot00000000000000"""Editor commands""" from __future__ import absolute_import, division, print_function, 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 main from .models import prefs 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.old_file_type = self.model.file_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 self.new_file_type = self.old_file_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) self.model.set_file_type(self.new_file_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) self.model.set_file_type(self.old_file_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 = main.Types.TEXT self.new_file_type = main.Types.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, no_edit=True) 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 = main.Types.TEXT self.new_file_type = main.Types.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 ResetMixed(ResetCommand): @staticmethod def tooltip(ref): tooltip = N_('The branch will be reset using "git reset --mixed %s"') return tooltip % ref def confirm(self): title = N_('Reset Branch and Stage (Mixed)') question = N_('Point the current branch head to a new commit?') info = self.tooltip(self.ref) ok_text = N_('Reset Branch') return Interaction.confirm(title, question, info, ok_text) def reset(self): return self.git.reset(self.ref, '--', mixed=True) class ResetKeep(ResetCommand): @staticmethod def tooltip(ref): tooltip = N_('The repository will be reset using "git reset --keep %s"') return tooltip % ref def confirm(self): title = N_('Restore Worktree and Reset All (Keep Unstaged Changes)') question = N_('Restore worktree, reset, and preserve unstaged edits?') info = self.tooltip(self.ref) ok_text = N_('Reset and Restore') return Interaction.confirm(title, question, info, ok_text) def reset(self): return self.git.reset(self.ref, '--', keep=True) class ResetMerge(ResetCommand): @staticmethod def tooltip(ref): tooltip = N_('The repository will be reset using "git reset --merge %s"') return tooltip % ref def confirm(self): title = N_('Restore Worktree and Reset All (Merge)') question = N_('Reset Worktree and Reset All?') info = self.tooltip(self.ref) ok_text = N_('Reset and Restore') return Interaction.confirm(title, question, info, ok_text) def reset(self): return self.git.reset(self.ref, '--', merge=True) class ResetSoft(ResetCommand): @staticmethod def tooltip(ref): tooltip = N_('The branch will be reset using "git reset --soft %s"') return tooltip % ref def confirm(self): title = N_('Reset Branch (Soft)') question = N_('Reset branch?') info = self.tooltip(self.ref) ok_text = N_('Reset Branch') return Interaction.confirm(title, question, info, ok_text) def reset(self): return self.git.reset(self.ref, '--', soft=True) class ResetHard(ResetCommand): @staticmethod def tooltip(ref): tooltip = N_('The repository will be reset using "git reset --hard %s"') return tooltip % ref def confirm(self): title = N_('Restore Worktree and Reset All (Hard)') question = N_('Restore Worktree and Reset All?') info = self.tooltip(self.ref) ok_text = N_('Reset and Restore') return Interaction.confirm(title, question, info, ok_text) def reset(self): return self.git.reset(self.ref, '--', hard=True) class RestoreWorktree(ConfirmAction): """Reset the worktree using the "git read-tree" command""" @staticmethod def tooltip(ref): tooltip = N_( 'The worktree will be restored using "git read-tree --reset -u %s"' ) return tooltip % ref def __init__(self, context, ref): super(RestoreWorktree, self).__init__(context) self.ref = ref def action(self): return self.git.read_tree(self.ref, reset=True, u=True) def command(self): return 'git read-tree --reset -u %s' % self.ref def error_message(self): return N_('Error') def success(self): self.model.update_file_status() def confirm(self): title = N_('Restore Worktree') question = N_('Restore Worktree to %s?') % self.ref info = self.tooltip(self.ref) ok_text = N_('Restore Worktree') return Interaction.confirm(title, question, info, ok_text) class UndoLastCommit(ResetCommand): """Undo the last commit""" # NOTE: this is the similar to ResetSoft() with an additional check for # published commits and different messages. def __init__(self, context): super(UndoLastCommit, self).__init__(context, 'HEAD^') def confirm(self): check_published = prefs.check_published_commits(self.context) if check_published and self.model.is_commit_published(): return 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_('Undo the published commit?'), N_('Undo Last Commit'), default=False, icon=icons.save(), ) title = N_('Undo Last Commit') question = N_('Undo last commit?') info = N_('The branch will be reset using "git reset --soft %s"') ok_text = N_('Undo Last Commit') info_text = info % self.ref return Interaction.confirm(title, question, info_text, ok_text) def reset(self): return self.git.reset('HEAD^', '--', soft=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, repo, entry, icon=None): super(RemoveFromSettings, self).__init__(context) self.context = context self.repo = repo self.entry = entry self.icon = icon def success(self): self.context.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.context.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.context.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 DiffText(EditModel): """Set the diff type to text""" def __init__(self, context): super(DiffText, self).__init__(context) self.new_file_type = main.Types.TEXT self.new_diff_type = main.Types.TEXT class ToggleDiffType(ContextCommand): """Toggle the diff type between image and text""" def __init__(self, context): super(ToggleDiffType, self).__init__(context) if self.model.diff_type == main.Types.IMAGE: self.new_diff_type = main.Types.TEXT self.new_value = False else: self.new_diff_type = main.Types.IMAGE self.new_value = True def do(self): diff_type = self.new_diff_type value = self.new_value self.model.set_diff_type(diff_type) filename = self.model.filename _, ext = os.path.splitext(filename) if ext.startswith('.'): cfg = 'cola.imagediff' + ext self.cfg.set_repo(cfg, value) 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_type = self.get_diff_type(filename) self.new_file_type = main.Types.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 get_diff_type(self, filename): """Query the diff type to use based on cola.imagediff.""" _, ext = os.path.splitext(filename) if ext.startswith('.'): # Check eg. "cola.imagediff.svg" to see if we should imagediff. cfg = 'cola.imagediff' + ext if self.cfg.get(cfg, True): result = main.Types.IMAGE else: result = main.Types.TEXT else: result = main.Types.IMAGE return result 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 and gitcmds.is_valid_ref(context, self.model.head): 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 ) 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 = main.Types.TEXT self.new_file_type = main.Types.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 = main.Types.TEXT self.new_file_type = main.Types.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 = main.Types.TEXT self.new_file_type = main.Types.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 = self.context.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(): """Set GIT_SEQUENCE_EDITOR for running git-cola-sequence-editor""" xbase = unix_path(resources.command('git-cola-sequence-editor')) if utils.is_win32(): editor = core.list2cmdline([unix_path(sys.executable), xbase]) else: editor = core.list2cmdline([xbase]) return editor class SequenceEditorEnvironment(object): """Set environment variables to enable git-cola-sequence-editor""" def __init__(self, context, **kwargs): self.env = { 'GIT_EDITOR': prefs.editor(context), 'GIT_SEQUENCE_EDITOR': sequence_editor(), 'GIT_COLA_SEQ_EDITOR_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 SequenceEditorEnvironment( self.context, GIT_COLA_SEQ_EDITOR_TITLE=N_('Rebase onto %s') % upstream_title, GIT_COLA_SEQ_EDITOR_ACTION=N_('Rebase'), ): # TODO this blocks the user interface window for the duration # of git-cola-sequence-editor. We would need to implement # signals for QProcess and continue running the main thread. # Alternatively, we can 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 SequenceEditorEnvironment( self.context, GIT_COLA_SEQ_EDITOR_TITLE=N_('Edit Rebase'), GIT_COLA_SEQ_EDITOR_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 SequenceEditorEnvironment( self.context, GIT_COLA_SEQ_EDITOR_TITLE=N_('Rebase'), GIT_COLA_SEQ_EDITOR_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 SequenceEditorEnvironment( self.context, GIT_COLA_SEQ_EDITOR_TITLE=N_('Rebase'), GIT_COLA_SEQ_EDITOR_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.set_diff_type(main.Types.TEXT) 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 = main.Types.TEXT self.new_file_type = main.Types.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) def format_hex(data): """Translate binary data into a hex dump""" hexdigits = '0123456789ABCDEF' result = '' offset = 0 byte_offset_to_int = compat.byte_offset_to_int_converter() while offset < len(data): result += '%04u |' % offset textpart = '' for i in range(0, 16): if i > 0 and i % 4 == 0: result += ' ' if offset < len(data): v = byte_offset_to_int(data[offset]) result += ' ' + hexdigits[v >> 4] + hexdigits[v & 0xF] textpart += chr(v) if 32 <= v < 127 else '.' offset += 1 else: result += ' ' textpart += ' ' result += ' | ' + textpart + ' |\n' return result class ShowUntracked(EditModel): """Show an untracked file.""" def __init__(self, context, filename): super(ShowUntracked, self).__init__(context) self.new_filename = filename if gitcmds.is_binary(context, filename): self.new_mode = self.model.mode_untracked self.new_diff_text = self.read(filename) else: self.new_mode = self.model.mode_untracked_diff self.new_diff_text = gitcmds.diff_helper( self.context, filename=filename, cached=False, untracked=True ) self.new_diff_type = main.Types.TEXT self.new_file_type = main.Types.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='bytes') except (IOError, OSError): result = '' truncated = len(result) == size encoding = cfg.file_encoding(filename) or core.ENCODING try: text_result = core.decode_maybe(result, encoding) except UnicodeError: text_result = format_hex(result) if truncated: text_result += '...' return text_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 # pylint: disable=all 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 StageModifiedAndUntracked(StageCarefully): """Stage all untracked files.""" @staticmethod def name(): return N_('Stage Modified and Untracked') def init_paths(self): self.paths = self.model.modified + self.model.untracked class StageOrUnstageAll(ContextCommand): """If the selection is staged, unstage it, otherwise stage""" @staticmethod def name(): return N_('Stage / Unstage All') def do(self): if self.model.staged: do(Unstage, self.context, self.model.staged) else: if self.cfg.get('cola.safemode', False): unstaged = self.model.modified else: unstaged = self.model.modified + self.model.untracked do(Stage, self.context, unstaged) 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 = context.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 = main.Types.TEXT self.new_file_type = main.Types.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 SubmoduleAdd(ConfirmAction): """Add specified submodules""" def __init__(self, context, url, path, branch, depth, reference): super(SubmoduleAdd, self).__init__(context) self.url = url self.path = path self.branch = branch self.depth = depth self.reference = reference def confirm(self): title = N_('Add Submodule...') question = N_('Add this submodule?') info = N_('The submodule will be added using\n' '"%s"' % self.command()) ok_txt = N_('Add Submodule') return Interaction.confirm(title, question, info, ok_txt, icon=icons.ok()) def action(self): context = self.context args = self.get_args() return context.git.submodule('add', *args) def success(self): self.model.update_file_status() self.model.update_submodules_list() def error_message(self): return N_('Error updating submodule %s' % self.path) def command(self): cmd = ['git', 'submodule', 'add'] cmd.extend(self.get_args()) return core.list2cmdline(cmd) def get_args(self): args = [] if self.branch: args.extend(['--branch', self.branch]) if self.reference: args.extend(['--reference', self.reference]) if self.depth: args.extend(['--depth', '%d' % self.depth]) args.extend(['--', self.url]) if self.path: args.append(self.path) return args 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 args = self.get_args() return context.git.submodule(*args) def success(self): self.model.update_file_status() def error_message(self): return N_('Error updating submodule %s' % self.path) def command(self): cmd = ['git', 'submodule'] cmd.extend(self.get_args()) return core.list2cmdline(cmd) def get_args(self): cmd = ['update'] if version.check_git(self.context, 'submodule-update-recursive'): cmd.append('--recursive') cmd.extend(['--', self.path]) return cmd 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 args = self.get_args() return context.git.submodule(*args) def success(self): self.model.update_file_status() def error_message(self): return N_('Error updating submodules') def command(self): cmd = ['git', 'submodule'] cmd.extend(self.get_args()) return core.list2cmdline(cmd) def get_args(self): cmd = ['update'] if version.check_git(self.context, 'submodule-update-recursive'): cmd.append('--recursive') return cmd 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.12.0/cola/compat.py000066400000000000000000000041341417222504200160500ustar00rootroot00000000000000# pylint: disable=unused-import,redefined-builtin,undefined-variable from __future__ import absolute_import, division, print_function, unicode_literals import os import sys try: import urllib2 as parse # noqa except ImportError: # Python 3 from urllib import parse # noqa PY_VERSION = sys.version_info[:2] # (2, 7) PY_VERSION_MAJOR = PY_VERSION[0] PY2 = PY_VERSION_MAJOR == 2 PY3 = PY_VERSION_MAJOR >= 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 # Qt's max 32-bit signed integer range (-2147483648 to 2147483647) maxint = (2 ** 31) - 1 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) def no_op(value): """Return the value as-is""" return value def byte_offset_to_int_converter(): """Return a function to convert byte string offsets into ints Indexing into python3 bytes returns ints, Python2 returns str. Thus, on Python2 we need to use `ord()` to convert the byte into an integer. It's already an int on Python3, so we use no_op there. """ if PY2: result = ord else: result = no_op return result git-cola-3.12.0/cola/core.py000066400000000000000000000336171417222504200155250ustar00rootroot00000000000000"""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 absolute_import, division, print_function, 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_maybe(value, encoding, errors='strict'): """Decode a value when the "decode" method exists""" if hasattr(value, 'decode'): result = value.decode(encoding, errors=errors) else: result = value return result 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) elif encoding == 'bytes': result = value 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, ValueError): 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.12.0/cola/dag.py000066400000000000000000000026351417222504200153240ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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, show=False) return app.application_start(context, view) git-cola-3.12.0/cola/decorators.py000066400000000000000000000041241417222504200167310ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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 interruptible 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.12.0/cola/diffparse.py000066400000000000000000000266121417222504200165350ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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 if 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.12.0/cola/difftool.py000066400000000000000000000137031417222504200163750ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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.12.0/cola/display.py000066400000000000000000000036431417222504200162360ustar00rootroot00000000000000"""Display models and utility functions""" from __future__ import absolute_import, division, print_function, unicode_literals import collections def shorten_paths(source_paths): """Shorten a sequence of paths into unique strings for display""" result = {} # Start by assuming that all paths are in conflict. # On each iteration we will collect all the path suffixes, move the newly # unique entries to the result, and repeat until no conflicts remain. count = 0 conflicts = list(source_paths) in_conflict = True while in_conflict: count += 1 # Gather the suffixes for the current paths in conflict suffixes = collections.defaultdict(list) for path in conflicts: suffix = path_suffix(path, count) suffixes[suffix].append(path) # Loop over the suffixes to gather new conflicts and unique entries. conflicts = [] in_conflict = False for suffix, paths in suffixes.items(): # If only a single path exists for the suffix then no conflict # exists, and the suffix is valid. if len(paths) == 1: result[paths[0]] = suffix # If this loop runs too long then bail out by using the full path. elif count >= 128: for path in paths: result[path] = path # If multiple paths map to the same suffix then the paths are # considered in conflict, and will be reprocessed. else: conflicts.extend(paths) in_conflict = True return result def path_suffix(path, count): """Return `count` number of trailing path components""" path = normalize_path(path) components = path.split('/')[-count:] return '/'.join(components) def normalize_path(path): """Normalize a path so that only "/" is used as a separator""" return path.replace('\\', '/') git-cola-3.12.0/cola/fsmonitor.py000066400000000000000000000465561417222504200166230ustar00rootroot00000000000000# 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 absolute_import, division, print_function, 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: try: self._inotify_fd = inotify.init() except OSError as e: self._inotify_fd = None self._running = False if e.errno == errno.EMFILE: self._log_out_of_wds_message() return self._pipe_r, self._pipe_w = os.pipe() # pylint: disable=no-member 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 if 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 in (errno.ENOSPC, errno.EMFILE): 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 if 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.12.0/cola/git.py000066400000000000000000000333701417222504200153540ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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.12.0/cola/gitcfg.py000066400000000000000000000404031417222504200160270ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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 . import version 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) # pylint: disable=redefined-variable-type 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._binary_cache = {} self._find_config_files() def reset(self): self._cache_key = None self._configs = [] self._config_files.clear() self._attr_cache = {} self._binary_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 = {} if version.check_git(self, 'config-includes'): args = ('--null', '--file', path, '--list', '--includes') else: 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 is_binary(self, path): """Return True if the file has the binary attribute set""" if not self.is_per_file_attrs_enabled(): return None cache = self._binary_cache try: value = cache[path] except KeyError: value = cache[path] = self._is_binary(path) return value def _is_binary(self, path): """Return the file encoding for a path""" value = self.check_attr('binary', path) return value == 'set' 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""" encoding = self.check_attr('encoding', path) if encoding in ('unspecified', 'unset', 'set'): result = None else: result = encoding return result def check_attr(self, attr, path): """Check file attributes for a path""" value = None status, out, _ = self.git.check_attr(attr, '--', path) if status == 0: header = '%s: %s: ' % (path, attr) if out.startswith(header): value = out[len(header) :].strip() return value 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: # pylint: disable=no-member r, g, b = struct.unpack(struct_layout, unhex(value)) except (struct.error, TypeError): # pylint: disable=no-member r, g, b = struct.unpack(struct_layout, unhex(default)) return (r, g, b) def hooks(self): """Return the path to the git hooks directory""" gitdir_hooks = self.git.git_path('hooks') return self.get('core.hookspath', default=gitdir_hooks) def hooks_path(self, *paths): """Return a path from within the git hooks directory""" return os.path.join(self.hooks(), *paths) 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.12.0/cola/gitcmds.py000066400000000000000000000707021417222504200162230ustar00rootroot00000000000000"""Git commands and queries for Git""" from __future__ import absolute_import, division, print_function, 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='main'): """Pure-python .git/HEAD reader""" # Common .git/HEAD "ref: refs/heads/main" 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) # pylint: disable=too-many-arguments 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, untracked=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: argv.extend(utils.shell_split(ref.strip())) elif head and amending and cached: argv.append(head) encoding = None if untracked: argv.append('--no-index') argv.append(os.devnull) argv.append(filename) elif 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) ) success = status == 0 # Diff will return 1 when comparing untracked file and it has change, # therefore we will check for diff header from output to differentiate # from actual error such as file not found. if untracked and status == 1: try: _, second, _ = out.split('\n', 2) except ValueError: second = '' success = second.startswith('new file mode ') if not success: # 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_rev_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: rev_idx = revs[cur_rev_idx:].index(rev) rev_idx += cur_rev_idx except ValueError: rev_idx = revs.index(rev) if rev_idx == cur_rev_idx + 1: patches_to_export[patchset_idx].append(rev) cur_rev_idx += 1 else: patches_to_export.append([rev]) cur_rev_idx = rev_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) def reset_paths(context, head, items): """Run "git reset" while preventing argument overflow""" items = list(set(items)) fn = context.git.reset status, out, err = utils.slice_fn(items, lambda paths: fn(head, '--', *paths)) return (status, out, err) def unstage_paths(context, args, head='HEAD'): """Unstage paths while accounting for git init""" status, out, err = reset_paths(context, head, 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): """Run the cola.preparecommitmessagehook to prepare the commit message""" config = context.cfg default_hook = config.hooks_path('cola-prepare-commit-msg') 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 def is_binary(context, filename): cfg_is_binary = context.cfg.is_binary(filename) if cfg_is_binary is not None: return cfg_is_binary # This is the same heuristic as xdiff-interface.c:buffer_is_binary(). size = 8000 try: result = core.read(filename, size=size, encoding='bytes') except (IOError, OSError): result = b'' return b'\0' in result def is_valid_ref(context, ref): """Is the provided Git ref a valid refname?""" status, _, _ = context.git.rev_parse(ref, quiet=True, verify=True) return status == 0 git-cola-3.12.0/cola/gravatar.py000066400000000000000000000117661417222504200164050ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, unicode_literals import time import hashlib from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from qtpy import QtNetwork from . import compat 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 = md5_hexdigest(email) # 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 def md5_hexdigest(value): """Return the md5 hexdigest for a value. Used for implementing the gravatar API. Not used for security purposes. """ encoded_value = core.encode(value) result = '' try: result = hashlib.md5(encoded_value).hexdigest() except ValueError: pass if not result and compat.PY_VERSION >= (3, 6): try: # pylint: disable=unexpected-keyword-arg result = hashlib.md5(encoded_value, usedforsecurity=False).hexdigest() except ValueError: # https://github.com/git-cola/git-cola/issues/1157 # ValueError: error:060800A3: # digital envelope routines: EVP_DigestInit_ex: disabled for fips # # Newer versions of Python, including Centos8's patched Python3.6 and # mainline Python 3.9+ have a "usedoforsecurity" parameter which allows us # to continue using hashlib.md5(). pass return core.decode(result) 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.12.0/cola/guicmds.py000066400000000000000000000222241417222504200162200ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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 = '@{upstream}..' 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_soft(context): title = N_('Reset Branch (Soft)') ok_text = N_('Reset Branch') ref = choose_ref(context, title, ok_text, default='HEAD^') if ref: cmds.do(cmds.ResetSoft, context, ref) def reset_mixed(context): title = N_('Reset Branch and Stage (Mixed)') ok_text = N_('Reset') ref = choose_ref(context, title, ok_text, default='HEAD^') if ref: cmds.do(cmds.ResetMixed, context, ref) def reset_keep(context): title = N_('Reset All (Keep Unstaged Changes)') ref = choose_ref(context, title, N_('Reset and Restore')) if ref: cmds.do(cmds.ResetKeep, context, ref) def reset_merge(context): title = N_('Restore Worktree and Reset All (Merge)') ok_text = N_('Reset and Restore') ref = choose_ref(context, title, ok_text, default='HEAD^') if ref: cmds.do(cmds.ResetMerge, context, ref) def reset_hard(context): title = N_('Restore Worktree and Reset All (Hard)') ok_text = N_('Reset and Restore') ref = choose_ref(context, title, ok_text, default='HEAD^') if ref: cmds.do(cmds.ResetHard, context, ref) def restore_worktree(context): title = N_('Restore Worktree') ok_text = N_('Restore Worktree') ref = choose_ref(context, title, ok_text, default='HEAD^') if ref: cmds.do(cmds.RestoreWorktree, context, ref) def install(): """Install the GUI-model interaction hooks""" Interaction.choose_ref = staticmethod(choose_ref) git-cola-3.12.0/cola/hidpi.py000066400000000000000000000024031417222504200156570ustar00rootroot00000000000000"""Provides High DPI support by wrapping Qt options""" from __future__ import absolute_import, division, print_function, 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.12.0/cola/hotkeys.py000066400000000000000000000104071417222504200162530ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, unicode_literals 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_SHORT = hotkey(Qt.Key_E) 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) GOTO_END = hotkey(Qt.SHIFT + Qt.Key_G) GOTO_START = hotkey(Qt.Key_G, Qt.Key_G) # gg 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_DIFF_ALT = hotkey(Qt.SHIFT + Qt.Key_S) STAGE_SELECTION = hotkey(Qt.CTRL + Qt.Key_S) STAGE_ALL = hotkey(Qt.CTRL + Qt.SHIFT + 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) APPLY = 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 # Text navigation DOWN = hotkey(Qt.Key_D) UP = hotkey(Qt.Key_U) SELECT_FORWARD = hotkey(Qt.SHIFT + Qt.Key_F) SELECT_BACK = hotkey(Qt.SHIFT + Qt.Key_B) SELECT_DOWN = hotkey(Qt.SHIFT + Qt.Key_D) SELECT_UP = hotkey(Qt.SHIFT + Qt.Key_U) git-cola-3.12.0/cola/i18n.py000066400000000000000000000056251417222504200153520ustar00rootroot00000000000000"""i18n and l10n support for git-cola""" from __future__ import absolute_import, division, print_function, 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 # pylint: disable=all try: import ctypes # pylint: disable=all 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.12.0/cola/icons.py000066400000000000000000000172441417222504200157060ustar00rootroot00000000000000"""The only file where icon filenames are mentioned""" from __future__ import absolute_import, division, print_function, 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 three_bars(): return icon('three-bars.svg') def add(): return from_theme('list-add', fallback='plus.svg') def alphabetical(): return from_theme('view-sort', fallback='a-z-order.svg') def branch(): return icon('git-branch.svg') def check_name(): return name_from_basename('check.svg') def cherry_pick(): return icon('git-commit.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 cut(): return from_theme('edit-cut', fallback='edit-cut.svg') def copy(): return from_theme('edit-copy', fallback='edit-copy.svg') def paste(): return from_theme('edit-paste', fallback='edit-paste.svg') def delete(): return from_theme('edit-delete', fallback='trashcan.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 from_theme('delete', fallback='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 from_theme('folder', fallback='folder.svg') def directory(): return from_theme('folder', fallback='file-directory.svg') def diff(): return icon('diff.svg') def edit(): return from_theme('document-edit', fallback='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 move_down(): return from_theme('go-previous', fallback='arrow-down.svg') def move_up(): return from_theme('go-next', fallback='arrow-up.svg') def new(): return from_theme('list-add', fallback='folder-new.svg') def ok(): return from_theme('checkmark', fallback='check.svg') def open_directory(): return from_theme('folder', fallback='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 from_theme('document-save', fallback='desktop-download.svg') def search(): return from_theme('search', fallback='search.svg') def select_all(): return from_theme('edit-select-all', fallback='edit-select-all') 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 redo(): return from_theme('edit-redo', fallback='edit-redo.svg') def style_dialog_apply(): return from_style(QtWidgets.QStyle.SP_DialogApplyButton) def style_dialog_discard(): return from_style(QtWidgets.QStyle.SP_DialogDiscardButton) def style_dialog_reset(): return from_style(QtWidgets.QStyle.SP_DialogResetButton) 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 from_theme('zoom-fit-best', fallback='zoom-fit-best.svg') def zoom_in(): return from_theme('zoom-in', fallback='zoom-in.svg') def zoom_out(): return from_theme('zoom-out', fallback='zoom-out.svg') git-cola-3.12.0/cola/inotify.py000066400000000000000000000043321417222504200162460ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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.12.0/cola/interaction.py000066400000000000000000000110341417222504200171010ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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 ) sys.stdout.flush() @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) sys.stdout.flush() 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.12.0/cola/main.py000066400000000000000000000503221417222504200155110ustar00rootroot00000000000000"""Launcher and command line interface to git-cola""" from __future__ import absolute_import, division, print_function, unicode_literals import argparse import sys from . import app from . import cmds from . import compat 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() # Newer versions of argparse (Python 3.6+) emit an error message for # "--help-commands" unless we register the flag on the main parser. if compat.PY_VERSION >= (3, 6): add_help_options(parser) parser.set_defaults(func=lambda _: parser.print_help()) 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_help_options(parser): """Add the --help-commands flag to the parser""" parser.add_argument( '--help-commands', default=False, action='store_true', help='show available sub-commands', ) 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' ) add_help_options(parser) 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 # pylint: disable=all 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) 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 # pylint: disable=all 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 # pylint: disable=all 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 # pylint: disable=all 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 # pylint: disable=all context = app.application_init(args, update=True) view = create_new_branch(context) return app.application_start(context, view) def cmd_browse(args): from .widgets.browse import worktree_browser # pylint: disable=all context = app.application_init(args) view = worktree_browser(context, show=False, update=False) return app.application_start(context, view) def cmd_clone(args): from .widgets import clone # pylint: disable=all context = app.application_init(args) view = clone.clone(context) 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 # pylint: disable=all context = app.application_init(args) view = preferences(context) return app.application_start(context, view) def cmd_dag(args): from .widgets import dag # pylint: disable=all 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, show=False) return app.application_start(context, view) def cmd_diff(args): from .difftool import diff_expression # pylint: disable=all 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 # pylint: disable=all 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 # pylint: disable=all 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 # pylint: disable=all 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 # pylint: disable=all 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 # pylint: disable=all version.print_version(brief=args.brief, build=args.build) return 0 def cmd_pull(args): from .widgets import remote # pylint: disable=all 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 # pylint: disable=all 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 # pylint: disable=all 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 # pylint: disable=all 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 # pylint: disable=all context = app.application_init(args) view = search(context) return app.application_start(context, view) def cmd_stash(args): from .widgets import stash # pylint: disable=all 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 # pylint: disable=all context = app.application_init(args) view = new_create_tag(context, name=args.name, ref=args.ref, sign=args.sign) 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.12.0/cola/models/000077500000000000000000000000001417222504200154745ustar00rootroot00000000000000git-cola-3.12.0/cola/models/__init__.py000066400000000000000000000000001417222504200175730ustar00rootroot00000000000000git-cola-3.12.0/cola/models/browse.py000066400000000000000000000310601417222504200173470ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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: 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.12.0/cola/models/dag.py000066400000000000000000000215231417222504200166040ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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 main # commit bdb0f6788fa5e3cacc4315e9ff318a27b2676ff4 (HEAD, main) # ... # # 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 main # commit bdb0f6788fa5e3cacc4315e9ff318a27b2676ff4 (HEAD -> main) # ... # # 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.12.0/cola/models/main.py000066400000000000000000000427351417222504200170050ustar00rootroot00000000000000"""The central cola model""" from __future__ import absolute_import, division, print_function, 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) # pylint: disable=too-many-public-methods 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_previous_contents = 'previous_contents' message_commit_message_changed = 'commit_message_changed' message_diff_text_changed = 'diff_text_changed' message_diff_text_updated = 'diff_text_updated' # "diff_type" {text,image} represents the diff viewer mode. message_diff_type_changed = 'diff_type_changed' # "file_type" {text,image} represents the selected file type. message_file_type_changed = 'file_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_untracked_diff = 'untracked-diff' # Diffing 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_diff)) # 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 = Types.TEXT self.file_type = Types.TEXT 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.cfg.hooks_path('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""" changed = diff_type != self.diff_type self.diff_type = diff_type if changed: self.notify_observers(self.message_diff_type_changed, diff_type) def set_file_type(self, file_type): # text, image """Set the file type to either text or image""" changed = file_type != self.file_type self.file_type = file_type if changed: self.notify_observers(self.message_file_type_changed, file_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_previous_contents, self.staged, self.unmerged, self.modified, self.untracked ) 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() class Types(object): """File types (used for image diff modes)""" IMAGE = 'image' TEXT = 'text' # 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.12.0/cola/models/prefs.py000066400000000000000000000176051417222504200171760ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, unicode_literals import sys from .. import core from .. import hidpi from .. import observable from .. import utils from ..cmd import Command AUTOCOMPLETE_PATHS = 'cola.autocompletepaths' AUTOTEMPLATE = 'cola.autoloadcommittemplate' BACKGROUND_EDITOR = 'cola.backgroundeditor' BLAME_VIEWER = 'cola.blameviewer' BOLD_HEADERS = 'cola.boldheaders' CHECK_CONFLICTS = 'cola.checkconflicts' CHECK_PUBLISHED_COMMITS = 'cola.checkpublishedcommits' COMMENT_CHAR = 'core.commentchar' DIFFCONTEXT = 'gui.diffcontext' DIFFTOOL = 'diff.tool' DISPLAY_UNTRACKED = 'gui.displayuntracked' EDITOR = 'gui.editor' EXPANDTAB = 'cola.expandtab' FONTDIFF = 'cola.fontdiff' HIDPI = 'cola.hidpi' 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' RESIZE_BROWSER_COLUMNS = 'cola.resizebrowsercolumns' SAFE_MODE = 'cola.safemode' SAVEWINDOWSETTINGS = 'cola.savewindowsettings' SHOW_PATH = 'cola.showpath' SORT_BOOKMARKS = 'cola.sortbookmarks' SPELL_CHECK = 'cola.spellcheck' STATUS_INDENT = 'cola.statusindent' STATUS_SHOW_TOTALS = 'cola.statusshowtotals' THEME = 'cola.theme' TABWIDTH = 'cola.tabwidth' TEXTWIDTH = 'cola.textwidth' USER_EMAIL = 'user.email' USER_NAME = 'user.name' 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 check_published_commits = 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 resize_browser_columns = False 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): """Return the configured "blame" viewer""" default = Defaults.blame_viewer return context.cfg.get(BLAME_VIEWER, default=default) def bold_headers(context): """Should we bold the Status column headers?""" return context.cfg.get(BOLD_HEADERS, default=Defaults.bold_headers) def check_conflicts(context): """Should we check for merge conflict markers in unmerged files?""" return context.cfg.get(CHECK_CONFLICTS, default=Defaults.check_conflicts) def check_published_commits(context): """Should we check for published commits when amending?""" return context.cfg.get( CHECK_PUBLISHED_COMMITS, default=Defaults.check_published_commits ) def display_untracked(context): """Should we display untracked files?""" return context.cfg.get(DISPLAY_UNTRACKED, default=Defaults.display_untracked) def editor(context): """Return the configured editor""" app = context.cfg.get(EDITOR, default=Defaults.editor) return _remap_editor(app) def background_editor(context): """Return the configured non-blocking background editor""" app = context.cfg.get(BACKGROUND_EDITOR, default=editor(context)) return _remap_editor(app) def _remap_editor(app): """Remap a configured editorinto a visual editor name""" # We do this for vim users because this configuration is convenient. return {'vim': 'gvim -f'}.get(app, app) def comment_char(context): """Return the configured git commit comment character""" return context.cfg.get(COMMENT_CHAR, default=Defaults.comment_char) def default_history_browser(): """Return the default history browser (e.g. git-dag, gitk)""" 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): """Return the configured history browser""" default = default_history_browser() return context.cfg.get(HISTORY_BROWSER, default=default) def linebreak(context): """Should we word-wrap lines in the commit message editor?""" return context.cfg.get(LINEBREAK, default=Defaults.linebreak) def maxrecent(context): """Return the configured maximum number of Recent Repositories""" value = Defaults.maxrecent if context: value = context.cfg.get(MAXRECENT, default=value) return value def spellcheck(context): """Should we spellcheck commit messages?""" return context.cfg.get(SPELL_CHECK, default=Defaults.spellcheck) def expandtab(context): """Should we expand tabs in commit messages?""" return context.cfg.get(EXPANDTAB, default=Defaults.expandtab) def sort_bookmarks(context): """Should we sort bookmarks by name?""" return context.cfg.get(SORT_BOOKMARKS, default=Defaults.sort_bookmarks) def tabwidth(context): """Return the configured tab width in the commit message editor""" return context.cfg.get(TABWIDTH, default=Defaults.tabwidth) def textwidth(context): """Return the configured text width for word wrapping commit messages""" return context.cfg.get(TEXTWIDTH, default=Defaults.textwidth) def status_indent(context): """Should we indent items in the status widget?""" return context.cfg.get(STATUS_INDENT, default=Defaults.status_indent) def status_show_totals(context): """Should we display count totals in the status widget headers?""" return context.cfg.get(STATUS_SHOW_TOTALS, default=Defaults.status_show_totals) class PreferencesModel(observable.Observable): """Interact with repo-local and user-global git config preferences""" 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): """Set a configuration 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): """Get a configured value""" 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): """Modify the model and store the updated configuration""" self.old_value = self.model.get_config(self.source, self.config) self.model.set_config(self.source, self.config, self.value) def undo(self): """Restore the configuration change to its original value""" if self.old_value is None: return self.model.set_config(self.source, self.config, self.old_value) git-cola-3.12.0/cola/models/selection.py000066400000000000000000000066361417222504200200460ustar00rootroot00000000000000"""Provides a selection model to handle selection.""" from __future__ import absolute_import, division, print_function, 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.12.0/cola/models/stash.py000066400000000000000000000147701417222504200172010ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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.12.0/cola/observable.py000066400000000000000000000020711417222504200167070ustar00rootroot00000000000000"""The Observable class for decoupled notifications""" from __future__ import absolute_import, division, print_function, 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.12.0/cola/qtcompat.py000066400000000000000000000032341417222504200164150ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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.12.0/cola/qtutils.py000066400000000000000000001000141417222504200162640ustar00rootroot00000000000000"""Miscellaneous Qt utility functions.""" from __future__ import absolute_import, division, print_function, 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) if not utils.is_darwin() and not utils.is_win32(): 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) icon = icons.name_from_basename(icon_name) return TreeWidgetItem(filename, icon, 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(name, 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(name) 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() if hasattr(self, 'setToolTipsVisible'): self.setToolTipsVisible(True) 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) if hasattr(parent, 'addMenu'): parent.addMenu(menu) else: 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.default_icon, defs.default_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): """Block Qt signals for all of the captured widgets""" self.values = [widget.blockSignals(True) for widget in self.widgets] return self def __exit__(self, exc_type, exc_val, exc_tb): """Restore Qt signals when we exit the scope""" for (widget, value) in zip(self.widgets, self.values): widget.blockSignals(value) 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, light): return QtGui.QColor.fromHslF( utils.clamp(h, 0.0, 1.0), utils.clamp(s, 0.0, 1.0), utils.clamp(light, 0.0, 1.0) ) def hsl_css(h, s, light): return rgb_css(hsl(h, s, light)) 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 def set_scrollbar_values(widget, hscroll_value, vscroll_value): """Set scrollbars to the specified values""" hscroll = widget.horizontalScrollBar() if hscroll and hscroll_value is not None: hscroll.setValue(hscroll_value) vscroll = widget.verticalScrollBar() if vscroll and vscroll_value is not None: vscroll.setValue(vscroll_value) def get_scrollbar_values(widget): """Return the current (hscroll, vscroll) scrollbar values for a widget""" hscroll = widget.horizontalScrollBar() if hscroll: hscroll_value = get(hscroll) else: hscroll_value = None vscroll = widget.verticalScrollBar() if vscroll: vscroll_value = get(vscroll) else: vscroll_value = None return (hscroll_value, vscroll_value) def scroll_to_item(widget, item): """Scroll to an item while retaining the horizontal scroll position""" hscroll = None hscrollbar = widget.horizontalScrollBar() if hscrollbar: hscroll = get(hscrollbar) widget.scrollToItem(item) if hscroll is not None: hscrollbar.setValue(hscroll) def select_item(widget, item): """Scroll to and make a QTreeWidget item selected and current""" scroll_to_item(widget, item) widget.setCurrentItem(item) item.setSelected(True) def get_selected_values(widget, top_level_idx, values): """Map the selected items under the top-level item to the values list""" # Get the top-level item item = widget.topLevelItem(top_level_idx) return tree_selection(item, values) def get_selected_items(widget, idx): """Return the selected items under the top-level item""" item = widget.topLevelItem(idx) return tree_selection_items(item) git-cola-3.12.0/cola/resources.py000066400000000000000000000064031417222504200166000ustar00rootroot00000000000000"""Functions for finding cola resources""" from __future__ import absolute_import, division, print_function, unicode_literals import os from os.path import dirname import webbrowser from . import core from . import compat # Default git-cola icon theme _default_icon_theme = 'light' _modpath = core.abspath(core.realpath(__file__)) if ( os.path.join('share', 'git-cola', 'lib') in _modpath or os.path.join('site-packages', 'cola') 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 get_prefix(): """Return the installation prefix""" return _prefix def prefix(*args): """Return a path relative to cola's installation prefix""" return os.path.join(get_prefix(), *args) def command(name): """Return a command from the bin/ directory""" if compat.WIN32: # Check for "${name}.exe" on Windows. path = prefix('bin', name) exe_path = prefix('bin', '%s.exe' % name) if core.exists(exe_path): result = exe_path else: result = path else: result = prefix('bin', name) return result 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.12.0/cola/sequenceeditor.py000066400000000000000000000504601417222504200176070ustar00rootroot00000000000000# flake8: noqa from __future__ import absolute_import, division, print_function, unicode_literals import sys import re from argparse import ArgumentParser from functools import partial 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 filelist 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-cola-sequence-editor 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 winmain(): """Windows git-cola-sequence-editor entrypoint""" return app.winmain(main) 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 = MainWindow(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 MainWindow(standard.MainWindow): """The main git-cola application window""" def __init__(self, context, parent=None): super(MainWindow, self).__init__(parent) self.context = context self.status = 1 self.editor = None default_title = '%s - git cola seqeuence editor' % core.getcwd() title = core.getenv('GIT_COLA_SEQ_EDITOR_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(context.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_COLA_SEQ_EDITOR_CANCEL_ACTION', 'abort') self.notifier = notifier = observable.Observable() self.diff = diff.DiffWidget(context, notifier, self) self.tree = RebaseTreeWidget(context, notifier, comment_char, self) self.filewidget = filelist.FileWidget(context, notifier, self) self.setFocusProxy(self.tree) self.rebase_button = qtutils.create_button( text=core.getenv('GIT_COLA_SEQ_EDITOR_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(), ) top = qtutils.splitter(Qt.Horizontal, self.tree, self.filewidget) top.setSizes([75, 25]) main_split = qtutils.splitter(Qt.Vertical, top, self.diff) main_split.setSizes([25, 75]) 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, main_split, 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-cola-sequence-editor') return text.text_dialog(context, help_text, title) git-cola-3.12.0/cola/settings.py000066400000000000000000000235351417222504200164330ustar00rootroot00000000000000"""Save settings, bookmarks, etc.""" from __future__ import absolute_import, division, print_function, unicode_literals import json import os import sys from . import core from . import display 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_bookmarks(self): """Remove "favorites" bookmarks that no longer exist""" missing_bookmarks = [] 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 def remove_missing_recent(self): """Remove "recent" repositories that no longer exist""" missing_recent = [] 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': display.normalize_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': display.normalize_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): normalize = display.normalize_path path = normalize(path) try: index = [normalize(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""" normalize = display.normalize_path path = normalize(path) try: index = [normalize(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, path=None): self.values.update(self.asdict(path=path)) self.upgrade_settings() return True @staticmethod def read(verify=git.is_git_worktree): """Load settings from disk""" settings = Settings(verify=verify) settings.load() return settings def upgrade_settings(self): """Upgrade git-cola settings""" # Upgrade bookmarks to the new dict-based bookmarks format. normalize = display.normalize_path if self.bookmarks and not isinstance(self.bookmarks[0], dict): bookmarks = [ dict(name=os.path.basename(path), path=normalize(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=normalize(path)) for path in self.recent ] self.values['recent'] = recent def asdict(self, path=None): if not path: 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) for key in self.values: try: values[key] = json_values[key] except KeyError: pass # Ensure that all stored bookmarks use normalized paths ("/" only). normalize = display.normalize_path for entry in values.get('bookmarks', []): entry['path'] = normalize(entry['path']) for entry in values.get('recent', []): entry['path'] = normalize(entry['path']) return values 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): normalize = display.normalize_path path = normalize(path) 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 result = True else: result = False return result class Session(Settings): """Store per-session settings XDG sessions are created by the QApplication::commitData() callback. These sessions are stored once, and loaded once. They are deleted once loaded. The behavior of path() is such that it forgets its session path() and behaves like a return Settings object after the session has been loaded once. Once the session is loaded, it is removed and further calls to save() will save to the usual $XDG_CONFIG_HOME/git-cola/settings location. """ _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}) self.expired = False def session_path(self): """The session-specific session file""" return os.path.join(self._sessions_dir, self.session_id) def path(self): base_path = super(Session, self).path() if self.expired: path = base_path else: path = self.session_path() if not os.path.exists(path): path = base_path return path def load(self, path=None): """Load the session and expire it for future loads The session should be loaded only once. We remove the session file when it's loaded, and set the session to be expired. This results in future calls to load() and save() using the default Settings path rather than the session-specific path. The use case for sessions is when the user logs out with apps running. We will restore their state, and if they then shutdown, it'll be just like a normal shutdown and settings will be stored to ~/.config/git-cola/settings instead of the session path. This is accomplished by "expiring" the session after it has been loaded initially. """ result = super(Session, self).load(path=path) # This is the initial load, so expire the session and remove the # session state file. Future calls will be equivalent to # Settings.load(). if not self.expired: self.expired = True path = self.session_path() if core.exists(path): try: os.unlink(path) except (OSError, ValueError): pass return True return False return result def update(self): """Reload settings from the base settings path""" # This method does not expire the session. path = super(Session, self).path() return super(Session, self).load(path=path) git-cola-3.12.0/cola/spellcheck.py000066400000000000000000000062621417222504200167060ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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.12.0/cola/textwrap.py000066400000000000000000000221011417222504200164350ustar00rootroot00000000000000"""Text wrapping and filling""" from __future__ import absolute_import, division, print_function, 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.12.0/cola/themes.py000066400000000000000000000447431417222504200160640ustar00rootroot00000000000000"""Themes generators""" from __future__ import absolute_import, division, print_function, 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.12.0/cola/utils.py000066400000000000000000000235241417222504200157310ustar00rootroot00000000000000"""Miscellaneous utility functions""" from __future__ import absolute_import, division, print_function, 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 split(name): """Split a path-like name. Returns tuple "(head, tail)" where "tail" is everything after the final slash. The "head" may be empty. This is the same as os.path.split() but only uses '/' as the delimiter. >>> split('a/b/c') ('a/b', 'c') >>> split('xyz') ('', 'xyz') """ return (dirname(name), basename(name)) def join(*paths): """Join paths using '/' regardless of platform >>> join('a', 'b', 'c') 'a/b/c' """ return '/'.join(paths) def normalize_slash(value): """Strip and normalize slashes in a string >>> normalize_slash('///Meow///Cat///') 'Meow/Cat' """ value = value.strip('/') new_value = value.replace('//', '/') while new_value != value: value = new_value new_value = value.replace('//', '/') return value def pathjoin(paths): """Join a list of paths using '/' regardless of platform >>> pathjoin(['a', 'b', 'c']) 'a/b/c' """ 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.12.0/cola/version.py000066400000000000000000000067011417222504200162540ustar00rootroot00000000000000"""Provide git-cola's version number""" from __future__ import absolute_import, division, print_function, 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 submodule update --recursive was introduced in 1.6.5 'submodule-update-recursive': '1.6.5', # git include.path pseudo-variable was introduced in 1.7.10 'config-includes': '1.7.10', # 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.12.0/cola/widgets/000077500000000000000000000000001417222504200156575ustar00rootroot00000000000000git-cola-3.12.0/cola/widgets/__init__.py000066400000000000000000000000001417222504200177560ustar00rootroot00000000000000git-cola-3.12.0/cola/widgets/about.py000066400000000000000000000453021417222504200173470ustar00rootroot00000000000000# encoding: utf-8 from __future__ import absolute_import, division, print_function, 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(2, 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-2020 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='Uri Okrent', title=N_('Developer')), dict(name='Javier Rodriguez Cuevas', 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='Ville Skyttä', title=N_('Developer')), dict(name='Szymon Judasz', title=N_('Developer')), dict(name='jm4R', title=N_('Developer')), dict(name='Stanislaw Halik', title=N_('Developer')), dict(name='Igor Galarraga', title=N_('Developer')), dict(name='Virgil Dupras', title=N_('Developer')), dict(name='wsdfhjxc', title=N_('Developer')), dict(name='Barry Roberts', 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='Pavel Rehak', title=N_('Developer')), dict(name='Benedict Lee', title=N_('Developer')), dict(name='Tim Brown', title=N_('Developer')), dict(name='Steffen Prohaska', title=N_('Developer')), dict(name='Filip Danilović', title=N_('Developer')), dict(name='NotSqrt', title=N_('Developer')), dict(name='Michael Geddes', title=N_('Developer')), dict(name='Rustam Safin', title=N_('Developer')), dict(name='Justin Lecher', 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='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='Victor Gambier', title=N_('Developer')), dict(name='bsomers', title=N_('Developer')), dict(name='real', title=N_('Developer')), dict(name='v.paritskiy', title=N_('Developer')), dict(name='vanderkoort', title=N_('Developer')), dict(name='wm4', title=N_('Developer')), dict(name='Audrius Karabanovas', 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='Jakub Szymański', title=N_('Developer')), dict(name='ochristi', title=N_('Developer')), dict(name='Miguel Boekhold', title=N_('Developer')), dict(name='MiguelBoekhold', title=N_('Developer')), dict(name='Mikhail Terekhov', title=N_('Developer')), dict(name='Jake Biesinger', title=N_('Developer')), dict(name='Iulian Udrea', 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='Ilya Tumaykin', 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='George Vasilakos', title=N_('Developer')), dict(name="Samsul Ma'arif", title=N_('Developer')), dict(name='Sebastian Brass', title=N_('Developer')), dict(name='Arthur Coelho', title=N_('Developer')), dict(name='Simon Peeters', title=N_('Developer')), dict(name='Felipe Morales', title=N_('Developer')), dict(name='David Zumbrunnen', title=N_('Developer')), dict(name='David Schwörer', title=N_('Developer')), dict(name='Stephen', title=N_('Developer')), dict(name='Andrej', title=N_('Developer')), dict(name='Daniel Pavel', title=N_('Developer')), dict(name='Daniel King', title=N_('Developer')), dict(name='Daniel Haskin', title=N_('Developer')), dict(name='Clément Pit--Claudel', title=N_('Developer')), dict(name='Vaibhav Sagar', title=N_('Developer')), dict(name='Ved Vyas', title=N_('Developer')), dict(name='Adrien be', title=N_('Developer')), dict(name='Charles', title=N_('Developer')), dict(name='Boris W', title=N_('Developer')), dict(name='Ben Boeckel', 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='Jamie Pate', title=N_('Developer')), dict(name='Jean-Francois Dagenais', title=N_('Developer')), dict(name='Joachim Lusiardi', title=N_('Developer')), dict(name='0xflotus', title=N_('Developer')), dict(name='AJ Bagwell', title=N_('Developer')), dict(name='Barrett Lowe', 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')), ) 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='Zhang Han', title=N_('Simplified Chinese translation')), dict(name='Victorhck', title=N_('Spanish translation')), dict(name='Vitor Lobo', title=N_('Brazilian translation')), dict(name='Igor Kopach', title=N_('Ukranian translation')), dict(name='Łukasz Wojniłowicz', title=N_('Polish translation')), dict(name='Rafael Nascimento', title=N_('Brazilian translation')), dict(name='Barış ÇELİK', title=N_('Turkish translation')), dict(name='Minarto Margoliono', title=N_('Indonesian translation')), dict(name='Sven Claussner', title=N_('German translation')), dict(name='Shun Sakai', title=N_('Japanese translation')), dict(name='Vaiz', title=N_('Russian translation')), dict(name='adlgrbz', title=N_('Turkish translation')), dict(name='fu7mu4', title=N_('Japanese translation')), dict(name='Guo Yunhe', title=N_('Simplified Chinese translation')), dict(name="Samsul Ma'arif", title=N_('Indonesian 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='Balázs Meskó', title=N_('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='林博仁(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 # pylint: disable=all 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.12.0/cola/widgets/action.py000066400000000000000000000061521417222504200175120ustar00rootroot00000000000000"""Actions widget""" from __future__ import absolute_import, division, print_function, 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(10, 10)) 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.12.0/cola/widgets/archive.py000066400000000000000000000204621417222504200176560ustar00rootroot00000000000000"""Git Archive dialog""" from __future__ import absolute_import, division, print_function, 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.12.0/cola/widgets/bookmarks.py000066400000000000000000000321461417222504200202270ustar00rootroot00000000000000"""Provides widgets related to bookmarks""" from __future__ import absolute_import, division, print_function, 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 ..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.context = context self.style = style self.tree = BookmarksTreeWidget(context, style, 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.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, parent=None): standard.TreeWidget.__init__(self, parent=parent) self.context = context self.style = style 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 ) self.remove_missing_action = qtutils.add_action( self, N_('Prune Missing Entries'), self.remove_missing ) self.remove_missing_action.setToolTip( N_('Remove stale entries for repositories that no longer exist') ) # 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 = context.settings builder = BuildItem(context) # bookmarks if self.style == BOOKMARKS: entries = settings.bookmarks # recent items elif self.style == RECENT_REPOS: 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.addAction(self.remove_missing_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): settings = self.context.settings if self.style == BOOKMARKS: rename = settings.rename_bookmark elif self.style == RECENT_REPOS: rename = settings.rename_recent else: rename = disable_rename if rename(item.path, item.name, new_name): 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): settings = self.context.settings settings.load() settings.add_bookmark(normpath, name) 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, item.path, item.name, icon=icons.discard()) if ok: self.refresh() def remove_missing(self): """Remove missing entries from the favorites/recent file list""" settings = self.context.settings if self.style == BOOKMARKS: settings.remove_missing_bookmarks() elif self.style == RECENT_REPOS: settings.remove_missing_recent() 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.12.0/cola/widgets/branch.py000066400000000000000000000606031417222504200174730ustar00rootroot00000000000000"""Provides widgets related to branches""" from __future__ import absolute_import, division, print_function, 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.12.0/cola/widgets/browse.py000066400000000000000000000700311417222504200175330ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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, show=True): """Create a new worktree browser""" view = Browser(context, parent, update=update) 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): standard.Widget.__init__(self, parent) 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(context.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._columns_sized = 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(force=True) 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, force=False): """Set the column widths.""" cfg = self.context.cfg should_resize = cfg.get('cola.resizebrowsercolumns', default=False) if not force and not should_resize: return 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 # Resize the columns once when cola.resizebrowsercolumns is False. # This provides a good initial size since we will not be resizing # the columns during expand/collapse. if not self._columns_sized: self._columns_sized = True self.size_columns(force=True) 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.12.0/cola/widgets/cfgactions.py000066400000000000000000000251531417222504200203570ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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(10, 10) self.argstxt.setMinimumSize(10, 10) 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.12.0/cola/widgets/clone.py000066400000000000000000000155121417222504200173350ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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, 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, progress, task_finished, spawn) def clone_repo(context, parent, show, 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) prompt.result.connect(fn) return prompt def prompt_for_clone(context, show=True): """Presents a GUI for cloning a repository""" view = Clone(context, 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, 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(context.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.12.0/cola/widgets/commitmsg.py000066400000000000000000000602141417222504200202330ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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() 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.setIcon(icons.style_dialog_apply()) self.signoff_action.setToolTip(N_('Sign off on this commit')) self.commit_action = qtutils.add_action( self, N_('Commit@@verb'), self.commit, hotkeys.APPLY ) 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_at_line(context, self) self.launch_difftool = actions.launch_difftool(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, 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.setIcon(icons.edit()) 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.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.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 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) with qtutils.BlockSignals(self.autowrap_action): self.autowrap_action.setChecked(brk) 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 with qtutils.BlockSignals(self.amend_action): self.amend_action.setEnabled(can_amend) self.amend_action.setChecked(checked) 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) check_published = prefs.check_published_commits(context) if ( amend and check_published 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(fm.width('MMMM'), 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.12.0/cola/widgets/common.py000066400000000000000000000040421417222504200175210ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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.12.0/cola/widgets/compare.py000066400000000000000000000217711417222504200176670ustar00rootroot00000000000000"""Provides dialogs for comparing branches and commits.""" from __future__ import absolute_import, division, print_function, 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/main' in remote_branches: return gitcmds.merge_base(context, branch, 'origin/main') 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.12.0/cola/widgets/completion.py000066400000000000000000000650621417222504200204130ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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 try: self.wait() except RuntimeError: # The C++ object may have already been deleted by python while # the application is tearing down. This is fine. pass 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.12.0/cola/widgets/createbranch.py000066400000000000000000000277031417222504200206630ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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=''): """Launches a dialog for creating a new branch""" view = CreateBranchDialog(context, 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, 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=context.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.12.0/cola/widgets/createtag.py000066400000000000000000000101441417222504200201700ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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, parent=None): """Entry point for external callers.""" opts = TagOptions(name, ref, sign) view = CreateTag(context, opts, parent=parent) return view def create_tag(context, name='', ref='', sign=False): """Entry point for external callers.""" view = new_create_tag( context, name=name, ref=ref, sign=sign, 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, 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) settings = context.settings 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.12.0/cola/widgets/dag.py000066400000000000000000002222521417222504200167710ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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, 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) 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_mixed(self): context = self.context self.with_oid(lambda oid: cmds.do(cmds.ResetMixed, context, ref=oid)) def reset_keep(self): context = self.context self.with_oid(lambda oid: cmds.do(cmds.ResetKeep, 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 restore_worktree(self): context = self.context self.with_oid(lambda oid: cmds.do(cmds.RestoreWorktree, 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_mixed'].setEnabled(has_single_selection) self.menu_actions['reset_keep'].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['restore_worktree'].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_soft']) reset_menu.addAction(self.menu_actions['reset_mixed']) reset_menu.addAction(self.menu_actions['restore_worktree']) reset_menu.addSeparator() reset_menu.addAction(self.menu_actions['reset_keep']) reset_menu.addAction(self.menu_actions['reset_merge']) 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 set_icon(icon, action): """"Set the icon for an action and return the action""" action.setIcon(icon) return action def viewer_actions(widget): return { 'diff_this_selected': set_icon( icons.compare(), qtutils.add_action( widget, N_('Diff this -> selected'), widget.proxy.diff_this_selected ), ), 'diff_selected_this': set_icon( icons.compare(), qtutils.add_action( widget, N_('Diff selected -> this'), widget.proxy.diff_selected_this ), ), 'create_branch': set_icon( icons.branch(), qtutils.add_action(widget, N_('Create Branch'), widget.proxy.create_branch), ), 'create_patch': set_icon( icons.save(), qtutils.add_action(widget, N_('Create Patch'), widget.proxy.create_patch), ), 'create_tag': set_icon( icons.tag(), qtutils.add_action(widget, N_('Create Tag'), widget.proxy.create_tag), ), 'create_tarball': set_icon( icons.file_zip(), qtutils.add_action( widget, N_('Save As Tarball/Zip...'), widget.proxy.create_tarball ), ), 'cherry_pick': set_icon( icons.cherry_pick(), qtutils.add_action(widget, N_('Cherry Pick'), widget.proxy.cherry_pick), ), 'revert': set_icon( icons.undo(), qtutils.add_action(widget, N_('Revert'), widget.proxy.revert) ), 'diff_commit': set_icon( icons.diff(), qtutils.add_action( widget, N_('Launch Diff Tool'), widget.proxy.show_diff, hotkeys.DIFF ), ), 'diff_commit_all': set_icon( icons.diff(), 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_soft': set_icon( icons.style_dialog_reset(), qtutils.add_action( widget, N_('Reset Branch (Soft)'), widget.proxy.reset_soft ), ), 'reset_mixed': set_icon( icons.style_dialog_reset(), qtutils.add_action( widget, N_('Reset Branch and Stage (Mixed)'), widget.proxy.reset_mixed ), ), 'reset_keep': set_icon( icons.style_dialog_reset(), qtutils.add_action( widget, N_('Restore Worktree and Reset All (Keep Unstaged Edits)'), widget.proxy.reset_keep, ), ), 'reset_merge': set_icon( icons.style_dialog_reset(), qtutils.add_action( widget, N_('Restore Worktree and Reset All (Merge)'), widget.proxy.reset_merge, ), ), 'reset_hard': set_icon( icons.style_dialog_reset(), qtutils.add_action( widget, N_('Restore Worktree and Reset All (Hard)'), widget.proxy.reset_hard, ), ), 'restore_worktree': set_icon( icons.edit(), qtutils.add_action( widget, N_('Restore Worktree'), widget.proxy.restore_worktree ), ), 'save_blob': set_icon( icons.save(), qtutils.add_action( widget, N_('Grab File...'), widget.proxy.save_blob_dialog ), ), 'copy': set_icon( icons.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): 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.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('Log', 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('Files', N_('Files'), self) self.file_dock.setWidget(self.filewidget) self.diff_dock = qtutils.create_dock('Diff', 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('Graph', 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(context.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) 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): """Disable notifications during sections that cause notification loops""" 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) 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) text_pen = QtGui.QPen() text_pen.setColor(QtGui.QColor(Qt.darkGray)) text_pen.setWidth(1) 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 with qtutils.BlockSignals(item): item.setSelected(True) 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 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.12.0/cola/widgets/defs.py000066400000000000000000000016141417222504200171540ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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) default_icon = scale(16) 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.12.0/cola/widgets/diff.py000066400000000000000000001212261417222504200171450ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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 main 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) diff_type_changed = Signal(object) file_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.diff_type_changed.emit) self.diff_type_changed.connect(self.set_diff_type, type=Qt.QueuedConnection) # Observe the file type file_type_msg = model.message_file_type_changed model.add_observer(file_type_msg, self.file_type_changed.emit) self.file_type_changed.connect(self.set_file_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.options.show_line_numbers.isChecked() state['image_diff_mode'] = self.options.image_mode.currentIndex() state['image_zoom_mode'] = self.options.zoom_mode.currentIndex() state['word_wrap'] = self.options.enable_word_wrapping.isChecked() return state def apply_state(self, state): diff_numbers = bool(state.get('show_diff_line_numbers', False)) self.set_line_numbers(diff_numbers, update=True) 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) word_wrap = bool(state.get('word_wrap', True)) self.set_word_wrapping(word_wrap, update=True) return True def set_diff_type(self, diff_type): """Manage the image and text diff views when selection changes""" # The "diff type" is whether the diff viewer is displaying an image. self.options.set_diff_type(diff_type) if diff_type == main.Types.IMAGE: self.stack.setCurrentWidget(self.image) self.render() else: self.stack.setCurrentWidget(self.text) def set_file_type(self, file_type): """Manage the diff options when the file type changes""" # The "file type" is whether the file itself is an image. self.options.set_file_type(file_type) def set_options(self): """Emit a signal indicating that options have changed""" self.text.set_options() def set_line_numbers(self, enabled, update=False): """Enable/disable line numbers in the text widget""" self.text.set_line_numbers(enabled, update=update) def set_word_wrapping(self, enabled, update=False): """Enable/disable word wrapping in the text widget""" self.text.set_word_wrapping(enabled, update=update) 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) # Create widgets 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 = qtutils.add_action_bool( self, N_('Show line numbers'), self.set_line_numbers, True ) self.enable_word_wrapping = qtutils.add_action_bool( self, N_('Enable word wrapping'), self.set_word_wrapping, True ) self.options = qtutils.create_action_button( tooltip=N_('Diff Options'), icon=icons.configure() ) self.toggle_image_diff = qtutils.create_action_button( tooltip=N_('Toggle image diff'), icon=icons.visualize() ) self.toggle_image_diff.hide() 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'), self.options) self.options.setMenu(menu) menu.addAction(self.ignore_space_at_eol) menu.addAction(self.ignore_space_change) menu.addAction(self.ignore_all_space) menu.addSeparator() menu.addAction(self.function_context) menu.addAction(self.show_line_numbers) menu.addSeparator() menu.addAction(self.enable_word_wrapping) # Layouts layout = qtutils.hbox( defs.no_margin, defs.button_spacing, self.image_mode, self.zoom_mode, self.options, self.toggle_image_diff, ) self.setLayout(layout) # Policies self.image_mode.setFocusPolicy(Qt.NoFocus) self.zoom_mode.setFocusPolicy(Qt.NoFocus) self.options.setFocusPolicy(Qt.NoFocus) self.toggle_image_diff.setFocusPolicy(Qt.NoFocus) self.setFocusPolicy(Qt.NoFocus) def set_file_type(self, file_type): """Set whether we are viewing an image file type""" is_image = file_type == main.Types.IMAGE self.toggle_image_diff.setVisible(is_image) def set_diff_type(self, diff_type): """Toggle between image and text diffs""" is_text = diff_type == main.Types.TEXT is_image = diff_type == main.Types.IMAGE self.options.setVisible(is_text) self.image_mode.setVisible(is_image) self.zoom_mode.setVisible(is_image) if is_image: self.toggle_image_diff.setIcon(icons.diff()) else: self.toggle_image_diff.setIcon(icons.visualize()) def add_option(self, title): """Add a diff option which calls set_options() on change""" action = qtutils.add_action(self, title, self.set_options) action.setCheckable(True) return action def set_options(self): """Update diff options in response to UI events""" 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.set_options() def set_line_numbers(self, value): self.widget.set_line_numbers(value, update=False) def set_word_wrapping(self, value): """Respond to Qt action callbacks""" self.widget.set_word_wrapping(value, update=False) # 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, hotkeys.STAGE_DIFF_ALT, ) 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.EDIT_SHORT, *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) qtutils.connect_button(options.toggle_image_diff, self.toggle_diff_type) def toggle_diff_type(self): cmds.do(cmds.ToggleDiffType, self.context) def refresh(self): enabled = False s = self.selection_model.selection() model = self.model if model.stageable(): item = s.modified[0] if s.modified else None if item in model.submodules: pass elif item not in model.unstaged_deleted: enabled = True self.action_revert_selection.setEnabled(enabled) def set_line_numbers(self, enabled, update=False): """Enable/disable the diff line number display""" self.numbers.setVisible(enabled) if update: with qtutils.BlockSignals(self.options.show_line_numbers): self.options.show_line_numbers.setChecked(enabled) # Refresh the display. Not doing this results in the display not # correctly displaying the line numbers widget until the text scrolls. self.set_value(self.value()) def set_word_wrapping(self, enabled, update=False): """Enable/disable word wrapping""" if update: with qtutils.BlockSignals(self.options.enable_word_wrapping): self.options.enable_word_wrapping.setChecked(enabled) if enabled: self.setWordWrapMode(QtGui.QTextOption.WordWrap) self.setLineWrapMode(QtWidgets.QPlainTextEdit.WidgetWidth) else: self.setWordWrapMode(QtGui.QTextOption.NoWrap) self.setLineWrapMode(QtWidgets.QPlainTextEdit.NoWrap) def set_options(self): 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 model.stageable(): item = s.modified[0] if s.modified else None 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 or s.untracked): 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()) with qtutils.BlockSignals(self): self.setText(self._display) 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.12.0/cola/widgets/editremotes.py000066400000000000000000000360741417222504200205670ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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() # Ignore notifications from self.remotes while mutating. with qtutils.BlockSignals(self.remotes): 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) 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.12.0/cola/widgets/filelist.py000066400000000000000000000102721417222504200200460ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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.12.0/cola/widgets/filetree.py000066400000000000000000000024651417222504200200370ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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.12.0/cola/widgets/finder.py000066400000000000000000000154671417222504200175150ustar00rootroot00000000000000"""File finder widgets""" from __future__ import absolute_import, division, print_function, 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.12.0/cola/widgets/gitignore.py000066400000000000000000000074511417222504200202270ustar00rootroot00000000000000"""Provides the StashView dialog.""" from __future__ import absolute_import, division, print_function, 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.12.0/cola/widgets/grep.py000066400000000000000000000323611417222504200171730ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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.12.0/cola/widgets/highlighter.py000066400000000000000000000064641417222504200205410ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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.12.0/cola/widgets/imageview.py000066400000000000000000000400211417222504200202030ustar00rootroot00000000000000# 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, print_function, 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 if not roi: return 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 if not roi: return 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 # pylint: disable=all 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.12.0/cola/widgets/log.py000066400000000000000000000051111417222504200170100ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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.12.0/cola/widgets/main.py000066400000000000000000001363301417222504200171630ustar00rootroot00000000000000"""Main UI for authoring commits and other Git Cola interactions""" from __future__ import absolute_import, division, print_function, 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 .. 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): # pylint: disable=too-many-statements,too-many-locals 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.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( 'Browser', N_('Browser'), self, widget=browser ) # "Actions" widget self.actionsdock = create_dock( 'Actions', N_('Actions'), self, widget=action.ActionButtons(context, self) ) qtutils.hide_dock(self.actionsdock) # "Repository Status" widget self.statusdock = create_dock( 'Status', N_('Status'), self, fn=lambda dock: status.StatusWidget(context, dock.titleBarWidget(), dock), ) self.statuswidget = self.statusdock.widget() # "Switch Repository" widgets self.bookmarksdock = create_dock( 'Favorites', N_('Favorites'), self, fn=lambda dock: bookmarks.bookmark(context, dock) ) bookmarkswidget = self.bookmarksdock.widget() qtutils.hide_dock(self.bookmarksdock) self.recentdock = create_dock( 'Recent', 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( 'Branches', 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( 'Submodules', 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('Commit', 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( 'Console', N_('Console'), self, widget=self.logwidget ) qtutils.hide_dock(self.logdock) # "Diff Viewer" widget self.diffdock = create_dock( 'Diff', 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.setIcon(icons.edit()) 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.undo_commit_action = add_action( self, N_('Undo Last Commit'), cmds.run(cmds.UndoLastCommit, context) ) self.undo_commit_action.setIcon(icons.style_dialog_discard()) 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.show_diffstat_action.setIcon(icons.diff()) 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.apply_patches_action.setIcon(icons.diff()) self.export_patches_action = add_action( self, N_('Export Patches...'), partial(guicmds.export_patches, context), hotkeys.EXPORT, ) self.export_patches_action.setIcon(icons.save()) 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.preferences_action.setIcon(icons.configure()) self.edit_remotes_action = add_action( self, N_('Edit Remotes...'), partial(editremotes.editor, context) ) self.edit_remotes_action.setIcon(icons.edit()) 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.search()) self.browse_recently_modified_action = add_action( self, N_('Recently Modified Files...'), partial(recent.browse_recent_files, context), hotkeys.EDIT_SECONDARY, ) self.browse_recently_modified_action.setIcon(icons.directory()) self.cherry_pick_action = add_action( self, N_('Cherry-Pick...'), partial(guicmds.cherry_pick, context), hotkeys.CHERRY_PICK, ) self.cherry_pick_action.setIcon(icons.cherry_pick()) self.load_commitmsg_action = add_action( self, N_('Load Commit Message...'), partial(guicmds.load_commitmsg, context) ) self.load_commitmsg_action.setIcon(icons.file_text()) 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.save_tarball_action.setIcon(icons.file_zip()) 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.grep_action.setIcon(icons.search()) self.merge_local_action = add_action( self, N_('Merge...'), partial(merge.local_merge, context), hotkeys.MERGE ) self.merge_local_action.setIcon(icons.merge()) self.merge_abort_action = add_action( self, N_('Abort Merge...'), cmds.run(cmds.AbortMerge, context) ) self.merge_abort_action.setIcon(icons.style_dialog_reset()) self.update_submodules_action = add_action( self, N_('Update All Submodules...'), cmds.run(cmds.SubmodulesUpdate, context), ) self.update_submodules_action.setIcon(icons.sync()) self.add_submodule_action = add_action( self, N_('Add Submodule...'), partial(submodules.add_submodule, context, parent=self), ) self.add_submodule_action.setIcon(icons.add()) self.fetch_action = add_action( self, N_('Fetch...'), partial(remote.fetch, context), hotkeys.FETCH ) self.fetch_action.setIcon(icons.download()) self.push_action = add_action( self, N_('Push...'), partial(remote.push, context), hotkeys.PUSH ) self.push_action.setIcon(icons.push()) self.pull_action = add_action( self, N_('Pull...'), partial(remote.pull, context), hotkeys.PULL ) self.pull_action.setIcon(icons.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.stash_action.setIcon(icons.commit()) self.reset_soft_action = add_action( self, N_('Reset Branch (Soft)'), partial(guicmds.reset_soft, context) ) self.reset_soft_action.setIcon(icons.style_dialog_reset()) self.reset_soft_action.setToolTip(cmds.ResetSoft.tooltip('')) self.reset_mixed_action = add_action( self, N_('Reset Branch and Stage (Mixed)'), partial(guicmds.reset_mixed, context), ) self.reset_mixed_action.setIcon(icons.style_dialog_reset()) self.reset_mixed_action.setToolTip(cmds.ResetMixed.tooltip('')) self.reset_keep_action = add_action( self, N_('Restore Worktree and Reset All (Keep Unstaged Changes)'), partial(guicmds.reset_keep, context), ) self.reset_keep_action.setIcon(icons.style_dialog_reset()) self.reset_keep_action.setToolTip(cmds.ResetKeep.tooltip('')) self.reset_merge_action = add_action( self, N_('Restore Worktree and Reset All (Merge)'), partial(guicmds.reset_merge, context), ) self.reset_merge_action.setIcon(icons.style_dialog_reset()) self.reset_merge_action.setToolTip(cmds.ResetMerge.tooltip('')) self.reset_hard_action = add_action( self, N_('Restore Worktree and Reset All (Hard)'), partial(guicmds.reset_hard, context), ) self.reset_hard_action.setIcon(icons.style_dialog_reset()) self.reset_hard_action.setToolTip(cmds.ResetHard.tooltip('')) self.restore_worktree_action = add_action( self, N_('Restore Worktree'), partial(guicmds.restore_worktree, context) ) self.restore_worktree_action.setIcon(icons.edit()) self.restore_worktree_action.setToolTip( cmds.RestoreWorktree.tooltip('') ) self.clone_repo_action = add_action( self, N_('Clone...'), partial(clone.clone, context) ) 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_current_action.setIcon(icons.visualize()) self.visualize_all_action = add_action( self, N_('Visualize All Branches...'), cmds.run(cmds.VisualizeAll, context) ) self.visualize_all_action.setIcon(icons.visualize()) self.search_commits_action = add_action( self, N_('Search...'), partial(search.search, context) ) self.search_commits_action.setIcon(icons.search()) self.browse_branch_action = add_action( self, N_('Browse Current Branch...'), partial(guicmds.browse_current, context), ) self.browse_branch_action.setIcon(icons.directory()) self.browse_other_branch_action = add_action( self, N_('Browse Other Branch...'), partial(guicmds.browse_other, context) ) self.browse_other_branch_action.setIcon(icons.directory()) self.load_commitmsg_template_action = add_action( self, N_('Get Commit Message Template'), cmds.run(cmds.LoadCommitMessageFromTemplate, context), ) self.load_commitmsg_template_action.setIcon(icons.style_dialog_apply()) 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.diff_expression_action.setIcon(icons.compare()) self.branch_compare_action = add_action( self, N_('Branches...'), partial(compare.compare_branches, context) ) self.branch_compare_action.setIcon(icons.compare()) self.create_tag_action = add_action( self, N_('Create Tag...'), partial(createtag.create_tag, context), ) self.create_tag_action.setIcon(icons.tag()) self.create_branch_action = add_action( self, N_('Create...'), partial(createbranch.create_new_branch, context), 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_branch_action.setIcon(icons.discard()) self.delete_remote_branch_action = add_action( self, N_('Delete Remote Branch...'), partial(guicmds.delete_remote_branch, context), ) self.delete_remote_branch_action.setIcon(icons.discard()) self.rename_branch_action = add_action( self, N_('Rename Branch...'), partial(guicmds.rename_branch, context) ) self.rename_branch_action.setIcon(icons.edit()) self.checkout_branch_action = add_action( self, N_('Checkout...'), partial(guicmds.checkout_branch, context), hotkeys.CHECKOUT, ) self.checkout_branch_action.setIcon(icons.branch()) self.branch_review_action = add_action( self, N_('Review...'), partial(guicmds.review_branch, context) ) self.branch_review_action.setIcon(icons.compare()) 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, ) select_widgets = copy_widgets + (self.statuswidget.tree,) edit_proxy.override('copy', copy_widgets) edit_proxy.override('selectAll', select_widgets) edit_menu = self.edit_menu = add_menu(N_('&Edit'), self.menubar) undo = add_action(edit_menu, N_('Undo'), edit_proxy.undo, hotkeys.UNDO) undo.setIcon(icons.undo()) redo = add_action(edit_menu, N_('Redo'), edit_proxy.redo, hotkeys.REDO) redo.setIcon(icons.redo()) edit_menu.addSeparator() cut = add_action(edit_menu, N_('Cut'), edit_proxy.cut, hotkeys.CUT) cut.setIcon(icons.cut()) copy = add_action(edit_menu, N_('Copy'), edit_proxy.copy, hotkeys.COPY) copy.setIcon(icons.copy()) paste = add_action(edit_menu, N_('Paste'), edit_proxy.paste, hotkeys.PASTE) paste.setIcon(icons.paste()) delete = add_action(edit_menu, N_('Delete'), edit_proxy.delete, hotkeys.DELETE) delete.setIcon(icons.delete()) edit_menu.addSeparator() select_all = add_action( edit_menu, N_('Select All'), edit_proxy.selectAll, hotkeys.SELECT_ALL ) select_all.setIcon(icons.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.addAction(self.add_submodule_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.addAction(self.undo_commit_action) self.commit_menu.addSeparator() self.commit_menu.addAction(self.statuswidget.tree.process_selection_action) self.commit_menu.addAction(self.statuswidget.tree.stage_or_unstage_all_action) 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.menubar) 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) # Reset menu self.reset_menu = add_menu(N_('Reset'), self.menubar) self.reset_menu.addAction(self.unstage_all_action) self.reset_menu.addAction(self.undo_commit_action) self.reset_menu.addSeparator() self.reset_menu.addAction(self.reset_soft_action) self.reset_menu.addAction(self.reset_mixed_action) self.reset_menu.addAction(self.restore_worktree_action) self.reset_menu.addSeparator() self.reset_menu.addAction(self.reset_keep_action) self.reset_menu.addAction(self.reset_merge_action) self.reset_menu.addAction(self.reset_hard_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( lambda names_and_shortcuts: _install_config_actions( context, self.actions_menu, names_and_shortcuts, ), type=Qt.QueuedConnection, ) self.init_state(context.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) context = self.context menu_action = menu.addAction( N_('New Toolbar'), partial(toolbar.add_toolbar, context, self) ) menu_action.setIcon(icons.add()) menu.addSeparator() 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): cmd = cmds.OpenRepo context = self.context settings = context.settings settings.load() menu = self.open_recent_menu menu.clear() worktree = context.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 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() def _install_config_actions(context, menu, names_and_shortcuts): """Install .gitconfig-defined actions""" if not names_and_shortcuts: return menu.addSeparator() cache = {} for (name, shortcut) in names_and_shortcuts: sub_menu, action_name = build_menus(name, menu, cache) callback = cmds.run(cmds.RunConfigAction, context, name) menu_action = sub_menu.addAction(action_name, callback) if shortcut: menu_action.setShortcut(shortcut) def build_menus(name, menu, cache): """Create a chain of QMenu entries parented under a root QMenu A name of "a/b/c" create a menu chain of menu -> QMenu("a") -> QMenu("b") and returns a tuple of (QMenu("b"), "c"). :param name: The full entry path, ex: "a/b/c" where "a/b" is the menu chain. :param menu: The root menu under which to create the menu chain. :param cache: A dict cache of previously created menus to avoid duplicates. """ # NOTE: utils.split() and friends are used instead of os.path.split() because # slash '/' is the only supported "/name" separator. Use of os.path.split() # would introduce differences in behavior across platforms. # If the menu_path is empty then no parent menus need to be created. # The action will be added to the root menu. menu_path, text = utils.split(utils.normalize_slash(name)) if not menu_path: return (menu, text) # When menu_path contains ex: "a/b" we will create two menus: "a" and "b". # The root menu is the parent of "a" and "a" is the parent of "b". # The menu returned to the caller is "b". # # Loop over the individual menu basenames alongside the full subpath returned by # pathset(). The subpath is a cache key for finding previously created menus. menu_names = utils.splitpath(menu_path) # ['a', 'b'] menu_pathset = utils.pathset(menu_path) # ['a', 'a/b'] for menu_name, menu_id in zip(menu_names, menu_pathset): try: menu = cache[menu_id] except KeyError: menu = cache[menu_id] = menu.addMenu(menu_name) return (menu, text) git-cola-3.12.0/cola/widgets/merge.py000066400000000000000000000212061417222504200173310ustar00rootroot00000000000000from __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.12.0/cola/widgets/patch.py000066400000000000000000000214241417222504200173330ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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.12.0/cola/widgets/prefs.py000066400000000000000000000406261417222504200173600ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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): """Set a value on a widget without emitting notifications""" with qtutils.BlockSignals(widget): 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) 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) tooltip = N_('Check whether a commit has been published when amending') self.check_published_commits = 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.add_row( N_('Check Published Commits when Amending'), self.check_published_commits ) self.set_config( { prefs.AUTOTEMPLATE: (self.autotemplate, Defaults.autotemplate), prefs.CHECK_CONFLICTS: (self.check_conflicts, Defaults.check_conflicts), prefs.CHECK_PUBLISHED_COMMITS: ( self.check_published_commits, Defaults.check_published_commits, ), 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.resize_browser_columns = qtutils.checkbox(checked=False) 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_('Resize File Browser columns'), self.resize_browser_columns) 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.RESIZE_BROWSER_COLUMNS: ( self.resize_browser_columns, Defaults.resize_browser_columns, ), 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): """Update widgets to the current config values""" FormWidget.update_from_config(self) context = self.context with qtutils.BlockSignals(self.fixed_font): font = qtutils.diff_font(context) self.fixed_font.setCurrentFont(font) with qtutils.BlockSignals(self.font_size): font_size = font.pointSize() self.font_size.setValue(font_size) 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.12.0/cola/widgets/recent.py000066400000000000000000000114461417222504200175170ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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.12.0/cola/widgets/remote.py000066400000000000000000000617001417222504200175300ustar00rootroot00000000000000"""Widgets for Fetch, Push, and Pull""" from __future__ import absolute_import, division, print_function, 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/main" becomes "main". """ branches = [utils.strip_one(branch) for branch in remote_branches] return [branch for branch in branches if branch != 'HEAD'] def get_default_remote(context): """Get the name of the default remote to use for pushing. This will be the remote the branch is set to track, if it is set. If it is not, remote.pushDefault will be used (or origin if not set) """ upstream_remote = gitcmds.upstream_remote(context) return upstream_remote or context.cfg.get('remote.pushDefault', default='origin') 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 = get_default_remote(context) 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 main" 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.12.0/cola/widgets/search.py000066400000000000000000000262251417222504200175050ustar00rootroot00000000000000"""A widget for searching git commits""" from __future__ import absolute_import, division, print_function, 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(10, 10)) 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.cherry_pick() ) 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.12.0/cola/widgets/selectcommits.py000066400000000000000000000142461417222504200211130ustar00rootroot00000000000000"""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 completion 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.revision_label = QtWidgets.QLabel() self.revision_label.setText(N_('Revision Expression:')) self.revision = completion.GitRefLineEdit(context) self.revision.setReadOnly(True) self.search_label = QtWidgets.QLabel() self.search_label.setText(N_('Search:')) self.search = QtWidgets.QLineEdit() self.search.setReadOnly(False) # pylint: disable=no-member self.search.textChanged.connect(self.search_list) self.select_button = qtutils.ok_button(N_('Select'), enabled=False) # 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.spacing, self.search_label, self.search, qtutils.STRETCH, self.revision_label, self.revision, self.select_button, ) self.main_layout = qtutils.vbox( defs.margin, defs.margin, self.input_layout, self.splitter ) 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) 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() def search_list(self, text): if text: for i in range(self.commits.count()): self.commits.item(i).setHidden(True) search_items = self.commits.findItems(text, Qt.MatchContains) for items in search_items: items.setHidden(False) 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.12.0/cola/widgets/spellcheck.py000066400000000000000000000100071417222504200203440ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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.12.0/cola/widgets/standard.py000066400000000000000000000751521417222504200200430ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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-cola-sequence-editor # 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.read() settings.save_gui_state(self) def restore_state(self, settings=None): if settings is None: settings = Settings.read() 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) if context is None: settings = Settings.read() else: settings = context.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, logo=None): """Launches a QMessageBox question with the provided title and message. Passing "default=False" will make "No" the default choice.""" parent = qtutils.active_window() if logo is None: 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.12.0/cola/widgets/startup.py000066400000000000000000000233461417222504200177430ustar00rootroot00000000000000"""The startup dialog is presented when no repositories can be found at startup""" from __future__ import absolute_import, division, print_function, unicode_literals from qtpy.QtCore import Qt from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets from ..i18n import N_ from .. import core from .. import display from .. import guicmds from .. import hotkeys 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): 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() self.bookmarks_model = bookmarks_model = QtGui.QStandardItemModel() self.items = items = [] item = QtGui.QStandardItem(N_('Open...')) item.setEditable(False) item.setIcon(icons.open_directory()) bookmarks_model.appendRow(item) # The tab bar allows choosing between Folder and List mode self.tab_bar = QtWidgets.QTabBar() self.tab_bar.setMovable(False) self.tab_bar.addTab(icons.directory(), N_('Folder')) self.tab_bar.addTab(icons.three_bars(), N_('List')) # Bookmarks/"Favorites" and Recent are lists of {name,path: str} settings = context.settings bookmarks = settings.bookmarks recent = settings.recent all_repos = bookmarks + recent directory_icon = icons.directory() user_role = Qt.UserRole normalize = display.normalize_path paths = set([normalize(repo['path']) for repo in all_repos]) short_paths = display.shorten_paths(paths) self.short_paths = short_paths added = set() for repo in all_repos: path = normalize(repo['path']) if path in added: continue added.add(path) item = QtGui.QStandardItem(path) item.setEditable(False) item.setData(path, user_role) item.setIcon(directory_icon) item.setToolTip(path) item.setText(self.short_paths.get(path, path)) bookmarks_model.appendRow(item) items.append(item) selection_mode = QtWidgets.QAbstractItemView.SingleSelection self.bookmarks = bookmarks = QtWidgets.QListView() bookmarks.setSelectionMode(selection_mode) bookmarks.setModel(bookmarks_model) bookmarks.setViewMode(QtWidgets.QListView.IconMode) bookmarks.setResizeMode(QtWidgets.QListView.Adjust) bookmarks.setGridSize(make_size(defs.large_icon)) bookmarks.setIconSize(make_size(defs.medium_icon)) bookmarks.setDragEnabled(False) bookmarks.setWordWrap(True) self.tab_layout = qtutils.vbox( defs.no_margin, defs.no_spacing, self.tab_bar, self.bookmarks ) 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.main_layout = qtutils.grid(defs.margin, defs.spacing) self.main_layout.addItem(self.logo_layout, 1, 1) self.main_layout.addItem(self.tab_layout, 1, 2) self.main_layout.addItem(self.button_layout, 2, 1, columnSpan=2) 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) # Open the selected repository when "enter" is pressed. self.action_open_repo = qtutils.add_action( self, N_('Open'), self.open_selected_bookmark, *hotkeys.ACCEPT ) # pylint: disable=no-member self.tab_bar.currentChanged.connect(self.tab_changed) self.bookmarks.activated.connect(self.open_bookmark) self.init_state(settings, self.resize_widget) self.setFocusProxy(self.bookmarks) self.bookmarks.setFocus() # Update the list mode list_mode = context.cfg.get('cola.startupmode', default='folder') self.list_mode = list_mode if list_mode == 'list': self.tab_bar.setCurrentIndex(1) def tab_changed(self, idx): bookmarks = self.bookmarks if idx == 0: bookmarks.setViewMode(QtWidgets.QListView.IconMode) bookmarks.setIconSize(make_size(defs.medium_icon)) bookmarks.setGridSize(make_size(defs.large_icon)) list_mode = 'folder' for item in self.items: path = item.data(Qt.UserRole) item.setText(self.short_paths.get(path, path)) else: bookmarks.setViewMode(QtWidgets.QListView.ListMode) bookmarks.setIconSize(make_size(defs.default_icon)) bookmarks.setGridSize(QtCore.QSize()) list_mode = 'list' for item in self.items: path = item.data(Qt.UserRole) item.setText(path) if list_mode != self.list_mode: self.list_mode = list_mode self.context.cfg.set_user('cola.startupmode', list_mode) 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 progress = standard.progress('', '', self) clone.clone_repo(context, self, True, 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_selected_bookmark(self): selected = self.bookmarks.selectedIndexes() if selected: self.open_bookmark(selected[0]) def open_bookmark(self, index): if index.row() == 0: self.open_repo() else: self.repodir = self.bookmarks_model.data(index, Qt.UserRole) if not self.repodir: return if not core.exists(self.repodir): self.handle_broken_repo(index) return self.accept() def handle_broken_repo(self, index): settings = self.context.settings all_repos = settings.bookmarks + settings.recent repodir = self.bookmarks_model.data(index, Qt.UserRole) repo = next(repo for repo in all_repos if repo['path'] == repodir) title = N_('Repository Not Found') text = N_('%s could not be opened. Remove from bookmarks?') % repo['path'] logo = icons.from_style(QtWidgets.QStyle.SP_MessageBoxWarning) if standard.question(title, text, N_('Remove'), logo=logo): self.context.settings.remove_bookmark(repo['path'], repo['name']) self.context.settings.remove_recent(repo['path']) self.context.settings.save() item = self.bookmarks_model.item(index.row()) self.items.remove(item) self.bookmarks_model.removeRow(index.row()) def get_selected_bookmark(self): selected = self.bookmarks.selectedIndexes() if selected and selected[0].row() != 0: return self.bookmarks_model.data(selected[0], Qt.UserRole) return None def make_size(size): """Construct a QSize from a single value""" return QtCore.QSize(size, size) git-cola-3.12.0/cola/widgets/stash.py000066400000000000000000000231211417222504200173520ustar00rootroot00000000000000"""Widgets for manipulating git stashes""" from __future__ import absolute_import, division, print_function, 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 hotkeys 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]) # Apply stash with Ctrl+Enter self.apply_action = qtutils.add_action( self, N_('Apply'), self.stash_apply, hotkeys.APPLY ) # Pop stash with Ctrl+Backspace self.pop_action = qtutils.add_action( self, N_('Pop'), self.stash_pop, hotkeys.DELETE_FILE_SECONDARY ) # Drop stash with Ctrl+Shift+Backspace self.drop_action = qtutils.add_action( self, N_('Pop'), self.stash_drop, hotkeys.DELETE_FILE ) # 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() self.stash_index.setEnabled(is_staged) is_changed = self.model.is_changed() self.keep_index.setEnabled(is_changed) self.button_save.setEnabled(is_changed) is_selected = bool(self.selected_stash()) self.apply_action.setEnabled(is_selected) self.drop_action.setEnabled(is_selected) self.pop_action.setEnabled(is_selected) 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.12.0/cola/widgets/status.py000066400000000000000000001551731417222504200175700ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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 ..settings import Settings from .. import actions from .. import cmds from .. import core from .. import hotkeys from .. import icons from .. import qtutils from .. import utils from . import common from . import completion from . import defs from . import text # Top-level status widget item indexes. HEADER_IDX = -1 STAGED_IDX = 0 UNMERGED_IDX = 1 MODIFIED_IDX = 2 UNTRACKED_IDX = 3 END_IDX = 4 # Indexes into the saved_selection entries. NEW_PATHS_IDX = 0 OLD_PATHS_IDX = 1 SELECTION_IDX = 2 SELECT_FN_IDX = 3 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() set_previous_contents = Signal(list, list, list, list) updated = Signal() diff_text_changed = Signal() # 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.previous_contents = 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.process_selection_action.setIcon(icons.add()) self.stage_or_unstage_all_action = qtutils.add_action( self, cmds.StageOrUnstageAll.name(), cmds.run(cmds.StageOrUnstageAll, self.context), hotkeys.STAGE_ALL, ) self.stage_or_unstage_all_action.setIcon(icons.add()) 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_at_line( 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()) self.about_to_update.connect(self._about_to_update, type=Qt.QueuedConnection) self.set_previous_contents.connect( self._set_previous_contents, type=Qt.QueuedConnection) self.updated.connect(self.refresh, type=Qt.QueuedConnection) self.diff_text_changed.connect( self._make_current_item_visible, type=Qt.QueuedConnection ) # The model is stored as self.m because self.model() is a # QTreeWidgetItem method that returns a QAbstractItemModel. self.m = context.model # Forward the previous_contents notification through self.set_previous_contents. self.m.add_observer( self.m.message_previous_contents, self.set_previous_contents.emit ) # Forward the about_to_update notification through self.about_to_update. self.m.add_observer(self.m.message_about_to_update, self.about_to_update.emit) # Forward the updated notification through self.updated. 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(cmds.run(cmds.StageOrUnstage, self.context)) 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: qtutils.scroll_to_item(self, 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): """Apply the old selection to the newly updated items""" # This function is called after a new set of items have been added to # the per-category file lists. Its purpose is to either restore the # existing selection or to create a new intuitive selection based on # a combination of the old items, the old selection and the new items. if not self.old_selection or not self.old_contents: return # The old set of categorized files. old_c = self.old_contents # The old selection. old_s = self.old_selection # The current/new set of categorized files. new_c = self.contents() select_staged = partial( _select_item, self, new_c.staged, self._staged_item ) select_unmerged = partial( _select_item, self, new_c.unmerged, self._unmerged_item ) select_modified = partial( _select_item, self, new_c.modified, self._modified_item ) select_untracked = partial( _select_item, self, 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 _apply_toplevel_selection(self, category, idx): return # Reselect the current item selection_info = saved_selection[category] new = selection_info[NEW_PATHS_IDX] old = selection_info[OLD_PATHS_IDX] reselect = selection_info[SELECT_FN_IDX] try: item = old[idx] except IndexError: item = None if item and item in new: reselect(item, current=True) # Restore previously selected items. # When reselecting in this section we only care that the items are # selected; we do not need to rerun the callbacks which were triggered # above for the current item. Block signals to skip the callbacks. # # Reselect items that were previously selected and still exist in the # current path lists. This handles a common case such as a Ctrl-R # refresh which results in the same exact path state. did_reselect = False with qtutils.BlockSignals(self): for (new, old, sel, reselect) in saved_selection: for item in sel: if item in new: reselect(item, current=False) did_reselect = True # The status widget is used to interactively work your way down the # list of Staged, Unmerged, Modified and Untracked items and perform # an operation on them. # # For Staged items we intend to work our way down the list of Staged # items while we unstage each item. For every other category we work # our way down the list of {Unmerged,Modified,Untracked} items while # we stage each item. # # The following block of code implements the behavior of selecting # the next item based on the previous selection. 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 # If we already reselected stuff then there's nothing more to do. if did_reselect: return # If we got this far then nothing was reselected and made current. # Try a few more heuristics that we can use to keep something selected. if self.old_current_item: category, idx = self.old_current_item _transplant_selection_across_sections( category, idx, self.previous_contents, saved_selection ) def _restore_scrollbars(self): """Restore scrollbars to the stored values""" qtutils.set_scrollbar_values(self, self.old_hscroll, self.old_vscroll) self.old_hscroll = None self.old_vscroll = None def _stage_selection(self): """Stage or unstage files according to the selection""" context = self.context selected_indexes = self.selected_indexes() is_header = any( category == HEADER_IDX for (category, idx) in selected_indexes ) if is_header: is_staged = any( idx == STAGED_IDX and category == HEADER_IDX for (category, idx) in selected_indexes ) is_modified = any( idx == MODIFIED_IDX and category == HEADER_IDX for (category, idx) in selected_indexes ) is_untracked = any( idx == UNTRACKED_IDX and category == HEADER_IDX for (category, idx) in selected_indexes ) # A header item: 'Staged', 'Modified' or 'Untracked'. if is_staged: # If we have the staged header selected then the only sensible # thing to do is to unstage everything and nothing else, even # if the modified or untracked headers are selected. cmds.do(cmds.UnstageAll, context) return # Everything was unstaged. There's nothing more to be done. elif is_modified and is_untracked: # If both modified and untracked headers are selected then # stage everything. cmds.do(cmds.StageModifiedAndUntracked, context) return # Nothing more to do. # At this point we may stage all modified and untracked, and then # possibly a subset of the other category (eg. all modified and # some untracked). We don't return here so that StageOrUnstage # gets a chance to run below. elif is_modified: cmds.do(cmds.StageModified, context) elif is_untracked: cmds.do(cmds.StageUntracked, context) else: # Do nothing for unmerged items, by design pass # Now handle individual files cmds.do(cmds.StageOrUnstage, context) def _staged_item(self, itemidx): return self._subtree_item(STAGED_IDX, itemidx) def _modified_item(self, itemidx): return self._subtree_item(MODIFIED_IDX, itemidx) def _unmerged_item(self, itemidx): return self._subtree_item(UNMERGED_IDX, itemidx) def _untracked_item(self, itemidx): return self._subtree_item(UNTRACKED_IDX, itemidx) def _unstaged_item(self, itemidx): # is it modified? item = self.topLevelItem(MODIFIED_IDX) count = item.childCount() if itemidx < count: return item.child(itemidx) # is it unmerged? item = self.topLevelItem(UNMERGED_IDX) count += item.childCount() if itemidx < count: return item.child(itemidx) # is it untracked? item = self.topLevelItem(UNTRACKED_IDX) 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 _set_previous_contents(self, staged, unmerged, modified, untracked): """Callback triggered right before the model changes its contents""" self.previous_contents = selection.State(staged, unmerged, modified, untracked) def _about_to_update(self): self._save_scrollbars() self._save_selection() def _save_scrollbars(self): """Store the scrollbar values for later application""" hscroll, vscroll = qtutils.get_scrollbar_values(self) if hscroll is not None: self.old_hscroll = hscroll if vscroll is not None: self.old_vscroll = vscroll 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) if idx.parent().isValid(): parent_idx = idx.parent() entry = (parent_idx.row(), idx.row()) else: entry = (HEADER_IDX, 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.""" with qtutils.BlockSignals(self): self._set_subtree( items, STAGED_IDX, N_('Staged'), staged=True, deleted_set=self.m.staged_deleted, ) def _set_modified(self, items): """Adds items to the 'Modified' subtree.""" with qtutils.BlockSignals(self): self._set_subtree( items, MODIFIED_IDX, 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)]) with qtutils.BlockSignals(self): self._set_subtree( items, UNMERGED_IDX, N_('Unmerged'), deleted_set=deleted_set ) def _set_untracked(self, items): """Adds items to the 'Untracked' subtree.""" with qtutils.BlockSignals(self): self._set_subtree( items, UNTRACKED_IDX, 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.""" 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) 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 == HEADER_IDX: 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) settings = Settings.read() copy_formats = 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 == STAGED_IDX: menu.addAction( icons.remove(), N_('Unstage All'), cmds.run(cmds.UnstageAll, context) ) elif idx == UNMERGED_IDX: action = menu.addAction( icons.add(), cmds.StageUnmerged.name(), cmds.run(cmds.StageUnmerged, context), ) action.setShortcut(hotkeys.STAGE_SELECTION) elif idx == MODIFIED_IDX: action = menu.addAction( icons.add(), cmds.StageModified.name(), cmds.run(cmds.StageModified, context), ) action.setShortcut(hotkeys.STAGE_SELECTION) elif idx == UNTRACKED_IDX: 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 = (HEADER_IDX, 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 all of the current files in a selection.State container""" return selection.State( self.m.staged, self.m.unmerged, self.m.modified, self.m.untracked ) def all_files(self): """Return all of the current active files as a flast list""" 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, STAGED_IDX), (c.unmerged, UNMERGED_IDX), (c.modified, MODIFIED_IDX), (c.untracked, UNTRACKED_IDX), ] 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: qtutils.select_item(self, item) return idx -= len(content) def staged(self): return qtutils.get_selected_values(self, STAGED_IDX, self.m.staged) def unstaged(self): return self.unmerged() + self.modified() + self.untracked() def modified(self): return qtutils.get_selected_values(self, MODIFIED_IDX, self.m.modified) def unmerged(self): return qtutils.get_selected_values(self, UNMERGED_IDX, self.m.unmerged) def untracked(self): return qtutils.get_selected_values(self, UNTRACKED_IDX, self.m.untracked) def staged_items(self): return qtutils.get_selected_items(self, STAGED_IDX) def unstaged_items(self): return self.unmerged_items() + self.modified_items() + self.untracked_items() def modified_items(self): return qtutils.get_selected_items(self, MODIFIED_IDX) def unmerged_items(self): return qtutils.get_selected_items(self, UNMERGED_IDX) def untracked_items(self): return qtutils.get_selected_items(self, UNTRACKED_IDX) def show_selection(self): """Show the selected item.""" context = self.context qtutils.scroll_to_item(self, 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 == HEADER_IDX if header: cls = { STAGED_IDX: cmds.DiffStagedSummary, MODIFIED_IDX: cmds.Diffstat, # TODO implement UnmergedSummary # UNMERGED_IDX: cmds.UnmergedSummary, UNTRACKED_IDX: cmds.UntrackedSummary, }.get(idx, cmds.Diffstat) cmds.do(cls, context) return staged = category == STAGED_IDX modified = category == MODIFIED_IDX unmerged = category == UNMERGED_IDX untracked = category == UNTRACKED_IDX 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) # Update the diff text if 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) # Images are diffed differently. # DiffImage transitions the diff mode to image. # DiffText transitions the diff mode to text. if image: cmds.do( cmds.DiffImage, context, path, deleted, staged, modified, unmerged, untracked, ) else: cmds.do(cmds.DiffText, context) def select_header(self): """Select an active header, which triggers a diffstat""" for idx in ( STAGED_IDX, UNMERGED_IDX, MODIFIED_IDX, UNTRACKED_IDX, ): 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 == HEADER_IDX: item = self.itemAbove(self.topLevelItem(toplevel_idx)) if item is not None: qtutils.select_item(self, 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 == HEADER_IDX: item = self.itemBelow(self.topLevelItem(toplevel_idx)) if item is not None: qtutils.select_item(self, 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.context = context 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) QtCore.QTimer.singleShot(0, self.reload_settings) def reload_settings(self): # Called once after the GUI is initialized settings = self.context.settings settings.load() table = self.table for entry in 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) settings = self.context.settings while settings.copy_formats: settings.copy_formats.pop() settings.copy_formats.extend(copy_formats) settings.save() self.accept() def table_selection_changed(self): items = self.table.selectedItems() self.remove_button.setEnabled(bool(items)) def _select_item(widget, path_list, widget_getter, item, current=False): """Select the widget item based on the list index""" # The path lists and widget indexes have a 1:1 correspondence. # Lookup the item filename in the list and use that index to # retrieve the widget item and select it. idx = path_list.index(item) item = widget_getter(idx) if current: widget.setCurrentItem(item) item.setSelected(True) def _apply_toplevel_selection(widget, category, idx): """Select a top-level "header" item (ex: the Staged parent item) Return True when a top-level item is selected. """ is_top_level_item = category == HEADER_IDX if is_top_level_item: root_item = widget.invisibleRootItem() item = root_item.child(idx) if item is not None and item.childCount() == 0: # The item now has no children. Select a different top-level item # corresponding to the previously selected item. if idx == STAGED_IDX: # If "Staged" was previously selected try "Modified" and "Untracked". item = _get_first_item_with_children( root_item.child(MODIFIED_IDX), root_item.child(UNTRACKED_IDX) ) elif idx == UNMERGED_IDX: # If "Unmerged" was previously selected try "Staged". item = _get_first_item_with_children(root_item.child(STAGED_IDX)) elif idx == MODIFIED_IDX: # If "Modified" was previously selected try "Staged" or "Untracked". item = _get_first_item_with_children( root_item.child(STAGED_IDX), root_item.child(UNTRACKED_IDX) ) elif idx == UNTRACKED_IDX: # If "Untracked" was previously selected try "Staged". item = _get_first_item_with_children(root_item.child(STAGED_IDX)) if item is not None: with qtutils.BlockSignals(widget): widget.setCurrentItem(item) item.setSelected(True) widget.show_selection() return is_top_level_item def _get_first_item_with_children(*items): """Return the first item that contains child items""" for item in items: if item.childCount() > 0: return item return None def _transplant_selection_across_sections( category, idx, previous_contents, saved_selection ): """Transplant the selection to a different category""" # This function is used when the selection would otherwise become empty. # Apply heuristics to select the items based on the previous state. if not previous_contents: return staged, unmerged, modified, untracked = saved_selection prev_staged, prev_unmerged, prev_modified, prev_untracked = previous_contents # The current set of paths. staged_paths = staged[NEW_PATHS_IDX] unmerged_paths = unmerged[NEW_PATHS_IDX] modified_paths = modified[NEW_PATHS_IDX] untracked_paths = untracked[NEW_PATHS_IDX] # These callbacks select a path in the corresponding widget subtree lists. select_staged = staged[SELECT_FN_IDX] select_unmerged = unmerged[SELECT_FN_IDX] select_modified = modified[SELECT_FN_IDX] select_untracked = untracked[SELECT_FN_IDX] if category == STAGED_IDX: # Staged files can become Unmerged, Modified or Untracked. # If we previously had a staged file selected then try to select # it in either the Unmerged, Modified or Untracked sections. try: old_path = prev_staged[idx] except IndexError: return if old_path in unmerged_paths: select_unmerged(old_path, current=True) elif old_path in modified_paths: select_modified(old_path, current=True) elif old_path in untracked_paths: select_untracked(old_path, current=True) elif category == UNMERGED_IDX: # Unmerged files can become Staged, Modified or Untracked. # If we previously had an unmerged file selected then try to select it in # the Staged, Modified or Untracked sections. try: old_path = prev_unmerged[idx] except IndexError: return if old_path in staged_paths: select_staged(old_path, current=True) elif old_path in modified_paths: select_modified(old_path, current=True) elif old_path in untracked_paths: select_untracked(old_path, current=True) elif category == MODIFIED_IDX: # If we previously had a modified file selected then try to select # it in either the Staged or Untracked sections. try: old_path = prev_modified[idx] except IndexError: return if old_path in staged_paths: select_staged(old_path, current=True) elif old_path in untracked_paths: select_untracked(old_path, current=True) elif category == UNTRACKED_IDX: # If we previously had an untracked file selected then try to select # it in the Modified or Staged section. Modified is less common, but # it's possible for a file to be untracked and then the user adds and # modifies the file before we've refreshed our state. try: old_path = prev_untracked[idx] except IndexError: return if old_path in modified_paths: select_modified(old_path, current=True) elif old_path in staged_paths: select_staged(old_path, current=True) git-cola-3.12.0/cola/widgets/submodules.py000066400000000000000000000166461417222504200204300ustar00rootroot00000000000000"""Provides widgets related to submodules""" from __future__ import absolute_import, division, print_function, unicode_literals from qtpy import QtWidgets from qtpy.QtCore import Qt from qtpy.QtCore import Signal from .. import cmds from .. import compat from .. import core from .. import qtutils from .. import icons from ..i18n import N_ from ..widgets import defs from ..widgets import standard from ..widgets import text def add_submodule(context, parent): """Add a new submodule""" dlg = AddSubmodule(parent) dlg.show() if dlg.exec_() == standard.Dialog.Accepted: cmd = dlg.get(context) cmd.do() class SubmodulesWidget(QtWidgets.QFrame): def __init__(self, context, parent): super(SubmodulesWidget, self).__init__(parent) self.context = context 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.add_button = qtutils.create_action_button( tooltip=N_('Add Submodule'), icon=icons.add() ) 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.add_button, 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.add_button, self.add_submodule) qtutils.connect_button(self.refresh_button, self.refresh) qtutils.connect_button( self.open_parent_button, cmds.run(cmds.OpenParentRepo, context) ) def refresh(self): self.context.model.update_submodules_list() def add_submodule(self): add_submodule(self.context, self) class AddSubmodule(standard.Dialog): """Add a new submodule""" def __init__(self, parent): super(AddSubmodule, self).__init__(parent=parent) hint = N_('git://git.example.com/repo.git') tooltip = N_('Submodule URL (can be relative, ex: ../repo.git)') self.url_text = text.HintedDefaultLineEdit(hint, tooltip=tooltip, parent=self) hint = N_('path/to/submodule') tooltip = N_('Submodule path within the current repository (optional)') self.path_text = text.HintedDefaultLineEdit(hint, tooltip=tooltip, parent=self) hint = N_('Branch name') tooltip = N_('Submodule branch to track (optional)') self.branch_text = text.HintedDefaultLineEdit( hint, tooltip=tooltip, parent=self ) self.depth_spinbox = standard.SpinBox( mini=0, maxi=compat.maxint, value=0, parent=self ) self.depth_spinbox.setToolTip( N_( 'Create a shallow clone with history truncated to the ' 'specified number of revisions. 0 performs a full clone.' ) ) hint = N_('Reference URL') tooltip = N_('Reference repository to use when cloning (optional)') self.reference_text = text.HintedDefaultLineEdit( hint, tooltip=tooltip, parent=self ) self.add_button = qtutils.ok_button(N_('Add Submodule'), enabled=False) self.close_button = qtutils.close_button() self.form_layout = qtutils.form( defs.no_margin, defs.button_spacing, (N_('URL'), self.url_text), (N_('Path'), self.path_text), (N_('Branch'), self.branch_text), (N_('Depth'), self.depth_spinbox), (N_('Reference Repository'), self.reference_text), ) self.button_layout = qtutils.hbox( defs.no_margin, defs.button_spacing, qtutils.STRETCH, self.add_button, self.close_button, ) self.main_layout = qtutils.vbox( defs.large_margin, defs.spacing, self.form_layout, self.button_layout ) self.setLayout(self.main_layout) self.init_size(parent=qtutils.active_window()) # pylint: disable=no-member self.url_text.textChanged.connect(lambda x: self._update_widgets()) qtutils.connect_button(self.add_button, self.accept) qtutils.connect_button(self.close_button, self.close) def _update_widgets(self): value = self.url_text.value() self.add_button.setEnabled(bool(value)) def get(self, context): return cmds.SubmoduleAdd( context, self.url_text.value(), self.path_text.value(), self.branch_text.value(), self.depth_spinbox.value(), self.reference_text.value(), ) # 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.12.0/cola/widgets/text.py000066400000000000000000000731071417222504200172250ustar00rootroot00000000000000"""Text widgets""" # pylint: disable=unexpected-keyword-arg from __future__ import absolute_import, division, print_function, 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): """Update the widget to the specified value""" if block: with qtutils.BlockSignals(self): self._set_value(value) else: self._set_value(value) def _set_value(self, value): """Implementation helper to update the widget to the specified value""" pos = self.cursorPosition() self.setText(value) self.setCursorPosition(pos) 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(10, 10)) 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): """Update the widget to the specified value""" if block: with qtutils.BlockSignals(self): self._set_value(value) else: self._set_value(value) def _set_value(self, value): """Implementation helper to update the widget to the specified value""" # 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) 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) def anchor_mode(select): """Return the QTextCursor mode to keep/discard the cursor selection""" if select: mode = QtGui.QTextCursor.KeepAnchor else: mode = QtGui.QTextCursor.MoveAnchor return mode # 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('End', hotkeys.GOTO_END) 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('Start', hotkeys.GOTO_START) self.add_navigation('StartOfLine', hotkeys.START_OF_LINE) self.add_navigation('EndOfLine', hotkeys.END_OF_LINE) qtutils.add_action( widget, 'PageUp', widget.page_up, hotkeys.SECONDARY_ACTION, hotkeys.UP ) qtutils.add_action( widget, 'PageDown', widget.page_down, hotkeys.PRIMARY_ACTION, hotkeys.DOWN ) qtutils.add_action( widget, 'SelectPageUp', lambda: widget.page_up(select=True), hotkeys.SELECT_BACK, hotkeys.SELECT_UP, ) qtutils.add_action( widget, 'SelectPageDown', lambda: widget.page_down(select=True), hotkeys.SELECT_FORWARD, hotkeys.SELECT_DOWN, ) 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, select=True), shift ) def move(self, direction, select=False, n=1): widget = self.widget cursor = widget.textCursor() mode = anchor_mode(select) for _ in range(n): if cursor.movePosition(direction, mode, 1): self.set_text_cursor(cursor) def page(self, offset, select=False): 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: cursor = widget.textCursor() mode = anchor_mode(select) cursor.setPosition(new_cursor.position(), mode) self.set_text_cursor(cursor) def page_down(self, select=False): widget = self.widget widget.page(widget.height() // 2, select=select) def page_up(self, select=False): widget = self.widget widget.page(-widget.height() // 2, select=select) 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. select = event.modifiers() & Qt.ShiftModifier mode = anchor_mode(select) 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, select=False): return self._mixin.page(offset, select=select) def page_up(self, select=False): return self._mixin.page_up(select=select) def page_down(self, select=False): return self._mixin.page_down(select=select) 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, select=False): return self._mixin.page(offset, select=select) def page_up(self, select=False): return self._mixin.page_up(select=select) def page_down(self, select=False): return self._mixin.page_down(select=select) def keyPressEvent(self, event): return self._mixin.keyPressEvent(event) class HintedDefaultLineEdit(LineEdit): """A line edit with hint text""" def __init__(self, hint, tooltip=None, parent=None): LineEdit.__init__(self, parent=parent, get_value=get_value_hinted) if tooltip: self.setToolTip(tooltip) self.hint = HintWidget(self, hint) self.hint.init() # pylint: disable=no-member self.textChanged.connect(lambda text: self.hint.refresh()) class HintedLineEdit(HintedDefaultLineEdit): """A monospace line edit with hint text""" def __init__(self, context, hint, tooltip=None, parent=None): super(HintedLineEdit, self).__init__(hint, tooltip=tooltip, parent=parent) self.setFont(qtutils.diff_font(context)) 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.12.0/cola/widgets/toolbar.py000066400000000000000000000437361417222504200177100ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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 .. 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::Grep', 'Actions::Search', ], 'Commit@@verb': [ 'Commit::Stage', 'Commit::AmendLast', 'Commit::UndoLastCommit', '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', ], 'Reset': [ 'Commit::UndoLastCommit', 'Commit::UnstageAll', 'Actions::ResetSoft', 'Actions::ResetMixed', 'Actions::RestoreWorktree', 'Actions::ResetKeep', 'Actions::ResetHard', ], 'View': ['View::DAG', 'View::FileBrowser'], } def configure(toolbar, parent=None): """Launches the Toolbar configure dialog""" if not parent: parent = qtutils.active_window() view = ToolbarView(toolbar, parent) 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']) try: toolbar.set_toolbar_style(data['toolbar_style']) except KeyError: # Maintain compatibility for toolbars created in git-cola <= 3.11.0 if data['show_icons']: data['toolbar_style'] = ToolBar.STYLE_FOLLOW_SYSTEM toolbar.set_toolbar_style(ToolBar.STYLE_FOLLOW_SYSTEM) else: data['toolbar_style'] = ToolBar.STYLE_TEXT_ONLY toolbar.set_toolbar_style(ToolBar.STYLE_TEXT_ONLY) 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 kept for backwards compatibility in git-cola <= 3.11.0 'show_icons': toolbar.toolbar_style() != ToolBar.STYLE_TEXT_ONLY, 'toolbar_style': toolbar.toolbar_style(), 'visible': toolbar.isVisible(), 'items': items, } ) return result class ToolBar(QtWidgets.QToolBar): SEPARATOR = 'Separator' STYLE_FOLLOW_SYSTEM = 'follow-system' STYLE_ICON_ONLY = 'icon' STYLE_TEXT_ONLY = 'text' STYLE_TEXT_BESIDE_ICON = 'text-beside-icon' STYLE_TEXT_UNDER_ICON = 'text-under-icon' STYLE_NAMES = [ N_('Follow System Style'), N_('Icon Only'), N_('Text Only'), N_('Text Beside Icon'), N_('Text Under Icon'), ] STYLE_SYMBOLS = [ STYLE_FOLLOW_SYSTEM, STYLE_ICON_ONLY, STYLE_TEXT_ONLY, STYLE_TEXT_BESIDE_ICON, STYLE_TEXT_UNDER_ICON, ] @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.setToolButtonStyle(Qt.ToolButtonFollowStyle) self.context = context self.tree_layout = tree_layout self.commands = toolbar_commands def set_toolbar_style(self, style_id): style_to_qt = { self.STYLE_FOLLOW_SYSTEM: Qt.ToolButtonFollowStyle, self.STYLE_ICON_ONLY: Qt.ToolButtonIconOnly, self.STYLE_TEXT_ONLY: Qt.ToolButtonTextOnly, self.STYLE_TEXT_BESIDE_ICON: Qt.ToolButtonTextBesideIcon, self.STYLE_TEXT_UNDER_ICON: Qt.ToolButtonTextUnderIcon, } default = Qt.ToolButtonFollowStyle return self.setToolButtonStyle(style_to_qt.get(style_id, default)) def toolbar_style(self): qt_to_style = { Qt.ToolButtonFollowStyle: self.STYLE_FOLLOW_SYSTEM, Qt.ToolButtonIconOnly: self.STYLE_ICON_ONLY, Qt.ToolButtonTextOnly: self.STYLE_TEXT_ONLY, Qt.ToolButtonTextBesideIcon: self.STYLE_TEXT_BESIDE_ICON, Qt.ToolButtonTextUnderIcon: self.STYLE_TEXT_UNDER_ICON, } default = self.STYLE_FOLLOW_SYSTEM return qt_to_style.get(self.toolButtonStyle(), default) 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) tooltip = command.get('tooltip', None) if tooltip: toolbar_action.setToolTip('%s\n%s' % (title, tooltip)) def delete_toolbar(self): self.parent().removeToolBar(self) def contextMenuEvent(self, event): menu = QtWidgets.QMenu() tool_config = menu.addAction(N_('Configure Toolbar'), partial(configure, self)) tool_config.setIcon(icons.configure()) tool_delete = menu.addAction(N_('Delete Toolbar'), self.delete_toolbar) tool_delete.setIcon(icons.remove()) menu.exec_(event.globalPos()) def encode_toolbar_area(toolbar_area): """Encode a Qt::ToolBarArea as a string""" default = 'bottom' return { Qt.LeftToolBarArea: 'left', Qt.RightToolBarArea: 'right', Qt.TopToolBarArea: 'top', Qt.BottomToolBarArea: 'bottom', }.get(toolbar_area, default) def decode_toolbar_area(string): """Decode an encoded toolbar area string into a Qt::ToolBarArea""" default = Qt.BottomToolBarArea return { 'left': Qt.LeftToolBarArea, 'right': Qt.RightToolBarArea, 'top': Qt.TopToolBarArea, 'bottom': Qt.BottomToolBarArea, }.get(string, default) 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')) self.toolbar_style_label = QtWidgets.QLabel(N_('Toolbar Style:')) self.toolbar_style = QtWidgets.QComboBox() for style_name in ToolBar.STYLE_NAMES: self.toolbar_style.addItem(style_name) style_idx = get_index_from_style(toolbar.toolbar_style()) self.toolbar_style.setCurrentIndex(style_idx) 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.toolbar_style_label, self.toolbar_style, 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): commands = self.toolbar.commands for action in self.toolbar.actions(): data = action.data() if data['child'] == self.toolbar.SEPARATOR: self.add_separator_action() else: try: child_data = data['child'] command = commands[child_data] except KeyError: pass title = command['title'] icon = command.get('icon', None) tooltip = command.get('tooltip', None) self.right_list.add_item(title, tooltip, data, icon) def load_left_items(self): commands = self.toolbar.commands for parent in self.toolbar.tree_layout: top = self.left_list.insert_top(parent) for item in self.toolbar.tree_layout[parent]: try: command = commands[item] except KeyError: pass icon = command.get('icon', None) tooltip = command.get('tooltip', None) child = create_child(parent, item, command['title'], tooltip, 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() style = get_style_from_index(self.toolbar_style.currentIndex()) self.toolbar.set_toolbar_style(style) 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) def get_style_from_index(index): """Return the symbolic toolbar style name for the given (combobox) index""" return ToolBar.STYLE_SYMBOLS[index] def get_index_from_style(style): """Return the toolbar style (combobox) index for the symbolic name""" return ToolBar.STYLE_SYMBOLS.index(style) 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, tooltip, data, icon): item = QtWidgets.QListWidgetItem() item.setText(N_(title)) item.setData(Qt.UserRole, data) if tooltip: item.setToolTip(tooltip) if icon: icon_func = getattr(icons, icon) item.setIcon(icon_func()) 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, tooltip, icon): data = {'parent': parent, 'child': child} item = create_item(title, data) if tooltip: item.setToolTip(tooltip) if icon: icon_func = getattr(icons, icon, None) item.setIcon(icon_func()) 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.12.0/cola/widgets/toolbarcmds.py000066400000000000000000000215511417222504200205460ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, 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': 'edit', }, 'File::RecentModified': { 'title': 'Recently Modified Files...', 'action': recent.browse_recent_files, 'icon': 'edit', }, 'File::ApplyPatches': { 'title': 'Apply Patches...', 'action': patch.apply_patches, 'icon': 'diff', }, 'File::ExportPatches': { 'title': 'Export Patches...', 'action': guicmds.export_patches, 'icon': 'save', }, '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': 'download'}, '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': 'commit'}, 'Actions::CreateTag': { 'title': 'Create Tag...', 'action': createtag.create_tag, 'icon': 'tag', }, 'Actions::CherryPick': { 'title': 'Cherry-Pick...', 'action': guicmds.cherry_pick, 'icon': 'cherry_pick', }, 'Actions::Merge': { 'title': 'Merge...', 'action': merge.local_merge, 'icon': 'merge', }, 'Actions::AbortMerge': { 'title': 'Abort Merge...', 'action': cmds.run(cmds.AbortMerge), 'icon': 'undo', }, 'Actions::UpdateSubmodules': { 'title': 'Update All Submodules...', 'action': cmds.run(cmds.SubmodulesUpdate), 'icon': 'sync', }, 'Actions::ResetSoft': { 'title': 'Reset Branch (Soft)', 'action': guicmds.reset_soft, 'icon': 'style_dialog_reset', 'tooltip': cmds.ResetSoft.tooltip(''), }, 'Actions::ResetMixed': { 'title': 'Reset Branch and Stage (Mixed)', 'action': guicmds.reset_mixed, 'icon': 'style_dialog_reset', 'tooltip': cmds.ResetMixed.tooltip(''), }, 'Actions::RestoreWorktree': { 'title': 'Restore Worktree', 'action': guicmds.restore_worktree, 'icon': 'edit', 'tooltip': cmds.RestoreWorktree.tooltip(''), }, 'Actions::ResetKeep': { 'title': 'Restore Worktree and Reset All (Keep Unstaged Changes)', 'action': guicmds.reset_keep, 'icon': 'style_dialog_reset', 'tooltip': cmds.ResetKeep.tooltip(''), }, 'Actions::ResetHard': { 'title': 'Restore Worktre and Reset All (Hard)', 'action': guicmds.reset_hard, 'icon': 'style_dialog_reset', 'tooltip': cmds.ResetHard.tooltip(''), }, 'Actions::Grep': { 'title': 'Grep', 'action': grep.grep, 'icon': 'search', }, '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': 'edit', }, 'Commit::UndoLastCommit': { 'title': 'Undo Last Commit', 'action': cmds.run(cmds.UndoLastCommit), 'icon': 'style_dialog_discard', }, 'Commit::StageAll': { 'title': 'Stage All Untracked', 'action': cmds.run(cmds.StageUntracked), 'icon': 'add', }, 'Commit::UnstageAll': { 'title': 'Unstage All', 'action': cmds.run(cmds.UnstageAll), 'icon': 'remove', }, 'Commit::Unstage': { 'title': 'Unstage', 'action': cmds.run(cmds.UnstageSelected), 'icon': 'remove', }, 'Commit::LoadCommitMessage': { 'title': 'Load Commit Message...', 'action': guicmds.load_commitmsg, 'icon': 'file_text', }, 'Commit::GetCommitMessageTemplate': { 'title': 'Get Commit Message Template', 'action': cmds.run(cmds.LoadCommitMessageFromTemplate), 'icon': 'style_dialog_apply', }, 'Diff::Difftool': { 'title': 'Launch Diff tool', 'action': cmds.run(cmds.LaunchDifftool), 'icon': 'diff', }, 'Diff::Expression': { 'title': 'Expression...', 'action': guicmds.diff_expression, 'icon': 'compare', }, 'Diff::Branches': { 'title': 'Branches...', 'action': compare.compare_branches, 'icon': 'compare', }, 'Diff::Diffstat': { 'title': 'Diffstat', 'action': cmds.run(cmds.Diffstat), 'icon': 'diff', }, 'Branch::Review': { 'title': 'Review...', 'action': guicmds.review_branch, 'icon': 'compare', }, 'Branch::Create': { 'title': 'Create...', 'action': createbranch.create_new_branch, 'icon': 'branch', }, 'Branch::Checkout': { 'title': 'Checkout...', 'action': guicmds.checkout_branch, 'icon': 'branch', }, 'Branch::Delete': { 'title': 'Delete...', 'action': guicmds.delete_branch, 'icon': 'discard', }, 'Branch::DeleteRemote': { 'title': 'Delete Remote Branch...', 'action': guicmds.delete_remote_branch, 'icon': 'discard', }, 'Branch::Rename': { 'title': 'Rename Branch...', 'action': guicmds.rename_branch, 'icon': 'edit', }, 'Branch::BrowseCurrent': { 'title': 'Browse Current Branch...', 'action': guicmds.browse_current, 'icon': 'directory', }, 'Branch::BrowseOther': { 'title': 'Browse Other Branch...', 'action': guicmds.browse_other, 'icon': 'directory', }, 'Branch::VisualizeCurrent': { 'title': 'Visualize Current Branch...', 'action': cmds.run(cmds.VisualizeCurrent), 'icon': 'visualize', }, 'Branch::VisualizeAll': { 'title': 'Visualize All Branches...', 'action': cmds.run(cmds.VisualizeAll), 'icon': 'visualize', }, '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.12.0/contrib/000077500000000000000000000000001417222504200147335ustar00rootroot00000000000000git-cola-3.12.0/contrib/README.md000066400000000000000000000012051417222504200162100ustar00rootroot00000000000000Miscellaneous 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 [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.12.0/contrib/darwin/000077500000000000000000000000001417222504200162175ustar00rootroot00000000000000git-cola-3.12.0/contrib/darwin/.gitignore000066400000000000000000000000151417222504200202030ustar00rootroot00000000000000/git-cola.py git-cola-3.12.0/contrib/darwin/Info.plist000066400000000000000000000027151417222504200201740ustar00rootroot00000000000000 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.12.0/contrib/darwin/PkgInfo000066400000000000000000000000101417222504200174660ustar00rootroot00000000000000APPL????git-cola-3.12.0/contrib/darwin/git-cola000077500000000000000000000004141417222504200176430ustar00rootroot00000000000000#!/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.12.0/contrib/darwin/git-cola.icns000066400000000000000000006161131417222504200206040ustar00rootroot00000000000000icnsKTOC 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.12.0/contrib/git-cola-completion.bash000066400000000000000000000050121417222504200214360ustar00rootroot00000000000000# 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.12.0/contrib/svg.tidy000066400000000000000000000011341417222504200164240ustar00rootroot00000000000000// 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.12.0/contrib/win32/000077500000000000000000000000001417222504200156755ustar00rootroot00000000000000git-cola-3.12.0/contrib/win32/README.md000066400000000000000000000010351417222504200171530ustar00rootroot00000000000000Windows 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.12.0/contrib/win32/cola000077500000000000000000000023251417222504200165430ustar00rootroot00000000000000#!/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.12.0/contrib/win32/dag000077500000000000000000000011211417222504200163510ustar00rootroot00000000000000#!/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.12.0/contrib/win32/git.bmp000066400000000000000000003171501417222504200171670ustar00rootroot00000000000000BMh6(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.12.0/contrib/win32/git.ico000066400000000000000000000537261417222504200171710ustar00rootroot0000000000000000f 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.12.0/contrib/win32/gpl-2.0.rtf000066400000000000000000000400701417222504200174720ustar00rootroot00000000000000{\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.12.0/contrib/win32/pynsist-preamble.py000066400000000000000000000002541417222504200215460ustar00rootroot00000000000000import os pythondir = os.path.join(installdir, 'Python') # noqa path = os.environ.get('PATH', '') os.environ['PATH'] = os.pathsep.join([pythondir, pkgdir, path]) # noqa git-cola-3.12.0/contrib/win32/run-pynsist.sh000077500000000000000000000002471417222504200205520ustar00rootroot00000000000000#!/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.12.0/docs000077700000000000000000000000001417222504200174322share/doc/git-colaustar00rootroot00000000000000git-cola-3.12.0/extras/000077500000000000000000000000001417222504200146015ustar00rootroot00000000000000git-cola-3.12.0/extras/README.md000066400000000000000000000006361417222504200160650ustar00rootroot00000000000000extras ====== 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.12.0/extras/__init__.py000066400000000000000000000005651417222504200167200ustar00rootroot00000000000000# pylint: disable=import-error,no-name-in-module from __future__ import absolute_import, division, print_function, unicode_literals from distutils.command.build import build from extras.build_mo import build_mo from extras.build_pot import build_pot cmdclass = { 'build_mo': build_mo, 'build_pot': build_pot, } build.sub_commands.insert(0, ('build_mo', None)) git-cola-3.12.0/extras/build_mo.py000066400000000000000000000100451417222504200167450ustar00rootroot00000000000000"""build_mo command for setup.py""" # pylint: disable=attribute-defined-outside-init,import-error,no-name-in-module from __future__ import absolute_import, division, print_function, 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.12.0/extras/build_pot.py000066400000000000000000000111731417222504200171370ustar00rootroot00000000000000"""build_pot command for setup.py""" # pylint: disable=attribute-defined-outside-init,import-error,no-name-in-module from __future__ import absolute_import, division, print_function, 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', '--no-fuzzy-matching', '--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): with open(src, 'rb') as f: content = f.read().decode('utf-8') if dst is None: dst = src f = open(dst, 'wb') try: f.write(build_util.encode(content)) finally: f.close() git-cola-3.12.0/extras/build_util.py000066400000000000000000000005741417222504200173150ustar00rootroot00000000000000def 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.12.0/extras/generate-build-version.sh000077500000000000000000000004331417222504200215120ustar00rootroot00000000000000#!/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.12.0/extras/qtpy/000077500000000000000000000000001417222504200155765ustar00rootroot00000000000000git-cola-3.12.0/extras/qtpy/AUTHORS.md000066400000000000000000000005441417222504200172500ustar00rootroot00000000000000# Authors ## Maintainer Spyder Development Team ([Spyder-IDE](http://github.com/spyder-ide)) ## Main Authors * Colin Duquesnoy ([@ColinDuquesnoy](http://github.com/ColinDuquesnoy)) * [The QtPy Contributors](https://github.com/spyder-ide/qtpy/graphs/contributors) ## Contributors * Thomas Robitaille ([@astrofrog](http://www.github.com/astrofrog)) git-cola-3.12.0/extras/qtpy/CHANGELOG.md000066400000000000000000000571131417222504200174160ustar00rootroot00000000000000# History of changes ## Version 1.11.2 (2021-09-23) ### Issues Closed * [Issue 248](https://github.com/spyder-ide/qtpy/issues/248) - Missing QtDataVisualization ([PR 249](https://github.com/spyder-ide/qtpy/pull/249) by [@dalthviz](https://github.com/dalthviz)) In this release 1 issue was closed. ### Pull Requests Merged * [PR 249](https://github.com/spyder-ide/qtpy/pull/249) - PR: Add handling for QtDataVisualization when missing, by [@dalthviz](https://github.com/dalthviz) ([248](https://github.com/spyder-ide/qtpy/issues/248)) In this release 1 pull request was closed. ---- ## Version 1.11.1 (2021-09-13) ### Issues Closed * [Issue 245](https://github.com/spyder-ide/qtpy/issues/245) - Importing `qtpy.uic` raises an exception ([PR 246](https://github.com/spyder-ide/qtpy/pull/246) by [@dalthviz](https://github.com/dalthviz)) In this release 1 issue was closed. ### Pull Requests Merged * [PR 246](https://github.com/spyder-ide/qtpy/pull/246) - PR: Wrap `pysideuic` and `pyside2uic` imports since they could be unavailable, by [@dalthviz](https://github.com/dalthviz) ([245](https://github.com/spyder-ide/qtpy/issues/245)) * [PR 244](https://github.com/spyder-ide/qtpy/pull/244) - qtpy/tests/test_uic.py: skip if pyside2uic not installed, by [@AndrewAmmerlaan](https://github.com/AndrewAmmerlaan) In this release 2 pull requests were closed. ---- ## Version 1.11.0 (2021-09-03) ### Issues Closed * [Issue 201](https://github.com/spyder-ide/qtpy/issues/201) - Missing QWebEngineProfile from QtWebEngineWidgets ([PR 242](https://github.com/spyder-ide/qtpy/pull/242) by [@dalthviz](https://github.com/dalthviz)) In this release 1 issue was closed. ### Pull Requests Merged * [PR 243](https://github.com/spyder-ide/qtpy/pull/243) - PR: `QtDataVisualization` backward compatibility handling on Windows, by [@dalthviz](https://github.com/dalthviz) * [PR 242](https://github.com/spyder-ide/qtpy/pull/242) - PR: Add `QtWebEngineWidgets.QWebEngineProfile` for PyQt5 and PySide2, by [@dalthviz](https://github.com/dalthviz) ([201](https://github.com/spyder-ide/qtpy/issues/201)) * [PR 228](https://github.com/spyder-ide/qtpy/pull/228) - PR: Rename QtDatavisualization to use uppercase v, by [@antlarr](https://github.com/antlarr) * [PR 219](https://github.com/spyder-ide/qtpy/pull/219) - PR: Add support for QStyleOptionFrameV3 from PyQt4, by [@PierreRaybaut](https://github.com/PierreRaybaut) * [PR 218](https://github.com/spyder-ide/qtpy/pull/218) - PR: Add QtWinExtras module, by [@phil65](https://github.com/phil65) * [PR 209](https://github.com/spyder-ide/qtpy/pull/209) - PR: Add support for QtSerialPort add-on, by [@Stanowczo](https://github.com/Stanowczo) * [PR 205](https://github.com/spyder-ide/qtpy/pull/205) - PR: Add support for the QtPositioning module, by [@avalentino](https://github.com/avalentino) * [PR 202](https://github.com/spyder-ide/qtpy/pull/202) - PR: Add loadUiType implementation for PySide2, by [@avalentino](https://github.com/avalentino) In this release 8 pull requests were closed. ---- ## Version 1.10.0 (2021-08-17) ### Issues Closed * [Issue 238](https://github.com/spyder-ide/qtpy/issues/238) - PySide2 and Python3.9: xml.etree.ElementTree.Element' object has no attribute 'getchildren * [Issue 222](https://github.com/spyder-ide/qtpy/issues/222) - Imported modules are not respected * [Issue 220](https://github.com/spyder-ide/qtpy/issues/220) - MNT: Stop using ci-helpers in appveyor.yml * [Issue 206](https://github.com/spyder-ide/qtpy/issues/206) - DeprecationWarning for getchildren ([PR 224](https://github.com/spyder-ide/qtpy/pull/224) by [@irrcombat](https://github.com/irrcombat)) * [Issue 198](https://github.com/spyder-ide/qtpy/issues/198) - PyQt4-sip==4.19.13 not supported In this release 5 issues were closed. ### Pull Requests Merged * [PR 241](https://github.com/spyder-ide/qtpy/pull/241) - PR: Update setup.py classifiers, by [@dalthviz](https://github.com/dalthviz) * [PR 230](https://github.com/spyder-ide/qtpy/pull/230) - PR: Fix imported modules logic if 'FORCE_QT_API' is empty, by [@hiaselhans](https://github.com/hiaselhans) * [PR 224](https://github.com/spyder-ide/qtpy/pull/224) - PR: Support python 3.9 `custom_widgets` iteration, by [@irrcombat](https://github.com/irrcombat) ([206](https://github.com/spyder-ide/qtpy/issues/206)) * [PR 215](https://github.com/spyder-ide/qtpy/pull/215) - PR: Slight typo fix, by [@altendky](https://github.com/altendky) * [PR 214](https://github.com/spyder-ide/qtpy/pull/214) - PR: Handle QtCore.SignalInstance/pyqtBoundSignal, by [@altendky](https://github.com/altendky) * [PR 208](https://github.com/spyder-ide/qtpy/pull/208) - PR: Move CI to Github Actions, by [@goanpeca](https://github.com/goanpeca) * [PR 204](https://github.com/spyder-ide/qtpy/pull/204) - PR: Add Python 3.9 compatibility for `collections.abc` module, by [@tirkarthi](https://github.com/tirkarthi) * [PR 199](https://github.com/spyder-ide/qtpy/pull/199) - PR: Add support to PyQt4-sip 4.19.13, by [@milanmatic](https://github.com/milanmatic) In this release 8 pull requests were closed. ---- ## 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.12.0/extras/qtpy/LICENSE.txt000066400000000000000000000021301417222504200174150ustar00rootroot00000000000000The 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.12.0/extras/sphinxtogithub/000077500000000000000000000000001417222504200176605ustar00rootroot00000000000000git-cola-3.12.0/extras/sphinxtogithub/__init__.py000066400000000000000000000013601417222504200217710ustar00rootroot00000000000000"""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.12.0/extras/sphinxtogithub/sphinxtogithub.py000066400000000000000000000242571417222504200233230ustar00rootroot00000000000000#! /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.12.0/po/000077500000000000000000000000001417222504200137115ustar00rootroot00000000000000git-cola-3.12.0/po/.gitignore000066400000000000000000000000111417222504200156710ustar00rootroot00000000000000*.msg *~ git-cola-3.12.0/po/README000066400000000000000000000001451417222504200145710ustar00rootroot00000000000000These are from the git-gui sources. Please see git-gui's po/README file for more details. TODO: todo git-cola-3.12.0/po/cs.po000066400000000000000000001630521417222504200146650ustar00rootroot00000000000000# 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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: cs\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 could not be opened. Remove from bookmarks?" msgstr "" #, 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 Submodule" msgstr "" msgid "Add Submodule..." msgstr "" msgid "New 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 this submodule?" msgstr "" 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 "Add to exclusions" msgstr "" msgid "Add to local .git/info/exclude" msgstr "" 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 "Autocomplete Paths" msgstr "" msgid "Automatically Load Commit Message Template" msgstr "" 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" msgid "Branch name" msgstr "" #, 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 Published Commits when Amending" msgstr "" msgid "Check Spelling" msgstr "Kontrolovat pravopis" msgid "Check spelling" msgstr "Kontrolovat pravopis" msgid "Check whether a commit has been published when amending" msgstr "" 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 open %s." msgstr "" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "Nedaří se zpracovat Git URL: „%s“" msgid "Create" msgstr "" 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 a new repository at that location?" msgstr "" msgid "Create a shallow clone with history truncated to the specified number of revisions. 0 performs a full clone." msgstr "" 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…" #, python-format msgid "Delete branch \"%s\"?" msgstr "" 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 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 "Depth" msgstr "" 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 "Disable" msgstr "" 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 "Enable path autocompletion in tools" msgstr "" 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" msgid "Error Opening Repository" msgstr "" #, 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 branch \"%s\"" msgstr "" #, 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 "Folder" 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-cola-sequence-editor" msgstr "Nápověda – git-cola-sequence-editor" 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 "Ignore..." msgstr "" 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 "Japanese translation" msgstr "" 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 "List" 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 "Prune Missing Entries" msgstr "" 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 "Reference Repository" msgstr "" msgid "Reference URL" msgstr "" msgid "Reference repository to use when cloning (optional)" msgstr "" 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 "Remove stale entries for repositories that no longer exist" msgstr "" 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í" msgid "Repository Not Found" msgstr "" #, 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 All (Keep Unstaged Changes)" msgstr "" msgid "Reset Branch" msgstr "Resetovat větev" msgid "Reset Branch (Soft)" msgstr "" msgid "Reset Branch and Stage (Mixed)" msgstr "" msgid "Reset Branch?" msgstr "Resetovat větev?" msgid "Reset Layout" msgstr "" msgid "Reset Worktree and Reset All?" msgstr "" msgid "Reset and Restore" msgstr "" msgid "Reset branch?" msgstr "" #, 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 "Restore Worktree" msgstr "" msgid "Restore Worktree and Reset All (Hard)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Changes)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Edits)" msgstr "" msgid "Restore Worktree and Reset All (Merge)" msgstr "" msgid "Restore Worktree and Reset All?" msgstr "" #, python-format msgid "Restore Worktree to %s?" msgstr "" msgid "Restore worktree, reset, and preserve unstaged edits?" 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 a parent directory for the new clone" msgstr "Vybrat nadřazenou složku pro nový klon" 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 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 / Unstage All" msgstr "" 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 Modified and Untracked" msgstr "" 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 "Submodule URL (can be relative, ex: ../repo.git)" msgstr "" msgid "Submodule branch to track (optional)" msgstr "" msgid "Submodule path within the current repository (optional)" msgstr "" 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 --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:" #, python-format msgid "The repository will be reset using \"git reset --hard %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --keep %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --merge %s\"" msgstr "" msgid "The revision expression cannot be empty." msgstr "Výraz revize nemůže zůstat nevyplněný." #, python-format msgid "" "The submodule will be added using\n" "\"%s\"" msgstr "" #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be restored using \"git read-tree --reset -u %s\"" msgstr "" 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 image diff" 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 "Translation" msgstr "" 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 "Undo Last Commit" msgstr "" msgid "Undo last commit?" msgstr "" msgid "Undo the published commit?" msgstr "" 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 "git://git.example.com/repo.git" msgstr "" msgid "grep result..." msgstr "výsledek z grep…" msgid "hotkeys.html" msgstr "hotkeys.html" msgid "path/to/submodule" msgstr "" msgid "title" msgstr "" 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 "Delete selected branch?" #~ msgstr "Smazat vybranou větev?" #~ msgid "Hide Details.." #~ msgstr "Skrýt podrobnosti…" #~ msgid "PATCH %(current)d/%(count)d" #~ msgstr "PATCH %(current)d/%(count)d" #~ msgid "Rename remote?" #~ msgstr "Přejmenovat vzdálenou?" #~ msgid "Reset Branch Head" #~ msgstr "Resetovat hlavu větve" #~ 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?" #~ msgid "Select File" #~ msgstr "Vybrat soubor" #~ msgid "Select Repository..." #~ msgstr "Vybrat repozitář…" #~ msgid "Select manually..." #~ msgstr "Vybrat ručně…" #~ msgid "Show Details..." #~ msgstr "Zobrazit podrobnosti…" #~ msgid "Summary:" #~ msgstr "Shrnutí:" #~ msgid "The branch will be reset using \"git reset --hard %s\"" #~ msgstr "Větev bude resetována za použití \"git reset --hard %s\"" #~ msgid "The branch will be reset using \"git reset --merge %s\"" #~ msgstr "Větev bude resetována za použití \"git reset --merge %s\"" #~ msgid "The worktree will be reset using \"git reset --keep %s\"" #~ msgstr "Větev bude resetována za použití \"git reset --keep %s\"" git-cola-3.12.0/po/de.po000066400000000000000000002723361417222504200146560ustar00rootroot00000000000000# 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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: de\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 could not be opened. Remove from bookmarks?" msgstr "" #, 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 Submodule" msgstr "" msgid "Add Submodule..." msgstr "" msgid "New 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 this submodule?" msgstr "" 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 "Add to exclusions" msgstr "" msgid "Add to local .git/info/exclude" msgstr "" 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 "Autocomplete Paths" msgstr "" msgid "Automatically Load Commit Message Template" msgstr "" 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" msgid "Branch name" msgstr "" #, 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 Published Commits when Amending" msgstr "" msgid "Check Spelling" msgstr "Rechtschreibung prüfen" msgid "Check spelling" msgstr "Rechtschreibung prüfen" msgid "Check whether a commit has been published when amending" msgstr "" 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 open %s." msgstr "" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "URL konnte nicht ausgewertet werden: \"%s\"" msgid "Create" msgstr "" 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 a new repository at that location?" msgstr "" msgid "Create a shallow clone with history truncated to the specified number of revisions. 0 performs a full clone." msgstr "" 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..." #, python-format msgid "Delete branch \"%s\"?" msgstr "" 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 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 "Depth" msgstr "" 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 "Disable" msgstr "" 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 "Enable path autocompletion in tools" msgstr "" 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" msgid "Error Opening Repository" msgstr "" #, 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 branch \"%s\"" msgstr "" #, 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 "Folder" 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-cola-sequence-editor" msgstr "Hilfe - git-cola-sequence-editor" 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 "Ignore..." msgstr "" 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 "Japanese translation" msgstr "" 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 "List" 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 "Prune Missing Entries" msgstr "" 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 "Reference Repository" msgstr "" msgid "Reference URL" msgstr "" msgid "Reference repository to use when cloning (optional)" msgstr "" 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 "Remove stale entries for repositories that no longer exist" msgstr "" 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" msgid "Repository Not Found" msgstr "" #, 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 All (Keep Unstaged Changes)" msgstr "" msgid "Reset Branch" msgstr "Branch zurücksetzen" msgid "Reset Branch (Soft)" msgstr "" msgid "Reset Branch and Stage (Mixed)" msgstr "" msgid "Reset Branch?" msgstr "Branch zurücksetzen?" msgid "Reset Layout" msgstr "" msgid "Reset Worktree and Reset All?" msgstr "" msgid "Reset and Restore" msgstr "" msgid "Reset branch?" msgstr "" #, 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 "Restore Worktree" msgstr "" msgid "Restore Worktree and Reset All (Hard)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Changes)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Edits)" msgstr "" msgid "Restore Worktree and Reset All (Merge)" msgstr "" msgid "Restore Worktree and Reset All?" msgstr "" #, python-format msgid "Restore Worktree to %s?" msgstr "" msgid "Restore worktree, reset, and preserve unstaged edits?" 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 a parent directory for the new clone" msgstr "Wählen Sie das übergeordnete Verzeichnis für den Klon" 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 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 / Unstage All" msgstr "" 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 Modified and Untracked" msgstr "" 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 "Submodule URL (can be relative, ex: ../repo.git)" msgstr "" msgid "Submodule branch to track (optional)" msgstr "" msgid "Submodule path within the current repository (optional)" msgstr "" 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 --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:" #, python-format msgid "The repository will be reset using \"git reset --hard %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --keep %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --merge %s\"" msgstr "" msgid "The revision expression cannot be empty." msgstr "Der Ausdruck darf nicht leer sein." #, python-format msgid "" "The submodule will be added using\n" "\"%s\"" msgstr "" #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be restored using \"git read-tree --reset -u %s\"" msgstr "" 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 image diff" msgstr "" 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 "Translation" msgstr "" 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 "Undo Last Commit" msgstr "" msgid "Undo last commit?" msgstr "" msgid "Undo the published commit?" msgstr "" 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 "git://git.example.com/repo.git" msgstr "" msgid "grep result..." msgstr "Ergebnis von grep..." msgid "hotkeys.html" msgstr "hotkeys_de.html" msgid "path/to/submodule" msgstr "" msgid "title" msgstr "" 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 "Delete selected branch?" #~ msgstr "Gewählten Branch löschen?" #~ 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:" #~ 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 Branch Head" #~ msgstr "Branch-Head zurücksetzen" #~ msgid "Reset Worktree" #~ msgstr "Arbeitsbaum zurücksetzen" #~ 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 "Reset worktree?" #~ msgstr "Arbeitsbaum 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 Repository..." #~ msgstr "Repository wählen..." #~ msgid "Select file from \"%s\"" #~ msgstr "Datei von \"%s\" auswählen" #~ msgid "Select manually..." #~ msgstr "Selbst 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 (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 'main' branch has not been initialized." #~ msgstr "Der »main«-Zweig wurde noch nicht initialisiert." #~ msgid "The branch will be reset using \"git reset --hard %s\"" #~ msgstr "Der Branch wird zurückgesetzt mit \"git reset --hard %s\"" #~ msgid "The branch will be reset using \"git reset --merge %s\"" #~ msgstr "Der Branch wird zurückgesetzt mit \"git reset --merge %s\"" #~ 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 "The worktree will be reset using \"git reset --keep %s\"" #~ msgstr "Der Arbeitsbaum wird zurückgesetzt mit \"git reset --keep %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.12.0/po/es.po000066400000000000000000001704771417222504200147000ustar00rootroot00000000000000# 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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: es_ES\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 could not be opened. Remove from bookmarks?" msgstr "" #, 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 Submodule" msgstr "" msgid "Add Submodule..." msgstr "" msgid "New 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 this submodule?" msgstr "" 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 "Add to exclusions" msgstr "" msgid "Add to local .git/info/exclude" msgstr "" 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 "Autocomplete Paths" msgstr "" msgid "Automatically Load Commit Message Template" msgstr "" 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" msgid "Branch name" msgstr "" #, 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 Published Commits when Amending" msgstr "" msgid "Check Spelling" msgstr "Comprobar ortografía" msgid "Check spelling" msgstr "Comprobar ortografía" msgid "Check whether a commit has been published when amending" msgstr "" 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 open %s." msgstr "" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "No fue posible procesar la Git URL: \"%s\"" msgid "Create" msgstr "" 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 a new repository at that location?" msgstr "" msgid "Create a shallow clone with history truncated to the specified number of revisions. 0 performs a full clone." msgstr "" 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..." #, python-format msgid "Delete branch \"%s\"?" msgstr "" 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 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 "Depth" msgstr "" 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 "Disable" msgstr "" 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 "Enable path autocompletion in tools" msgstr "" 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" msgid "Error Opening Repository" msgstr "" #, 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 branch \"%s\"" msgstr "" #, 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 "Folder" 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-cola-sequence-editor" msgstr "Ayuda - git-cola-sequence-editor" 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 "Ignore..." msgstr "" 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 "Japanese translation" msgstr "" 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 "List" 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 "Prune Missing Entries" msgstr "" 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 "Reference Repository" msgstr "" msgid "Reference URL" msgstr "" msgid "Reference repository to use when cloning (optional)" msgstr "" 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 "Remove stale entries for repositories that no longer exist" msgstr "" 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" msgid "Repository Not Found" msgstr "" #, 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 All (Keep Unstaged Changes)" msgstr "" msgid "Reset Branch" msgstr "Reiniciar rama" msgid "Reset Branch (Soft)" msgstr "" msgid "Reset Branch and Stage (Mixed)" msgstr "" msgid "Reset Branch?" msgstr "¿Reiniciar rama?" msgid "Reset Layout" msgstr "" msgid "Reset Worktree and Reset All?" msgstr "" msgid "Reset and Restore" msgstr "" msgid "Reset branch?" msgstr "" #, 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 "Restore Worktree" msgstr "" msgid "Restore Worktree and Reset All (Hard)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Changes)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Edits)" msgstr "" msgid "Restore Worktree and Reset All (Merge)" msgstr "" msgid "Restore Worktree and Reset All?" msgstr "" #, python-format msgid "Restore Worktree to %s?" msgstr "" msgid "Restore worktree, reset, and preserve unstaged edits?" 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 a parent directory for the new clone" msgstr "Seleccione un directorio padre para el nuevo clonado" 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 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 / Unstage All" msgstr "" msgid "Stage All Untracked" msgstr "" msgid "Stage Changed Files To Commit" msgstr "" msgid "Stage Diff Hunk" msgstr "" msgid "Stage Modified" msgstr "" msgid "Stage Modified and Untracked" 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 "Submodule URL (can be relative, ex: ../repo.git)" msgstr "" msgid "Submodule branch to track (optional)" msgstr "" msgid "Submodule path within the current repository (optional)" msgstr "" 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 --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:" #, python-format msgid "The repository will be reset using \"git reset --hard %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --keep %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --merge %s\"" msgstr "" 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 added using\n" "\"%s\"" msgstr "" #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be restored using \"git read-tree --reset -u %s\"" msgstr "" 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 image diff" msgstr "" 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 "Translation" msgstr "" 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 "Undo Last Commit" msgstr "" msgid "Undo last commit?" msgstr "" msgid "Undo the published commit?" 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 "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 "git://git.example.com/repo.git" msgstr "" msgid "grep result..." msgstr "resultados de grep..." msgid "hotkeys.html" msgstr "hotkeys.html" msgid "path/to/submodule" msgstr "" msgid "title" msgstr "" 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" #~ msgid "Delete selected branch?" #~ msgstr "¿Desea eliminar la rama seleccionada?" #~ msgid "Hide Details.." #~ msgstr "Ocultar detalles..." #~ msgid "Reset Branch Head" #~ msgstr "Reiniciar inicio (head) de 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?" #~ msgid "Select Repository..." #~ msgstr "Seleccionar repositorio..." #~ msgid "Select manually..." #~ msgstr "Seleccionar manualmente..." #~ msgid "Show Details..." #~ msgstr "Mostrar detalles..." #~ msgid "The branch will be reset using \"git reset --hard %s\"" #~ msgstr "La rama será reiniciada utilizando \"git reset --hard %s\"" #~ msgid "The branch will be reset using \"git reset --merge %s\"" #~ msgstr "La rama será reiniciada utilizando \"git reset --merge %s\"" #~ msgid "The worktree will be reset using \"git reset --keep %s\"" #~ msgstr "El árbol de trabajo será reiniciado utilizando \"git reset --keep %s\"" git-cola-3.12.0/po/fr.po000066400000000000000000002025611417222504200146660ustar00rootroot00000000000000# 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 # Maxime Leroy , 2021 # msgid "" msgstr "" "Project-Id-Version: git-cola VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-12-01 00:00+0100\n" "PO-Revision-Date: 2021-12-18 02:25+0200\n" "Last-Translator: Maxime Leroy \n" "Language-Team: français <>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: fr\n" "X-Generator: Poedit 3.0\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Poedit-Bookmarks: -1,537,-1,-1,-1,-1,-1,-1,-1,-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 "" "\n" "
\n" " Git Cola a été traduit dans différentes langues grâce\n" " à l'aide des personnes listées en dessous.\n" "\n" "
\n" "

\n" " Le plus grand soin a été apporté à ces traductions. Mais si vous trouvez\n" " des erreurs, n'hésitez pas à ouvrir un ticket sur Github :\n" "

\n" "\n" "

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

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

\n" " Nous vous invitons à participer aux traductions en en ajoutant\n" " ou en modifiant puis à faire une 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 en 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" " 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 "" "\n" " Format des Variables\n" " -----------------------\n" " %(path)s = chemin de fichier relatif\n" " %(abspath)s = chemin de fichier absolu\n" " %(dirname)s = chemin de répertoire relatif\n" " %(absdirname)s = chemin de répertoire absolu\n" " %(filename)s = nom de fichier\n" " %(basename)s = nom de fichier sans l'extension\n" " %(ext)s = extension du fichier\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" "Commandes\n" "--------\n" "pick = utiliser le commit\n" "reword = utiliser le commit, mais modifier le message du commit\n" "edit = utiliser le commit, mais arrêter pour la correction\n" "squash = utiliser le commit, mais fusionner avec le commit précédent\n" "fixup = comme \"squash\", mais effacer le message de journal de ce commit\n" "exec = lancer une commande (la suite de la ligne) via le shell\n" "\n" "L'ordre de ces lignes peut être changé ; elles sont exécutées de haut en bas.\n" "\n" "Si vous désactivez une ligne ici CE COMMIT SERA PERDU.\n" "\n" "Mais si vous désactivez tout, ce rétablissement sera annulé.\n" "\n" "Raccourcis clavier\n" "------------------\n" "? = afficher l'aide\n" "j = se déplacer vers le bas\n" "k = se déplacer vers le haut\n" "J = déplacer la ligne vers le bas\n" "K = déplacer la ligne vers le haut\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "espace = changer l'activation\n" "\n" "ctrl+entrée = accepter les modifications et rétablir\n" "ctrl+q = tout annuler dont le rétablissement\n" "ctrl+d = lancer 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" "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 "La branche « %(branch)s » a été supprimée de « %(remote)s »." #, python-format msgid "\"%(command)s\" returned exit status \"%(status)d\"" msgstr "La commande « %(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 retourné le statut de sortie %(status)d" #, python-format msgid "\"%s\" already exists" msgstr "« %s » existe déjà" #, python-format msgid "\"%s\" already exists, cola will create a new directory" msgstr "« %s » existe déjà, git-cola va créer un nouveau répertoire" #, python-format msgid "\"%s\" requires a selected file." msgstr "« %s » nécessite de sélectionner 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 "%d 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 conflits de fusion.\n" "\n" "Vous devriez ignorer ce fichier.\n" "Le commiter malgré tout ?" #, python-format msgid "%s could not be opened. Remove from bookmarks?" msgstr "%s n'a pu être ouvert. Le retirer des marque-pages ?" #, 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 "&Éditer" msgid "&File" msgstr "&Fichier" msgid "(Amending)" msgstr "(Correction)" msgid "*** Branch Point ***" msgstr "*** Point de branchement ***" msgid "*** Sandbox ***" msgstr "*** Bac à sable ***" 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 "" "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 "Un crochet doit être spécifié à « %s »" #, 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 "Abandonner l'action" msgid "Abort Merge" msgstr "Abandonner la fusion" msgid "Abort Merge..." msgstr "Abandonner la 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 entraînera la perte de *TOUTES* les modifications non commitées.\n" "La récupération des modifications non commitées ne sera pas possible." msgid "Aborting the current merge?" msgstr "Abandonner la fusion actuelle ?" msgid "About" msgstr "A propos" msgid "About git-cola" msgstr "À propos de git-cola" msgid "Accept" msgstr "Accepter" msgid "" "Accept changes and rebase\n" "Shortcut: Ctrl+Enter" msgstr "" "Accepter les modifications et rétablir\n" "Raccourcis : Ctrl+Entrée" msgid "Action Name" msgstr "Nom de l'action" msgid "Actions" msgstr "Actions" msgid "Actions..." msgstr "Actions..." msgid "Add" msgstr "Ajouter" msgid "Add Favorite" msgstr "Ajouter comme marque-page" msgid "Add Remote" msgstr "Ajouter un élément distant" msgid "Add Separator" msgstr "Ajouter un séparateur" msgid "Add Submodule" msgstr "Ajouter un sous-module" msgid "Add Submodule..." msgstr "Ajouter un sous-module..." msgid "New Toolbar" msgstr "Nouvelle barre d'outils" 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électionnant 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 this submodule?" msgstr "Ajouter ce sous-module ?" 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 "Add to exclusions" msgstr "Marquer à exclure" msgid "Add to local .git/info/exclude" msgstr "Ajouter au fichier local .git/info/exclude" msgid "Additions" msgstr "Ajouts" msgid "Advanced" msgstr "Avancé" msgid "Age" msgstr "Âge" msgid "All Repositories" msgstr "Tous les dépôts" #, python-format msgid "" "All submodules will be updated using\n" "\"%s\"" msgstr "" "Tous les sous-modules seront mis à jour avec\n" "« %s »" 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 le commit" msgid "Amend Last Commit" msgstr "Corriger le 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 "Apparence" 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 "Appliquer et supprimer le remisage sélectionné (git stash pop)" 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 "Auto" msgid "Auto-Wrap Lines" msgstr "Retour à la ligne automatique" msgid "Autocomplete Paths" msgstr "Auto-compléter les chemins" msgid "Automatically Load Commit Message Template" msgstr "Charger automatiquement le modèle de message de commit" msgid "Basic Regexp" msgstr "Regexp basique" msgid "Blame Viewer" msgstr "Visionneur de fichier" msgid "Blame selected paths" msgstr "Visionner les chemins sélectionnés" msgid "Blame..." msgstr "Visionner..." msgid "Bold on dark headers instead of italic" msgstr "Police en gras avec fond sombre pour les en-têtes plutôt que l'italique" 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 "Visionneur de différence de branches" msgid "Branch Exists" msgstr "La branche existe" msgid "Branch Name" msgstr "Nom de branche" msgid "Branch name" msgstr "Nom de branche" #, python-format msgid "Branch: %s" msgstr "Branche : %s" msgid "Branches" msgstr "Branches" 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 "" "Annuler le rétablissement\n" "Raccourcis : Ctrl+Q" 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 Published Commits when Amending" msgstr "Vérifier la publication d'un commit lors de sa correction" msgid "Check Spelling" msgstr "Vérifier l'orthographe" msgid "Check spelling" msgstr "Vérifier l'orthographe" msgid "Check whether a commit has been published when amending" msgstr "Vérifier si un commit a été publié avant qu'il soit corriger" msgid "Checkout" msgstr "Emprunter" msgid "Checkout After Creation" msgstr "Emprunt après création" msgid "Checkout Branch" msgstr "Emprunter la branche" msgid "Checkout Detached HEAD" msgstr "Emprunter le HEAD détaché" msgid "Checkout as new branch" msgstr "Emprunter comme nouvelle branche" 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 pour « git grep »" msgid "Clear Default Repository" msgstr "Effacer 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 "Commande" msgid "Commit" msgstr "Commit" msgid "Commit failed" msgstr "Le commit a échoué" msgid "Commit staged changes" msgstr "Commiter les modifications pré-commitées" 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 "Configurer la barre d'outils" msgid "Console" msgstr "Terminal" msgid "Continue" msgstr "Continuer" msgid "Copy" msgstr "Copier" msgid "Copy Basename to Clipboard" msgstr "Copier le nom de base dans le presse-papiers" msgid "Copy Leading Path to Clipboard" msgstr "Copier le chemin principal dans le presse-papiers" 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-papiers" msgid "Copy SHA-1" msgstr "Copier SHA-1" msgid "Copy..." msgstr "Copier..." #, python-format msgid "Could not open %s." msgstr "Ne peut pas ouvrir %s." #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "Impossible d'interpréter l'URL Git : « %s »" msgid "Create" msgstr "Créer" msgid "Create Branch" msgstr "Créer branche" msgid "Create Patch" msgstr "Créer patch" msgid "Create Remote Branch" msgstr "Créer une 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 une nouvelle branche distante ?" msgid "Create a new repository at that location?" msgstr "Créer un nouveau dépôt à cet emplacement ?" msgid "Create a shallow clone with history truncated to the specified number of revisions. 0 performs a full clone." msgstr "Créer un clonage de surface avec l'historique limité au nombre de révision spécifiée. 0 pour un clonage en entier." 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 "Actions de copie personnalisées" msgid "Customize..." msgstr "Personnaliser..." msgid "Cut" msgstr "Couper" msgid "Czech translation" msgstr "Traduction tchèque" msgid "DAG..." msgstr "DAG..." msgid "Dark Theme" msgstr "Thème sombre" msgid "Date, Time" msgstr "Date, heure" msgid "Default" msgstr "Défaut" 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 la 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 le dépôt distant" msgid "Delete Remote Branch" msgstr "Supprimer la branche distante" msgid "Delete Remote Branch..." msgstr "Supprimer la branche distante..." #, python-format msgid "Delete branch \"%s\"?" msgstr "Supprimer la branche « %s » ?" 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 Toolbar" msgstr "Supprimer la barre d'outils" msgid "Delete..." msgstr "Supprimer..." #, python-format msgid "Deleting \"%s\" failed" msgstr "Suppression de « %s » a échoué" msgid "Deletions" msgstr "Suppressions" msgid "Depth" msgstr "Profondeur" msgid "Detach" msgstr "Détacher" msgid "Detect Conflict Markers" msgstr "Détecter les 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 "Diffstat" msgid "Difftool" msgstr "Difftool" msgid "Directory Exists" msgstr "Le répertoire existe" msgid "Disable" msgstr "Désactiver" 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 "Modifier les éléments distants en les sélectionnant depuis la liste" 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 "Email des contributeurs" msgid "Enable path autocompletion in tools" msgstr "Activer l’auto-complétion des chemins dans les outils" msgid "Enabled" msgstr "Activé" msgid "Enter New Branch Name" msgstr "Entrez le nouveau nom de la branche" msgid "Enter a name for the new bare repo" msgstr "Entrez un nom pour le nouveau dépôt vide" 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 en modifiant le 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" msgid "Error Opening Repository" msgstr "Erreur lors de l'ouverture du dépôt" #, python-format msgid "Error creating remote \"%s\"" msgstr "Erreur lors de la création de l'élément distant « %s »" msgid "Error creating stash" msgstr "Erreur lors de la création du rétablissement" #, python-format msgid "Error deleting branch \"%s\"" msgstr "Erreur lors de la suppression de la branche « %s »" #, 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 "Erreur lors du renommage de « %(name)s » en « %(new_name)s »" msgid "Error running prepare-commitmsg hook" msgstr "Erreur lors du lancement de « prepare-commitmsg hook »" #, python-format msgid "Error updating submodule %s" msgstr "Erreur lors de la mise à jour du sous-module « %s »" msgid "Error updating submodules" msgstr "Erreur lors de la mise à jour des sous-modules" 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 "Exécution de l'action %s" 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 "Détailler la description..." 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 "Récupérer la branche suivie" msgid "Fetch..." msgstr "Récupérer..." msgid "File Browser..." msgstr "Navigateur de fichier..." msgid "File Differences" msgstr "Différences des fichiers" 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 des changements dans le système de fichiers : activé.\n" msgid "Filename" msgstr "Nom de fichier" msgid "Files" msgstr "Fichiers" msgid "Filter branches..." msgstr "Filtrer les branches..." msgid "Filter paths..." msgstr "Filtrer les chemins..." msgid "Find Files" msgstr "Trouver des fichiers" msgid "Fixed String" msgstr "Chaîne fixe" msgid "Fixed-Width Font" msgstr "Police à largeur fixe" msgid "Fixup" msgstr "Réparer" msgid "Fixup Previous Commit" msgstr "Réparer le commit précédent" msgid "Flat dark blue" msgstr "Simple bleu foncé" msgid "Flat dark green" msgstr "Simple vert foncé" msgid "Flat dark grey" msgstr "Simple gris foncé" msgid "Flat dark red" msgstr "Simple rouge foncé" msgid "Flat light blue" msgstr "Simple bleu clair" msgid "Flat light green" msgstr "Simple vert clair" msgid "Flat light grey" msgstr "Simple gris clair" msgid "Flat light red" msgstr "Simple rouge clair" msgid "Folder" msgstr "Répertoire" 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 poussée ?" #, python-format msgid "Force fetching from %s?" msgstr "Forcer la récupération depuis %s ?" #, python-format msgid "Force push to %s?" msgstr "Forcer la poussée vers %s ?" msgid "Format String" msgstr "Le texte du format" msgid "French translation" msgstr "Traduction française" msgid "GPG-sign the merge commit" msgstr "GPG-signer le commit fusionné" msgid "GUI theme" msgstr "Thème de l'interface" #, python-format msgid "Gathering info for \"%s\"..." msgstr "Récupération 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é récemment ?" msgid "Help" msgstr "Aide" msgid "Help - Custom Copy Actions" msgstr "Aide - Actions de copie personnalisées" msgid "Help - Find Files" msgstr "Aide - Trouver des fichiers" msgid "Help - git-cola-sequence-editor" msgstr "Aide - git-cola-sequence-editor" msgid "High DPI" msgstr "Haut DPI" msgid "History Browser" msgstr "Navigateur de l'historique" msgid "Hungarian translation" msgstr "Traduction hongroise" msgid "Icon theme" msgstr "Thème des icônes" 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" msgid "Ignore changes in whitespace at EOL" msgstr "Ignorer les changements d'espaces à la fin des lignes" msgid "Ignore custom pattern" msgstr "Ignorer les motifs personnalisés" msgid "Ignore exact filename" msgstr "Ignorer les noms de fichier exacts" msgid "Ignore filename or pattern" msgstr "Ignorer un nom de fichier ou un motif" msgid "Ignore..." msgstr "Ignorer..." msgid "Include tags " msgstr "Inclure les marques " msgid "Indent Status paths" msgstr "Indenter le chemin des statuts" msgid "Indonesian translation" msgstr "Traduction indonésienne" msgid "Initialize Git Annex" msgstr "Initialiser Git Annex" msgid "Initialize Git LFS" msgstr "Initialiser Git LFS" msgid "Inititalize submodules" msgstr "Initialiser les sous-modules" msgid "Insert spaces instead of tabs" msgstr "Insérer des espaces au lieu de tabulations" msgid "Interactive Rebase" msgstr "Rétablissement interactif" msgid "Invalid Revision" msgstr "Révision invalide" msgid "Japanese translation" msgstr "Traduction japonaise" 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 "" "Lancer un outil de diff externe\n" "Raccourcis : Ctrl+D" 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 "Thème clair" msgid "List" msgstr "Liste" 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 du précédent commit" msgid "Loading..." msgstr "Chargement..." msgid "Local" msgstr "Local" msgid "Local Branch" msgstr "Branche locale" msgid "Local branch" msgstr "Branche locale" msgid "Lock Layout" msgstr "Verrouiller la disposition" msgid "Log" msgstr "Journal" msgid "Maintainer (since 2007) and developer" msgstr "Mainteneur (depuis 2007) et développeur" msgid "Merge" msgstr "Fusionner" #, python-format msgid "Merge \"%(revision)s\" into \"%(branch)s\"" msgstr "Fusionner « %(revision)s » vers « %(branch)s »" msgid "Merge Tool" msgstr "Outil de fusion" msgid "Merge Verbosity" msgstr "Fusion détaillée" msgid "Merge failed. Conflict resolution is required." msgstr "La fusion a échouée. Il est nécessaire de résoudre les conflits." #, python-format msgid "Merge into \"%s\"" msgstr "Fusionner dans « %s »" msgid "Merge into current branch" msgstr "Fusionner dans la branche actuelle" 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ées manquantes" 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 "Nouveau dépôt vide..." 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 "Rien à 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 un dépôt Git..." msgid "Open Parent" msgstr "Ouvrir le parent" 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 "Autres branches" msgid "Overwrite" msgstr "Écraser" #, 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 "" "Interpréter 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 "Choisir" msgid "Pixel XOR" msgstr "Ou-exclusif des pixels" 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 à marquer." 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 : Vide.\n" "- Lignes suivantes : Expliquer l'intérêt de vos modifications.\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 "Supprimer" msgid "Preferences" msgstr "Préférences" msgid "Prefix" msgstr "Préfixe" msgid "Prepare Commit Message" msgstr "Préparer le message de commit" msgid "Prevent \"Stage\" from staging all files when nothing is selected" msgstr "Empêcher \"Pré-commiter\" de tout pré-commiter si aucun fichier n'est sélectionné" 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éée des nouvelles branches distantes" msgid "Prune " msgstr "Réviser " msgid "Prune Missing Entries" msgstr "Réviser les entrées manquantes" 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 "Rétablissement arrêté" msgid "Rebase the current branch instead of merging" msgstr "Rétablir la branche courante au lieu de la fusionner" msgid "Rebasing" msgstr "Rétablir" msgid "Recent" msgstr "Récent" msgid "Recent repositories" msgstr "Dépôts récents" msgid "Recent repository count" msgstr "Nombre de dépôts récents" 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é n'est pas possible." msgid "Recovering lost commits may not be easy." msgstr "Récupérer les commits perdus n'est pas toujours évident." msgid "Redo" msgstr "Refaire" msgid "Reduce commit history to minimum" msgstr "Réduire l'historique des commits au minimum" msgid "Reference Repository" msgstr "Dépôt de référence" msgid "Reference URL" msgstr "URL de référence" msgid "Reference repository to use when cloning (optional)" msgstr "Le dépôt de référence à utiliser lors du clonage (facultatif)" 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 sauf si l'en-tête actuelle est déjà mis à jour ou bien que la fusion peut être résolue rapidement" msgid "Remote" msgstr "Élément distant" 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 "Supprimer l'élément" msgid "Remove remote-tracking branches that no longer exist on the remote" msgstr "Retirer les branches distantes suivies qui n'existent plus dans l'élément distant" msgid "Remove selected (Delete)" msgstr "Supprimer la sélection" msgid "Remove stale entries for repositories that no longer exist" msgstr "Retirer les entrées obsolètes du dépôt qui n'existent plus" msgid "Rename" msgstr "Renommer" #, python-format msgid "Rename \"%s\"" msgstr "Renommer « %s »" msgid "Rename Branch" msgstr "Renommer branche" msgid "Rename Branch..." msgstr "Renommer branche..." msgid "Rename Existing Branch" msgstr "Renommer la branche existante" msgid "Rename Remote" msgstr "Renommer l'élément distant" msgid "Rename Repository" msgstr "Renommer le dépôt" msgid "Rename branch" msgstr "Renommer branche" #, python-format msgid "Rename remote \"%(current)s\" to \"%(new)s\"?" msgstr "Renommage de l'élément distant « %(current)s » en « %(new)s » ?" msgid "Rename selected paths" msgstr "Renommer les chemins sélectionnés" msgid "Repository Not Found" msgstr "Dépôt non trouvé" #, 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 All (Keep Unstaged Changes)" msgstr "Tout réinitialiser (Garder les modifications non pré-commitées)" msgid "Reset Branch" msgstr "Réinitialiser la branche" msgid "Reset Branch (Soft)" msgstr "Réinitialiser la banche (Soft)" msgid "Reset Branch and Stage (Mixed)" msgstr "Réinitialiser la branche et pré-commiter (Mixed)" msgid "Reset Branch?" msgstr "Réinitialiser la branche ?" msgid "Reset Layout" msgstr "Réinitialiser la mise en page" msgid "Reset Worktree and Reset All?" msgstr "Réinitialiser l'arbre de travail et tout rétablir ?" msgid "Reset and Restore" msgstr "Réinitialiser et rétablir" msgid "Reset branch?" msgstr "Réinitialiser la branche ?" #, python-format msgid "Resetting \"%(branch)s\" to \"%(revision)s\" will lose commits." msgstr "Réinitialiser « %(branch)s » à « %(revision)s » perdra les commits." msgid "Restart the application after changing appearance settings." msgstr "Redémarrez l'application pour appliquer les modifications de l'apparence." msgid "Restore Worktree" msgstr "Rétablir l'arbre de travail" msgid "Restore Worktree and Reset All (Hard)" msgstr "Réinitialiser l'arbre de travail et tout rétablir (Hard)" msgid "Restore Worktree and Reset All (Keep Unstaged Changes)" msgstr "Réinitialiser l'arbre de travail et tout rétablir (Garder les modifications non pré-commitées)" msgid "Restore Worktree and Reset All (Keep Unstaged Edits)" msgstr "Réinitialiser l'arbre de travail et tout rétablir (Garder les modifications non pré-commitées)" msgid "Restore Worktree and Reset All (Merge)" msgstr "Réinitialiser l'arbre de travail et tout rétablir (Fusionner)" msgid "Restore Worktree and Reset All?" msgstr "Réinitialiser l'arbre de travail et tout rétablir ?" #, python-format msgid "Restore Worktree to %s?" msgstr "Rétablir l'arbre de travail à %s ?" msgid "Restore worktree, reset, and preserve unstaged edits?" msgstr "Réinitialiser l'arbre de travail, rétablir, et garder les modifications non pré-commitées ?" msgid "Revert" msgstr "Rétablir" 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 Diff Hunk?" msgstr "Rétablir la section de différences ?" msgid "Revert Selected Lines" msgstr "Inverser les lignes sélectionnées" msgid "Revert Selected Lines..." msgstr "Inverser les 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 les modifications non pré-commitées" msgid "Revert Unstaged Changes?" msgstr "Rétablir les modifications non pré-commitées ?" msgid "Revert Unstaged Edits..." msgstr "Rétablir les modifications non pré-commitées..." 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 "Renommer" 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 "Mode sûr" msgid "Save" msgstr "Enregistrer" msgid "Save Archive" msgstr "Enregistrer l'archive" msgid "Save As Tarball/Zip..." msgstr "Enregistrer comme 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 » dans « %(destination)s »" msgid "Search" msgstr "Rechercher" msgid "Search Authors" msgstr "Rechercher les auteurs" msgid "Search Commit Messages" msgstr "Rechercher par messages de commit" msgid "Search Committers" msgstr "Rechercher les commiteurs" msgid "Search Date Range" msgstr "Rechercher une période ciblée" msgid "Search Diffs" msgstr "Rechercher les différences" msgid "Search by Expression" msgstr "Rechercher par expression" msgid "Search by Path" msgstr "Rechercher par chemin" msgid "Search for a fixed string" msgstr "Rechercher pour une chaîne donnée" msgid "Search using a POSIX basic regular expression" msgstr "Rechercher en utilisant une expression régulière basique POSIX" msgid "Search using a POSIX extended regular expression" msgstr "Rechercher en utilisant une expression régulière approfondie POSIX" msgid "Search..." msgstr "Rechercher..." 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 "Sélectionnez un répertoire..." msgid "Select New Upstream" msgstr "Sélectionner une nouvelle source" msgid "Select Newest Child" msgstr "Sélectionner l'enfant le plus récent" msgid "Select Oldest Parent" msgstr "Sélectionner le parent le plus ancien" msgid "Select Parent" msgstr "Sélectionner le parent" msgid "Select Previous Version" msgstr "Sélectionner la version précédente" msgid "Select a parent directory for the new clone" msgstr "Sélectionner un répertoire parent pour le nouveau clonage" msgid "Select output dir" msgstr "Sélectionner dossier de sortie" msgid "Select output directory" msgstr "Sélectionnez le répertoire de sortie" msgid "Select patch file(s)..." msgstr "Sélectionnez le(s) fichier(s) de patch..." msgid "Select repository" msgstr "Sélectionner le dépôt" msgid "Set Default Repository" msgstr "Définirr le dépôt par défaut" msgid "Set Upstream Branch" msgstr "Définir la branche à jour" msgid "" "Set the sort order for branches and tags.\n" "Toggle between date-based and version-name-based sorting." msgstr "" "Définir l'ordre des branches et des marqueurs.\n" "Changer l'ordre entre basé sur la date ou sur le nom de la version." msgid "Set upstream" msgstr "Modifier la source" msgid "Settings" msgstr "Préférences" msgid "Shell arguments" msgstr "Arguments Shell" msgid "Shift Down" msgstr "Vers le bas" msgid "Shift Up" msgstr "Vers le haut" msgid "Shortcuts" msgstr "Raccourcis" msgid "Show Diffstat After Merge" msgstr "Montrer le Diffstat après la fusion" msgid "Show Full Paths in the Window Title" msgstr "Afficher le chemin complet dans le titre de la fenêtre" msgid "Show Help" msgstr "Afficher l'aide" msgid "Show History" msgstr "Afficher l'historique" msgid "Show file counts in Status titles" msgstr "Afficher le nombre de fichiers dans le titre du statut" msgid "" "Show help\n" "Shortcut: ?" msgstr "" "Afficher l'aide\n" "Raccourci : ?" msgid "Show icon? (if available)" msgstr "Afficher l'icône ? (si disponible)" msgid "Show line numbers" msgstr "Afficher le numéro des lignes" msgid "Show whole surrounding functions of changes" msgstr "Afficher toutes les fonctions environnantes pour les changements" msgid "Showing changes since" msgstr "Afficher les modifications depuis" msgid "Side by side" msgstr "Côte-à-côte" msgid "Sign Off" msgstr "Signer" msgid "Sign Tag" msgstr "Signer le marqueur" msgid "Sign off on this commit" msgstr "Signer ce commit" msgid "Simplified Chinese translation" msgstr "Traductions en chinois simplifié" 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 "Définie 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 "Pré-commiter" msgid "Stage / Unstage" msgstr "Pré-commiter/non pré-commiter" msgid "Stage / Unstage All" msgstr "Pré-commiter/non pré-commiter tous" msgid "Stage All Untracked" msgstr "Pré-commiter tous les fichiers non suivis" msgid "Stage Changed Files To Commit" msgstr "Commiter les fichiers modifiés dans pré-commit" msgid "Stage Diff Hunk" msgstr "Pré-commiter cette section" msgid "Stage Modified" msgstr "Pré-commit modifiés" msgid "Stage Modified and Untracked" msgstr "Pré-commiter les modifiés ou non suivis" msgid "Stage Selected" msgstr "Pré-commiter la 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 "Non/Pré-commiter les chemins sélectionnés" msgid "Staged" msgstr "Pré-commité" #, python-format msgid "Staging: %s" msgstr "Pré-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 "Remiser l'index" msgid "Stash staged changes only" msgstr "Ne remiser que les modifications pré-commitées" msgid "Stash unstaged changes only, keeping staged changes" msgstr "Ne remiser que les modifications non pré-commitées, et garder celles pré-commitées" msgid "Stash..." msgstr "Cacher..." msgid "Status" msgstr "Statut" msgid "Stop tracking paths" msgstr "Stopper le suivi des chemins" msgid "Submodule URL (can be relative, ex: ../repo.git)" msgstr "L'URL du sous-module (peut être relatif, par ex. ../repo.git)" msgid "Submodule branch to track (optional)" msgstr "La branche du sous-module à suivre (facultatif)" msgid "Submodule path within the current repository (optional)" msgstr "Le chemin du sous-module dans le dépôt actuel (facultatif)" msgid "Submodules" msgstr "Sous-modules" msgid "Summarize Merge Commits" msgstr "Résumer les commits de fusion" msgid "Summary" msgstr "Résumé" msgid "Tab Width" msgstr "Largeur de la tabulation" msgid "Tag" msgstr "Marquer" 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 "Marqueurs" msgid "Text Width" msgstr "Largeur du texte" msgid "The branch will be no longer available." msgstr "Cette branche ne sera plus disponible." #, 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 :" #, python-format msgid "The repository will be reset using \"git reset --hard %s\"" msgstr "Le dépôt va être réinitialisé avec « git reset --hard %s »" #, python-format msgid "The repository will be reset using \"git reset --keep %s\"" msgstr "Le dépôt va être réinitialisé avec « git reset --keep %s »" #, python-format msgid "The repository will be reset using \"git reset --merge %s\"" msgstr "Le dépôt va être réinitialisé avec « git reset --merge %s »" msgid "The revision expression cannot be empty." msgstr "L'expression de révision est vide." #, python-format msgid "" "The submodule will be added using\n" "\"%s\"" msgstr "" "Le sous-module va être ajouté avec\n" "« %s »" #, python-format msgid "The worktree will be restored using \"git read-tree --reset -u %s\"" msgstr "L'arbre de travail sera restauré avec \"git read-tree --reset -u %s\"" msgid "This cannot be undone. Clear commit message?" msgstr "Cela ne peut pas être annulé. Effacer le message du 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 pourront 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 pourront 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 pourront 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 "Dés/activer actif" msgid "Toggle image diff" msgstr "Dés/activer le différence des images" msgid "Toggle the branches filter" msgstr "Dés/activer le filtre des branches" msgid "Toggle the paths filter" msgstr "Dés/activer le filtre des 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 "Translation" msgstr "Traduction" 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 "Traduction ukrainienne" msgid "Unable to rebase" msgstr "Impossible de rétablir" #, python-format msgid "Unable to set URL for \"%(name)s\" to \"%(url)s\"" msgstr "Impossible de mettre l'URL de « %(name)s » pour « %(url)s »" msgid "Undo" msgstr "Annuler" msgid "Undo Last Commit" msgstr "Annuler le dernier commit" msgid "Undo last commit?" msgstr "Annuler le dernier commit ?" msgid "Undo the published commit?" msgstr "Annuler le commit publié ?" msgid "Unmerged" msgstr "Non fusionné" msgid "Unstage" msgstr "Retirer du pré-commit" msgid "Unstage All" msgstr "Tout retirer du pré-commit" msgid "Unstage Diff Hunk" msgstr "Retirer ce diff du pré-commit" msgid "Unstage From Commit" msgstr "Retirer du pré-commit" msgid "Unstage Selected" msgstr "Retirer sélection du pré-commit" msgid "Unstage Selected Lines" msgstr "Retirer les lignes sélectionnées du pré-commit" #, python-format msgid "Unstaging: %s" msgstr "Retirer du pré-commit : %s" msgid "Untrack Selected" msgstr "Ne plus suivre la sélection" msgid "Untracked" msgstr "Non suivi" #, python-format msgid "Untracking: %s" msgstr "Non-suivi : %s" msgid "Update All Submodules..." msgstr "Mettre à jour tous les sous-modules..." msgid "Update Existing Branch:" msgstr "Mettre à jour branche existante :" msgid "Update Submodule" msgstr "Mettre à jour le sous-module" msgid "Update Submodule..." msgstr "Mettre à jour le sous-module..." msgid "Update Submodules" msgstr "Mettre à jour les sous-modules" msgid "Update all submodules?" msgstr "Mettre à jour tous les sous-modules ?" msgid "Update submodules..." msgstr "Mettre à jour les sous-modules..." msgid "Update this submodule" msgstr "Mettre à jour ce sous-module" msgid "Update this submodule?" msgstr "Mettre à jour ce sous-module ?" 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 sélectionné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 puis commiter tous les fichiers modifiés ?" msgid "XOR" msgstr "Ou-exclusif" msgid "Yes" msgstr "Oui" msgid "" "You are in the middle of a merge.\n" "Cannot amend while merging." msgstr "" "Vous êtes au milieu d'une fusion.\n" "Impossible de corriger durant cette fusion." msgid "You cannot rebase with uncommitted changes." msgstr "Vous ne pouvez pas rétablir avec des modifications non commitées." 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 "Zoom avant" msgid "Zoom Out" msgstr "Zoom arrière" 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 "erreur : impossible d'exécuter git" #, 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 valide." #, python-format msgid "git cola version %s" msgstr "Version de git cola %s" msgid "git-cola" msgstr "git-cola" msgid "git-cola diff" msgstr "git-cola diff" msgid "git://git.example.com/repo.git" msgstr "git://git.example.com/repo.git" msgid "grep result..." msgstr "Résultat de grep..." msgid "hotkeys.html" msgstr "hotkeys.html" msgid "path/to/submodule" msgstr "path/to/submodule" msgid "title" msgstr "titre" msgid "unknown" msgstr "inconnu" msgid "vX.Y.Z" msgstr "vX.Y.Z" msgid "x 1" msgstr "1x" msgid "x 1.5" msgstr "1.5x" msgid "x 2" msgstr "2x" msgid "yyyy-MM-dd" msgstr "dd/MM/yyyy" #~ msgid "Reset Branch Head" #~ msgstr "Supprimer la branche principale" #~ msgid "Reset Worktree" #~ msgstr "Réinitialiser l'arbre de travail" #~ msgid "Reset worktree?" #~ msgstr "Réinitialiser l'arbre de travail ?" #~ msgid "Select Repository..." #~ msgstr "Sélectionner le dépôt..." #~ msgid "Select manually..." #~ msgstr "Sélectionner manuellement..." #~ msgid "The branch will be reset using \"git reset --hard %s\"" #~ msgstr "La branche sera réinitialisée en utilisant « git reset --hard %s »" #~ msgid "The branch will be reset using \"git reset --merge %s\"" #~ msgstr "La branche sera réinitialisée en utilisant « git reset --merge %s »" #~ 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 »" git-cola-3.12.0/po/git-cola.pot000066400000000000000000001113071417222504200161370ustar00rootroot00000000000000msgid "" "\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 could not be opened. Remove from bookmarks?" 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 Submodule" msgstr "" msgid "Add Submodule..." 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 this submodule?" msgstr "" msgid "Add to .gitignore" msgstr "" msgid "Add to Git Annex" msgstr "" msgid "Add to Git LFS" msgstr "" msgid "Add to exclusions" msgstr "" msgid "Add to local .git/info/exclude" 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 "Autocomplete Paths" msgstr "" msgid "Automatically Load Commit Message Template" 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 "" 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 Published Commits when Amending" msgstr "" msgid "Check Spelling" msgstr "" msgid "Check spelling" msgstr "" msgid "Check whether a commit has been published when amending" 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 open %s." msgstr "" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "" msgid "Create" 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 a new repository at that location?" msgstr "" msgid "Create a shallow clone with history truncated to the specified number of revisions. 0 performs a full clone." 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 "" #, python-format msgid "Delete branch \"%s\"?" msgstr "" msgid "Delete remote" msgstr "" #, python-format msgid "Delete remote \"%s\"" msgstr "" msgid "Delete remote?" msgstr "" msgid "Delete toolbar" msgstr "" msgid "Delete..." msgstr "" #, python-format msgid "Deleting \"%s\" failed" msgstr "" msgid "Deletions" msgstr "" msgid "Depth" 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 "Disable" 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 "Enable path autocompletion in tools" 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 "" msgid "Error Opening Repository" msgstr "" #, python-format msgid "Error creating remote \"%s\"" msgstr "" msgid "Error creating stash" msgstr "" #, python-format msgid "Error deleting branch \"%s\"" 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 "Folder" 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-cola-sequence-editor" 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 "Ignore..." 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 "Japanese translation" 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 "List" 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 "Prune Missing Entries" 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 "Reference Repository" msgstr "" msgid "Reference URL" msgstr "" msgid "Reference repository to use when cloning (optional)" 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 "Remove stale entries for repositories that no longer exist" 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 "" msgid "Repository Not Found" msgstr "" #, python-format msgid "Repository: %s" msgstr "" msgid "Reset" msgstr "" #, python-format msgid "Reset \"%(branch)s\" to \"%(revision)s\"?" msgstr "" msgid "Reset All (Keep Unstaged Changes)" msgstr "" msgid "Reset Branch" msgstr "" msgid "Reset Branch (Soft)" msgstr "" msgid "Reset Branch and Stage (Mixed)" msgstr "" msgid "Reset Branch?" msgstr "" msgid "Reset Layout" msgstr "" msgid "Reset Worktree and Reset All?" msgstr "" msgid "Reset and Restore" msgstr "" msgid "Reset branch?" msgstr "" #, python-format msgid "Resetting \"%(branch)s\" to \"%(revision)s\" will lose commits." msgstr "" msgid "Restart the application after changing appearance settings." msgstr "" msgid "Restore Worktree" msgstr "" msgid "Restore Worktree and Reset All (Hard)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Changes)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Edits)" msgstr "" msgid "Restore Worktree and Reset All (Merge)" msgstr "" msgid "Restore Worktree and Reset All?" msgstr "" #, python-format msgid "Restore Worktree to %s?" msgstr "" msgid "Restore worktree, reset, and preserve unstaged edits?" 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 a parent directory for the new clone" 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 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 / Unstage All" msgstr "" msgid "Stage All Untracked" msgstr "" msgid "Stage Changed Files To Commit" msgstr "" msgid "Stage Diff Hunk" msgstr "" msgid "Stage Modified" msgstr "" msgid "Stage Modified and Untracked" 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 "Submodule URL (can be relative, ex: ../repo.git)" msgstr "" msgid "Submodule branch to track (optional)" msgstr "" msgid "Submodule path within the current repository (optional)" 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 --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 "" #, python-format msgid "The repository will be reset using \"git reset --hard %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --keep %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --merge %s\"" msgstr "" msgid "The revision expression cannot be empty." msgstr "" #, python-format msgid "" "The submodule will be added using\n" "\"%s\"" msgstr "" #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be restored using \"git read-tree --reset -u %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 image diff" 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 "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 "Undo Last Commit" msgstr "" msgid "Undo last commit?" msgstr "" msgid "Undo the published commit?" 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 "git://git.example.com/repo.git" msgstr "" msgid "grep result..." msgstr "" msgid "hotkeys.html" msgstr "" msgid "path/to/submodule" msgstr "" msgid "title" 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.12.0/po/glossary/000077500000000000000000000000001417222504200155545ustar00rootroot00000000000000git-cola-3.12.0/po/glossary/de.po000066400000000000000000000130211417222504200165010ustar00rootroot00000000000000# 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.12.0/po/glossary/it.po000066400000000000000000000131271417222504200165340ustar00rootroot00000000000000# 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.12.0/po/glossary/zh_cn.po000066400000000000000000000122401417222504200172140ustar00rootroot00000000000000# 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.12.0/po/glossary/zh_tw.po000066400000000000000000000157611417222504200172610ustar00rootroot00000000000000# 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.12.0/po/hu.po000066400000000000000000002056701417222504200146770ustar00rootroot00000000000000# 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 # Meskó Balázs , 2019. # Gyuris Gellért , 2019-2021. # 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: 2021-04-30 00:36+0200\n" "Last-Translator: Gyuris Gellért \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: Gtranslator 3.38.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" " 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 could not be opened. Remove from bookmarks?" msgstr "%s-t nem lehet megnyitni. Eltávolítja a könyvjelzők közül?" #, 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 Submodule" msgstr "Részmodul hozzáadása" msgid "Add Submodule..." msgstr "Részmodul hozzáadása…" msgid "New 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 this submodule?" msgstr "Hozzáadja ezt a részmodult?" 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 "Add to exclusions" msgstr "Hozzáadás a kizárásokhoz" msgid "Add to local .git/info/exclude" msgstr "Hozzáadás a helyi .git/info/exclude-hoz" 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 "Autocomplete Paths" msgstr "Útvonalak automatikus kiegészítése" msgid "Automatically Load Commit Message Template" msgstr "Véglegesítő üzenetsablon automatikus betölté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" 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 Published Commits when Amending" msgstr "Közzétett véglegesítések ellenőrzése javítás alatt" msgid "Check Spelling" msgstr "Helyesírás-ellenőrzés" msgid "Check spelling" msgstr "Helyesírás-ellenőrzés" msgid "Check whether a commit has been published when amending" msgstr "Javítás közben ellenőrizze, hogy a véglegesítések közzé lettek-e téve" 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 open %s." msgstr "Nem lehet megnyitni: %s." #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "Nem lehet feldolgozni a git URL-t: „%s”" msgid "Create" msgstr "Létrehozá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 a new repository at that location?" msgstr "Létrehozza a tárolót ezen a helyen?" msgid "" "Create a shallow clone with history truncated to the specified number of " "revisions. 0 performs a full clone." msgstr "" "Felszínes klón létrehozása a történet megadott számú revízióra " "csonkolásával. A 0 teljes klónt hoz létre." 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…" #, python-format msgid "Delete branch \"%s\"?" msgstr "Törli az ágat: „%s”?" 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 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 "Depth" msgstr "Mélység" 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 "Disable" msgstr "Letiltás" 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 "Enable path autocompletion in tools" msgstr "Útvonalak automatikus kiegészítésének engedélyezése az eszközökben" 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" msgid "Error Opening Repository" msgstr "Hiba a tároló megnyitá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 branch \"%s\"" msgstr "Hiba az ág törlésekor: „%s”" #, 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 "Folder" msgstr "Mappa" 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-cola-sequence-editor" msgstr "Súgó – git-cola-sequence-editor" 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 "Ignore..." msgstr "Mellőz…" 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 "Japanese translation" msgstr "Japán fordítás" 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 "List" msgstr "Lista" 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 "Prune Missing Entries" msgstr "Hiányzó bejegyzések tisztogatása" 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 "Reference Repository" msgstr "Hivatkozó tároló" msgid "Reference URL" msgstr "Hivatkozás URL" msgid "Reference repository to use when cloning (optional)" msgstr "Klónozáskor alkalmazott hivatkozó tároló (választható)" 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 "Remove stale entries for repositories that no longer exist" msgstr "Már nem létező elavult bejegyzések eltávolítása a tárolóból" 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" msgid "Repository Not Found" msgstr "Tároló nem található" #, 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 All (Keep Unstaged Changes)" msgstr "Minden visszaállítása (elengedett módosítások megtartása)" msgid "Reset Branch" msgstr "Ág visszaállítása" msgid "Reset Branch (Soft)" msgstr "Ág visszaállítása (nyugodt)" msgid "Reset Branch and Stage (Mixed)" msgstr "Ág visszaállítása és kiszemelés (kevert)" msgid "Reset Branch?" msgstr "Visszaállítja az ágat?" msgid "Reset Layout" msgstr "Elrendezés visszaállítása" msgid "Reset Worktree and Reset All?" msgstr "Visszaállítja a munkafát és mindent visszaállít?" msgid "Reset and Restore" msgstr "Visszaállítás és helyreállítás" msgid "Reset branch?" msgstr "Visszaállítja az ágat?" #, 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 "Restore Worktree" msgstr "Munkafa helyreállítása" msgid "Restore Worktree and Reset All (Hard)" msgstr "Munkafa helyreállítása és minden visszaállítása (teljes)" msgid "Restore Worktree and Reset All (Keep Unstaged Changes)" msgstr "" "Munkafa helyreállítása és minden visszaállítása (elengedett módosítások " "megtartása)" msgid "Restore Worktree and Reset All (Keep Unstaged Edits)" msgstr "" "Munkafa helyreállítása és minden visszaállítása (elengedett szerkesztések " "megtartása)" msgid "Restore Worktree and Reset All (Merge)" msgstr "Munkafa helyreállítása és minden visszaállítása (beolvasztás)" msgid "Restore Worktree and Reset All?" msgstr "Helyreállítja a munkát és mindent visszaállít?" #, python-format msgid "Restore Worktree to %s?" msgstr "Helyreállítja a munkafát erre: %s?" msgid "Restore worktree, reset, and preserve unstaged edits?" msgstr "" "Helyreállítja a munkafát, visszaállít és megőrzi az elengedett " "szerkesztéseket?" 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 összehasonlí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 a parent directory for the new clone" msgstr "Válasszon szülő mappát az új klón számára" 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 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 / Unstage All" msgstr "Összes kiszemelése/elengedése" 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 Modified and Untracked" msgstr "Módosítottak és nem követettek 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 "Submodule URL (can be relative, ex: ../repo.git)" msgstr "Részmodul URL (lehet relatív is, pl.: ../tároló.git)" msgid "Submodule branch to track (optional)" msgstr "Követett részmodul ág (választható)" msgid "Submodule path within the current repository (optional)" msgstr "Részmodul útvonala a jelenlegi tárolóban (választható)" 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 --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:" #, python-format msgid "The repository will be reset using \"git reset --hard %s\"" msgstr "A tároló vissza lesz állítva ezzel a paranccsal: „git reset --hard %s”" #, python-format msgid "The repository will be reset using \"git reset --keep %s\"" msgstr "A tároló vissza lesz állítva ezzel a paranccsal: „git reset --keep %s”" #, python-format msgid "The repository will be reset using \"git reset --merge %s\"" msgstr "" "A tároló vissza lesz állítva ezzel a paranccsal: „git reset --merge %s”" msgid "The revision expression cannot be empty." msgstr "A revíziókifejezés nem lehet üres." #, python-format msgid "" "The submodule will be added using\n" "\"%s\"" msgstr "" "A részmodul így lesz hozzáadva:\n" "„%s”" #, 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 restored using \"git read-tree --reset -u %s\"" msgstr "" "A munkafa helyre lesz állítva ezzel a paranccsal: „git read-tree --reset -u " "%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 image diff" msgstr "Képösszehasonlítá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 "Translation" msgstr "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 "Undo Last Commit" msgstr "Utolsó véglegesítés visszavonása" msgid "Undo last commit?" msgstr "Visszavonja az utolsó véglegesítést?" msgid "Undo the published commit?" msgstr "Visszavonja a már közzétett véglegesítést?" 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 "git://git.example.com/repo.git" msgstr "git://git.példa.com/tároló.git" msgid "grep result..." msgstr "grep eredmény…" msgid "hotkeys.html" msgstr "hotkeys.html" msgid "path/to/submodule" msgstr "útvonal/a/részmodulhoz" msgid "title" msgstr "cím" 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" #~ msgid "Delete selected branch?" #~ msgstr "Törli a kijelölt ágat?" #~ msgid "Hide Details.." #~ msgstr "Részletek elrejtése…" #~ msgid "Reset Branch Head" #~ msgstr "Ág fejének visszaállítása" #~ 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?" #~ msgid "Select Repository..." #~ msgstr "Tároló kijelölése…" #~ msgid "Select manually..." #~ msgstr "Kézi kijelölés…" #~ msgid "Show Details..." #~ msgstr "Részletek megjelenítése…" #~ 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”" #~ 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”" #~ msgid "The worktree will be reset using \"git reset --keep %s\"" #~ msgstr "A munkafa visszaáll ezzel a paranccsal: „git reset --keep %s”" git-cola-3.12.0/po/id_ID.po000066400000000000000000001535711417222504200152350ustar00rootroot00000000000000# 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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ASCII\n" "Content-Transfer-Encoding: 8bit\n" "Language: id\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 "" #, python-format msgid "%s could not be opened. Remove from bookmarks?" 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 Submodule" msgstr "" msgid "Add Submodule..." msgstr "" msgid "New 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 this submodule?" msgstr "" 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 "Add to exclusions" msgstr "" msgid "Add to local .git/info/exclude" 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 "Autocomplete Paths" msgstr "" msgid "Automatically Load Commit Message Template" msgstr "" 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" msgid "Branch name" msgstr "" #, 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 Published Commits when Amending" msgstr "" msgid "Check Spelling" msgstr "Periksa Ejaan" #, fuzzy msgid "Check spelling" msgstr "Periksa Ejaan" msgid "Check whether a commit has been published when amending" msgstr "" 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 open %s." msgstr "" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "Tidak dapat mengurai URL Git: \"%s\"" msgid "Create" msgstr "" 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 a new repository at that location?" msgstr "" msgid "Create a shallow clone with history truncated to the specified number of revisions. 0 performs a full clone." msgstr "" 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..." #, python-format msgid "Delete branch \"%s\"?" msgstr "" 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 Toolbar" msgstr "Markah" msgid "Delete..." msgstr "Hapus..." #, python-format msgid "Deleting \"%s\" failed" msgstr "Gagal menghapus \"%s\"" msgid "Deletions" msgstr "Penghapusan" msgid "Depth" msgstr "" 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 "Disable" msgstr "" 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 "Enable path autocompletion in tools" 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" msgid "Error Opening Repository" msgstr "" #, 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 branch \"%s\"" msgstr "" #, 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 "Folder" 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-cola-sequence-editor" 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 "Ignore..." 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 "Japanese translation" msgstr "" 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 "List" 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 "" msgid "Prune Missing Entries" 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 "Reference Repository" msgstr "" msgid "Reference URL" msgstr "" msgid "Reference repository to use when cloning (optional)" 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 "Remove stale entries for repositories that no longer exist" msgstr "" 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" msgid "Repository Not Found" msgstr "" #, 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 All (Keep Unstaged Changes)" msgstr "" msgid "Reset Branch" msgstr "Atur Ulang Cabang" msgid "Reset Branch (Soft)" msgstr "" msgid "Reset Branch and Stage (Mixed)" msgstr "" msgid "Reset Branch?" msgstr "Atur Ulang Cabang?" msgid "Reset Layout" msgstr "" msgid "Reset Worktree and Reset All?" msgstr "" msgid "Reset and Restore" msgstr "" msgid "Reset branch?" 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 "Restore Worktree" msgstr "" msgid "Restore Worktree and Reset All (Hard)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Changes)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Edits)" msgstr "" msgid "Restore Worktree and Reset All (Merge)" msgstr "" msgid "Restore Worktree and Reset All?" msgstr "" #, python-format msgid "Restore Worktree to %s?" msgstr "" msgid "Restore worktree, reset, and preserve unstaged edits?" 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 a parent directory for the new clone" msgstr "Pilih direktori di atasnya untuk klon baru" #, 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" 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 / Unstage All" msgstr "" 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 Modified and Untracked" msgstr "" 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 "Submodule URL (can be relative, ex: ../repo.git)" msgstr "" msgid "Submodule branch to track (optional)" msgstr "" msgid "Submodule path within the current repository (optional)" msgstr "" 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 --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:" #, python-format msgid "The repository will be reset using \"git reset --hard %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --keep %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --merge %s\"" msgstr "" msgid "The revision expression cannot be empty." msgstr "Ekspresi revisi tidak boleh kosong." #, python-format msgid "" "The submodule will be added using\n" "\"%s\"" msgstr "" #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be restored using \"git read-tree --reset -u %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 image diff" 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 "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 "Undo Last Commit" msgstr "" msgid "Undo last commit?" msgstr "" msgid "Undo the published commit?" 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 "git://git.example.com/repo.git" msgstr "" msgid "grep result..." msgstr "hasil grep..." msgid "hotkeys.html" msgstr "hotkeys.html" msgid "path/to/submodule" msgstr "" msgid "title" msgstr "" 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" #, fuzzy #~ msgid "Delete selected branch?" #~ msgstr "Hapus Cabang Hulu" #~ 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?" #, fuzzy #~ msgid "Reset Branch Head" #~ 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" #, fuzzy #~ msgid "Reset hard?" #~ msgstr "Atur Ulang Cabang?" #, fuzzy #~ msgid "Reset merge?" #~ msgstr "Atur Ulang Cabang?" #, fuzzy #~ msgid "Reset soft?" #~ msgstr "Reset" #~ msgid "Revert Uncommitted Changes..." #~ msgstr "Kembalikan Perubahan Tak Tercommit..." #~ msgid "Select File" #~ msgstr "Pilih Berkas" #~ msgid "Select Repository..." #~ msgstr "Pilih Repository..." #~ msgid "Select file from \"%s\"" #~ msgstr "Pilih berkas dari \"%s\"" #~ msgid "Select manually..." #~ msgstr "Pilih secara manual..." #, fuzzy #~ msgid "Show Details..." #~ msgstr "Hapus Berkas...?" #~ 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.12.0/po/it.po000066400000000000000000002246761417222504200147060ustar00rootroot00000000000000# 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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: \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 "" #, python-format msgid "%s could not be opened. Remove from bookmarks?" 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 Submodule" msgstr "" msgid "Add Submodule..." msgstr "" msgid "New 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 this submodule?" msgstr "" msgid "Add to .gitignore" msgstr "" msgid "Add to Git Annex" msgstr "" msgid "Add to Git LFS" msgstr "" msgid "Add to exclusions" msgstr "" msgid "Add to local .git/info/exclude" 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 "Autocomplete Paths" msgstr "" msgid "Automatically Load Commit Message Template" 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" msgid "Branch name" msgstr "" #, 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 Published Commits when Amending" msgstr "" msgid "Check Spelling" msgstr "" msgid "Check spelling" msgstr "" msgid "Check whether a commit has been published when amending" 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 open %s." msgstr "" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "" msgid "Create" 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 a new repository at that location?" msgstr "" msgid "Create a shallow clone with history truncated to the specified number of revisions. 0 performs a full clone." msgstr "" 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" #, python-format msgid "Delete branch \"%s\"?" msgstr "" #, 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 Toolbar" msgstr "Elimina ramo" msgid "Delete..." msgstr "Elimina..." #, python-format msgid "Deleting \"%s\" failed" msgstr "" #, fuzzy msgid "Deletions" msgstr "Elimina" msgid "Depth" msgstr "" #, 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 "Disable" msgstr "" 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 "Enable path autocompletion in tools" 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" msgid "Error Opening Repository" msgstr "" #, python-format msgid "Error creating remote \"%s\"" msgstr "" #, fuzzy msgid "Error creating stash" msgstr "Crea ramo" #, python-format msgid "Error deleting branch \"%s\"" msgstr "" #, 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 "Folder" 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-cola-sequence-editor" 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 "" msgid "Ignore..." 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 "Japanese translation" 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 "List" 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" msgid "Prune Missing Entries" msgstr "" #, 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 "Reference Repository" msgstr "" msgid "Reference URL" msgstr "" msgid "Reference repository to use when cloning (optional)" 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 "Remove stale entries for repositories that no longer exist" msgstr "" 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" msgid "Repository Not Found" msgstr "" #, fuzzy, python-format msgid "Repository: %s" msgstr "Archivio:" msgid "Reset" msgstr "Ripristina" #, python-format msgid "Reset \"%(branch)s\" to \"%(revision)s\"?" msgstr "" msgid "Reset All (Keep Unstaged Changes)" msgstr "" #, fuzzy msgid "Reset Branch" msgstr "Elimina ramo" msgid "Reset Branch (Soft)" msgstr "" msgid "Reset Branch and Stage (Mixed)" msgstr "" #, fuzzy msgid "Reset Branch?" msgstr "Elimina ramo" msgid "Reset Layout" msgstr "" msgid "Reset Worktree and Reset All?" msgstr "" msgid "Reset and Restore" msgstr "" msgid "Reset branch?" 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 "Restore Worktree" msgstr "" msgid "Restore Worktree and Reset All (Hard)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Changes)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Edits)" msgstr "" msgid "Restore Worktree and Reset All (Merge)" msgstr "" msgid "Restore Worktree and Reset All?" msgstr "" #, python-format msgid "Restore Worktree to %s?" msgstr "" msgid "Restore worktree, reset, and preserve unstaged edits?" 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 "" msgid "Select a parent directory for the new clone" msgstr "" #, 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 "" 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 / Unstage All" msgstr "" 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 "" msgid "Stage Modified and Untracked" 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 "Submodule URL (can be relative, ex: ../repo.git)" msgstr "" msgid "Submodule branch to track (optional)" msgstr "" msgid "Submodule path within the current repository (optional)" 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 --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 "" #, python-format msgid "The repository will be reset using \"git reset --hard %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --keep %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --merge %s\"" msgstr "" #, fuzzy msgid "The revision expression cannot be empty." msgstr "L'espressione di revisione è vuota." #, python-format msgid "" "The submodule will be added using\n" "\"%s\"" msgstr "" #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be restored using \"git read-tree --reset -u %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 image diff" 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 "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" msgid "Undo Last Commit" msgstr "" msgid "Undo last commit?" msgstr "" msgid "Undo the published commit?" msgstr "" #, 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 "git://git.example.com/repo.git" msgstr "" msgid "grep result..." msgstr "" msgid "hotkeys.html" msgstr "" msgid "path/to/submodule" msgstr "" msgid "title" 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" #, fuzzy #~ msgid "Delete selected branch?" #~ msgstr "Cancella ramo remoto" #~ 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" #, fuzzy #~ msgid "Reset Branch Head" #~ 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 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?" #, fuzzy #~ msgid "Reset hard?" #~ msgstr "Elimina ramo" #, fuzzy #~ msgid "Reset merge?" #~ msgstr "Elimina ramo" #, fuzzy #~ msgid "Reset soft?" #~ msgstr "Ripristinare '%s'?" #~ 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 Repository..." #~ msgstr "Archivio Git" #, fuzzy #~ msgid "Select file from \"%s\"" #~ msgstr "Cancellazione rami da %s" #, fuzzy #~ msgid "Select manually..." #~ msgstr "Seleziona tutto" #~ 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." #, fuzzy #~ msgid "Show Details..." #~ msgstr "Elimina..." #~ 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 'main' branch has not been initialized." #~ msgstr "Il ramo 'main' 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.12.0/po/ja.po000066400000000000000000003042051417222504200146470ustar00rootroot00000000000000# 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 , 2020. # 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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: \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 could not be opened. Remove from bookmarks?" msgstr "%s を開けませんでした。ブックマークから削除しますか?" #, 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 Submodule" msgstr "サブモジュールの追加" msgid "Add Submodule..." msgstr "サブモジュールの追加..." msgid "New 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 this submodule?" msgstr "このサブモジュールを追加しますか?" msgid "Add to .gitignore" msgstr ".gitignoreに追加" msgid "Add to Git Annex" msgstr "Git Annexに追加" msgid "Add to Git LFS" msgstr "Git LFSに追加" msgid "Add to exclusions" msgstr "exclusionsに追加" msgid "Add to local .git/info/exclude" msgstr "ローカルの .git/info/exclude に追加" 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 "Autocomplete Paths" msgstr "自動補完パス" msgid "Automatically Load Commit Message Template" 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 "ブランチ名" 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 Published Commits when Amending" msgstr "アメンド時の発行したコミットを確認" msgid "Check Spelling" msgstr "スペルチェック" msgid "Check spelling" msgstr "スペルチェック" msgid "Check whether a commit has been published when amending" 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 open %s." msgstr "%s を開けませんでした。" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "Git URL \"%s\"がパースできません。" msgid "Create" 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 a new repository at that location?" msgstr "この場所に新しいリポジトリを作成しますか?" msgid "Create a shallow clone with history truncated to the specified number of revisions. 0 performs a full clone." msgstr "指定した数まで履歴を切り詰めた浅いクローンを作成します。0 は完全なクローンになります。" 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 "リモートブランチの削除中..." #, python-format msgid "Delete branch \"%s\"?" msgstr "ブランチ \"%s\" を削除しますか?" msgid "Delete remote" msgstr "リモートの削除" #, python-format msgid "Delete remote \"%s\"" msgstr "リモート \"%s\"の削除" msgid "Delete remote?" msgstr "リモートを削除しますか?" msgid "Delete Toolbar" msgstr "ツールバーの削除" msgid "Delete..." msgstr "削除中…" #, python-format msgid "Deleting \"%s\" failed" msgstr "\"%s\"の削除に失敗しました。" msgid "Deletions" msgstr "削除" msgid "Depth" 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 "Disable" 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 "Enable path autocompletion in tools" 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 "履歴ブラウザ起動エラー" msgid "Error Opening Repository" msgstr "履歴オープン時のエラー" #, python-format msgid "Error creating remote \"%s\"" msgstr "リモート \"%s\"作成エラー" msgid "Error creating stash" msgstr "スタッシュ作成エラー" #, python-format msgid "Error deleting branch \"%s\"" msgstr "ブランチ削除エラー \"%s\"" #, 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 "Folder" 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-cola-sequence-editor" msgstr "ヘルプ - git-cola-sequence-editor" 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 "Ignore..." 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 "Japanese translation" 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 "List" 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 "Prune Missing Entries" 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 "%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 "Reference Repository" msgstr "参照リポジトリ" msgid "Reference URL" msgstr "参照URL" msgid "Reference repository to use when cloning (optional)" msgstr "clone時に使用する参照リポジトリ(任意)" 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 "Remove stale entries for repositories that no longer exist" 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 "選択したパスの名前を変更" msgid "Repository Not Found" 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 All (Keep Unstaged Changes)" msgstr "" msgid "Reset Branch" msgstr "ブランチのリセット" msgid "Reset Branch (Soft)" msgstr "" msgid "Reset Branch and Stage (Mixed)" msgstr "" msgid "Reset Branch?" msgstr "ブランチをリセットしますか?" msgid "Reset Layout" msgstr "レイアウトのリセット" msgid "Reset Worktree and Reset All?" msgstr "" msgid "Reset and Restore" msgstr "" msgid "Reset branch?" 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 "Restore Worktree" msgstr "" msgid "Restore Worktree and Reset All (Hard)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Changes)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Edits)" msgstr "" msgid "Restore Worktree and Reset All (Merge)" msgstr "" msgid "Restore Worktree and Reset All?" msgstr "" #, python-format msgid "Restore Worktree to %s?" msgstr "" msgid "Restore worktree, reset, and preserve unstaged edits?" 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 a parent directory for the new clone" 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 "" "ブランチやタグのソート順番を設定します。\n" "ソートを日付順とバージョン名順を切り替えます。" msgid "Set upstream" msgstr "アップストリームを設定" msgid "Settings" msgstr "設定" msgid "Shell arguments" msgstr "シェル引数" msgid "Shift Down" msgstr "シフトダウン" msgid "Shift Up" msgstr "シフトアップ" msgid "Shortcuts" 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 / Unstage All" msgstr "" msgid "Stage All Untracked" msgstr "全てのトラックしていないものをステージする" msgid "Stage Changed Files To Commit" msgstr "コミットするために変更されたファイルをステージする" msgid "Stage Diff Hunk" msgstr "差分のステージング" msgid "Stage Modified" msgstr "修正のステージング" msgid "Stage Modified and Untracked" 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 "Submodule URL (can be relative, ex: ../repo.git)" msgstr "サブモジュールのURL(取得可能なもの、例: ../repo.git)" msgid "Submodule branch to track (optional)" msgstr "追跡するサブモジュールのブランチ(任意)" msgid "Submodule path within the current repository (optional)" 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 --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 "以下のファイルは削除されます。:" #, python-format msgid "The repository will be reset using \"git reset --hard %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --keep %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --merge %s\"" msgstr "" msgid "The revision expression cannot be empty." msgstr "このリビジョン表記を空にできません。" #, python-format msgid "" "The submodule will be added using\n" "\"%s\"" msgstr "" "\"%s\"を使ってサブモジュールを\n" "追加します" #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" "\"%s\"を使ってサブモジュールを\n" "更新" #, python-format msgid "The worktree will be restored using \"git read-tree --reset -u %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" "この操作は、あなたが望んだ操作ではない可能性が高いです。" 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 image diff" 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 "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 "Undo Last Commit" msgstr "" msgid "Undo last commit?" msgstr "" msgid "Undo the published commit?" 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 "git://git.example.com/repo.git" msgstr "git://git.example.com/repo.git" msgid "grep result..." msgstr "grep 結果..." msgid "hotkeys.html" msgstr "hotkeys.html" msgid "path/to/submodule" msgstr "path/to/submodule" msgid "title" 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 "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 "Delete selected branch?" #~ 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 "Hide Details.." #~ 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 Branch Head" #~ msgstr "ブランチをHeadにリセット" #~ msgid "Reset Hard" #~ msgstr "ハードリセット" #~ msgid "Reset Merge" #~ msgstr "マージリセット" #~ msgid "Reset Soft" #~ msgstr "ソフトリセット" #~ msgid "Reset Worktree" #~ 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 "Reset hard?" #~ msgstr "ハードリセットをしますか?" #~ msgid "Reset merge?" #~ msgstr " マージリセットをしますか?" #~ msgid "Reset soft?" #~ msgstr "ソフトリセットをしますか?" #~ msgid "Reset worktree?" #~ msgstr "ワークツリーをリセットしますか?" #~ msgid "Revert changes in these %i files?" #~ msgstr "これら %i 個のファイルにした変更を元に戻しますか?" #~ msgid "Select File" #~ msgstr "全て選択" #~ msgid "Select Repository..." #~ msgstr "リポジトリを選択..." #~ msgid "Select file from \"%s\"" #~ msgstr "%s からブランチを削除しています。" #~ msgid "Select manually..." #~ msgstr "マニュアルで選択..." #~ msgid "Shared (Fastest, Not Recommended, No Backup)" #~ msgstr "共有(最高速・非推奨・バックアップ無し)" #~ msgid "Shared only available for local repository." #~ msgstr "共有方式は同一計算機上のリポジトリにのみ使えます。" #~ msgid "Show Details..." #~ 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 'main' branch has not been initialized." #~ msgstr "'main' ブランチが初期化されていません" #~ msgid "The branch will be reset using \"git reset --hard %s\"" #~ msgstr "このブランチは\"git reset --hard %s\"でリセットする。" #~ msgid "The branch will be reset using \"git reset --merge %s\"" #~ msgstr "このブランチは\"git reset --merge %s\"でリセットする。" #~ 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 "The worktree will be reset using \"git reset --keep %s\"" #~ msgstr "このワークツリーは\"git reset --keep %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.12.0/po/pl.po000066400000000000000000002022401417222504200146640ustar00rootroot00000000000000# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Łukasz Wojniłowicz , 2016, 2020, 2021. msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-17 01:06-0700\n" "PO-Revision-Date: 2021-11-13 13:46+0100\n" "Last-Translator: Łukasz Wojniłowicz \n" "Language-Team: Polish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: pl_PL\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 22.03.70\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 "" "\n" "
\n" " Git Cola została przetłumaczona na wiele języków dzięki\n" " pomocy osób wymienionych poniżej.\n" "\n" "
\n" "

\n" " Tłumaczenie jest przybliżone. Jeśli znajdziesz błąd,\n" " daj nam znać, zakładając błąd na Github:\n" "

\n" "\n" "

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

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

\n" " Zachęcamy do udziału w tłumaczeniu, poprzez dodawanie lub\n" " uaktualnianie tłumaczenia, a następnie utworzeniu prośby o" " wciągnięcie.\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 w wersji %(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" " Użyj %(bug_link)s do zgłaszania błędów.\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" " Zmienne do formatowania ciągu znaków\n" " -----------------------\n" " %(path)s = względna ścieżka do pliku\n" " %(abspath)s = bezwzględna ścieżka do pliku\n" " %(dirname)s = względna ścieżka do katalogu\n" " %(absdirname)s = bezwzględna ścieżka do katalogu\n" " %(filename)s = nazwa pliku\n" " %(basename)s = nazwa pliku bez jego rozszerzenia\n" " %(ext)s = rozszerzenie pliku\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" "Polecenia\n" "--------\n" "pick = użyj wdrożenia\n" "reword = użyj wdrożenia, lecz zmień jego opis\n" "edit = użyj wdrożenia, lecz zatrzymaj się na uzupełnienie wdrożenia\n" "squash = użyj wdrożenia, lecz złącz je z poprzednim\n" "fixup = tak jak \"squash\", lecz z porzuceniem tego opis wdrożenia\n" "exec = wykonaj polecenie (reszta wiersza) przy użyciu powłoki\n" "\n" "Można zmienić kolejność tych wierszy; będą one wykonywane od góry do dołu.\n" "\n" "Po wyłączeniu wiersza tutaj, to TO WDROŻENIE ZOSTANIE UTRACONE.\n" "\n" "Jednakże, po wyłączeniu wszystkiego, to zmiana podstawy zostanie przerwana.\n" "\n" "Skróty klawiszowe\n" "------------------\n" "? = pokaż pomoc\n" "j = przesuń w dół\n" "k = przesuń w górę\n" "J = przesuń wiersz w dół\n" "K = przesuń wiersz w górę\n" "\n" "1, p = pick\n" "2, r = reword\n" "3, e = edit\n" "4, f = fixup\n" "5, s = squash\n" "spacja = uwzględnij/nie uwzględniaj\n" "\n" "ctrl+enter = przyjmij zmiany i zmień podstawę\n" "ctrl+q = zaniechaj i przerwij zmianę podstawę\n" "ctrl+d = wywołaj narzędzie różnicy\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" "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 = Zmień 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" #, python-format msgid "\"%s\" already exists" msgstr "\"%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 could not be opened. Remove from bookmarks?" msgstr "Nie można otworzyć %s. Czy usunąć z zakładek?" #, 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 "100%" msgid "200%" msgstr "200%" msgid "25%" msgstr "25%" msgid "400%" msgstr "400%" msgid "50%" msgstr "50%" msgid "800%" msgstr "800%" 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 "Należy podać haczyk w \"%s\"" #, 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 programie" msgid "About git-cola" msgstr "O git-cola" msgid "Accept" msgstr "Przyjmij" msgid "" "Accept changes and rebase\n" "Shortcut: Ctrl+Enter" msgstr "" "Przyjmij zmiany i zmień podstawę\n" "Skrót: Ctrl+Enter" msgid "Action Name" msgstr "Nazwa działania" msgid "Actions" msgstr "Działania" msgid "Actions..." msgstr "Działania..." msgid "Add" msgstr "Dodaj" msgid "Add Favorite" msgstr "Dodaj ulubione" msgid "Add Remote" msgstr "Dodaj zdalne repozytorium" msgid "Add Separator" msgstr "Dodaj oddzielacz" msgid "Add Submodule" msgstr "Dodaj podmoduł" msgid "Add Submodule..." msgstr "Dodaj podmoduł..." msgid "New Toolbar" msgstr "Dodaj pasek narzędzi" 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 "" "Dodaj lub usuń zdalne repozytorium przy użyciu \n" "przycisku Dodaj(+) lub 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 this submodule?" msgstr "Czy dodać ten podmoduł?" msgid "Add to .gitignore" msgstr "Dodaj do .gitignore" msgid "Add to Git Annex" msgstr "Dodaj do Git Annex" msgid "Add to Git LFS" msgstr "Dodaj do Git LFS" msgid "Add to exclusions" msgstr "Dodaj do wykluczonych" msgid "Add to local .git/info/exclude" msgstr "Dodaj do lokalnego .git/info/exclude" 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 "" "Wszystkie podmoduły zostaną uaktualnione przy użyciu\n" "\"%s\"" msgid "" "Allow non-fast-forward updates. Using \"force\" can cause the remote" " repository to lose commits; use it with care" msgstr "" "Zezwól na uaktualnienia nie będące przewinięciem do przodu. Użycie \"wymuś\"" " może spowodować, że zdalne repozytoria zgubią wdrożenia; używaj z rozwagą" 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 "Wygląd" msgid "Apply" msgstr "Zastosuj" msgid "Apply Patches" msgstr "Stosowanie łat" msgid "Apply Patches..." msgstr "Zastosuj łaty..." msgid "Apply and drop the selected stash (git stash pop)" msgstr "Zastosuj i porzuć wybraną przechowalnię (git stash pop)" msgid "Apply the selected stash" msgstr "Zastosuj wybraną przechowalnię" msgid "Arguments" msgstr "Argumenty" msgid "Attach" msgstr "Dołącz" msgid "Author" msgstr "Autor" msgid "Authors" msgstr "Autorzy" msgid "Auto" msgstr "Auto" msgid "Auto-Wrap Lines" msgstr "Zawijaj wiersze" msgid "Autocomplete Paths" msgstr "Uzupełniaj ścieżki" msgid "Automatically Load Commit Message Template" msgstr "Sam wczytuj szablon opisu wdrożenia" msgid "Basic Regexp" msgstr "Podstawowe wyrażenie regularne" msgid "Blame Viewer" msgstr "Przeglądarka autorów" msgid "Blame selected paths" msgstr "Obwiń wybrane ścieżki" msgid "Blame..." msgstr "Przejrzyj autorów..." msgid "Bold on dark headers instead of italic" msgstr "Wytłuść czcionkę zamiast ją pochylać na ciemnych nagłówkach" 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" msgid "Branch name" msgstr "Nazwa gałęzi" #, python-format msgid "Branch: %s" msgstr "Gałąź: %s" msgid "Branches" msgstr "Gałęzie" msgid "Branches..." msgstr "Pomiędzy gałęziami..." msgid "Brazilian translation" msgstr "Tłumaczenie na brazylijski" msgid "Browse" msgstr "Przeglądaj" msgid "Browse Commits..." msgstr "Przejrzyj wdrożenia..." msgid "Browse Current Branch..." msgstr "Przejrzyj bieżącą gałąź..." msgid "Browse Other Branch..." msgstr "Przejrzyj 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ń wykonywanie haczyków" msgid "Cancel" msgstr "Zaniechaj" msgid "" "Cancel rebase\n" "Shortcut: Ctrl+Q" msgstr "" "Zaniechaj zmieniania podstawy\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 Published Commits when Amending" msgstr "Uzupełniając wdrożenie, sprawdź jego opublikowanie" msgid "Check Spelling" msgstr "Sprawdź pisownię" msgid "Check spelling" msgstr "Sprawdź pisownię" msgid "Check whether a commit has been published when amending" msgstr "" "Sprawdź, czy wdrożenie zostało już opublikowane, przed jego uzupełnieniem" msgid "Checkout" msgstr "Przełącz" msgid "Checkout After Creation" msgstr "Przełącz po utworzeniu" msgid "Checkout Branch" msgstr "Przełącz na gałąź" msgid "Checkout Detached HEAD" msgstr "Przełącz na odłączony HEAD" msgid "Checkout as new branch" msgstr "Przełącz jako nowa 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ść..." msgid "Clone" msgstr "Pobierz" msgid "Clone Repository" msgstr "Pobieranie repozytorium" msgid "Clone..." msgstr "Pobierz..." #, python-format msgid "Cloning repository at %s" msgstr "Pobieranie repozytorium o adresie %s" msgid "Close" msgstr "Zamknij" msgid "Close..." msgstr "Zamknij..." msgid "Collapse all" msgstr "Zwiń wszystko" msgid "Command" msgstr "Polecenie" 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" msgid "Compare All" msgstr "Porównaj wszystkie" msgid "Configure the remote branch as the the new upstream" msgstr "Ustaw zdalną gałąź jako nową gałąź odgórną" msgid "Configure Toolbar" msgstr "Ustawienia paska narzędzi" msgid "Console" msgstr "Konsola" msgid "Continue" msgstr "Dalej" msgid "Copy" msgstr "Skopiuj " msgid "Copy Basename to Clipboard" msgstr "Skopiuj nazwę pliku do schowka" msgid "Copy Leading Path to Clipboard" msgstr "Skopiuj ścieżkę katalogu do schowka" msgid "Copy Path to Clipboard" msgstr "Skopiuj ścieżkę do schowka" msgid "Copy Relative Path to Clipboard" msgstr "Skopiuj względną ścieżkę do schowka" msgid "Copy SHA-1" msgstr "Skopiuj SHA-1" msgid "Copy..." msgstr "Skopiuj..." #, python-format msgid "Could not open %s." msgstr "Nie można otworzyć %s." #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "Nie można przetworzyć adresu URL Gita: \"%s\"" msgid "Create" msgstr "Utwórz" 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" msgid "Create a merge commit even when the merge resolves as a fast-forward" msgstr "" "Utwórz wdrożenie scalania, nawet gdy scalanie będzie polegać na przewinięciu" " do przodu" msgid "Create a new remote branch?" msgstr "Czy utworzyć nową zdalną gałąź?" msgid "Create a new repository at that location?" msgstr "Czy utworzyć nowe repozytorium w tym miejscu?" msgid "" "Create a shallow clone with history truncated to the specified number of" " revisions. 0 performs a full clone." msgstr "" "Pobierz płytko z historią przyciętą do danej liczby wydań. 0 wykonuje pobiera" " z całą historią." 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 "Własne działania kopiowania" msgid "Customize..." msgstr "Dostosuj..." msgid "Cut" msgstr "Wytnij" msgid "Czech translation" msgstr "Tłumaczenie na czeski" msgid "DAG..." msgstr "DAG..." msgid "Dark Theme" msgstr "Ciemne" msgid "Date, Time" msgstr "Data, czas" msgid "Default" msgstr "Domyślne" 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ń zdalną gałąź" msgid "Delete Remote Branch" msgstr "Usuń zdalną gałąź" msgid "Delete Remote Branch..." msgstr "Usuń zdalną gałąź..." #, python-format msgid "Delete branch \"%s\"?" msgstr "Usuń gałąź \"%s\"?" 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?" msgid "Delete Toolbar" msgstr "Usuń pasek narzędzi" msgid "Delete..." msgstr "Usuń..." #, python-format msgid "Deleting \"%s\" failed" msgstr "Nie udało się usunąć \"%s\"" msgid "Deletions" msgstr "Usunięto" msgid "Depth" msgstr "Głębokość" 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 "Programista" 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" msgid "Difftool" msgstr "Narzędzie różnicy" msgid "Directory Exists" msgstr "Katalog istnieje" msgid "Disable" msgstr "Wyłącz" 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ę" msgid "Edit" msgstr "Zmień" msgid "Edit Rebase" msgstr "Ustawienia zmiany podstawy" msgid "Edit Remotes" msgstr "Zmień zdalne repozytoria" msgid "Edit Remotes..." msgstr "Zmień zdalne repozytoria..." msgid "Edit remotes by selecting them from the list" msgstr "Zmień repozytoria zdalne poprzez wybranie ich z wykazu" msgid "Edit selected paths" msgstr "Zmień wybraną ścieżkę/ścieżki" msgid "Edit..." msgstr "Ustawienia..." msgid "Editor" msgstr "Edytor" msgid "Email Address" msgstr "Adres email" msgid "Email contributor" msgstr "Napisz do współtwórcy" msgid "Enable path autocompletion in tools" msgstr "Włącz uzupełnianie ścieżki w narzędziach" msgid "Enabled" msgstr "Uwzględnione" msgid "Enter New Branch Name" msgstr "Podaj nazwę nowej gałęzi" msgid "Enter a name for the new bare repo" msgstr "Wpisz nazwę do założenia nowego repozytorium" msgid "Enter a name for the stash" msgstr "Podaj nazwę dla przechowalni" msgid "Error" msgstr "Błąd" msgid "Error Cloning" msgstr "Błąd pobierania" 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" msgid "Error Opening Repository" msgstr "Błąd otwierania repozytorium" #, python-format msgid "Error creating remote \"%s\"" msgstr "Błąd podczas tworzenia zdalnego repozytorium \"%s\"" msgid "Error creating stash" msgstr "Błąd tworzenia przechowalni" #, python-format msgid "Error deleting branch \"%s\"" msgstr "Błąd usuwania gałęzi \"%s\"" #, python-format msgid "Error deleting remote \"%s\"" msgstr "Błąd usuwania zdalnego repozytorium \"%s\"" #, python-format msgid "Error renaming \"%(name)s\" to \"%(new_name)s\"" msgstr "Nie udało się przemianować \"%(name)s\" na \"%(new_name)s\"" msgid "Error running prepare-commitmsg hook" msgstr "Nie udało się wykonać haczyka prepare-commitmsg" #, python-format msgid "Error updating submodule %s" msgstr "Nie udało się uaktualnić podmodułu\"%s\"" msgid "Error updating submodules" msgstr "Nie udało się uaktualnić podmodułów" 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 pobrać \"%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 "Wykonywanie działania %s" msgid "Expand all" msgstr "Rozwiń wszystko" msgid "Export Patches" msgstr "Eksportowanie łat" msgid "Export Patches..." msgstr "Eksportuj łaty..." msgid "Expression..." msgstr "Pomiędzy wyrażeniami wdrożeń..." msgid "Extended Regexp" msgstr "Rozszerzone wyrażenie regularne" msgid "Extended description..." msgstr "Rozbudowany opis..." msgid "Fast Forward Only" msgstr "Tylko przewinięcie do przodu" msgid "Fast-forward only" msgstr "Tylko przewiń 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" msgid "Filter branches..." msgstr "Odfiltruj gałęzie..." 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 "Popraw" msgid "Fixup Previous Commit" msgstr "Popraw wcześniejsze wdrożenie" msgid "Flat dark blue" msgstr "Płaski, ciemny, niebieski" msgid "Flat dark green" msgstr "Płaski, ciemny, zielony" msgid "Flat dark grey" msgstr "Płaski, ciemny, szary" msgid "Flat dark red" msgstr "Płaski, ciemny, czerwony" msgid "Flat light blue" msgstr "Płaski, jasny, niebieski" msgid "Flat light green" msgstr "Płaski, jasny, zielony" msgid "Flat light grey" msgstr "Płaski, jasny, szary" msgid "Flat light red" msgstr "Płaski, jasny, czerwony" msgid "Folder" msgstr "Katalog" msgid "Font Size" msgstr "Rozmiar czcionki" msgid "Force" msgstr "Wymuś" 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?" msgid "Format String" msgstr "Sformatowany ciąg znaków" msgid "French translation" msgstr "Tłumaczenie na francuski" msgid "GPG-sign the merge commit" msgstr "Podpisz-GPG scalane wdrożenie" msgid "GUI theme" msgstr "Ogólny wygląd" #, python-format msgid "Gathering info for \"%s\"..." msgstr "Zbieranie informacji dla \"%s\"..." msgid "German translation" msgstr "Tłumaczenie na niemiecki" 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 zmieniłeś podstawę/zaciągnąłeś?" msgid "Help" msgstr "Pomoc" msgid "Help - Custom Copy Actions" msgstr "Pomoc - Własne działania kopiowania" msgid "Help - Find Files" msgstr "Pomoc - Znajdź pliki" msgid "Help - git-cola-sequence-editor" msgstr "Pomoc - git-cola-sequence-editor" msgid "High DPI" msgstr "Wysokie DPI" msgid "History Browser" msgstr "Przeglądarka historii" msgid "Hungarian translation" msgstr "Tłumaczenie na węgierski" msgid "Icon theme" msgstr "Zestaw ikon" 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 "Pomiń własny wzorzec" msgid "Ignore exact filename" msgstr "Pomiń dokładne nazwy plików" msgid "Ignore filename or pattern" msgstr "Pomiń nazwy plików lub wzorce" msgid "Ignore..." msgstr "Pomiń..." msgid "Include tags " msgstr "Uwzględnij znaczniki" msgid "Indent Status paths" msgstr "Wetnij ścieżki w oknie stanu" msgid "Indonesian translation" msgstr "Tłumaczenie na indonezyjski" msgid "Initialize Git Annex" msgstr "Przygotuj Git Annex" msgid "Initialize Git LFS" msgstr "Przygotuj Git LFS" msgid "Inititalize submodules" msgstr "Przygotuj podmoduły" msgid "Insert spaces instead of tabs" msgstr "Wstaw odstępy zamiast tabulatorów" msgid "Interactive Rebase" msgstr "Zmień podstawę interaktywnie" msgid "Invalid Revision" msgstr "Nieprawidłowe wydanie" msgid "Japanese translation" msgstr "Japońskie tłumaczenie" msgid "Keep *.orig Merge Backups" msgstr "Zachowaj kopie zapasowe *.orig po scalaniu" msgid "Keep Index" msgstr "Pozostaw indeks" msgid "Keyboard Shortcuts" msgstr "Skróty klawiszowe" msgid "Launch Diff Tool" msgstr "Wywołaj narzędzie różnicy" msgid "Launch Directory Diff Tool" msgstr "Wywołaj narzędzie różnicy na katalogu" msgid "Launch Editor" msgstr "Otwórz w edytorze" msgid "Launch Terminal" msgstr "Otwórz terminal" msgid "" "Launch external diff tool\n" "Shortcut: Ctrl+D" msgstr "" "Wywołaj zewnętrzne narzędzie różnicy\n" "Skrót: Ctrl+D" msgid "Launch git-cola" msgstr "Uruchom git-cola" msgid "Launch git-difftool against previous versions" msgstr "Uruchom git-difftool względem poprzednich wersji" msgid "Launch git-difftool on the current path" msgstr "Uruchom git-difftool dla bieżącej ścieżki" msgid "Light Theme" msgstr "Jasne" msgid "List" msgstr "Lista" 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 "Lokalne repozytoria" 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 "Opiekun (od 2007) i programista" 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 "Nie udało się scalić. Wymagane jest rozwiązanie sprzeczności." #, python-format msgid "Merge into \"%s\"" msgstr "Scal z \"%s\"" msgid "Merge into current branch" msgstr "Scal z bieżącą gałęzią" 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" msgid "New Bare Repository..." msgstr "Nowe repozytorium bez drzewa pracy..." 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 "Nie przewijaj do przodu" msgid "No fast-forward" msgstr "Nie przewijaj 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 otoczenia różnicy" msgid "Open" msgstr "Otwórz" msgid "Open Git Repository..." msgstr "Otwórz repozytorium Git..." msgid "Open Parent" msgstr "Otwórz nadrzędny" 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..." msgid "Other branches" msgstr "Inne gałęzie" 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 dobrany" msgid "Paste" msgstr "Wklej" msgid "Patch(es) Applied" msgstr "Zastosowano łatę/łaty" msgid "Path" msgstr "Ścieżka" msgid "Path or URL to clone (Env. $VARS okay)" msgstr "Ścieżka lub adres URL do pobrania (Zm. środowiskowe $VARS są OK)" msgid "Pick" msgstr "Użyj" msgid "Pixel XOR" msgstr "Pixel XOR" 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 "Tłumaczenie na polski" msgid "Pop" msgstr "Pobierz" msgid "Preferences" msgstr "Ustawienia" msgid "Prefix" msgstr "Przedrostek" msgid "Prepare Commit Message" msgstr "Przygotuj opis wdrożenia" msgid "Prevent \"Stage\" from staging all files when nothing is selected" msgstr "" "Uniemożliw dobranie wszystkich plików, gdy nie jest zaznaczony żaden plik" msgid "Previous File" msgstr "Poprzedni plik" msgid "Prompt on creation" msgstr "Zapytaj przed stworzeniem" msgid "Prompt when pushing creates new remote branches" msgstr "Zapytaj, gdy wypchnięcie miałoby utworzyć nową zdalną gałąź" msgid "Prune " msgstr "Przytnij " msgid "Prune Missing Entries" msgstr "Przytnij brakujące wpisy" 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 "Zmień podstawę" #, python-format msgid "Rebase onto %s" msgstr "Zmień podstawę na %s" msgid "Rebase stopped" msgstr "Zatrzymano zmianę podstawy" msgid "Rebase the current branch instead of merging" msgstr "Zmień podstawę bieżącej gałęzi zamiast scalić" msgid "Rebasing" msgstr "Zmiana podstawy" msgid "Recent" msgstr "Ostatnie" msgid "Recent repositories" msgstr "Ostatnie repozytoria" msgid "Recent repository count" msgstr "Liczba ostatnich repozytoriów" 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 "Przywróć" msgid "Reduce commit history to minimum" msgstr "Pomiń historię wdrożeń" msgid "Reference Repository" msgstr "Repozytorium odniesienia" msgid "Reference URL" msgstr "Adres URL odniesienia" msgid "Reference repository to use when cloning (optional)" msgstr "Repozytorium odniesienia, używane podczas pobierania (niewymagane)" 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 "" "Odmów scalenia do chwili uaktualnienia bieżącego HEAD lub rozwiązania" " scalenia poprzez przewinięcie do przodu." msgid "Remote" msgstr "Zdalne repozytoria" 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 przemianować" msgid "Remove" msgstr "Usuń" #, python-format msgid "Remove %s from the recent list?" msgstr "Usunąć %s z listy ostatnich?" msgid "Remove Element" msgstr "Usuń element" msgid "Remove remote-tracking branches that no longer exist on the remote" msgstr "Usuń gałęzie zdalne, które już nie istnieją w repozytorium zdalnym" msgid "Remove selected (Delete)" msgstr "Usuń wybrane (Usuń)" msgid "Remove stale entries for repositories that no longer exist" msgstr "Usuń zawisłe wpisy dla repozytoriów, które już nie istnieją" msgid "Rename" msgstr "Przemianuj " #, python-format msgid "Rename \"%s\"" msgstr "Przemianuj \"%s\"" msgid "Rename Branch" msgstr "Przemianuj gałąź" msgid "Rename Branch..." msgstr "Przemianuj gałąź..." msgid "Rename Existing Branch" msgstr "Przemianuj istniejącą gałąź" msgid "Rename Remote" msgstr "Przemianuj zdalne repozytorium" msgid "Rename Repository" msgstr "Przemianuj repozytorium" msgid "Rename branch" msgstr "Przemianuj gałąź" #, python-format msgid "Rename remote \"%(current)s\" to \"%(new)s\"?" msgstr "Przemianuj zdalne repozytorium z \"%(current)s\" na \"%(new)s\"?" msgid "Rename selected paths" msgstr "Przemianuj wybrane ścieżki" msgid "Repository Not Found" msgstr "Nie znaleziono repozytorium" #, 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 All (Keep Unstaged Changes)" msgstr "Wyzeruj wszystko (zachowaj niedobrane zmiany)" msgid "Reset Branch" msgstr "Wyzeruj gałąź" msgid "Reset Branch (Soft)" msgstr "Wyzeruj gałąź (miękko)" msgid "Reset Branch and Stage (Mixed)" msgstr "Wyzeruj gałąź i dobierz (mieszanie)" msgid "Reset Branch?" msgstr "Wyzerować gałąź?" msgid "Reset Layout" msgstr "Wyzeruj układ" msgid "Reset Worktree and Reset All?" msgstr "Czy wyzerować drzewo pracy i wszystko?" msgid "Reset and Restore" msgstr "Wyzeruj i przywróć" msgid "Reset branch?" msgstr "Czy wyzerować gałąź?" #, 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 "Uruchom aplikację ponownie po zmianie ustawień wyglądu." msgid "Restore Worktree" msgstr "Przywróć drzewo pracy" msgid "Restore Worktree and Reset All (Hard)" msgstr "Przywróć drzewo i wyzeruj wszystko (twardo)" msgid "Restore Worktree and Reset All (Keep Unstaged Changes)" msgstr "Przywróć drzewo i wyzeruj wszystko (zachowaj niedobrane zmiany)" msgid "Restore Worktree and Reset All (Keep Unstaged Edits)" msgstr "Przywróć drzewo i wyzeruj wszystko (zachowaj niedobrane edycje)" msgid "Restore Worktree and Reset All (Merge)" msgstr "Przywróć drzewo i wyzeruj wszystko (scal)" msgid "Restore Worktree and Reset All?" msgstr "Czy przywrócić drzewo i wyzerować wszystko?" #, python-format msgid "Restore Worktree to %s?" msgstr "Czy przywrócić drzewo pracy do %s?" msgid "Restore worktree, reset, and preserve unstaged edits?" msgstr "Czy przywrócić drzewo pracy, wyzerować i zachować niedobrane edycje?" msgid "Revert" msgstr "Wycofaj" 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?" msgid "Revert uncommitted changes to selected paths" msgstr "Wycofaj niewdrożone zmiany w wybranych ścieżkach" msgid "Revert unstaged changes to selected paths" msgstr "Wycofaj niezebrane zmiany w wybranych ścieżkach" msgid "Review" msgstr "Przejrzyj" 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 "Zmień opis" 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 "Tłumaczenie na rosyjski" msgid "SHA-1" msgstr "SHA-1" msgid "Safe Mode" msgstr "Tryb bezpieczny" msgid "Save" msgstr "Przechowaj" msgid "Save Archive" msgstr "Zapisz archiwum" msgid "Save As Tarball/Zip..." msgstr "Zapisz jako tarball/zip..." msgid "Save GUI Settings" msgstr "Zachowaj ustawienia interfejsu" 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" msgid "Select Directory..." msgstr "Wybierz katalog..." msgid "Select New Upstream" msgstr "Wybierz nową gałąź odgórną" 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 a parent directory for the new clone" msgstr "Wybierz katalog nadrzędny do pobrania" msgid "Select output dir" msgstr "Wybierz katalog do wyników" msgid "Select output directory" msgstr "Wybierz katalog do wyników" msgid "Select patch file(s)..." msgstr "Wybierz plik(i) łat(y)..." msgid "Select repository" msgstr "Wybierz repozytorium" msgid "Set Default Repository" msgstr "Ustaw domyślne repozytorium" msgid "Set Upstream Branch" msgstr "Ustaw gałąź odgórną" msgid "" "Set the sort order for branches and tags.\n" "Toggle between date-based and version-name-based sorting." msgstr "" "Ustaw porządek szeregowania dla gałęzi i znaczników.\n" "Przełącz pomiędzy szeregowaniem wg daty oraz nazwy wersji." msgid "Set upstream" msgstr "Zapamiętaj gałąź odgórną" msgid "Settings" msgstr "Ustawienia" msgid "Shell arguments" msgstr "Argumenty powłoki" msgid "Shift Down" msgstr "Przesuń w dół" msgid "Shift Up" msgstr "Przesuń w górę" msgid "Shortcuts" msgstr "Skróty" msgid "Show Diffstat After Merge" msgstr "Pokaż statystykę różnicy po scaleniu" msgid "Show Full Paths in the Window Title" msgstr "Pokaż pełne ścieżki w nazwie okna" msgid "Show Help" msgstr "Pokaż pomoc" msgid "Show History" msgstr "Pokaż historię" msgid "Show file counts in Status titles" msgstr "Pokaż liczbę plików w oknie stanu" msgid "" "Show help\n" "Shortcut: ?" msgstr "" "Pokaż pomoc\n" "Skrót: ?" msgid "Show icon? (if available)" msgstr "Pokazać ikonę? (jeśli dostępna)" msgid "Show line numbers" msgstr "Pokaż numery wierszy" 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 "Obok siebie" 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 "Tłumaczenie na uproszczony chiński" msgid "Skip" msgstr "Pomiń" msgid "Skip Current Patch" msgstr "Pomiń bieżącą łatę" msgid "Sort bookmarks alphabetically" msgstr "Uszereguj zakładki alfabetycznie" msgid "Spanish translation" msgstr "Tłumaczenie na hiszpański" 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 "Sprawdź 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 / Unstage All" msgstr "Dobierz / Odłóż wszystkie" msgid "Stage All Untracked" msgstr "Dobierz wszystkie niezarządzane" msgid "Stage Changed Files To Commit" msgstr "Dobierz wszystkie zmienione" msgid "Stage Diff Hunk" msgstr "Dobierz kawałek różnicy" msgid "Stage Modified" msgstr "Dobierz zmienone" msgid "Stage Modified and Untracked" msgstr "Dobierz zmienione i niezarządzane" 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 "Zmień podstawę interaktywnie..." msgid "Starting Revision" msgstr "Rozpoczynanie wydania" msgid "Stash" msgstr "Przechowalnia" msgid "Stash Index" msgstr "Przechowaj indeks" msgid "Stash staged changes only" msgstr "Przechowaj tylko dobrane zmiany" msgid "Stash unstaged changes only, keeping staged changes" msgstr "Przechowaj tylko niedobrane zmiany, nie dotykając dobranych zmian" msgid "Stash..." msgstr "Przechowaj..." msgid "Status" msgstr "Stan" msgid "Stop tracking paths" msgstr "Zaprzestań zarządzanie ścieżką/ścieżkami" msgid "Submodule URL (can be relative, ex: ../repo.git)" msgstr "Adres URL podmodułu (może być względny, np.: ../repo.git)" msgid "Submodule branch to track (optional)" msgstr "Gałąź podmodułu do śledzenia (niewymagane)" msgid "Submodule path within the current repository (optional)" msgstr "Ścieżka podmodułu z bieżącym repozytorium (niewymagane)" msgid "Submodules" msgstr "Podmoduły" 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 "Znaczniki" msgid "Text Width" msgstr "Szerokość tekstu" msgid "The branch will be no longer available." msgstr "Po tym gałąź stanie się niedostępna." #, python-format msgid "The branch will be reset using \"git reset --mixed %s\"" msgstr "Gałąź zostanie wyzerowana przy użyciu \"git reset --mixed %s\"" #, python-format msgid "The branch will be reset using \"git reset --soft %s\"" msgstr "Gałąź zostanie wyzerowana przy użyciu \"git reset --soft %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:" #, python-format msgid "The repository will be reset using \"git reset --hard %s\"" msgstr "Repozytorium zostanie wyzerowane przy użyciu \"git reset --hard %s\"" #, python-format msgid "The repository will be reset using \"git reset --keep %s\"" msgstr "Repozytorium zostanie wyzerowane przy użyciu \"git reset --keep %s\"" #, python-format msgid "The repository will be reset using \"git reset --merge %s\"" msgstr "Repozytorium zostanie wyzerowane przy użyciu \"git reset --merge %s\"" msgid "The revision expression cannot be empty." msgstr "Wyrażenie wydania nie może być puste." #, python-format msgid "" "The submodule will be added using\n" "\"%s\"" msgstr "" "Zostanie dodany podmoduł przy użyciu\n" "\"%s\"" #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" "Ten podmoduł zostanie uaktualniony przy użyciu\n" "\"%s\"" #, python-format msgid "The worktree will be restored using \"git read-tree --reset -u %s\"" msgstr "" "Drzewo pracy zostanie przywrócone przy użyciu \"git read-tree --reset -u %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." 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 "" "W repozytorium następuje zmiana podstawy .\n" "Wyjaśnij sprzeczności, wdroż zmiany i wykonaj:\n" " Zmiana podstawy > Dalej" 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 "Uwzględnij/nie uwzględniaj" msgid "Toggle image diff" msgstr "Przełącz różnicę obrazu" msgid "Toggle the branches filter" msgstr "Przełącz filtr gałęzi" 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 "Tłumaczenia na tradycyjny chiński (Tajwan)" msgid "Translation" msgstr "Tłumaczenie" msgid "Translators" msgstr "Tłumacze" msgid "Turkish translation" msgstr "Tłumaczenie na turecki" msgid "URL" msgstr "Adres URL" #, python-format msgid "URL: %s" msgstr "Adres URL: %s" msgid "Ukranian translation" msgstr "Tłumaczenie na ukraiński" msgid "Unable to rebase" msgstr "Nie można zmienić podstawy" #, python-format msgid "Unable to set URL for \"%(name)s\" to \"%(url)s\"" msgstr "Nie można ustawić URL dla \"%(name)s\" na \"%(url)s\"" msgid "Undo" msgstr "Cofnij" msgid "Undo Last Commit" msgstr "Wycofaj ostatnie wdrożenie" msgid "Undo last commit?" msgstr "Czy wycofać ostatnie wdrożenie?" msgid "Undo the published commit?" msgstr "Czy wycofać opublikowane wdrożenie?" 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 "Uaktualnij wszystkie podmoduły..." msgid "Update Existing Branch:" msgstr "Uaktualnij bieżącą gałąź:" msgid "Update Submodule" msgstr "Uaktualnij podmoduł" msgid "Update Submodule..." msgstr "Uaktualnij podmoduł..." msgid "Update Submodules" msgstr "Uaktualnij podmoduły" msgid "Update all submodules?" msgstr "Uaktualnić wszystkie podmoduły?" msgid "Update submodules..." msgstr "Uaktualnij podmoduły..." msgid "Update this submodule" msgstr "Uaktualnij ten podmoduł" msgid "Update this submodule?" msgstr "Uaktualnić ten podmoduł?" msgid "Updating" msgstr "Uaktualnianie" msgid "User Name" msgstr "Nazwa użytkownika" msgid "Version" msgstr "Wersja" 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 "XOR" msgid "Yes" msgstr "Tak" 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 zmienić podstawy, 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 "Powiększ" msgid "Zoom Out" msgstr "Pomniejsz" msgid "Zoom to Fit" msgstr "Zmieść" msgid "command-line arguments" msgstr "argumenty wiersza poleceń" msgid "error: unable to execute git" msgstr "błąd: nie można uruchomić git" #, 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 "git://git.example.com/repo.git" msgstr "git://git.example.com/repo.git" msgid "grep result..." msgstr "wyszukaj w wynikach..." msgid "hotkeys.html" msgstr "hotkeys.html" msgid "path/to/submodule" msgstr "ściezka/do/podmodułu" msgid "title" msgstr "tytuł" msgid "unknown" msgstr "nieznany" 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" #, 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 "Delete selected branch?" #~ msgstr "Usunąć zdalną gałąź?" #~ 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" #~ msgid "Hide Details.." #~ msgstr "Ukryj szczegóły..." #, 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 "Reset Branch Head" #~ msgstr "Wyzeruj HEAD gałęzi" #~ msgid "Reset Hard" #~ msgstr "Wyzeruj twardo" #~ msgid "Reset Merge" #~ msgstr "Wyzeruj ze scaleniem" #~ msgid "Reset Soft" #~ msgstr "Wyzeruj miękko" #~ msgid "Reset Worktree" #~ msgstr "Wyzeruj drzewo pracy" #~ msgid "Reset hard?" #~ msgstr "Wyzerować twardo?" #~ msgid "Reset merge?" #~ msgstr "Wyzerować ze scaleniem?" #~ msgid "Reset soft?" #~ msgstr "Wyzerować miękko?" #~ msgid "Reset worktree?" #~ msgstr "Wyzerować drzewo pracy?" #~ msgid "Select File" #~ msgstr "Wybierz plik" #~ msgid "Select Repository..." #~ msgstr "Wybierz repozytorium..." #~ msgid "Select file from \"%s\"" #~ msgstr "Wybierz plik z \"%s\"" #~ msgid "Select manually..." #~ msgstr "Wybierz ręcznie..." #~ msgid "Show Details..." #~ msgstr "Pokaż szczegóły..." #~ msgid "Staging Area" #~ msgstr "Punkt zbiorczy" #~ msgid "Summary:" #~ msgstr "Nazwa:" #~ msgid "The branch will be reset using \"git reset --hard %s\"" #~ msgstr "Gałąź zostanie wyzerowana przy użyciu \"git reset --hard %s\"" #~ msgid "The branch will be reset using \"git reset --merge %s\"" #~ msgstr "Gałąź zostanie wyzerowana przy użyciu \"git reset --merge %s\"" #~ msgid "The worktree will be reset using \"git reset --keep %s\"" #~ msgstr "Drzewo z pracą zostanie wyzerowane przy użyciu \"git reset --keep %s\"" #~ 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.12.0/po/pt_BR.po000066400000000000000000001716301417222504200152670ustar00rootroot00000000000000# 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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: pt_BR\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?" #, python-format msgid "%s could not be opened. Remove from bookmarks?" msgstr "" #, 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 Submodule" msgstr "" msgid "Add Submodule..." msgstr "" msgid "New 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 this submodule?" msgstr "Adicionar este submódulo?" 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 "Add to exclusions" msgstr "" msgid "Add to local .git/info/exclude" msgstr "" 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 "Automático" msgid "Auto-Wrap Lines" msgstr "Auto-Quebra de Linhas" msgid "Autocomplete Paths" msgstr "Autocompletar Caminhos" msgid "Automatically Load Commit Message Template" msgstr "Carregar template de mensagens de commit automaticamente" 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" 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 Published Commits when Amending" msgstr "Verificar commits publicados em Amending" msgid "Check Spelling" msgstr "Verificar Ortografia" msgid "Check spelling" msgstr "Verificar ortografia" msgid "Check whether a commit has been published when amending" msgstr "" 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 "Cherry Pick" msgid "Cherry-Pick Commit" msgstr "Cherry-Pick Commit" msgid "Cherry-Pick..." msgstr "Cherry-Pick..." 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 "Commit@@verbo" 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 "Console" 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 open %s." msgstr "" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "Não foi possível analisar o URL do Git \"%s\"" msgid "Create" msgstr "" 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 a new repository at that location?" msgstr "" msgid "Create a shallow clone with history truncated to the specified number of revisions. 0 performs a full clone." msgstr "" 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 "Tema Escuro" 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..." #, python-format msgid "Delete branch \"%s\"?" msgstr "Remover branch \"%s\"?" 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 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 "Depth" msgstr "" 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 "Disable" msgstr "" 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 "Editor" msgid "Email Address" msgstr "Endereço de Email" msgid "Email contributor" msgstr "Email do Contribuidor" msgid "Enable path autocompletion in tools" msgstr "Habilitar autocomplete de caminhos em ferramentas" 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" msgid "Error Opening Repository" msgstr "" #, 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 branch \"%s\"" msgstr "Erro ao remover branch \"%s\"" #, 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 "Fetch..." 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 "Flat dark blue" msgid "Flat dark green" msgstr "Flat dark green" msgid "Flat dark grey" msgstr "Flat dark grey" msgid "Flat dark red" msgstr "Flat dark red" msgid "Flat light blue" msgstr "Flat light blue" msgid "Flat light green" msgstr "Flat light green" msgid "Flat light grey" msgstr "Flat light grey" msgid "Flat light red" msgstr "Flat light red" msgid "Folder" 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 "Tradução francesa" 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 "Tradução alemã" 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 "Grep" 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-cola-sequence-editor" msgstr "Ajuda - git-cola-sequence-editor" msgid "High DPI" msgstr "DPI Alto" 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 "Ignore..." msgstr "Ignorar..." 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 "Japanese translation" msgstr "" 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 "List" 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 "" msgid "Prune Missing Entries" 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 "Rebase" #, 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 "Rebasing" 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 "Reference Repository" msgstr "" msgid "Reference URL" msgstr "" msgid "Reference repository to use when cloning (optional)" msgstr "" 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 "Remove stale entries for repositories that no longer exist" msgstr "" 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" msgid "Repository Not Found" msgstr "" #, 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 All (Keep Unstaged Changes)" msgstr "" msgid "Reset Branch" msgstr "Resetar Branch" msgid "Reset Branch (Soft)" msgstr "" msgid "Reset Branch and Stage (Mixed)" msgstr "" msgid "Reset Branch?" msgstr "Resetar Branch?" msgid "Reset Layout" msgstr "" msgid "Reset Worktree and Reset All?" msgstr "" msgid "Reset and Restore" msgstr "" msgid "Reset branch?" msgstr "" #, 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 "Restore Worktree" msgstr "" msgid "Restore Worktree and Reset All (Hard)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Changes)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Edits)" msgstr "" msgid "Restore Worktree and Reset All (Merge)" msgstr "" msgid "Restore Worktree and Reset All?" msgstr "" #, python-format msgid "Restore Worktree to %s?" msgstr "" msgid "Restore worktree, reset, and preserve unstaged edits?" msgstr "" 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 "Tradução russa" 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 a parent directory for the new clone" msgstr "Selecionar um diretório pai para o novo clone" 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 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 "Exibe número de arquivos no título de status" 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 "Trandução espanhola" 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 "Squash" msgid "Squash the merged commits into a single commit" msgstr "Unir os commits mesclados em um commit único" msgid "Stage" msgstr "Estágio" msgid "Stage / Unstage" msgstr "Estágio / Sem estágio " msgid "Stage / Unstage All" msgstr "" 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 Modified and Untracked" msgstr "" 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 "Stash" 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 "Submodule URL (can be relative, ex: ../repo.git)" msgstr "" msgid "Submodule branch to track (optional)" msgstr "" msgid "Submodule path within the current repository (optional)" msgstr "" 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 --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:" #, python-format msgid "The repository will be reset using \"git reset --hard %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --keep %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --merge %s\"" msgstr "" 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 added using\n" "\"%s\"" msgstr "" #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be restored using \"git read-tree --reset -u %s\"" msgstr "" 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 image diff" msgstr "" 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 "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 "Undo Last Commit" msgstr "" msgid "Undo last commit?" msgstr "" msgid "Undo the published commit?" msgstr "" 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 "git://git.example.com/repo.git" msgstr "" msgid "grep result..." msgstr "resultados do grep..." msgid "hotkeys.html" msgstr "" msgid "path/to/submodule" msgstr "" msgid "title" 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 "Delete selected branch?" #~ msgstr "Remover branch selecionada?" #~ 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" #~ msgid "Hide Details.." #~ msgstr "Esconder Detalhes..." #, 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 "Reset Branch Head" #~ msgstr "Resetar Head do 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?" #~ msgid "Select File" #~ msgstr "Selecionar Arquivo" #~ msgid "Select Repository..." #~ msgstr "Selecionar Repositório" #~ msgid "Select file from \"%s\"" #~ msgstr "Selecione um arquivo de \"%s\"" #~ msgid "Select manually..." #~ msgstr "Selecione manualmente" #~ msgid "Show Details..." #~ msgstr "Mostrar Detalhes..." #~ msgid "Summary:" #~ msgstr "Sumário:" #~ msgid "The branch will be reset using \"git reset --hard %s\"" #~ msgstr "O branch será resetado usando \"git reset --hard %s\"" #~ msgid "The branch will be reset using \"git reset --merge %s\"" #~ msgstr "O branch será resetado usando \"git reset --merge %s\"" #~ msgid "The worktree will be reset using \"git reset --keep %s\"" #~ msgstr "O worktree será resetado usando \"git reset --keep %s\"" #~ msgid "Updating..." #~ msgstr "Atualização..." git-cola-3.12.0/po/ru.po000066400000000000000000003154451417222504200147130ustar00rootroot00000000000000# 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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: \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 could not be opened. Remove from bookmarks?" 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 "" 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 Submodule" msgstr "" msgid "Add Submodule..." msgstr "" msgid "New 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 this submodule?" msgstr "" msgid "Add to .gitignore" msgstr "Добавить в .gitignore" #, fuzzy msgid "Add to Git Annex" msgstr "Добавить в .gitignore" msgid "Add to Git LFS" msgstr "" msgid "Add to exclusions" msgstr "" msgid "Add to local .git/info/exclude" 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 "Autocomplete Paths" msgstr "" msgid "Automatically Load Commit Message Template" 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 "Название ветви" 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 Published Commits when Amending" msgstr "" msgid "Check Spelling" msgstr "Проверить правописание" #, fuzzy msgid "Check spelling" msgstr "Проверить правописание" msgid "Check whether a commit has been published when amending" 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 open %s." msgstr "" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "Неполучилось разобрать Git URL: \"%s\"" msgid "Create" 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 "Создать неподписанный тег" #, 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 a new repository at that location?" msgstr "" msgid "Create a shallow clone with history truncated to the specified number of revisions. 0 performs a full clone." 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 "Удалить внешнюю ветвь..." #, python-format msgid "Delete branch \"%s\"?" msgstr "" msgid "Delete remote" msgstr "Удалить внешний репозиторий" #, python-format msgid "Delete remote \"%s\"" msgstr "Удалить внешнюю ветвь \"%s\"" msgid "Delete remote?" msgstr "Удалить внешнюю ветвь?" #, fuzzy msgid "Delete Toolbar" msgstr "Удалить закладку" msgid "Delete..." msgstr "Удалить..." #, python-format msgid "Deleting \"%s\" failed" msgstr "Не удалось удалить \"%s\"" msgid "Deletions" msgstr "Удалено строк" msgid "Depth" 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 "Disable" 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 "Enable path autocompletion in tools" 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 "Ошибка запуска Просмотрщика истории" msgid "Error Opening Repository" msgstr "" #, python-format msgid "Error creating remote \"%s\"" msgstr "Не удалось создать внешную ветвь \"%s\"" #, fuzzy msgid "Error creating stash" msgstr "При создании ветви возникла ошибка" #, python-format msgid "Error deleting branch \"%s\"" 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 "Folder" 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-cola-sequence-editor" 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 "Ignore..." 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 "Japanese translation" 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 "List" 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 "Prune Missing Entries" 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 "Reference Repository" msgstr "" msgid "Reference URL" msgstr "" msgid "Reference repository to use when cloning (optional)" 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 "Remove stale entries for repositories that no longer exist" msgstr "" 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 "Редактировать выбранный путь(и)" msgid "Repository Not Found" 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 All (Keep Unstaged Changes)" msgstr "" msgid "Reset Branch" msgstr "Сбросить (reset) ветвь" msgid "Reset Branch (Soft)" msgstr "" msgid "Reset Branch and Stage (Mixed)" msgstr "" msgid "Reset Branch?" msgstr "Сбросить (reset) ветвь?" msgid "Reset Layout" msgstr "" msgid "Reset Worktree and Reset All?" msgstr "" msgid "Reset and Restore" msgstr "" msgid "Reset branch?" 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 "Restore Worktree" msgstr "" msgid "Restore Worktree and Reset All (Hard)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Changes)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Edits)" msgstr "" msgid "Restore Worktree and Reset All (Merge)" msgstr "" msgid "Restore Worktree and Reset All?" msgstr "" #, python-format msgid "Restore Worktree to %s?" msgstr "" msgid "Restore worktree, reset, and preserve unstaged edits?" 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 a parent directory for the new clone" 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 "Горячие клавиши" 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 / Unstage All" msgstr "" msgid "Stage All Untracked" msgstr "Добавить к коммиту все неотслеживемые файлы" msgid "Stage Changed Files To Commit" msgstr "Добавить к коммиту измененные файлы" msgid "Stage Diff Hunk" msgstr "Добавить эту часть к коммиту" msgid "Stage Modified" msgstr "Добавить к коммиту измененые файлы" msgid "Stage Modified and Untracked" 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 "Submodule URL (can be relative, ex: ../repo.git)" msgstr "" msgid "Submodule branch to track (optional)" msgstr "" msgid "Submodule path within the current repository (optional)" 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 --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 "Следующие файлы будут удалены:" #, python-format msgid "The repository will be reset using \"git reset --hard %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --keep %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --merge %s\"" msgstr "" msgid "The revision expression cannot be empty." msgstr "Поле версии не может быть пустым." #, python-format msgid "" "The submodule will be added using\n" "\"%s\"" msgstr "" #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be restored using \"git read-tree --reset -u %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 "" msgid "Toggle image diff" 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 "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 "Undo Last Commit" msgstr "" msgid "Undo last commit?" msgstr "" msgid "Undo the published commit?" 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 "git://git.example.com/repo.git" msgstr "" msgid "grep result..." msgstr "результаты поиска..." msgid "hotkeys.html" msgstr "" msgid "path/to/submodule" msgstr "" msgid "title" 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 "Удалить только в случае, если было объединение с" #, fuzzy #~ msgid "Delete selected branch?" #~ 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 "Перечитать" #, fuzzy #~ msgid "Reset Branch Head" #~ msgstr "Сбросить (reset) ветвь" #, fuzzy #~ msgid "Reset Hard" #~ msgstr "Сбросить (reset) ветвь" #, fuzzy #~ msgid "Reset Merge" #~ msgstr "Версия для объединения" #, fuzzy #~ msgid "Reset Soft" #~ 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" #~ "Продолжить?" #, fuzzy #~ msgid "Reset hard?" #~ msgstr "Сбросить (reset) ветвь?" #, fuzzy #~ msgid "Reset merge?" #~ msgstr "Сбросить (reset) ветвь?" #, fuzzy #~ msgid "Reset soft?" #~ msgstr "Сбросить '%s'?" #~ msgid "Revert changes in these %i files?" #~ msgstr "Отменить изменения в %i файле(-ах)?" #~ msgid "Select File" #~ msgstr "Выбрать файл" #~ msgid "Select Repository..." #~ msgstr "Выбрать репозиторий..." #~ msgid "Select file from \"%s\"" #~ msgstr "Выбрать файл из \"%s\"" #~ msgid "Select manually..." #~ msgstr "Выбрать вручную..." #~ msgid "Shared (Fastest, Not Recommended, No Backup)" #~ msgstr "Общий (Самый быстрый, не рекомендуется, без резервной копии)" #~ msgid "Shared only available for local repository." #~ msgstr "Общий клон возможен только для локального репозитория." #, fuzzy #~ msgid "Show Details..." #~ 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 'main' branch has not been initialized." #~ msgstr "Не инициализирована ветвь 'main'." #~ 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.12.0/po/sv.po000066400000000000000000002222701417222504200147060ustar00rootroot00000000000000# 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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: \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 "" #, python-format msgid "%s could not be opened. Remove from bookmarks?" 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 Submodule" msgstr "" msgid "Add Submodule..." msgstr "" msgid "New 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 this submodule?" msgstr "" msgid "Add to .gitignore" msgstr "" msgid "Add to Git Annex" msgstr "" msgid "Add to Git LFS" msgstr "" msgid "Add to exclusions" msgstr "" msgid "Add to local .git/info/exclude" 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 "Autocomplete Paths" msgstr "" msgid "Automatically Load Commit Message Template" 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" msgid "Branch name" msgstr "" #, 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 Published Commits when Amending" msgstr "" msgid "Check Spelling" msgstr "" msgid "Check spelling" msgstr "" msgid "Check whether a commit has been published when amending" 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 open %s." msgstr "" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "" msgid "Create" 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 a new repository at that location?" msgstr "" msgid "Create a shallow clone with history truncated to the specified number of revisions. 0 performs a full clone." msgstr "" 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" #, python-format msgid "Delete branch \"%s\"?" msgstr "" #, 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 Toolbar" msgstr "Ta bort gren" msgid "Delete..." msgstr "Ta bort..." #, python-format msgid "Deleting \"%s\" failed" msgstr "" #, fuzzy msgid "Deletions" msgstr "Ta bort" msgid "Depth" msgstr "" #, 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 "Disable" msgstr "" 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 "Enable path autocompletion in tools" 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" msgid "Error Opening Repository" msgstr "" #, python-format msgid "Error creating remote \"%s\"" msgstr "" #, fuzzy msgid "Error creating stash" msgstr "Skapa gren" #, python-format msgid "Error deleting branch \"%s\"" msgstr "" #, 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 "Folder" 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-cola-sequence-editor" 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 "" msgid "Ignore..." 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 "Japanese translation" 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 "List" 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" msgid "Prune Missing Entries" msgstr "" #, 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 "Reference Repository" msgstr "" msgid "Reference URL" msgstr "" msgid "Reference repository to use when cloning (optional)" 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 "Remove stale entries for repositories that no longer exist" msgstr "" 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" msgid "Repository Not Found" msgstr "" #, fuzzy, python-format msgid "Repository: %s" msgstr "Arkiv:" msgid "Reset" msgstr "Återställ" #, python-format msgid "Reset \"%(branch)s\" to \"%(revision)s\"?" msgstr "" msgid "Reset All (Keep Unstaged Changes)" msgstr "" #, fuzzy msgid "Reset Branch" msgstr "Ta bort gren" msgid "Reset Branch (Soft)" msgstr "" msgid "Reset Branch and Stage (Mixed)" msgstr "" #, fuzzy msgid "Reset Branch?" msgstr "Ta bort gren" msgid "Reset Layout" msgstr "" msgid "Reset Worktree and Reset All?" msgstr "" msgid "Reset and Restore" msgstr "" msgid "Reset branch?" 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 "Restore Worktree" msgstr "" msgid "Restore Worktree and Reset All (Hard)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Changes)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Edits)" msgstr "" msgid "Restore Worktree and Reset All (Merge)" msgstr "" msgid "Restore Worktree and Reset All?" msgstr "" #, python-format msgid "Restore Worktree to %s?" msgstr "" msgid "Restore worktree, reset, and preserve unstaged edits?" 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 "" msgid "Select a parent directory for the new clone" msgstr "" #, 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 "" 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 / Unstage All" msgstr "" 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 "" msgid "Stage Modified and Untracked" 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 "Submodule URL (can be relative, ex: ../repo.git)" msgstr "" msgid "Submodule branch to track (optional)" msgstr "" msgid "Submodule path within the current repository (optional)" 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 --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 "" #, python-format msgid "The repository will be reset using \"git reset --hard %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --keep %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --merge %s\"" msgstr "" #, fuzzy msgid "The revision expression cannot be empty." msgstr "Revisionsuttrycket är tomt." #, python-format msgid "" "The submodule will be added using\n" "\"%s\"" msgstr "" #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be restored using \"git read-tree --reset -u %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 image diff" 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 "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" msgid "Undo Last Commit" msgstr "" msgid "Undo last commit?" msgstr "" msgid "Undo the published commit?" msgstr "" #, 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 "git://git.example.com/repo.git" msgstr "" msgid "grep result..." msgstr "" msgid "hotkeys.html" msgstr "" msgid "path/to/submodule" msgstr "" msgid "title" 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" #, fuzzy #~ msgid "Delete selected branch?" #~ msgstr "Ta bort fjärrgren" #~ 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" #, fuzzy #~ msgid "Reset Branch Head" #~ 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 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?" #, 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 "Revert changes in these %i files?" #~ msgstr "Återställ ändringarna i dessa %i filer?" #, fuzzy #~ msgid "Select File" #~ msgstr "Markera alla" #, fuzzy #~ msgid "Select Repository..." #~ msgstr "Gitarkiv" #, fuzzy #~ msgid "Select file from \"%s\"" #~ msgstr "Tar bort grenar från %s" #, fuzzy #~ msgid "Select manually..." #~ msgstr "Markera alla" #~ 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." #, fuzzy #~ msgid "Show Details..." #~ msgstr "Ta bort..." #~ 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 'main' branch has not been initialized." #~ msgstr "Grenen \"main\" 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.12.0/po/tr_TR.po000066400000000000000000001273501417222504200153130ustar00rootroot00000000000000# 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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: tr_TR\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 could not be opened. Remove from bookmarks?" 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 Submodule" msgstr "" msgid "Add Submodule..." msgstr "" msgid "New 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 this submodule?" msgstr "" msgid "Add to .gitignore" msgstr "" msgid "Add to Git Annex" msgstr "" msgid "Add to Git LFS" msgstr "" msgid "Add to exclusions" msgstr "" msgid "Add to local .git/info/exclude" 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 "Autocomplete Paths" msgstr "" msgid "Automatically Load Commit Message Template" 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ı" msgid "Branch name" msgstr "" #, 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 Published Commits when Amending" msgstr "" msgid "Check Spelling" msgstr "" msgid "Check spelling" msgstr "" msgid "Check whether a commit has been published when amending" 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 open %s." msgstr "" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "" msgid "Create" 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 a new repository at that location?" msgstr "" msgid "Create a shallow clone with history truncated to the specified number of revisions. 0 performs a full clone." 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..." #, python-format msgid "Delete branch \"%s\"?" msgstr "" msgid "Delete remote" msgstr "" #, python-format msgid "Delete remote \"%s\"" msgstr "Uzaktakini sil \"%s\"" msgid "Delete remote?" msgstr "Uzaktakini sil?" 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 "Depth" 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 "Disable" 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 "Enable path autocompletion in tools" 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 "" msgid "Error Opening Repository" msgstr "" #, python-format msgid "Error creating remote \"%s\"" msgstr "Uzak \"%s\" oluşturulurken hata" msgid "Error creating stash" msgstr "" #, python-format msgid "Error deleting branch \"%s\"" 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 "Folder" msgstr "" 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-cola-sequence-editor" 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 "Ignore..." 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 "Japanese translation" 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 "List" msgstr "" 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 "Prune Missing Entries" 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 "Reference Repository" msgstr "" msgid "Reference URL" msgstr "" msgid "Reference repository to use when cloning (optional)" 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 "Remove stale entries for repositories that no longer exist" 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 "" msgid "Repository Not Found" 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 All (Keep Unstaged Changes)" msgstr "" msgid "Reset Branch" msgstr "Dalı Sıfırla" msgid "Reset Branch (Soft)" msgstr "" msgid "Reset Branch and Stage (Mixed)" msgstr "" msgid "Reset Branch?" msgstr "Dalı Sıfırla?" msgid "Reset Layout" msgstr "" msgid "Reset Worktree and Reset All?" msgstr "" msgid "Reset and Restore" msgstr "" msgid "Reset branch?" msgstr "" #, python-format msgid "Resetting \"%(branch)s\" to \"%(revision)s\" will lose commits." msgstr "" msgid "Restart the application after changing appearance settings." msgstr "" msgid "Restore Worktree" msgstr "" msgid "Restore Worktree and Reset All (Hard)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Changes)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Edits)" msgstr "" msgid "Restore Worktree and Reset All (Merge)" msgstr "" msgid "Restore Worktree and Reset All?" msgstr "" #, python-format msgid "Restore Worktree to %s?" msgstr "" msgid "Restore worktree, reset, and preserve unstaged edits?" 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 a parent directory for the new clone" 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 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 / Unstage All" msgstr "" msgid "Stage All Untracked" msgstr "" msgid "Stage Changed Files To Commit" msgstr "" msgid "Stage Diff Hunk" msgstr "" msgid "Stage Modified" msgstr "" msgid "Stage Modified and Untracked" 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 "Submodule URL (can be relative, ex: ../repo.git)" msgstr "" msgid "Submodule branch to track (optional)" msgstr "" msgid "Submodule path within the current repository (optional)" 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 --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:" #, python-format msgid "The repository will be reset using \"git reset --hard %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --keep %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --merge %s\"" msgstr "" msgid "The revision expression cannot be empty." msgstr "" #, python-format msgid "" "The submodule will be added using\n" "\"%s\"" msgstr "" #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be restored using \"git read-tree --reset -u %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 image diff" 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 "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 "Undo Last Commit" msgstr "" msgid "Undo last commit?" msgstr "" msgid "Undo the published commit?" 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 "git://git.example.com/repo.git" msgstr "" msgid "grep result..." msgstr "grep sonucu..." msgid "hotkeys.html" msgstr "hotkeys.html" msgid "path/to/submodule" msgstr "" msgid "title" msgstr "" 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 Repository..." #~ msgstr "Depoyu Seç..." #~ msgid "Select file from \"%s\"" #~ msgstr "Select file from \"%s\"" #~ msgid "Show Details..." #~ msgstr "Ayrıntıları Göster..." #~ 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.12.0/po/uk.po000066400000000000000000002221161417222504200146740ustar00rootroot00000000000000# 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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: uk_UA\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 could not be opened. Remove from bookmarks?" 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 "" 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 Submodule" msgstr "" msgid "Add Submodule..." msgstr "" msgid "New 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 this submodule?" msgstr "" msgid "Add to .gitignore" msgstr "Додати до .gitignore" #, fuzzy msgid "Add to Git Annex" msgstr "Додати до .gitignore" msgid "Add to Git LFS" msgstr "" msgid "Add to exclusions" msgstr "" msgid "Add to local .git/info/exclude" 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 "Autocomplete Paths" msgstr "" msgid "Automatically Load Commit Message Template" 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 "Назва гілки" 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 Published Commits when Amending" msgstr "" msgid "Check Spelling" msgstr "Перевірити правопис" msgid "Check spelling" msgstr "Перевірити правопис" msgid "Check whether a commit has been published when amending" 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 open %s." msgstr "" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "Не вдалось розпізнати Git URL: \"%s\"" msgid "Create" 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 a new repository at that location?" msgstr "" msgid "Create a shallow clone with history truncated to the specified number of revisions. 0 performs a full clone." 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 "Видалити віддалену гілку..." #, python-format msgid "Delete branch \"%s\"?" msgstr "" msgid "Delete remote" msgstr "Видалити віддалений репозиторій" #, python-format msgid "Delete remote \"%s\"" msgstr "Видалити віддалений репозиторій \"%s\"" msgid "Delete remote?" msgstr "Видалити віддалений репозиторій?" #, fuzzy msgid "Delete Toolbar" msgstr "Видалити закладку" msgid "Delete..." msgstr "Видалити..." #, python-format msgid "Deleting \"%s\" failed" msgstr "Не вдалось видалити \"%s\"" msgid "Deletions" msgstr "Видалено" msgid "Depth" 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 "Disable" 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 "Enable path autocompletion in tools" 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 "Помилка запуску браузера історії" msgid "Error Opening Repository" msgstr "" #, python-format msgid "Error creating remote \"%s\"" msgstr "Не вдалось створити віддалений репозиторій \"%s\"" #, fuzzy msgid "Error creating stash" msgstr "Помилка при створенні гілки" #, python-format msgid "Error deleting branch \"%s\"" 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 "Folder" 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-cola-sequence-editor" 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 "Ignore..." 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 "Japanese translation" 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 "List" 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 "Prune Missing Entries" 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 "Reference Repository" msgstr "" msgid "Reference URL" msgstr "" msgid "Reference repository to use when cloning (optional)" 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 "Remove stale entries for repositories that no longer exist" 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 "Редагувати вибрані шляхи" msgid "Repository Not Found" 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 All (Keep Unstaged Changes)" msgstr "" msgid "Reset Branch" msgstr "Скинути гілку" msgid "Reset Branch (Soft)" msgstr "" msgid "Reset Branch and Stage (Mixed)" msgstr "" msgid "Reset Branch?" msgstr "Скинути гілку?" msgid "Reset Layout" msgstr "" msgid "Reset Worktree and Reset All?" msgstr "" msgid "Reset and Restore" msgstr "" msgid "Reset branch?" 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 "Restore Worktree" msgstr "" msgid "Restore Worktree and Reset All (Hard)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Changes)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Edits)" msgstr "" msgid "Restore Worktree and Reset All (Merge)" msgstr "" msgid "Restore Worktree and Reset All?" msgstr "" #, python-format msgid "Restore Worktree to %s?" msgstr "" msgid "Restore worktree, reset, and preserve unstaged edits?" 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 a parent directory for the new clone" 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 "Поєднання клавіш" 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 / Unstage All" msgstr "" msgid "Stage All Untracked" msgstr "Проіндексувати всі непроіндексовані файли" msgid "Stage Changed Files To Commit" msgstr "Додати змінені файли до коміту" msgid "Stage Diff Hunk" msgstr "Додати частину різниці до проіндексованого" msgid "Stage Modified" msgstr "Проіндексувати зміни" msgid "Stage Modified and Untracked" 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 "Submodule URL (can be relative, ex: ../repo.git)" msgstr "" msgid "Submodule branch to track (optional)" msgstr "" msgid "Submodule path within the current repository (optional)" 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 --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 "Наступні файли будуть видалені:" #, python-format msgid "The repository will be reset using \"git reset --hard %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --keep %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --merge %s\"" msgstr "" msgid "The revision expression cannot be empty." msgstr "Поле ревізії не може бути порожнім." #, python-format msgid "" "The submodule will be added using\n" "\"%s\"" msgstr "" #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be restored using \"git read-tree --reset -u %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" " Перемістити (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 image diff" 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 "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 "Undo Last Commit" msgstr "" msgid "Undo last commit?" msgstr "" msgid "Undo the published commit?" 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 "git://git.example.com/repo.git" msgstr "" msgid "grep result..." msgstr "шукати в результатах..." msgid "hotkeys.html" msgstr "" msgid "path/to/submodule" msgstr "" msgid "title" 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 "Delete selected branch?" #~ msgstr "Видалити виділену гілку?" #~ 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 "Reset Branch Head" #~ msgstr "Скинути HEAD гілки" #, 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 "Скинути робоче дерево?" #~ msgid "Select File" #~ msgstr "Вибрати файл" #~ msgid "Select Repository..." #~ msgstr "Вибрати репозиторій..." #~ msgid "Select file from \"%s\"" #~ msgstr "Вибрати файл з \"%s\"" #~ msgid "Select manually..." #~ msgstr "Вибрати вручну..." #, fuzzy #~ msgid "Show Details..." #~ msgstr "Видалити файли..." #~ msgid "Summary:" #~ msgstr "Підсумок:" #, fuzzy #~ msgid "The branch will be reset using \"git reset --hard %s\"" #~ msgstr "Глку буде скинуто, використовуючи \"git reset --mixed %s\"" #, fuzzy #~ msgid "The branch will be reset using \"git reset --merge %s\"" #~ msgstr "Глку буде скинуто, використовуючи \"git reset --mixed %s\"" #, fuzzy #~ msgid "The worktree will be reset using \"git reset --keep %s\"" #~ msgstr "Робче дерево буде скинуто, використовуючи \"git reset --merge %s\"" #~ 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.12.0/po/zh_CN.po000066400000000000000000002352431417222504200152630ustar00rootroot00000000000000# 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" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: zh_CN\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 could not be opened. Remove from bookmarks?" 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 Submodule" msgstr "" msgid "Add Submodule..." msgstr "" msgid "New 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 this submodule?" msgstr "" msgid "Add to .gitignore" msgstr "添加至 .gitignore" msgid "Add to Git Annex" msgstr "添加至 Git Annex" msgid "Add to Git LFS" msgstr "添加至 Git LFS" msgid "Add to exclusions" msgstr "" msgid "Add to local .git/info/exclude" 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 "" "操作正在进行中.\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 "Autocomplete Paths" msgstr "" msgid "Automatically Load Commit Message Template" 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 "分支名" 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 Published Commits when Amending" msgstr "" msgid "Check Spelling" msgstr "检查拼写" msgid "Check spelling" msgstr "检查拼写" msgid "Check whether a commit has been published when amending" 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 open %s." msgstr "" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "无法解析 URL \"%s\"" msgid "Create" msgstr "" 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 a new repository at that location?" msgstr "" msgid "Create a shallow clone with history truncated to the specified number of revisions. 0 performs a full clone." 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 "删除远程分支..." #, python-format msgid "Delete branch \"%s\"?" msgstr "" msgid "Delete remote" msgstr "删除远程" #, python-format msgid "Delete remote \"%s\"" msgstr "删除远程 \"%s\"" msgid "Delete remote?" msgstr "删除远程吗?" msgid "Delete Toolbar" msgstr "删除工具栏" msgid "Delete..." msgstr "删除..." #, python-format msgid "Deleting \"%s\" failed" msgstr "删除 \"%s\" 失败" msgid "Deletions" msgstr "删除内容" msgid "Depth" 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 "Disable" 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 "Enable path autocompletion in tools" 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 "启动历史浏览器出错" msgid "Error Opening Repository" msgstr "" #, python-format msgid "Error creating remote \"%s\"" msgstr "创建远程 \"%s\" 出错" msgid "Error creating stash" msgstr "创建暂存出错" #, python-format msgid "Error deleting branch \"%s\"" 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 "Folder" 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-cola-sequence-editor" msgstr "帮助 - git-cola-sequence-editor" 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 "Ignore..." 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 "Japanese translation" 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 "List" 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 "Prune Missing Entries" 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 "衍合到 %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 "Reference Repository" msgstr "" msgid "Reference URL" msgstr "" msgid "Reference repository to use when cloning (optional)" 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 "Remove stale entries for repositories that no longer exist" 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 "重命名所选路径" msgid "Repository Not Found" 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 All (Keep Unstaged Changes)" msgstr "" msgid "Reset Branch" msgstr "重置分支" msgid "Reset Branch (Soft)" msgstr "" msgid "Reset Branch and Stage (Mixed)" msgstr "" msgid "Reset Branch?" msgstr "重置分支吗?" msgid "Reset Layout" msgstr "" msgid "Reset Worktree and Reset All?" msgstr "" msgid "Reset and Restore" msgstr "" msgid "Reset branch?" 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 "Restore Worktree" msgstr "" msgid "Restore Worktree and Reset All (Hard)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Changes)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Edits)" msgstr "" msgid "Restore Worktree and Reset All (Merge)" msgstr "" msgid "Restore Worktree and Reset All?" msgstr "" #, python-format msgid "Restore Worktree to %s?" msgstr "" msgid "Restore worktree, reset, and preserve unstaged edits?" 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 a parent directory for the new clone" 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 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 / Unstage All" msgstr "" msgid "Stage All Untracked" msgstr "缓存所有未跟踪项目" msgid "Stage Changed Files To Commit" msgstr "缓存修改的文件为提交" msgid "Stage Diff Hunk" msgstr "缓存差异区域" msgid "Stage Modified" msgstr "缓存已修改的文件" msgid "Stage Modified and Untracked" 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 "Submodule URL (can be relative, ex: ../repo.git)" msgstr "" msgid "Submodule branch to track (optional)" msgstr "" msgid "Submodule path within the current repository (optional)" 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 --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 "如下文件会被删除:" #, python-format msgid "The repository will be reset using \"git reset --hard %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --keep %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --merge %s\"" msgstr "" msgid "The revision expression cannot be empty." msgstr "版本表达式不能为空." #, python-format msgid "" "The submodule will be added using\n" "\"%s\"" msgstr "" #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be restored using \"git read-tree --reset -u %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 image diff" 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 "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 "Undo Last Commit" msgstr "" msgid "Undo last commit?" msgstr "" msgid "Undo the published commit?" 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 "git://git.example.com/repo.git" msgstr "" msgid "grep result..." msgstr "筛选结果..." msgid "hotkeys.html" msgstr "hotkeys_zh_CN.html" msgid "path/to/submodule" msgstr "" msgid "title" msgstr "" 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 "Delete selected branch?" #~ 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 "Hide Details.." #~ 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 Branch Head" #~ msgstr "复位分支头" #, fuzzy #~ msgid "Reset Hard" #~ msgstr "复位分支头" #, fuzzy #~ msgid "Reset Merge" #~ msgstr "要合并的版本" #, fuzzy #~ msgid "Reset Soft" #~ msgstr "重置工作树" #~ msgid "Reset Worktree" #~ 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" #~ "是否要继续复位当前的改动?" #, fuzzy #~ msgid "Reset hard?" #~ msgstr "重置分支吗?" #, fuzzy #~ msgid "Reset merge?" #~ msgstr "要重置工作树吗?" #, fuzzy #~ msgid "Reset soft?" #~ msgstr "复位 '%s'?" #~ msgid "Reset worktree?" #~ msgstr "要重置工作树吗?" #~ msgid "Revert Uncommitted Changes..." #~ msgstr "撤销未提交修改..." #~ msgid "Revert changes in these %i files?" #~ msgstr "撤销这些 (%i个) 文件的改动?" #~ msgid "Select File" #~ msgstr "选择文件" #~ msgid "Select Repository..." #~ msgstr "选择版本库..." #~ msgid "Select file from \"%s\"" #~ msgstr "从“%s”中选择文件" #~ msgid "Select manually..." #~ msgstr "手动选择..." #~ msgid "Shared (Fastest, Not Recommended, No Backup)" #~ msgstr "共享方式 (最快, 不推荐, 不做备份)" #~ msgid "Shared only available for local repository." #~ msgstr "共享方式仅当是本地版本库时有效." #~ msgid "Show Details..." #~ 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 'main' branch has not been initialized." #~ msgstr "'main'分支尚未初始化." #~ 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.12.0/po/zh_TW.po000066400000000000000000002613111417222504200153100ustar00rootroot00000000000000# 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" "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" 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 could not be opened. Remove from bookmarks?" 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 "中止分支合併(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 Submodule" msgstr "" msgid "Add Submodule..." msgstr "" msgid "New 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 this submodule?" 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 "Add to exclusions" msgstr "" msgid "Add to local .git/info/exclude" 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 "" "一個操作仍在進行。\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 "Autocomplete Paths" msgstr "" msgid "Automatically Load Commit Message Template" 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 "分支名稱" 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 Published Commits when Amending" msgstr "" msgid "Check Spelling" msgstr "檢查拼字問題" msgid "Check spelling" msgstr "檢查拼字問題" msgid "Check whether a commit has been published when amending" 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 open %s." msgstr "" #, python-format msgid "Could not parse Git URL: \"%s\"" msgstr "無法分析 Git URL:「%s」" msgid "Create" msgstr "" 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 a new repository at that location?" msgstr "" msgid "Create a shallow clone with history truncated to the specified number of revisions. 0 performs a full clone." 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 "移除遠端分支……" #, python-format msgid "Delete branch \"%s\"?" msgstr "" msgid "Delete remote" msgstr "移除遠端版控庫" #, python-format msgid "Delete remote \"%s\"" msgstr "移除「%s」遠端版控庫" msgid "Delete remote?" msgstr "要移除遠端版控庫嗎?" msgid "Delete Toolbar" msgstr "刪除工具列" msgid "Delete..." msgstr "移除..." #, python-format msgid "Deleting \"%s\" failed" msgstr "「%s」移除失敗" msgid "Deletions" msgstr "移除行數" msgid "Depth" 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 "Disable" 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 "Enable path autocompletion in tools" 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 "無法啟動變動紀錄瀏覽器" msgid "Error Opening Repository" msgstr "" #, python-format msgid "Error creating remote \"%s\"" msgstr "建立「%s」遠端分支時發生錯誤" msgid "Error creating stash" msgstr "建立新的珍藏項目時發生錯誤" #, python-format msgid "Error deleting branch \"%s\"" 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 "Folder" 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-cola-sequence-editor" msgstr "尋求幫助 - git-cola-sequence-editor" 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 "Ignore..." 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 "Japanese translation" 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 "List" 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 "Prune Missing Entries" msgstr "" 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 "Reference Repository" msgstr "" msgid "Reference URL" msgstr "" msgid "Reference repository to use when cloning (optional)" 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 "Remove stale entries for repositories that no longer exist" 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 "重新命名選取的路徑" msgid "Repository Not Found" 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 All (Keep Unstaged Changes)" msgstr "" msgid "Reset Branch" msgstr "重設分支" msgid "Reset Branch (Soft)" msgstr "" msgid "Reset Branch and Stage (Mixed)" msgstr "" msgid "Reset Branch?" msgstr "要重設分支嗎?" msgid "Reset Layout" msgstr "" msgid "Reset Worktree and Reset All?" msgstr "" msgid "Reset and Restore" msgstr "" msgid "Reset branch?" 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 "Restore Worktree" msgstr "" msgid "Restore Worktree and Reset All (Hard)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Changes)" msgstr "" msgid "Restore Worktree and Reset All (Keep Unstaged Edits)" msgstr "" msgid "Restore Worktree and Reset All (Merge)" msgstr "" msgid "Restore Worktree and Reset All?" msgstr "" #, python-format msgid "Restore Worktree to %s?" msgstr "" msgid "Restore worktree, reset, and preserve unstaged edits?" 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 a parent directory for the new clone" msgstr "選取新克隆的 Git 版控庫要放置的目錄" 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 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 / Unstage All" msgstr "" msgid "Stage All Untracked" msgstr "將所有尚未追蹤其版本的項目移動到新修訂版準備區域" msgid "Stage Changed Files To Commit" msgstr "將所有被修改的檔案移入新修訂版準備區域" msgid "Stage Diff Hunk" msgstr "將此內容差異區塊移入新修訂版準備區域" msgid "Stage Modified" msgstr "將已變更的項目移入新修訂版準備區域" msgid "Stage Modified and Untracked" 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 "Submodule URL (can be relative, ex: ../repo.git)" msgstr "" msgid "Submodule branch to track (optional)" msgstr "" msgid "Submodule path within the current repository (optional)" 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 --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 "下列檔案將會被移除:" #, python-format msgid "The repository will be reset using \"git reset --hard %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --keep %s\"" msgstr "" #, python-format msgid "The repository will be reset using \"git reset --merge %s\"" msgstr "" msgid "The revision expression cannot be empty." msgstr "修訂版表達式不可以是空的。" #, python-format msgid "" "The submodule will be added using\n" "\"%s\"" msgstr "" #, python-format msgid "" "The submodule will be updated using\n" "\"%s\"" msgstr "" #, python-format msgid "The worktree will be restored using \"git read-tree --reset -u %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" "您可能不想要做此操作。" 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 image diff" 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 "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 "Undo Last Commit" msgstr "" msgid "Undo last commit?" msgstr "" msgid "Undo the published commit?" 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 "git://git.example.com/repo.git" msgstr "" msgid "grep result..." msgstr "搜尋結果……" msgid "hotkeys.html" msgstr "hotkeys_zh_TW.html" msgid "path/to/submodule" msgstr "" msgid "title" msgstr "" 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 "Delete selected branch?" #~ 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 "Hide Details.." #~ 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 Branch Head" #~ msgstr "重設分支 Head" #~ msgid "Reset Hard" #~ msgstr "硬式重設" #~ msgid "Reset Merge" #~ msgstr "合併式重設" #~ msgid "Reset Soft" #~ msgstr "軟式重設" #~ msgid "Reset Worktree" #~ 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 "Reset hard?" #~ msgstr "要進行硬式重設嗎?" #~ msgid "Reset merge?" #~ msgstr "要進行合併式重設嗎?" #~ msgid "Reset soft?" #~ msgstr "要進行軟式重設嗎?" #~ msgid "Reset worktree?" #~ msgstr "要重設工作目錄樹嗎?" #~ msgid "Revert Uncommitted Changes..." #~ msgstr "撤銷尚未建立修訂版提交的內容變動" #~ msgid "Revert changes in these %i files?" #~ msgstr "撤銷這些 (%i個) 文件的改動?" #~ msgid "Select File" #~ msgstr "選取檔案" #~ msgid "Select Repository..." #~ msgstr "選擇版控庫……" #~ msgid "Select file from \"%s\"" #~ msgstr "於「%s」中選取檔案" #~ msgid "Select manually..." #~ msgstr "手動選取……" #~ msgid "Shared (Fastest, Not Recommended, No Backup)" #~ msgstr "共享方式 (最快, 不推薦, 不做備份)" #~ msgid "Shared only available for local repository." #~ msgstr "共享方式僅當是本地版本庫時有效." #~ msgid "Show Details..." #~ 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 'main' branch has not been initialized." #~ msgstr "'main'分支尚未初始化." #~ msgid "The branch will be reset using \"git reset --hard %s\"" #~ msgstr "這個分支將會被用「git reset --hard %s」命令重設" #~ msgid "The branch will be reset using \"git reset --merge %s\"" #~ msgstr "這個分支將會被用「git reset --merge %s」命令重設" #~ 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 "The worktree will be reset using \"git reset --keep %s\"" #~ msgstr "工作目錄樹將被用「git reset --keep %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.12.0/pynsist.cfg000066400000000000000000000077151417222504200154770ustar00rootroot00000000000000# https://pynsist.readthedocs.io/en/latest/cfgfile.html [Application] name = git-cola version = 3.12.0 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.7.9 bitness = 64 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-cola-sequence-editor] entry_point = cola.sequenceeditor:winmain extra_preamble = contrib/win32/pynsist-preamble.py [Command git-dag] entry_point = cola.dag:winmain extra_preamble = contrib/win32/pynsist-preamble.py # To identify unused DLL files to exclude, we can use Process Explorer. # https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer # Run git-cola and use the Help->Keyboard Shortcut feature and the DAG feature. # Take note of the loaded DLL files under the pythonw.exe process. # This will also include windows and python DLL files. # Sorting the DLL files list under Process Explorer by path will list # the git-cola DLL files first together. # This gives a list of necessary DLLs and the rest can be excluded. [Include] packages = cola qtpy pypi_wheels = PyQt5==5.14.2 PyQt5-sip==12.7.2 pywin32==227 send2trash==1.7.1 files = share/ exclude = pkgs/PyQt5/Qt/bin/Qt5Bluetooth.dll pkgs/PyQt5/Qt/bin/Qt5DBus.dll pkgs/PyQt5/Qt/bin/Qt5Designer.dll pkgs/PyQt5/Qt/bin/Qt5Help.dll pkgs/PyQt5/Qt/bin/Qt5Location.dll pkgs/PyQt5/Qt/bin/Qt5Multimedia.dll pkgs/PyQt5/Qt/bin/Qt5MultimediaWidgets.dll pkgs/PyQt5/Qt/bin/Qt5NetworkAuth.dll pkgs/PyQt5/Qt/bin/Qt5Nfc.dll pkgs/PyQt5/Qt/bin/Qt5Positioning.dll pkgs/PyQt5/Qt/bin/Qt5PositioningQuick.dll pkgs/PyQt5/Qt/bin/Qt5PrintSupport.dll pkgs/PyQt5/Qt/bin/Qt5Qml.dll pkgs/PyQt5/Qt/bin/Qt5QmlModels.dll pkgs/PyQt5/Qt/bin/Qt5QmlWorkerScript.dll pkgs/PyQt5/Qt/bin/Qt5Quick.dll pkgs/PyQt5/Qt/bin/Qt5QuickControls2.dll pkgs/PyQt5/Qt/bin/Qt5QuickParticles.dll pkgs/PyQt5/Qt/bin/Qt5QuickShapes.dll pkgs/PyQt5/Qt/bin/Qt5QuickTemplates.dll pkgs/PyQt5/Qt/bin/Qt5QuickTemplates2.dll pkgs/PyQt5/Qt/bin/Qt5QuickTest.dll pkgs/PyQt5/Qt/bin/Qt5QuickWidgets.dll pkgs/PyQt5/Qt/bin/Qt5RemoteObjects.dll pkgs/PyQt5/Qt/bin/Qt5Sensors.dll pkgs/PyQt5/Qt/bin/Qt5SerialPort.dll pkgs/PyQt5/Qt/bin/Qt5Sql.dll pkgs/PyQt5/Qt/bin/Qt5Test.dll pkgs/PyQt5/Qt/bin/Qt5WebSockets.dll pkgs/PyQt5/Qt/bin/Qt5WinExtras.dll pkgs/PyQt5/Qt/bin/Qt5Xml.dll pkgs/PyQt5/Qt/bin/Qt5XmlPatterns.dll pkgs/PyQt5/Qt/bin/concrt140.dll pkgs/PyQt5/Qt/bin/d3dcompiler_47.dll pkgs/PyQt5/Qt/bin/libeay32.dll pkgs/PyQt5/Qt/bin/msvcp140.dll pkgs/PyQt5/Qt/bin/opengl32sw.dll pkgs/PyQt5/Qt/bin/vcruntime140.dll pkgs/PyQt5/Qt/plugins/audio pkgs/PyQt5/Qt/plugins/generic pkgs/PyQt5/Qt/plugins/geometryloaders pkgs/PyQt5/Qt/plugins/geoservices pkgs/PyQt5/Qt/plugins/mediaservice pkgs/PyQt5/Qt/plugins/platforms/qminimal.dll pkgs/PyQt5/Qt/plugins/platforms/qoffscreen.dll pkgs/PyQt5/Qt/plugins/platforms/qwebgl.dll pkgs/PyQt5/Qt/plugins/platformthemes pkgs/PyQt5/Qt/plugins/playlistformats pkgs/PyQt5/Qt/plugins/position pkgs/PyQt5/Qt/plugins/printsupport pkgs/PyQt5/Qt/plugins/sceneparsers pkgs/PyQt5/Qt/plugins/sensorgestures pkgs/PyQt5/Qt/plugins/sensors pkgs/PyQt5/Qt/plugins/sqldrivers pkgs/PyQt5/Qt/plugins/styles pkgs/PyQt5/Qt/plugins/texttospeech pkgs/PyQt5/Qt/plugins/webview pkgs/PyQt5/QtBluetooth.pyd pkgs/PyQt5/QtDesigner.pyd pkgs/PyQt5/QtQml.pyd pkgs/PyQt5/QtQuick.pyd pkgs/PyQt5/QtQuickWidgets.pyd git-cola-3.12.0/pyproject.toml000066400000000000000000000003031417222504200162030ustar00rootroot00000000000000[build-system] requires = ["setuptools>=42", "wheel", "setuptools_scm[toml]>=3.4.1"] build-backend = "setuptools.build_meta" [tool.black] skip-string-normalization = true [tool.setuptools_scm] git-cola-3.12.0/pytest.ini000066400000000000000000000004271417222504200153270ustar00rootroot00000000000000[pytest] norecursedirs=dist build .tox .eggs env* addopts=--doctest-modules --flake8 doctest_optionflags=ALLOW_UNICODE ELLIPSIS filterwarnings= # https://github.com/pytest-dev/pytest/issues/6928 ignore:direct construction of .*Item has been deprecated:DeprecationWarning git-cola-3.12.0/qtpy/000077500000000000000000000000001417222504200142705ustar00rootroot00000000000000git-cola-3.12.0/qtpy/Qt3DAnimation.py000066400000000000000000000017141417222504200172600ustar00rootroot00000000000000# -*- 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.12.0/qtpy/Qt3DCore.py000066400000000000000000000016701417222504200162320ustar00rootroot00000000000000# -*- 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.12.0/qtpy/Qt3DExtras.py000066400000000000000000000017001417222504200166020ustar00rootroot00000000000000# -*- 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.12.0/qtpy/Qt3DInput.py000066400000000000000000000016741417222504200164450ustar00rootroot00000000000000# -*- 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.12.0/qtpy/Qt3DLogic.py000066400000000000000000000016741417222504200164030ustar00rootroot00000000000000# -*- 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.12.0/qtpy/Qt3DRender.py000066400000000000000000000017001417222504200165530ustar00rootroot00000000000000# -*- 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.12.0/qtpy/QtCharts.py000066400000000000000000000013751417222504200164010ustar00rootroot00000000000000# -*- 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.12.0/qtpy/QtCore.py000066400000000000000000000110161417222504200160360ustar00rootroot00000000000000# -*- 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 pyqtBoundSignal as SignalInstance 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, pyqtBoundSignal, 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 pyqtBoundSignal as SignalInstance 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, pyqtBoundSignal, 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.12.0/qtpy/QtDataVisualization.py000066400000000000000000000014451417222504200206060ustar00rootroot00000000000000# -*- 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.12.0/qtpy/QtDatavisualization.py000066400000000000000000000014451417222504200206460ustar00rootroot00000000000000# -*- 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.12.0/qtpy/QtDesigner.py000066400000000000000000000006171417222504200167130ustar00rootroot00000000000000# -*- 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.12.0/qtpy/QtGui.py000066400000000000000000000207501417222504200156770ustar00rootroot00000000000000# -*- 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 try: from PyQt4.Qt import QKeySequence, QTextCursor except ImportError: # In PyQt4-sip 4.19.13 QKeySequence and QTextCursor are in PyQt4.QtGui from PyQt4.QtGui 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.12.0/qtpy/QtHelp.py000066400000000000000000000007101417222504200160350ustar00rootroot00000000000000# -*- 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.12.0/qtpy/QtLocation.py000066400000000000000000000011071417222504200167160ustar00rootroot00000000000000# -*- 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.12.0/qtpy/QtMultimedia.py000066400000000000000000000005641417222504200172460ustar00rootroot00000000000000import 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.12.0/qtpy/QtMultimediaWidgets.py000066400000000000000000000011421417222504200205660ustar00rootroot00000000000000# -*- 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.12.0/qtpy/QtNetwork.py000066400000000000000000000010601417222504200165750ustar00rootroot00000000000000# -*- 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.12.0/qtpy/QtOpenGL.py000066400000000000000000000013171417222504200162750ustar00rootroot00000000000000# -*- 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.12.0/qtpy/QtPositioning.py000066400000000000000000000011021417222504200174430ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright 2020 Antonio Valentino # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Provides QtPositioning classes and functions.""" # Local imports from . import PYQT5, PYSIDE2, PythonQtError if PYQT5: from PyQt5.QtPositioning import * elif PYSIDE2: from PySide2.QtPositioning import * else: raise PythonQtError('No Qt bindings could be found') git-cola-3.12.0/qtpy/QtPrintSupport.py000066400000000000000000000016151417222504200176430ustar00rootroot00000000000000# -*- 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.12.0/qtpy/QtQml.py000066400000000000000000000010701417222504200156760ustar00rootroot00000000000000# -*- 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.12.0/qtpy/QtQuick.py000066400000000000000000000010761417222504200162270ustar00rootroot00000000000000# -*- 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.12.0/qtpy/QtQuickWidgets.py000066400000000000000000000011231417222504200175470ustar00rootroot00000000000000# -*- 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.12.0/qtpy/QtSerialPort.py000066400000000000000000000010601417222504200172300ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright © 2020 Marcin Stano # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Provides QtSerialPort classes and functions.""" # Local imports from . import PYQT5, PythonQtError if PYQT5: from PyQt5.QtSerialPort import * else: raise PythonQtError('No Qt bindings could be found') git-cola-3.12.0/qtpy/QtSql.py000066400000000000000000000013001417222504200157000ustar00rootroot00000000000000# -*- 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.12.0/qtpy/QtSvg.py000066400000000000000000000013001417222504200157000ustar00rootroot00000000000000# -*- 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.12.0/qtpy/QtTest.py000066400000000000000000000013011417222504200160610ustar00rootroot00000000000000# -*- 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.12.0/qtpy/QtWebChannel.py000066400000000000000000000011151417222504200171530ustar00rootroot00000000000000# -*- 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.12.0/qtpy/QtWebEngineWidgets.py000066400000000000000000000034141417222504200203430ustar00rootroot00000000000000# -*- 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 # Based on the work at https://github.com/spyder-ide/qtpy/pull/203 from PyQt5.QtWebEngineWidgets import QWebEngineProfile 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 # Based on the work at https://github.com/spyder-ide/qtpy/pull/203 from PySide2.QtWebEngineWidgets import QWebEngineProfile 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.12.0/qtpy/QtWebSockets.py000066400000000000000000000011151417222504200172160ustar00rootroot00000000000000# -*- 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.12.0/qtpy/QtWidgets.py000066400000000000000000000144131417222504200165600ustar00rootroot00000000000000# -*- 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 QStyleOptionFrame = QStyleOptionFrameV3 del QStyleOptionFrameV3 # 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.12.0/qtpy/QtWinExtras.py000066400000000000000000000006711417222504200170770ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright © 2009- The Spyder Development Team # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) from . import PYQT5, PYSIDE2, PythonQtError if PYQT5: from PyQt5.QtWinExtras import * elif PYSIDE2: from PySide2.QtWinExtras import * else: raise PythonQtError('No Qt bindings could be found') git-cola-3.12.0/qtpy/QtXmlPatterns.py000066400000000000000000000013051417222504200174270ustar00rootroot00000000000000# -*- 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.12.0/qtpy/__init__.py000066400000000000000000000170001417222504200163770ustar00rootroot00000000000000# -*- 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 independent 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__ from .py3compat import PY2 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 not os.environ.get('FORCE_QT_API'): 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 try: from PyQt4.Qt import PYQT_VERSION_STR as PYQT_VERSION # analysis:ignore from PyQt4.Qt import QT_VERSION_STR as QT_VERSION # analysis:ignore except ImportError: # In PyQt4-sip 4.19.13 PYQT_VERSION_STR and QT_VERSION_STR are in PyQt4.QtCore from PyQt4.QtCore import PYQT_VERSION_STR as PYQT_VERSION # analysis:ignore from PyQt4.QtCore 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 try: # QtDataVisualization backward compatibility (QtDataVisualization vs. QtDatavisualization) # Only available for Qt5 bindings > 5.9 on Windows from . import QtDataVisualization as QtDatavisualization except ImportError: passgit-cola-3.12.0/qtpy/_patch/000077500000000000000000000000001417222504200155265ustar00rootroot00000000000000git-cola-3.12.0/qtpy/_patch/__init__.py000066400000000000000000000000001417222504200176250ustar00rootroot00000000000000git-cola-3.12.0/qtpy/_patch/qcombobox.py000066400000000000000000000100461417222504200200720ustar00rootroot00000000000000# 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.12.0/qtpy/_patch/qheaderview.py000066400000000000000000000064201417222504200204060ustar00rootroot00000000000000# -*- 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.12.0/qtpy/_version.py000066400000000000000000000001111417222504200164570ustar00rootroot00000000000000version_info = (1, 11, 2) __version__ = '.'.join(map(str, version_info)) git-cola-3.12.0/qtpy/compat.py000066400000000000000000000170371417222504200161350ustar00rootroot00000000000000# -*- 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 from . import PYQT4 from .QtWidgets import QFileDialog from .py3compat import Callable, 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.12.0/qtpy/py3compat.py000066400000000000000000000145541417222504200165720ustar00rootroot00000000000000# -*- 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 from collections import Callable, MutableMapping 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 Callable, MutableMapping else: from collections import Callable, 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.12.0/qtpy/uic.py000066400000000000000000000254061417222504200154310ustar00rootroot00000000000000import 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', 'loadUiType'] # 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 try: from pysideuic import compileUi except ImportError: pass elif PYSIDE2: from PySide2.QtCore import QMetaObject from PySide2.QtUiTools import QUiLoader try: from pyside2uic import compileUi except ImportError: pass 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 list(custom_widgets): 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 def loadUiType(uifile, from_imports=False): """Load a .ui file and return the generated form class and the Qt base class. The "loadUiType" command convert the ui file to py code in-memory first and then execute it in a special frame to retrieve the form_class. Credit: https://stackoverflow.com/a/14195313/15954282 """ import sys if sys.version_info >= (3, 0): from io import StringIO else: from io import BytesIO as StringIO from xml.etree.ElementTree import ElementTree from . import QtWidgets # Parse the UI file etree = ElementTree() ui = etree.parse(uifile) widget_class = ui.find('widget').get('class') form_class = ui.find('class').text with open(uifile, 'r') as fd: code_stream = StringIO() frame = {} compileUi(fd, code_stream, indent=0, from_imports=from_imports) pyc = compile(code_stream.getvalue(), '', 'exec') exec(pyc, frame) # Fetch the base_class and form class based on their type in the # xml from designer form_class = frame['Ui_%s' % form_class] base_class = getattr(QtWidgets, widget_class) return form_class, base_class git-cola-3.12.0/requirements/000077500000000000000000000000001417222504200160165ustar00rootroot00000000000000git-cola-3.12.0/requirements/requirements-dev.txt000066400000000000000000000011441417222504200220560ustar00rootroot00000000000000# Development packages are used to run the test suite and build documentation ## pylint, flake8 checkers are used by "make check". astroid==1.6.5; python_version == '2.7' enum34==1.1.6; python_version < '3.4' flake8 mock pbr pylint==1.9.4; python_version == '2.7' pylint==2.7.0; python_version >= '3.6' PyYAML ## mock and pytest packages are used by the "make test" test suite. pytest>=3.6 pytest-cov pytest-flake8 pytest-black-multipy ## Build and install documentation using "make doc" and "make install-doc". Sphinx sphinx-rtd-theme==0.4.3; python_version < '3.0' sphinx-rtd-theme; python_version >= '3.0' git-cola-3.12.0/requirements/requirements-maint.txt000066400000000000000000000001571417222504200224130ustar00rootroot00000000000000# Maintainer packages ## Upload packages to pypi twine; python_version >= '3.0' ## Windows installer pynsist git-cola-3.12.0/requirements/requirements-optional.txt000066400000000000000000000002501417222504200231220ustar00rootroot00000000000000# Optional packages enable additional functionality. # These packages are not required in order to build or run Git Cola. ## Enable "Send to Trash". send2trash==1.7.1 git-cola-3.12.0/requirements/requirements.txt000066400000000000000000000012131417222504200212770ustar00rootroot00000000000000# These packages are required to run git-cola. # # Additional functionality can be enabled by installing the packages # in "requirements-optional.txt". # qtpy provides a PyQt4/PyQt5/PySide2 abstraction layer. # Git Cola ships with a vendored copy of "qtpy", but can also be made # to use a distro-provided qtpy package. See README.md for more details. qtpy # Git Cola can run with either PyQt5 or PySide2. You only need one of the two. # Install one of the following packages. Git Cola is authored using PyQt5, # but PySide2 (and even PyQt4) is also supported and should work in practice. # PyQt5; python_version>='3.0' # recommended # PySide2 git-cola-3.12.0/setup.cfg000066400000000000000000000013301417222504200151110ustar00rootroot00000000000000[bdist_rpm] release = 1 requires = python build_requires = python 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/ [options] packages = cola cola.models cola.widgets include_package_data = true python_requires = >=2.7 install_requires = importlib_metadata; python_version<"3.8" setup_requires = setuptools_scm[toml] >= 3.4.1 [options.extras_require] testing = # upstream pytest >= 3.5, !=3.7.3 pytest-checkdocs >= 1.2.3 pytest-flake8 pytest-black-multipy pytest-cov # local PyQt5; python_version>='3.0' PySide2; python_version=='2.7' git-cola-3.12.0/setup.py000077500000000000000000000104751417222504200150170ustar00rootroot00000000000000#!/usr/bin/env python # usage: use the Makefile instead of invoking this script directly. # pylint: disable=import-error,no-name-in-module from __future__ import absolute_import, division, print_function, unicode_literals from glob import glob from distutils.command import build_scripts from distutils.core import setup import os import re import sys sys.path.insert(1, os.path.dirname(__file__)) from extras import cmdclass # 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 distutils 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: if sys.version_info[0] < 3: # Python2 accepts the r'' unicode literal. pattern = re.compile(r'^should not match$') else: # Python3 reads files as bytes and requires that the regex pattern is # specified as bytes. pattern = re.compile(b'^should not match$') build_scripts.first_line_re = pattern # Disable installation of the private cola package by passing --no-private-libs or # by setting GIT_COLA_NO_PRIVATE_LIBS=1 in th environment. try: sys.argv.remove('--no-private-libs') private_libs = False except ValueError: private_libs = not os.getenv('GIT_COLA_NO_PRIVATE_LIBS', '') # Disable vendoring of qtpy and friends by passing --no-vendor-libs to setup.py or # by setting GIT_COLA_NO_VENDOR_LIBS=1 in the environment. try: sys.argv.remove('--no-vendor-libs') vendor_libs = False except ValueError: vendor_libs = not os.getenv('GIT_COLA_NO_VENDOR_LIBS', '') # fmt: off here = os.path.dirname(__file__) version = os.path.join(here, 'cola', '_version.py') scope = {} # flake8: noqa exec(open(version).read(), scope) # pylint: disable=exec-used version = scope['VERSION'] # fmt: on def main(): """Runs distutils.setup()""" scripts = [ 'bin/git-cola', 'bin/git-cola-sequence-editor', 'bin/git-dag', ] if sys.platform == 'win32': scripts.append('contrib/win32/cola') packages = [str('cola'), str('cola.models'), str('cola.widgets')] 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, packages=packages, 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/metainfo', '*.xml'), _app_path('share/applications', '*.desktop'), _app_path('share/doc/git-cola', '*.rst'), _app_path('share/doc/git-cola', '*.html'), ] if private_libs: data.extend( [_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.12.0/share/000077500000000000000000000000001417222504200143755ustar00rootroot00000000000000git-cola-3.12.0/share/applications/000077500000000000000000000000001417222504200170635ustar00rootroot00000000000000git-cola-3.12.0/share/applications/git-cola-folder-handler.desktop000066400000000000000000000003311417222504200250360ustar00rootroot00000000000000[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.12.0/share/applications/git-cola.desktop000066400000000000000000000005251417222504200221570ustar00rootroot00000000000000[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.12.0/share/applications/git-dag.desktop000066400000000000000000000003211417222504200217660ustar00rootroot00000000000000[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.12.0/share/doc/000077500000000000000000000000001417222504200151425ustar00rootroot00000000000000git-cola-3.12.0/share/doc/git-cola/000077500000000000000000000000001417222504200166415ustar00rootroot00000000000000git-cola-3.12.0/share/doc/git-cola/.gitignore000066400000000000000000000000161417222504200206260ustar00rootroot00000000000000/_build /html git-cola-3.12.0/share/doc/git-cola/Makefile000066400000000000000000000053761417222504200203140ustar00rootroot00000000000000prefix ?= $(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 = -a 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.12.0/share/doc/git-cola/_static/000077500000000000000000000000001417222504200202675ustar00rootroot00000000000000git-cola-3.12.0/share/doc/git-cola/_static/.gitignore000066400000000000000000000000001417222504200222450ustar00rootroot00000000000000git-cola-3.12.0/share/doc/git-cola/_templates/000077500000000000000000000000001417222504200207765ustar00rootroot00000000000000git-cola-3.12.0/share/doc/git-cola/_templates/.gitignore000066400000000000000000000000011417222504200227550ustar00rootroot00000000000000 git-cola-3.12.0/share/doc/git-cola/conf.py000066400000000000000000000035011417222504200201370ustar00rootroot00000000000000# -*- coding: utf-8 -*- import os import sys try: import sphinx_rtd_theme except ImportError: sphinx_rtd_theme = None # 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', ] if sphinx_rtd_theme: extensions.append('sphinx_rtd_theme') templates_path = ['_templates'] source_suffix = '.rst' source_encoding = 'utf-8' master_doc = 'index' project = 'git-cola' copyright = '2007-2020, 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' if sphinx_rtd_theme: html_theme = 'sphinx_rtd_theme' 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'), ] # Sphinx 4.0 creates sub-directories for each man section. # Disable this feature for consistency across Sphinx versions. man_make_section_directory = False latex_documents = [ ( 'index', 'git-cola.tex', 'git-cola Documentation', 'David Aguilar and contributors', 'manual', ), ] git-cola-3.12.0/share/doc/git-cola/git-cola.rst000066400000000000000000001071301417222504200210740ustar00rootroot00000000000000=========== 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 diff or grep screens 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. Many of `git cola`'s editors understand vim-style hotkeys, eg. `{h,j,k,l}` for navigating in the diff, status, grep, and file browser widgets. `{d,u}` move down/up one half page at a time (similar to vim's `ctrl-{d,u}`). The `space` and `shift-space` hotkeys are mapped to the same operations. `Shift-{j,k,d,u,f,b,page-up,page-down,left,right,up,down}` can be be used in the diff editor to select lines while navigating. `s` is a useful hotkey in the diff editor. It stages/unstages the current selection when a selection is present. When nothing is selected, the diff hunk at the current text cursor position is staged. This makes it very easy to review changes by selecting good hunks with `s` while navigating down and over hunks that are not going to be staged. `Ctrl-u` in the diff editor reverts unstaged edits, and respects the selection. This is useful for selectively reverted edits from the worktree. This same hotkey reverts the entire file when used from the status tool. `Ctrl-s` in the diff editor and status tools stages/unstages the entire file. You can see the available shortcuts by pressing 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 main 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 patches 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. DARK MODE AND WINDOW MANAGER THEMES =================================== Git Cola contains a ``default`` theme which follows the current Qt style and a handful of built-in color themes. See :ref:`cola_theme` for more details. To use icons appropriate for a dark application theme, configure ``git config --global cola.icontheme dark`` to use the dark icon theme. See :ref:`cola_icontheme` for more details. On Linux, you may want Qt to follow the Window manager theme by configuring it to do so using the ``qt5ct`` Qt5 configuration tool. Install ``qt5ct`` on Debian/Ubuntu systems to make this work.:: sudo apt install qt5ct Once installed, update your `~/.bash_profile` to activate ``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 theme-specific colors. On macOS, using the ``default`` theme will automatically inherit "Dark Mode" color themes when configured via System Preferences. You will need to configure the dark icon theme as noted above when dark mode is enabled. 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 and binary file support. This tells `git cola` to honor the configured encoding when displaying and applying diffs. A `.gitattributes` file can set the ``binary`` attribute in order to force specific untracked paths to be treated as binary files when diffing. Binary files are displayed using a hexdump display. .. sourcecode:: sh # Treat *.exr files as binary files. *.exr binary 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: 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.imagediff. -------------------------- Enable image diffs for the specified file extension. For example, configuring `git config --global cola.imagediff.svg false` will disable use of the visual image diff for `.svg` files in all repos until is is explicitly toggled on. Defaults to `true`. 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.resizebrowsercolumns ------------------------- `git cola` will automatically resize the file browser columns as folders are expanded/collapsed when ``cola.resizebrowsercolumns`` is set to `true`. 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.startupmode ---------------- Control how the list of repositories is displayed in the startup dialog. Set to `list` to view the list of repositories as a list, or `folder` to view the list of repositories as a collection of folder icons. Defaults to `list`. 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: 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 to an invalid value, then the default style will be used. The `default` theme is generated by Qt internal engine and should look native but may look noticeably different on different platforms. 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. cola.turbo ---------- Set to `true` to enable "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' core.hooksPath -------------- Hooks are programs you can place in a hooks directory to trigger actions at certain points in git’s execution. Hooks that don’t have the executable bit set are ignored. By default the hooks directory is ``$GIT_DIR/hooks``, but that can be changed via the ``core.hooksPath`` configuration variable The ``cola-prepare-commit-msg`` hook functionality and Cola's Git LFS detection honors this configuration. Please see the `git hooks documentation `_ for more details. 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 :ref:`cola_icontheme` 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). If ```` contains slashes (``/``) then the leading part of the name, up until the final slash, is treated like a path of submenus under which the actions will be created. For example, configuring ``guitool.Commands/Util/echo.cmd`` creates a ``Commands`` menu inside the top-level ``Actions`` menu, a ``Util`` menu inside the ``Commands`` menu and an ``echo`` action inside the ``Commands`` submenu. 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 set up 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 SSH Agents for Key-based Authentication --------------------------------------- You may need to setup ssh-agent in order to use SSH key-based authentication on Windows. It has been reported that starting OpenSSH agent in Windows Services and adding the key using Powershell are necessary in order to get things working. Please see the following links for more details. https://stackoverflow.com/questions/18683092/how-to-run-ssh-add-on-windows FIPS Security Mode ================== `FIPS Security Mode `_ is available in newer versions of Python. These include Python 3.9+ and the patched Python 3.6 used by CentOS8/RHEL8 (and possibly others). Git Cola uses the ``hashlib.md5`` function and adheres to the FIPS security mode when available. Git Cola does not use the MD5 value for security purposes. MD% is used only for the purposes of implementing the ``cola/gravatar.py`` Gravatar client. 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.12.0/share/doc/git-cola/git-dag.rst000066400000000000000000000036131417222504200207120ustar00rootroot00000000000000========== 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 `main -- Makefile` will display only commits on the `main` 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.12.0/share/doc/git-cola/hotkeys.html000066400000000000000000000147141417222504200212240ustar00rootroot00000000000000 Keyboard shortcuts
    Commit
Ctrl + Return : Commit staged changes
Ctrl + Shift + Return : Prepare commit message hook
Ctrl + S : Stage / unstage selected files
Ctrl + Shift + S : Stage / unstage all 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 + Enter : Apply Stash
Ctrl + Backspace : Pop Stash
Ctrl + Shift + Backspace : Drop 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.12.0/share/doc/git-cola/hotkeys_de.html000066400000000000000000000143701417222504200216720ustar00rootroot00000000000000 Tastenkürzel
    Version
Ctrl + Return : Vorgemerkte Änderungen versionieren
Ctrl + Shift + Return : Prepare commit message hook
Ctrl + S : Ausgewählte Dateien vormerken
Ctrl + Shift + S : Stage / unstage all files
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 + Enter : Apply Stash
Ctrl + Backspace : Pop Stash
Ctrl + Shift + Backspace : Drop Stash
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.12.0/share/doc/git-cola/hotkeys_zh_CN.html000066400000000000000000000141551417222504200223040ustar00rootroot00000000000000 键盘快捷键
    提交
Ctrl + Return : 提交已缓存变更
Ctrl + Shift + Return : Prepare commit message hook
Ctrl + S : 缓存所选项目
Ctrl + Shift + S : Stage / unstage all files
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 + Enter : Apply Stash
Ctrl + Backspace : Pop Stash
Ctrl + Shift + Backspace : Drop Stash
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.12.0/share/doc/git-cola/hotkeys_zh_TW.html000066400000000000000000000153131417222504200223330ustar00rootroot00000000000000 鍵盤快捷鍵
    提交版本
Ctrl + Return : 提交版本提交準備區域中的變更
Ctrl + Shift + Return : Prepare commit message hook
Ctrl + S : 將被選取的項目移入版本提交準備區域
Ctrl + Shift + S : Stage / unstage all files
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 + Enter : Apply Stash
Ctrl + Backspace : Pop Stash
Ctrl + Shift + Backspace : Drop Stash
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.12.0/share/doc/git-cola/index.rst000066400000000000000000000004331417222504200205020ustar00rootroot00000000000000====================== 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.12.0/share/doc/git-cola/relnotes.rst000066400000000000000000000004651417222504200212330ustar00rootroot00000000000000======== Releases ======== Latest Release ============== :ref:`v3.12.0 ` 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`` .. include:: ../../../CHANGES.rst git-cola-3.12.0/share/doc/git-cola/thanks.rst000066400000000000000000000103651417222504200206700ustar00rootroot00000000000000Thanks ====== `git-cola` was made possible thanks to the contributions of the following people: * Aaron Cook * Aaron Malpas * Aaron Wolf * Abid Ahmad * 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 * Audrey Yeena Toskin * Audrius Karabanovas * Axel Heider * Balázs Meskó * balping * Barış ÇELİK * Barry Roberts * Boris W * Ben Boeckel * Ben Cole * Benedict Lee * Benjamin Somers * Benoît Nouyrigat * Bernd K * Bert Jacobs * Birger Skogeng Pedersen * Björn Ketelaars * Bob van der Linden * 林博仁 (Buo-ren Lin) * cclaus * Charles 101 * Christian Jann * Christoph Erhardt * Christopher Meng * Clément Pit--Claudel * Constantine Grantcharov * Daniel Fahlke * Daniel Jay Haskin * Daniel Harding * Daniel King * Dave Cottlehuber * Dave Thomas * David Aguilar * David Fernandez * David LeGare * David Martínez Martí * David Roman * Dawid Drozd * Dennis Gilmore * Demodian * deniz1a * Dmitriy Bogdanov * Dmitry Kann * Dmitry Pashkevich * Doug Hoskisson * Drugoy * Efimov Vasily * Eric Drechsel * Erop @EgZvor * Erwan Bousse * Fabio Coatti * Fang Pengfei * Felipe Morales * Filip Danilović * Floris Lambrechts * 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 * Jason Newton * 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 * lcjh * Leho Kraav * Lev Zlotin * Louis Rousseau * Libor Jelinek * Liviu Cristian Mirea-Ghiban * Luca Ottaviano * Łukasz Wojniłowicz * Luke Bakken * Luke Horwell * 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 * Max Harmathy * Melike Kecelioglu * Micha Rosenbaum * Michael Geddes * Michael Homer * Mickael Albertus * Miguel Boekhold * Mike Hanson * MikHulk * Mikołaj Milej * Minarto Margoliono * Mithil Poojary * Mosaab Alzoubi * Muhammad Bashir Al-Noimi * Myz * Naraesk * Nanda Lopes * Niel Buys * Nick Todd * Nicolas Dietrich * Nikos Roussos * Noel Grandin * NotSqrt * nyanpasu64 * 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 * Ray Haleblian * RealTehreal * Ricardo J. Barberis * Robbert Korving * Robert Pollak * Rolando Espinoza La fuente * Rustam Safin * Sabri Ünal * Samsul Ma'arif * Sean Allred * 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 Gates * Tim Schumacher * Trevor Alexander * Ugo Riboni * Uri Okrent * Utku Karatas * V字龍 (Vdragon) * Vaibhav Sagar * Vaiz * vanderkoort * Ved Vyas * Victor Gambier * Victor Nepveu * Victorhck * Ville Skyttä * Virgil Dupras * Vitor Lobo * v.paritskiy * waterzch * Wolfgang Ocker * wm4 * wsdfhjxc * Xie Hua Liang (xieofxie) * Yi EungJun * Zauber Paracelsus * Zeioth * Zhang Han * 0xflotus git-cola-3.12.0/share/git-cola/000077500000000000000000000000001417222504200160745ustar00rootroot00000000000000git-cola-3.12.0/share/git-cola/bin/000077500000000000000000000000001417222504200166445ustar00rootroot00000000000000git-cola-3.12.0/share/git-cola/bin/ssh-askpass000077500000000000000000000033661417222504200210420ustar00rootroot00000000000000#!/usr/bin/env tclsh # Tcl ignores the next line -*- tcl -*- \ exec wish "$0" -- "$@" # This is a trivial implementation of a 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 proc on_hide_input_changed {args} { global hide_input if {$hide_input} { .e configure -show "*" } else { .e configure -show "" } } trace add variable hide_input write "on_hide_input_changed" set hide_input 0 if {!$yesno} { if {"Password" in $prompt || "passphrase" in $prompt} { set hide_input 1 } checkbutton .cb_hide -text "Hide input" -variable hide_input pack .cb_hide -side top -anchor nw } 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.12.0/share/git-cola/bin/ssh-askpass-darwin000077500000000000000000000014311417222504200223130ustar00rootroot00000000000000#! /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.12.0/share/git-cola/icons/000077500000000000000000000000001417222504200172075ustar00rootroot00000000000000git-cola-3.12.0/share/git-cola/icons/README.md000066400000000000000000000053411417222504200204710ustar00rootroot00000000000000# 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 - three-bars.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+ ### Google Material Icons (v2.2) The following files are by Google: - arrow-down.svg - arrow-up.svg - edit-copy.svg - edit-cut.svg - edit-paste.svg - edit-redo.svg - edit-select-all.svg - edit-undo.svg - file-download.svg License: [Creative Commons BY 3.0](http://creativecommons.org/licenses/by/3.0/) git-cola-3.12.0/share/git-cola/icons/a-z-order.svg000066400000000000000000000025071417222504200215340ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/arrow-down.svg000066400000000000000000000002531417222504200220270ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/arrow-up.svg000066400000000000000000000002521417222504200215030ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/check.svg000066400000000000000000000003151417222504200210040ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/circle-slash-red.svg000066400000000000000000000007501417222504200230530ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/circle-slash.svg000066400000000000000000000007511417222504200223040ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/000077500000000000000000000000001417222504200201305ustar00rootroot00000000000000git-cola-3.12.0/share/git-cola/icons/dark/README.md000066400000000000000000000041421417222504200214100ustar00rootroot00000000000000Git 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 below ). 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.12.0/share/git-cola/icons/dark/a-z-order.svg000066400000000000000000000025071417222504200224550ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/arrow-down.svg000066400000000000000000000002751417222504200227540ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/arrow-up.svg000066400000000000000000000002771417222504200224330ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/check.svg000066400000000000000000000003151417222504200217250ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/circle-slash-red.svg000066400000000000000000000007501417222504200237740ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/circle-slash.svg000066400000000000000000000007501417222504200232240ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/desktop-download.svg000066400000000000000000000003401417222504200241240ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/diff.svg000066400000000000000000000003741417222504200215650ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/document-save-symbolic.svg000066400000000000000000000020331417222504200252400ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/edit-copy.svg000066400000000000000000000006521417222504200225510ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/edit-cut.svg000066400000000000000000000025421417222504200223720ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/edit-paste.svg000066400000000000000000000012341417222504200227100ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/edit-redo.svg000066400000000000000000000006521417222504200225300ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/edit-select-all.svg000066400000000000000000000104211417222504200236170ustar00rootroot00000000000000 image/svg+xml git-cola-3.12.0/share/git-cola/icons/dark/edit-undo.svg000066400000000000000000000006711417222504200225450ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/ellipsis.svg000066400000000000000000000007171417222504200225020ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/eye.svg000066400000000000000000000010651417222504200214350ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/file-binary.svg000066400000000000000000000011121417222504200230450ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/file-code.svg000066400000000000000000000010271417222504200225000ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/file-directory.svg000066400000000000000000000006651417222504200236010ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/file-download.svg000066400000000000000000000011621417222504200233750ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/file-media.svg000066400000000000000000000006671417222504200226560ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/file-text.svg000066400000000000000000000007511417222504200225550ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/file-zip.svg000066400000000000000000000014341417222504200223720ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/fold.svg000066400000000000000000000012541417222504200215770ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/folder-new.svg000066400000000000000000000023521417222504200227150ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/folder.svg000066400000000000000000000013441417222504200221260ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/gear.svg000066400000000000000000000014571417222504200215760ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/git-branch.svg000066400000000000000000000030721417222504200226710ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/git-cola.ico000066400000000000000000013226261417222504200223370ustar00rootroot00000000000000 ( 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.12.0/share/git-cola/icons/dark/git-cola.svg000066400000000000000000000146231417222504200223560ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/git-commit.svg000066400000000000000000000005421417222504200227230ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/git-compare.svg000066400000000000000000000027571417222504200230730ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/git-merge.svg000066400000000000000000000027011417222504200225310ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/last-first-order.svg000066400000000000000000000112501417222504200240510ustar00rootroot00000000000000 image/svg+xml git-cola-3.12.0/share/git-cola/icons/dark/link-external.svg000066400000000000000000000006201417222504200234240ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/modified.svg000066400000000000000000000002341417222504200224300ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/partial.svg000066400000000000000000000002341417222504200223040ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/pencil.svg000066400000000000000000000006771417222504200221350ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/plus.svg000066400000000000000000000003001417222504200216250ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/primitive-dot.svg000066400000000000000000000003761417222504200234530ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/question-plain.svg000066400000000000000000000007261417222504200236260ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/question.svg000066400000000000000000000015641417222504200225260ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/repo-pull.svg000066400000000000000000000011431417222504200225670ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/repo-push.svg000066400000000000000000000010741417222504200225750ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/repo.svg000066400000000000000000000011031417222504200216110ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/screen-full.svg000066400000000000000000000011331417222504200230660ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/search.svg000066400000000000000000000012771417222504200221250ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/staged.svg000066400000000000000000000002321417222504200221150ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/star.svg000066400000000000000000000004101417222504200216150ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/sync.svg000066400000000000000000000013601417222504200216250ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/tag.svg000066400000000000000000000012301417222504200214200ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/telescope.svg000066400000000000000000000015041417222504200226340ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/three-bars.svg000066400000000000000000000013461417222504200227110ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/trashcan.svg000066400000000000000000000014471417222504200224620ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/unfold.svg000066400000000000000000000012321417222504200221360ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/upstream.svg000066400000000000000000000002411417222504200225060ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/x.svg000066400000000000000000000004711417222504200211220ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/zoom-fit-best.svg000066400000000000000000000015261417222504200233540ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/zoom-in.svg000066400000000000000000000022441417222504200222430ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/dark/zoom-out.svg000066400000000000000000000023121417222504200224400ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/desktop-download.svg000066400000000000000000000003401417222504200232030ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/diff.svg000066400000000000000000000003741417222504200206440ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/document-save-symbolic.svg000066400000000000000000000020071417222504200243200ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/edit-copy.svg000066400000000000000000000006351417222504200216310ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/edit-cut.svg000066400000000000000000000025251417222504200214520ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/edit-paste.svg000066400000000000000000000012171417222504200217700ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/edit-redo.svg000066400000000000000000000006351417222504200216100ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/edit-select-all.svg000066400000000000000000000022151417222504200227000ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/edit-undo.svg000066400000000000000000000006541417222504200216250ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/ellipsis.svg000066400000000000000000000004001417222504200215460ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/eye.svg000066400000000000000000000005341417222504200205140ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/file-binary.svg000066400000000000000000000005241417222504200221320ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/file-code.svg000066400000000000000000000010271417222504200215570ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/file-directory.svg000066400000000000000000000006651417222504200226600ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/file-download.svg000066400000000000000000000011621417222504200224540ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/file-media.svg000066400000000000000000000006671417222504200217350ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/file-text.svg000066400000000000000000000007511417222504200216340ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/file-zip.svg000066400000000000000000000014341417222504200214510ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/fold.svg000066400000000000000000000012541417222504200206560ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/folder-new.svg000066400000000000000000000023521417222504200217740ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/folder.svg000066400000000000000000000013441417222504200212050ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/gear.svg000066400000000000000000000014571417222504200206550ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/git-branch.svg000066400000000000000000000030721417222504200217500ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/git-cola.ico000066400000000000000000013226261417222504200214160ustar00rootroot00000000000000 ( 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.12.0/share/git-cola/icons/git-cola.svg000066400000000000000000000146231417222504200214350ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/git-commit.svg000066400000000000000000000005461417222504200220060ustar00rootroot00000000000000git-cola-3.12.0/share/git-cola/icons/git-compare.svg000066400000000000000000000027571417222504200221520ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/git-merge.svg000066400000000000000000000027011417222504200216100ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/last-first-order.svg000066400000000000000000000112501417222504200231300ustar00rootroot00000000000000 image/svg+xml git-cola-3.12.0/share/git-cola/icons/link-external.svg000066400000000000000000000006201417222504200225030ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/modified.svg000066400000000000000000000034441417222504200215150ustar00rootroot00000000000000 image/svg+xml git-cola-3.12.0/share/git-cola/icons/partial.svg000066400000000000000000000002341417222504200213630ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/pencil.svg000066400000000000000000000006771417222504200212140ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/plus.svg000066400000000000000000000003001417222504200207040ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/primitive-dot.svg000066400000000000000000000003761417222504200225320ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/question-plain.svg000066400000000000000000000007261417222504200227050ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/question.svg000066400000000000000000000015641417222504200216050ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/repo-pull.svg000066400000000000000000000011431417222504200216460ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/repo-push.svg000066400000000000000000000010741417222504200216540ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/repo.svg000066400000000000000000000011031417222504200206700ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/screen-full.svg000066400000000000000000000011331417222504200221450ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/search.svg000066400000000000000000000012771417222504200212040ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/staged.svg000066400000000000000000000002321417222504200211740ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/star.svg000066400000000000000000000004101417222504200206740ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/sync.svg000066400000000000000000000013601417222504200207040ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/tag.svg000066400000000000000000000012301417222504200204770ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/telescope.svg000066400000000000000000000015041417222504200217130ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/three-bars.svg000066400000000000000000000013251417222504200217650ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/trashcan.svg000066400000000000000000000014471417222504200215410ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/unfold.svg000066400000000000000000000012261417222504200212200ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/upstream.svg000066400000000000000000000005541417222504200215740ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/x.svg000066400000000000000000000030661417222504200202040ustar00rootroot00000000000000 image/svg+xml git-cola-3.12.0/share/git-cola/icons/zoom-fit-best.svg000066400000000000000000000015511417222504200224310ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/zoom-in.svg000066400000000000000000000022441417222504200213220ustar00rootroot00000000000000 git-cola-3.12.0/share/git-cola/icons/zoom-out.svg000066400000000000000000000023121417222504200215170ustar00rootroot00000000000000 git-cola-3.12.0/share/metainfo/000077500000000000000000000000001417222504200161775ustar00rootroot00000000000000git-cola-3.12.0/share/metainfo/git-cola.appdata.xml000066400000000000000000000012361417222504200220330ustar00rootroot00000000000000 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.12.0/share/metainfo/git-dag.appdata.xml000066400000000000000000000005701417222504200216500ustar00rootroot00000000000000 git-dag.desktop CC0-1.0 GPL-2.0 Git DAG

git-dag is an advanced git DAG visualizer

https://git-cola.github.io/
git-cola-3.12.0/test/000077500000000000000000000000001417222504200142525ustar00rootroot00000000000000git-cola-3.12.0/test/__init__.py000066400000000000000000000000001417222504200163510ustar00rootroot00000000000000git-cola-3.12.0/test/app_test.py000066400000000000000000000007771417222504200164560ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, unicode_literals import argparse from cola import app def test_setup_environment(): # If the function doesn't throw an exception we are happy. assert hasattr(app, 'setup_environment') app.setup_environment() def test_add_common_arguments(): # If the function doesn't throw an exception we are happy. parser = argparse.ArgumentParser() assert hasattr(app, 'add_common_arguments') app.add_common_arguments(parser) git-cola-3.12.0/test/branch_test.py000066400000000000000000000135021417222504200171210ustar00rootroot00000000000000"""Tests related to the branches widget""" from __future__ import absolute_import, division, print_function, unicode_literals from cola.widgets import branch from .helper import Mock def test_create_tree_entries(): names = [ 'abc', 'cat/abc', 'cat/def', 'xyz/xyz', ] root = branch.create_tree_entries(names) expect = 3 actual = len(root.children) assert expect == actual # 'abc' abc = root.children[0] expect = 'abc' actual = abc.basename assert expect == actual expect = 'abc' actual = abc.refname assert expect == actual expect = [] actual = abc.children assert expect == actual # 'cat' cat = root.children[1] expect = 'cat' actual = 'cat' assert expect == actual assert cat.refname is None expect = 2 actual = len(cat.children) assert expect == actual # 'cat/abc' cat_abc = cat.children[0] expect = 'abc' actual = cat_abc.basename assert expect == actual expect = 'cat/abc' actual = cat_abc.refname assert expect == actual expect = [] actual = cat_abc.children assert expect == actual # 'cat/def' cat_def = cat.children[1] expect = 'def' actual = cat_def.basename assert expect == actual expect = 'cat/def' actual = cat_def.refname assert expect == actual expect = [] actual = cat_def.children assert expect == actual # 'xyz' xyz = root.children[2] expect = 'xyz' actual = xyz.basename assert expect == actual assert xyz.refname is None expect = 1 actual = len(xyz.children) assert expect == actual # 'xyz/xyz' xyz_xyz = xyz.children[0] expect = 'xyz' actual = xyz_xyz.basename assert expect == actual expect = 'xyz/xyz' actual = xyz_xyz.refname assert expect == actual expect = [] actual = xyz_xyz.children assert expect == actual def test_create_name_dict(): """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', ] inner_child = {'child_2_1_2': {}, 'child_2_1_1': {}} expect = { 'top_1': { 'child_1': {'child_1_2': {}, 'child_1_1': {}}, 'child_2': {'child_2_1': inner_child}, } } actual = branch.create_name_dict(branches) assert expect == actual def test_create_toplevel_item(): names = [ 'child_1', 'child_2/child_2_1', 'child_2/child_2_2', ] tree = branch.create_tree_entries(names) tree.basename = 'top' top = branch.create_toplevel_item(tree) expect = 'top' actual = top.name assert expect == actual expect = 2 actual = top.childCount() assert expect == actual expect = 'child_1' actual = top.child(0).name assert expect == actual expect = 'child_1' actual = top.child(0).refname assert expect == actual expect = 'child_2' actual = top.child(1).name assert expect == actual assert top.child(1).refname is None expect = 2 actual = top.child(1).childCount() assert expect == actual expect = 'child_2_1' actual = top.child(1).child(0).name assert expect == actual expect = 'child_2_2' actual = top.child(1).child(1).name assert expect == actual expect = 'child_2/child_2_1' actual = top.child(1).child(0).refname assert expect == actual expect = 'child_2/child_2_2' actual = top.child(1).child(1).refname assert expect == actual def test_get_toplevel_item(): items = _create_top_item() actual = branch.get_toplevel_item(items['child_1']) assert items['top'] is actual actual = branch.get_toplevel_item(items['sub_child_2_1']) assert items['top'] is actual def test_refname_attribute(): items = _create_top_item() actual = items['child_1'].refname expect = 'child_1' assert expect == actual actual = items['sub_child_2_2'].refname expect = 'child_2/sub_child_2_2' assert expect == actual def test_should_return_a_valid_child_on_find_child(): """Test the find_child function.""" items = _create_top_item() child = branch.find_by_refname(items['top'], 'child_1') assert child.refname == 'child_1' child = branch.find_by_refname(items['top'], 'child_2/sub_child_2_2') assert child.name == 'sub_child_2_2' def test_should_return_empty_state_on_save_state(): """Test the save_state function.""" top = _create_item('top', None, False) tree_helper = branch.BranchesTreeHelper() actual = tree_helper.save_state(top) assert {'top': {}} == actual def test_should_return_a_valid_state_on_save_state(): """Test the save_state function.""" items = _create_top_item() tree_helper = branch.BranchesTreeHelper() actual = tree_helper.save_state(items['top']) expect = { 'top': { 'child_1': {}, 'child_2': {'sub_child_2_1': {}, 'sub_child_2_2': {}}, } } assert expect == actual 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 = Mock(return_value=expanded) return item git-cola-3.12.0/test/browse_model_test.py000066400000000000000000000035241417222504200203500ustar00rootroot00000000000000"""Test interfaces used by the browser (git cola browse)""" # pylint: disable=redefined-outer-name from __future__ import absolute_import, division, print_function, unicode_literals from cola import core from cola import gitcmds from . import helper from .helper import app_context # These assertions make flake8 happy. It considers them unused imports otherwise. assert app_context is not None def test_stage_paths_untracked(app_context): """Test stage_paths() with an untracked file.""" model = app_context.model core.makedirs('foo/bar') helper.touch('foo/bar/baz') gitcmds.add(app_context, ['foo']) app_context.model.update_file_status() assert 'foo/bar/baz' in model.staged assert 'foo/bar/baz' not in model.modified assert 'foo/bar/baz' not in model.untracked def test_unstage_paths(app_context): """Test a simple usage of unstage_paths().""" helper.commit_files() helper.write_file('A', 'change') helper.run_git('add', 'A') model = app_context.model gitcmds.unstage_paths(app_context, ['A']) model.update_status() assert 'A' not in model.staged assert 'A' in model.modified def test_unstage_paths_init(app_context): """Test unstage_paths() on the root commit.""" model = app_context.model gitcmds.unstage_paths(app_context, ['A']) model.update_status() assert 'A' not in model.staged assert 'A' in model.untracked def test_unstage_paths_subdir(app_context): """Test unstage_paths() in a subdirectory.""" helper.run_git('commit', '-m', 'initial commit') core.makedirs('foo/bar') helper.touch('foo/bar/baz') helper.run_git('add', 'foo/bar/baz') model = app_context.model gitcmds.unstage_paths(app_context, ['foo']) model.update_status() assert 'foo/bar/baz' in model.untracked assert 'foo/bar/baz' not in model.staged git-cola-3.12.0/test/cmds_test.py000066400000000000000000000160321417222504200166130ustar00rootroot00000000000000"""Test the cmds module""" from __future__ import absolute_import, division, print_function, unicode_literals from cola import cmds from cola.compat import uchr from .helper import Mock, patch def test_Commit_strip_comments(): """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) assert expect == actual def test_commit_strip_comments_unicode(): """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) assert expect == actual def test_unix_path_win32(): 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) assert expect == actual def test_unix_path_network_win32(): 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) assert expect == actual def test_unix_path_is_a_noop_on_sane_platforms(): path = r'/:we/don\t/need/no/stinking/badgers!' expect = path actual = cmds.unix_path(path, is_win32=lambda: False) assert expect == actual def test_context_edit_command(): context = 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') assert model.set_filename.call_count == 1 @patch('cola.interaction.Interaction.confirm') def test_submodule_add(confirm): # "git submodule" should not be called if the answer is "no" context = Mock() url = 'url' path = '' reference = '' branch = '' depth = 0 cmd = cmds.SubmoduleAdd(context, url, path, branch, depth, reference) confirm.return_value = False cmd.do() assert not context.git.submodule.called expect = ['--', 'url'] actual = cmd.get_args() assert expect == actual cmd.path = 'path' expect = ['--', 'url', 'path'] actual = cmd.get_args() assert expect == actual cmd.reference = 'ref' expect = ['--reference', 'ref', '--', 'url', 'path'] actual = cmd.get_args() assert expect == actual cmd.branch = 'branch' expect = ['--branch', 'branch', '--reference', 'ref', '--', 'url', 'path'] actual = cmd.get_args() assert expect == actual cmd.reference = '' cmd.branch = '' cmd.depth = 1 expect = ['--depth', '1', '--', 'url', 'path'] actual = cmd.get_args() assert expect == actual # Run the command and assert that "git submodule" was called. confirm.return_value = True context.git.submodule.return_value = (0, '', '') cmd.do() context.git.submodule.assert_called_once_with('add', *expect) assert context.model.update_file_status.called assert context.model.update_submodules_list.called @patch('cola.version.check_git') @patch('cola.interaction.Interaction.confirm') def test_submodule_update(confirm, check_git): context = Mock() path = 'sub/path' update_path_cmd = cmds.SubmoduleUpdate(context, path) update_all_cmd = cmds.SubmodulesUpdate(context) # Nothing is called when confirm() returns False. confirm.return_value = False update_path_cmd.do() assert not context.git.submodule.called update_all_cmd.do() assert not context.git.submodule.called # Confirm command execution. confirm.return_value = True # Test the old command-line arguments first check_git.return_value = False expect = ['update', '--', 'sub/path'] actual = update_path_cmd.get_args() assert expect == actual context.model.update_file_status = Mock() context.git.submodule = Mock(return_value=(0, '', '')) update_path_cmd.do() context.git.submodule.assert_called_once_with(*expect) assert context.model.update_file_status.called expect = ['update'] actual = update_all_cmd.get_args() assert expect == actual context.model.update_file_status = Mock() context.git.submodule = Mock(return_value=(0, '', '')) update_all_cmd.do() context.git.submodule.assert_called_once_with(*expect) assert context.model.update_file_status.called # Test the new command-line arguments (git v1.6.5+) check_git.return_value = True expect = ['update', '--recursive', '--', 'sub/path'] actual = update_path_cmd.get_args() assert expect == actual context.model.update_file_status = Mock() context.git.submodule = Mock(return_value=(0, '', '')) update_path_cmd.do() context.git.submodule.assert_called_once_with(*expect) assert context.model.update_file_status.called expect = ['update', '--recursive'] actual = update_all_cmd.get_args() assert expect == actual context.model.update_file_status = Mock() context.git.submodule = Mock(return_value=(0, '', '')) update_all_cmd.do() context.git.submodule.assert_called_once_with(*expect) assert context.model.update_file_status.called @patch('cola.cmds.Interaction') @patch('cola.cmds.prefs') def test_undo_last_commit_confirms_action(prefs, interaction): """Test the behavior around confirmation of UndoLastCommit actions""" context = Mock() context.model = Mock() # First, test what happens when the commit is published and we say "yes". prefs.check_published_commits = Mock(return_value=True) context.model.is_commit_published = Mock(return_value=True) interaction.confirm = Mock(return_value=True) cmd = cmds.UndoLastCommit(context) assert cmd.confirm() context.model.is_commit_published.assert_called_once() interaction.confirm.assert_called_once() # Now, test what happens when we say "no". interaction.confirm = Mock(return_value=False) assert not cmd.confirm() interaction.confirm.assert_called_once() # Now check what happens when the commit is published but our preferences # say to not check for published commits. prefs.check_published_commits = Mock(return_value=False) context.model.is_commit_published = Mock(return_value=True) interaction.confirm = Mock(return_value=True) assert cmd.confirm() context.model.is_commit_published.assert_not_called() interaction.confirm.assert_called_once() # Lastly, check what when the commit is not published and we do check # for published commits. prefs.check_published_commits = Mock(return_value=True) context.model.is_commit_published = Mock(return_value=False) interaction.confirm = Mock(return_value=True) assert cmd.confirm() context.model.is_commit_published.assert_called_once() interaction.confirm.assert_called_once() git-cola-3.12.0/test/compat_test.py000066400000000000000000000007041417222504200171470ustar00rootroot00000000000000# encoding: utf-8 """Tests the compat module""" from __future__ import absolute_import, division, print_function, unicode_literals import os from cola import compat def test_setenv(): """Test the core.decode function""" key = 'COLA_UNICODE_TEST' value = '字龍' compat.setenv(key, value) assert key in os.environ assert os.getenv(key) compat.unsetenv(key) assert key not in os.environ assert not os.getenv(key) git-cola-3.12.0/test/core_test.py000066400000000000000000000031351417222504200166150ustar00rootroot00000000000000# encoding: utf-8 """Tests the cola.core module's unicode handling""" from __future__ import absolute_import, division, print_function, unicode_literals from cola import core from . import helper def test_core_decode(): """Test the core.decode function""" filename = helper.fixture('unicode.txt') expect = core.decode(core.encode('unicøde')) actual = core.read(filename).strip() assert expect == actual def test_core_encode(): """Test the core.encode function""" filename = helper.fixture('unicode.txt') expect = core.encode('unicøde') actual = core.encode(core.read(filename).strip()) assert expect == actual def test_decode_None(): """Ensure that decode(None) returns None""" expect = None actual = core.decode(None) assert expect == actual def test_decode_utf8(): filename = helper.fixture('cyrillic-utf-8.txt') actual = core.read(filename) assert actual.encoding == 'utf-8' def test_decode_non_utf8(): filename = helper.fixture('cyrillic-cp1251.txt') actual = core.read(filename) assert actual.encoding == 'iso-8859-15' def test_decode_non_utf8_string(): filename = helper.fixture('cyrillic-cp1251.txt') with open(filename, 'rb') as f: content = f.read() actual = core.decode(content) assert actual.encoding == 'iso-8859-15' def test_guess_mimetype(): value = '字龍.txt' expect = 'text/plain' actual = core.guess_mimetype(value) assert expect == actual # This function is robust to bytes vs. unicode actual = core.guess_mimetype(core.encode(value)) assert expect == actual git-cola-3.12.0/test/dag_test.py000066400000000000000000000101111417222504200164100ustar00rootroot00000000000000"""Tests DAG functionality""" # pylint: disable=redefined-outer-name from __future__ import absolute_import, division, print_function, unicode_literals import pytest from cola.models import dag from .helper import app_context from .helper import patch assert app_context is not None 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 main. 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 main """.strip().replace( # noqa '^A', chr(0x01) ).split( '\n' ) + [ '' ] # noqa class DAGTestData(object): """Test data provided by the dag_context fixture""" def __init__(self, app_context, head='HEAD', count=1000): self.context = app_context self.params = dag.DAG(head, count) self.reader = dag.RepoReader(app_context, self.params) @pytest.fixture def dag_context(app_context): """Provide DAGTestData for use by tests""" return DAGTestData(app_context) @patch('cola.models.dag.core') def test_repo_reader(core, dag_context): expect = len(LOG_LINES) - 1 actual = 0 core.readline.return_value = LOG_LINES[0] for idx, _ in enumerate(dag_context.reader.get()): core.readline.return_value = LOG_LINES[idx + 1] actual += 1 assert expect == actual @patch('cola.models.dag.core') def test_repo_reader_order(core, dag_context): commits = [ 'ad454b189fe5785af397fd6067cf103268b6626e', '1ba04ad185cf9f04c56c8482e9a73ef1bd35c695', 'fa5ad6c38be603e2ffd1f9b722a3a5c675f63de2', '103766573cd4e6799d3ee792bcd632b92cf7c6c0', 'e3f5a2d0248de6197d6e0e63c901810b8a9af2f8', 'f4fb8fd5baaa55d9b41faca79be289bb4407281e', '23e7eab4ba2c94e3155f5d261c693ccac1342eb9', ] core.readline.return_value = LOG_LINES[0] for idx, commit in enumerate(dag_context.reader.get()): assert commits[idx] == commit.oid core.readline.return_value = LOG_LINES[idx + 1] @patch('cola.models.dag.core') def test_repo_reader_parents(core, dag_context): parents = [ [], ['ad454b189fe5785af397fd6067cf103268b6626e'], ['1ba04ad185cf9f04c56c8482e9a73ef1bd35c695'], ['fa5ad6c38be603e2ffd1f9b722a3a5c675f63de2'], ['fa5ad6c38be603e2ffd1f9b722a3a5c675f63de2'], ['e3f5a2d0248de6197d6e0e63c901810b8a9af2f8'], ['f4fb8fd5baaa55d9b41faca79be289bb4407281e'], ] core.readline.return_value = LOG_LINES[0] for idx, commit in enumerate(dag_context.reader.get()): assert parents[idx] == [p.oid for p in commit.parents] core.readline.return_value = LOG_LINES[idx + 1] @patch('cola.models.dag.core') def test_repo_reader_contract(core, dag_context): core.exists.return_value = True core.readline.return_value = LOG_LINES[0] for idx, _ in enumerate(dag_context.reader.get()): core.readline.return_value = LOG_LINES[idx + 1] core.start_command.assert_called() call_args = core.start_command.call_args assert 'log.abbrevCommit=false' in call_args[0][0] assert 'log.showSignature=false' in call_args[0][0] git-cola-3.12.0/test/diffparse_test.py000066400000000000000000000235671417222504200176430ustar00rootroot00000000000000"""Tests for the diffparse module""" # pylint: disable=redefined-outer-name from __future__ import absolute_import, division, print_function, unicode_literals import pytest from cola import core from cola import diffparse from . import helper class DiffLinesTestData(object): """Test data used by DiffLines tests""" def __init__(self): self.parser = diffparse.DiffLines() fixture_path = helper.fixture('diff.txt') self.text = core.read(fixture_path) @pytest.fixture def difflines_data(): """Return test data for diffparse.DiffLines tests""" return DiffLinesTestData() def test_diff(): fixture_path = helper.fixture('diff.txt') parser = diffparse.DiffParser('cola/diffparse.py', core.read(fixture_path)) hunks = parser.hunks assert len(hunks) == 3 assert hunks[0].first_line_idx == 0 assert len(hunks[0].lines) == 23 assert hunks[0].lines[0] == '@@ -6,10 +6,21 @@ from cola import gitcmds\n' assert hunks[0].lines[1] == ' from cola import gitcfg\n' assert hunks[0].lines[2] == ' \n' assert hunks[0].lines[3] == ' \n' assert hunks[0].lines[4] == '+class DiffSource(object):\n' assert hunks[0].lines[-1] == ( r" self._header_start_re = re.compile('^@@ -(\d+)" r" \+(\d+),(\d+) @@.*')" '\n' ) assert hunks[1].first_line_idx == 23 assert len(hunks[1].lines) == 18 assert hunks[1].lines[0] == '@@ -29,13 +40,11 @@ class DiffParser(object):\n' assert hunks[1].lines[1] == ' self.diff_sel = []\n' assert hunks[1].lines[2] == ' self.selected = []\n' assert hunks[1].lines[3] == ' self.filename = filename\n' assert hunks[1].lines[4] == ( '+ self.diff_source = diff_source or DiffSource()\n' ) assert hunks[1].lines[-1] == ' self.header = header\n' assert hunks[2].first_line_idx == 41 assert len(hunks[2].lines) == 16 assert hunks[2].lines[0] == '@@ -43,11 +52,10 @@ class DiffParser(object):\n' assert hunks[2].lines[-1] == ( ' """Writes a new diff corresponding to the user\'s' ' selection."""\n' ) def test_diff_at_start(): fixture_path = helper.fixture('diff-start.txt') parser = diffparse.DiffParser('foo bar/a', core.read(fixture_path)) hunks = parser.hunks assert hunks[0].lines[0] == '@@ -1 +1,4 @@\n' assert hunks[-1].lines[-1] == '+c\n' assert hunks[0].old_start == 1 assert hunks[0].old_count == 1 assert hunks[0].new_start == 1 assert hunks[0].new_count == 4 assert 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' ) assert 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(): fixture_path = helper.fixture('diff-end.txt') parser = diffparse.DiffParser('rijndael.js', core.read(fixture_path)) hunks = parser.hunks assert hunks[0].lines[0] == '@@ -1,39 +1 @@\n' assert hunks[-1].lines[-1] == ( "+module.exports = require('./build/Release/rijndael');\n" ) assert hunks[0].old_start == 1 assert hunks[0].old_count == 39 assert hunks[0].new_start == 1 assert hunks[0].new_count == 1 def test_diff_that_empties_file(): fixture_path = helper.fixture('diff-empty.txt') parser = diffparse.DiffParser('filename', core.read(fixture_path)) hunks = parser.hunks assert hunks[0].lines[0] == '@@ -1,2 +0,0 @@\n' assert hunks[-1].lines[-1] == '-second\n' assert hunks[0].old_start == 1 assert hunks[0].old_count == 2 assert hunks[0].new_start == 0 assert hunks[0].new_count == 0 assert parser.generate_patch(1, 1) == ( '--- a/filename\n' '+++ b/filename\n' '@@ -1,2 +1 @@\n' '-first\n' ' second\n' ) assert 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(): diff_text = """\ deleted file mode 100755 @@ -1,1 +0,0 @@ -#!/bin/sh """ parser = diffparse.DiffParser('deleted.txt', diff_text) expect = 1 actual = len(parser.hunks) assert expect == actual # Selecting the first two lines generate no diff expect = None actual = parser.generate_patch(0, 1) assert 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) assert expect == actual # All three lines should map to the same hunk diff actual = parser.generate_hunk_patch(0) assert expect == actual actual = parser.generate_hunk_patch(1) assert expect == actual actual = parser.generate_hunk_patch(2) assert expect == actual def test_basic_diff_line_count(difflines_data): """Verify the basic line counts""" lines = difflines_data.parser.parse(difflines_data.text) expect = len(difflines_data.text.splitlines()) actual = len(lines) assert expect == actual def test_diff_line_count_ranges(difflines_data): parser = difflines_data.parser lines = parser.parse(difflines_data.text) # Diff header line = 0 count = 1 assert lines[line][0] == parser.DASH assert lines[line][1] == parser.DASH line += count # 3 lines of context count = 3 current_old = 6 current_new = 6 for i in range(count): assert lines[line + i][0] == current_old + i assert 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): assert lines[line + i][0] == parser.EMPTY assert lines[line + i][1] == current_new + i line += count current_new += count # 3 more lines of context count = 3 for i in range(count): assert lines[line + i][0] == current_old + i assert 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): assert lines[line + i][0] == current_old + i assert lines[line + i][1] == parser.EMPTY line += count current_old += count # 2 lines of addition count = 2 for i in range(count): assert lines[line + i][0] == parser.EMPTY assert lines[line + i][1] == current_new + i line += count current_new += count # 3 more lines of context count = 3 for i in range(count): assert lines[line + i][0] == current_old + i assert 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): assert lines[line + i][0] == parser.DASH assert 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): assert lines[line + i][0] == current_old + i assert lines[line + i][1] == current_new + i line += count current_new += count current_old += count expect_max_old = 54 assert expect_max_old == parser.old.max_value expect_max_new = 62 assert expect_max_new == parser.new.max_value assert parser.digits() == 2 def test_diff_line_for_merge(difflines_data): """Verify the basic line counts""" text = """@@@ -1,23 -1,33 +1,75 @@@ ++<<<<<<< upstream + +Ok """ parser = difflines_data.parser lines = parser.parse(text) assert len(lines) == 4 assert len(lines[0]) == 3 assert len(lines[1]) == 3 assert len(lines[2]) == 3 assert len(lines[3]) == 3 assert lines[0][0] == parser.DASH assert lines[0][1] == parser.DASH assert lines[0][2] == parser.DASH assert lines[1][0] == parser.EMPTY assert lines[1][1] == parser.EMPTY assert lines[1][2] == 1 assert lines[2][0] == 1 assert lines[2][1] == parser.EMPTY assert lines[2][2] == 2 assert lines[3][0] == 2 assert lines[3][1] == parser.EMPTY assert lines[3][2] == 3 def test_format_basic(): fmt = diffparse.FormatDigits() fmt.set_digits(2) expect = '01 99' actual = fmt.value(1, 99) assert expect == actual def test_format_reuse(): fmt = diffparse.FormatDigits() fmt.set_digits(3) expect = '001 099' actual = fmt.value(1, 99) assert expect == actual fmt.set_digits(4) expect = '0001 0099' actual = fmt.value(1, 99) assert expect == actual def test_format_special_values(): fmt = diffparse.FormatDigits(dash='-') fmt.set_digits(3) expect = ' 099' actual = fmt.value(fmt.EMPTY, 99) assert expect == actual expect = '001 ' actual = fmt.value(1, fmt.EMPTY) assert expect == actual expect = ' ' actual = fmt.value(fmt.EMPTY, fmt.EMPTY) assert expect == actual expect = '--- 001' actual = fmt.value(fmt.DASH, 1) assert expect == actual expect = '099 ---' actual = fmt.value(99, fmt.DASH) assert expect == actual expect = '--- ---' actual = fmt.value(fmt.DASH, fmt.DASH) assert expect == actual expect = ' ---' actual = fmt.value(fmt.EMPTY, fmt.DASH) assert expect == actual expect = '--- ' actual = fmt.value(fmt.DASH, fmt.EMPTY) assert expect == actual def test_parse_range_str(): start, count = diffparse.parse_range_str('1,2') assert start == 1 assert count == 2 def test_parse_range_str_single_line(): start, count = diffparse.parse_range_str('2') assert start == 2 assert count == 1 def test_parse_range_str_empty(): start, count = diffparse.parse_range_str('0,0') assert start == 0 assert count == 0 git-cola-3.12.0/test/display_test.py000066400000000000000000000014741417222504200173360ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, unicode_literals from cola import display def test_shorten_paths(): paths = ( '/usr/src/git-cola/src', '/usr/src/example/src', '/usr/src/super/lib/src', '/usr/src/super/tools/src', '/usr/src/super/example/src', '/lib/src', ) actual = display.shorten_paths(paths) assert actual[paths[0]] == 'git-cola/src' assert actual[paths[1]] == 'src/example/src' assert actual[paths[2]] == 'super/lib/src' assert actual[paths[3]] == 'tools/src' assert actual[paths[4]] == 'super/example/src' assert actual[paths[5]] == '/lib/src' def test_normalize_path(): path = r'C:\games\doom2' expect = 'C:/games/doom2' actual = display.normalize_path(path) assert expect == actual git-cola-3.12.0/test/fixtures/000077500000000000000000000000001417222504200161235ustar00rootroot00000000000000git-cola-3.12.0/test/fixtures/.gitattributes000066400000000000000000000002401417222504200210120ustar00rootroot00000000000000# 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.12.0/test/fixtures/bin/000077500000000000000000000000001417222504200166735ustar00rootroot00000000000000git-cola-3.12.0/test/fixtures/bin/exe-cmd.exe000066400000000000000000000000001417222504200207060ustar00rootroot00000000000000git-cola-3.12.0/test/fixtures/cyrillic-cp1251.txt000066400000000000000000000010051417222504200214030ustar00rootroot00000000000000 Git Git ? , , Git, , . Git, , , Subversion Perforce. Git' , . Git'. git-cola-3.12.0/test/fixtures/cyrillic-utf-8.txt000066400000000000000000000015751417222504200214470ustar00rootroot00000000000000Основы Git Так что же такое Git в двух словах? Эту часть важно усвоить, поскольку если вы поймёте, что такое Git, и каковы принципы его работы, вам будет гораздо проще пользоваться им эффективно. Изучая Git, постарайтесь освободиться от всего, что вы знали о других СКВ, таких как Subversion или Perforce. В Git'е совсем не такие понятия об информации и работе с ней как в других системах, хотя пользовательский интерфейс очень похож. Знание этих различий защитит вас от путаницы при использовании Git'а. git-cola-3.12.0/test/fixtures/diff-empty.txt000066400000000000000000000000371417222504200207300ustar00rootroot00000000000000@@ -1,2 +0,0 @@ -first -second git-cola-3.12.0/test/fixtures/diff-end.txt000066400000000000000000000021301417222504200203340ustar00rootroot00000000000000@@ -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.12.0/test/fixtures/diff-start.txt000066400000000000000000000000341417222504200207240ustar00rootroot00000000000000@@ -1 +1,4 @@ bar +a +b +c git-cola-3.12.0/test/fixtures/diff.txt000066400000000000000000000047641417222504200176070ustar00rootroot00000000000000@@ -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.12.0/test/fixtures/unicode.txt000066400000000000000000000000111417222504200203020ustar00rootroot00000000000000unicøde git-cola-3.12.0/test/git_test.py000066400000000000000000000253551417222504200164600ustar00rootroot00000000000000"""Test the cola.git module""" # pylint: disable=redefined-outer-name from __future__ import absolute_import, division, print_function, unicode_literals from cola import git from cola.git import STDOUT from .helper import patch # 16k+1 bytes to exhaust any output buffers. BUFFER_SIZE = (16 * 1024) + 1 @patch('cola.git.is_git_dir') def test_find_git_dir_None(is_git_dir): paths = git.find_git_directory(None) assert not is_git_dir.called assert paths.git_dir is None assert paths.git_file is None assert paths.worktree is None @patch('cola.git.is_git_dir') def test_find_git_dir_empty_string(is_git_dir): paths = git.find_git_directory('') assert not is_git_dir.called assert paths.git_dir is None assert paths.git_file is None assert paths.worktree is None @patch('cola.git.is_git_dir') def test_find_git_dir_never_found(is_git_dir): is_git_dir.return_value = False paths = git.find_git_directory('/does/not/exist') assert is_git_dir.called assert paths.git_dir is None assert paths.git_file is None assert paths.worktree is None expect = 8 actual = is_git_dir.call_count assert expect == actual is_git_dir.assert_has_calls( [ (('/does/not/exist',), {}), (('/does/not/exist/.git',), {}), (('/does/not',), {}), (('/does/not/.git',), {}), (('/does',), {}), (('/does/.git',), {}), (('/',), {}), (('/.git',), {}), ] ) @patch('cola.git.is_git_dir') def test_find_git_dir_found_right_away(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) assert is_git_dir.called assert git_dir == paths.git_dir assert paths.git_file is None assert worktree == paths.worktree @patch('cola.git.is_git_dir') def test_find_git_does_discovery(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') assert git_dir == paths.git_dir assert paths.git_file is None assert 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(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') assert git_dir == paths.git_dir assert git_file == paths.git_file assert worktree == paths.worktree expect = 6 actual = is_git_dir.call_count assert expect == actual is_git_dir.assert_has_calls( [ (('/the/root/sub/dir',), {}), (('/the/root/sub/dir/.git',), {}), (('/the/root/sub',), {}), (('/the/root/sub/.git',), {}), (('/the/root',), {}), (('/the/root/.git',), {}), ] ) 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(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') assert paths.git_dir is None assert paths.git_file is None assert paths.worktree is None assert is_git_dir.call_count == 4 is_git_dir.assert_has_calls( [ (('/ceiling/sub/dir',), {}), (('/ceiling/sub/dir/.git',), {}), (('/ceiling/sub',), {}), (('/ceiling/sub/.git',), {}), ] ) @patch('cola.core.islink') @patch('cola.core.isdir') @patch('cola.core.isfile') def test_is_git_dir_finds_linked_repository(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 assert git.is_git_dir('/foo/.git/worktrees/foo') assert git.is_git_dir('/foo/.git') @patch('cola.core.getenv') @patch('cola.git.is_git_dir') def test_find_git_worktree_from_GIT_DIR(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) assert is_git_dir.called assert git_dir == paths.git_dir assert paths.git_file is None assert worktree == paths.worktree @patch('cola.git.is_git_dir') def test_finds_no_worktree_from_bare_repo(is_git_dir): git_dir = '/repos/bare.git' worktree = None is_git_dir.return_value = True paths = git.find_git_directory(git_dir) assert is_git_dir.called assert git_dir == paths.git_dir assert paths.git_file is None assert worktree == paths.worktree @patch('cola.core.getenv') @patch('cola.git.is_git_dir') def test_find_git_directory_uses_GIT_WORK_TREE(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) assert is_git_dir.called assert git_dir == paths.git_dir assert paths.git_file is None assert worktree == paths.worktree @patch('cola.core.getenv') @patch('cola.git.is_git_dir') def test_uses_cwd_for_worktree_with_GIT_DIR(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) assert is_git_dir.called assert getenv.called assert git_dir == paths.git_dir assert paths.git_file is None assert worktree == paths.worktree def test_transform_kwargs_empty(): expect = [] actual = git.transform_kwargs(foo=None, bar=False) assert expect == actual def test_transform_kwargs_single_dash_from_True(): """Single dash for one-character True""" expect = ['-a'] actual = git.transform_kwargs(a=True) assert expect == actual def test_transform_kwargs_no_single_dash_from_False(): """No single-dash for False""" expect = [] actual = git.transform_kwargs(a=False) assert expect == actual def test_transform_kwargs_double_dash_from_True(): """Double-dash for longer True""" expect = ['--abc'] actual = git.transform_kwargs(abc=True) assert expect == actual def test_transform_kwargs_no_double_dash_from_True(): """No double-dash for False""" expect = [] actual = git.transform_kwargs(abc=False) assert expect == actual def test_transform_kwargs_single_dash_int(): expect = ['-a1'] actual = git.transform_kwargs(a=1) assert expect == actual def test_transform_kwargs_double_dash_int(): expect = ['--abc=1'] actual = git.transform_kwargs(abc=1) assert expect == actual def test_transform_kwargs_single_dash_float(): expect = ['-a1.5'] actual = git.transform_kwargs(a=1.5) assert expect == actual def test_transform_kwargs_double_dash_float(): expect = ['--abc=1.5'] actual = git.transform_kwargs(abc=1.5) assert expect == actual def test_transform_kwargs_single_dash_string(): expect = ['-abc'] actual = git.transform_kwargs(a='bc') assert expect == actual def test_transform_double_single_dash_string(): expect = ['--abc=def'] actual = git.transform_kwargs(abc='def') assert expect == actual def test_version(): """Test running 'git version'""" gitcmd = git.Git() version = gitcmd.version()[STDOUT] assert version.startswith('git version') def test_stdout(): """Test overflowing the stdout buffer""" # Write to stdout only code = ( r'import sys;' r'value = "\0" * %d;' r'sys.stdout.write(value);' ) % BUFFER_SIZE status, out, err = git.Git.execute(['python', '-c', code], _raw=True) assert status == 0 expect = BUFFER_SIZE actual = len(out) assert expect == actual expect = 0 actual = len(err) assert expect == actual def test_stderr(): """Test that stderr is seen""" # Write to stderr and capture it code = ( r'import sys;' r'value = "\0" * %d;' r'sys.stderr.write(value);' ) % BUFFER_SIZE status, out, err = git.Git.execute(['python', '-c', code], _raw=True) expect = 0 actual = status assert expect == actual expect = 0 actual = len(out) assert expect == actual expect = BUFFER_SIZE actual = len(err) assert expect == actual def test_stdout_and_stderr(): """Test ignoring stderr when stdout+stderr are provided (v2)""" # Write to stdout and stderr but only capture stdout code = ( r'import sys;' r'value = "\0" * %d;' r'sys.stdout.write(value);' r'sys.stderr.write(value);' ) % BUFFER_SIZE status, out, err = git.Git.execute(['python', '-c', code], _raw=True) expect = 0 actual = status assert expect == actual expect = BUFFER_SIZE actual = len(out) assert expect == actual actual = len(err) assert expect == actual def test_it_doesnt_deadlock(): """Test that we don't deadlock with both stderr and stdout""" code = ( r'import sys;' r'value = "\0" * %d;' r'sys.stderr.write(value);' r'sys.stdout.write(value);' ) % BUFFER_SIZE status, out, err = git.Git.execute(['python', '-c', code], _raw=True) expect = 0 actual = status assert expect == actual expect = '\0' * BUFFER_SIZE actual = out assert expect == actual actual = err assert expect == actual git-cola-3.12.0/test/gitcfg_test.py000066400000000000000000000110501417222504200171230ustar00rootroot00000000000000"""Test the cola.gitcfg module.""" # pylint: disable=redefined-outer-name from __future__ import absolute_import, division, print_function, unicode_literals from . import helper from .helper import app_context # These assertions make flake8 happy. It considers them unused imports otherwise. assert app_context is not None def assert_color(context, expect, git_value, key='test', default=None): """Helper function for testing color values""" helper.run_git('config', 'cola.color.%s' % key, git_value) context.cfg.reset() actual = context.cfg.color(key, default) assert expect == actual def test_string(app_context): """Test string values in get().""" helper.run_git('config', 'test.value', 'test') assert app_context.cfg.get('test.value') == 'test' def test_int(app_context): """Test int values in get().""" helper.run_git('config', 'test.int', '42') expect = 42 actual = app_context.cfg.get('test.int') assert expect == actual def test_true(app_context): """Test bool values in get().""" helper.run_git('config', 'test.bool', 'true') assert app_context.cfg.get('test.bool') is True def test_false(app_context): helper.run_git('config', 'test.bool', 'false') assert app_context.cfg.get('test.bool') is False def test_yes(app_context): helper.run_git('config', 'test.bool', 'yes') assert app_context.cfg.get('test.bool') is True def test_no(app_context): helper.run_git('config', 'test.bool', 'no') assert app_context.cfg.get('test.bool') is False def test_bool_no_value(app_context): helper.append_file('.git/config', '[test]\n') helper.append_file('.git/config', '\tbool\n') assert app_context.cfg.get('test.bool') is True def test_empty_value(app_context): helper.append_file('.git/config', '[test]\n') helper.append_file('.git/config', '\tvalue = \n') assert app_context.cfg.get('test.value') == '' def test_default(app_context): """Test default values in get().""" assert app_context.cfg.get('does.not.exist') is None assert app_context.cfg.get('does.not.exist', default=42) == 42 def test_get_all(app_context): """Test getting multiple values in get_all()""" helper.run_git('config', '--add', 'test.value', 'abc') helper.run_git('config', '--add', 'test.value', 'def') expect = ['abc', 'def'] assert expect == app_context.cfg.get_all('test.value') def test_color_rrggbb(app_context): assert_color(app_context, (0xAA, 0xBB, 0xCC), 'aabbcc') assert_color(app_context, (0xAA, 0xBB, 0xCC), '#aabbcc') def test_color_int(app_context): assert_color(app_context, (0x10, 0x20, 0x30), '102030') assert_color(app_context, (0x10, 0x20, 0x30), '#102030') def test_guitool_opts(app_context): helper.run_git('config', 'guitool.hello world.cmd', 'hello world') opts = app_context.cfg.get_guitool_opts('hello world') expect = 'hello world' actual = opts['cmd'] assert expect == actual def test_guitool_names(app_context): helper.run_git('config', 'guitool.hello meow.cmd', 'hello meow') names = app_context.cfg.get_guitool_names() assert 'hello meow' in names def test_guitool_names_mixed_case(app_context): helper.run_git('config', 'guitool.Meow Cat.cmd', 'cat hello') names = app_context.cfg.get_guitool_names() assert 'Meow Cat' in names def test_find_mixed_case(app_context): helper.run_git('config', 'guitool.Meow Cat.cmd', 'cat hello') opts = app_context.cfg.find('guitool.Meow Cat.*') assert opts['guitool.Meow Cat.cmd'] == 'cat hello' def test_guitool_opts_mixed_case(app_context): helper.run_git('config', 'guitool.Meow Cat.cmd', 'cat hello') opts = app_context.cfg.get_guitool_opts('Meow Cat') assert opts['cmd'] == 'cat hello' def test_hooks(app_context): helper.run_git('config', 'core.hooksPath', '/test/hooks') expect = '/test/hooks' actual = app_context.cfg.hooks() assert expect == actual def test_hooks_lowercase(app_context): helper.run_git('config', 'core.hookspath', '/test/hooks-lowercase') expect = '/test/hooks-lowercase' actual = app_context.cfg.hooks() assert expect == actual def test_hooks_path(app_context): helper.run_git('config', 'core.hooksPath', '/test/hooks') expect = '/test/hooks/example' actual = app_context.cfg.hooks_path('example') assert expect == actual def test_hooks_path_lowercase(app_context): helper.run_git('config', 'core.hookspath', '/test/hooks-lowercase') expect = '/test/hooks-lowercase/example' actual = app_context.cfg.hooks_path('example') assert expect == actual git-cola-3.12.0/test/gitcmds_test.py000066400000000000000000000162271417222504200173250ustar00rootroot00000000000000"""Test the cola.gitcmds module""" # pylint: disable=redefined-outer-name from __future__ import absolute_import, division, print_function, unicode_literals import os from cola import gitcmds from cola.widgets.remote import get_default_remote from . import helper from .helper import app_context # These assertions make flake8 happy. It considers them unused imports otherwise. assert app_context is not None def test_currentbranch(app_context): """Test current_branch().""" assert gitcmds.current_branch(app_context) == 'main' def test_branch_list_local(app_context): """Test branch_list(remote=False).""" helper.commit_files() expect = ['main'] actual = gitcmds.branch_list(app_context, remote=False) assert expect == actual def test_branch_list_remote(app_context): """Test branch_list(remote=False).""" expect = [] actual = gitcmds.branch_list(app_context, remote=True) assert expect == actual helper.commit_files() helper.run_git('remote', 'add', 'origin', '.') helper.run_git('fetch', 'origin') expect = ['origin/main'] actual = gitcmds.branch_list(app_context, remote=True) assert expect == actual helper.run_git('remote', 'rm', 'origin') expect = [] actual = gitcmds.branch_list(app_context, remote=True) assert expect == actual def test_upstream_remote(app_context): """Test getting the configured upstream remote""" assert gitcmds.upstream_remote(app_context) is None helper.run_git('config', 'branch.main.remote', 'test') app_context.cfg.reset() assert gitcmds.upstream_remote(app_context) == 'test' def test_default_push(app_context): """Test getting what default branch to push to""" # no default push, no remote branch configured assert get_default_remote(app_context) == 'origin' # default push set, no remote branch configured helper.run_git('config', 'remote.pushDefault', 'test') app_context.cfg.reset() assert get_default_remote(app_context) == 'test' # default push set, default remote branch configured helper.run_git('config', 'branch.main.remote', 'test2') app_context.cfg.reset() assert get_default_remote(app_context) == 'test2' # default push set, default remote branch configured, on different branch helper.run_git('checkout', '-b', 'other-branch') assert get_default_remote(app_context) == 'test' def test_tracked_branch(app_context): """Test tracked_branch().""" assert gitcmds.tracked_branch(app_context) is None helper.run_git('config', 'branch.main.remote', 'test') helper.run_git('config', 'branch.main.merge', 'refs/heads/main') app_context.cfg.reset() assert gitcmds.tracked_branch(app_context) == 'test/main' def test_tracked_branch_other(app_context): """Test tracked_branch('other')""" assert gitcmds.tracked_branch(app_context, 'other') is None helper.run_git('config', 'branch.other.remote', 'test') helper.run_git('config', 'branch.other.merge', 'refs/heads/other/branch') app_context.cfg.reset() assert gitcmds.tracked_branch(app_context, 'other') == 'test/other/branch' def test_untracked_files(app_context): """Test untracked_files().""" helper.touch('C', 'D', 'E') assert gitcmds.untracked_files(app_context) == ['C', 'D', 'E'] def test_all_files(app_context): helper.touch('other-file') all_files = gitcmds.all_files(app_context) assert 'A' in all_files assert 'B' in all_files assert 'other-file' in all_files def test_tag_list(app_context): """Test tag_list()""" helper.commit_files() helper.run_git('tag', 'a') helper.run_git('tag', 'b') helper.run_git('tag', 'c') assert gitcmds.tag_list(app_context) == ['c', 'b', 'a'] def test_merge_message_path(app_context): """Test merge_message_path().""" helper.touch('.git/SQUASH_MSG') assert gitcmds.merge_message_path(app_context) == os.path.abspath('.git/SQUASH_MSG') helper.touch('.git/MERGE_MSG') assert gitcmds.merge_message_path(app_context) == os.path.abspath('.git/MERGE_MSG') os.unlink(gitcmds.merge_message_path(app_context)) assert gitcmds.merge_message_path(app_context) == os.path.abspath('.git/SQUASH_MSG') os.unlink(gitcmds.merge_message_path(app_context)) assert gitcmds.merge_message_path(app_context) is None def test_all_refs(app_context): helper.commit_files() helper.run_git('branch', 'a') helper.run_git('branch', 'b') helper.run_git('branch', 'c') helper.run_git('tag', 'd') helper.run_git('tag', 'e') helper.run_git('tag', 'f') helper.run_git('remote', 'add', 'origin', '.') helper.run_git('fetch', 'origin') refs = gitcmds.all_refs(app_context) assert refs == [ 'a', 'b', 'c', 'main', 'origin/a', 'origin/b', 'origin/c', 'origin/main', 'f', 'e', 'd', ] def test_all_refs_split(app_context): helper.commit_files() helper.run_git('branch', 'a') helper.run_git('branch', 'b') helper.run_git('branch', 'c') helper.run_git('tag', 'd') helper.run_git('tag', 'e') helper.run_git('tag', 'f') helper.run_git('remote', 'add', 'origin', '.') helper.run_git('fetch', 'origin') local, remote, tags = gitcmds.all_refs(app_context, split=True) assert local == ['a', 'b', 'c', 'main'] assert remote == ['origin/a', 'origin/b', 'origin/c', 'origin/main'] assert tags == ['f', 'e', 'd'] def test_binary_files(app_context): # Create a binary file and ensure that it's detected as binary. with open('binary-file.txt', 'wb') as f: f.write(b'hello\0world\n') assert gitcmds.is_binary(app_context, 'binary-file.txt') # Create a text file and ensure that it's not detected as binary. with open('text-file.txt', 'w') as f: f.write('hello world\n') assert not gitcmds.is_binary(app_context, 'text-file.txt') # Create a .gitattributes file and mark text-file.txt as binary. app_context.cfg.reset() with open('.gitattributes', 'w') as f: f.write('text-file.txt binary\n') assert gitcmds.is_binary(app_context, 'text-file.txt') # Remove the "binary" attribute using "-binary" from binary-file.txt. # Ensure that we do not flag this file as binary. with open('.gitattributes', 'w') as f: f.write('binary-file.txt -binary\n') assert not gitcmds.is_binary(app_context, 'binary-file.txt') def test_is_valid_ref(app_context): """Verify the behavior of is_valid_ref()""" # We are initially in a "git init" state. HEAD must be invalid. assert not gitcmds.is_valid_ref(app_context, 'HEAD') # Create the first commit onto the "test" branch. app_context.git.symbolic_ref('HEAD', 'refs/heads/test') app_context.git.commit(m='initial commit') assert gitcmds.is_valid_ref(app_context, 'HEAD') assert gitcmds.is_valid_ref(app_context, 'test') assert gitcmds.is_valid_ref(app_context, 'refs/heads/test') def test_diff_helper(app_context): helper.commit_files() with open('A', 'w') as f: f.write('A change\n') helper.run_git('add', 'A') expect = '+A change\n' actual = gitcmds.diff_helper(app_context, ref='HEAD', cached=True) assert expect in actual git-cola-3.12.0/test/gitops_test.py000066400000000000000000000017271417222504200171770ustar00rootroot00000000000000"""Tests basic git operations: commit, log, config""" # pylint: disable=redefined-outer-name from __future__ import absolute_import, division, print_function, unicode_literals from . import helper from .helper import app_context # These assertions make flake8 happy. It considers them unused imports otherwise. assert app_context is not None def test_git_commit(app_context): """Test running 'git commit' via cola.git""" helper.write_file('A', 'A') helper.write_file('B', 'B') helper.run_git('add', 'A', 'B') app_context.git.commit(m='initial commit') log = helper.run_git('-c', 'log.showsignature=false', 'log', '--pretty=oneline') expect = 1 actual = len(log.splitlines()) assert expect == actual def test_git_config(app_context): """Test cola.git.config()""" helper.run_git('config', 'section.key', 'value') expect = (0, 'value', '') actual = app_context.git.config('section.key', get=True) assert expect == actual git-cola-3.12.0/test/gravatar_test.py000066400000000000000000000010161417222504200174700ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, unicode_literals from cola import gravatar from cola.compat import ustr def test_url_for_email_(): 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) assert expect == actual assert isinstance(actual, ustr) git-cola-3.12.0/test/helper.py000066400000000000000000000056521417222504200161130ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, unicode_literals import os import shutil import stat import tempfile import pytest try: from unittest.mock import Mock, patch # noqa pylint: disable=unused-import except ImportError: from mock import Mock, patch # noqa pylint: disable=unused-import 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) # 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') def touch(*paths): """Open and close a file to either create it or update its mtime""" for path in paths: open(path, 'a').close() def write_file(path, content): """Write content to the specified file path""" with open(path, 'w') as f: f.write(content) def append_file(path, content): """Open a file in append mode and write content to it""" with open(path, 'a') as f: f.write(content) def run_git(*args): """Run git with the specified arguments""" status, out, _ = core.run_command(['git'] + list(args)) assert status == 0 return out def commit_files(): """Commit the current state as the initial commit""" run_git('commit', '-m', 'initial commit') def initialize_repo(): """Initialize a git repository in the current directory""" run_git('init') run_git('symbolic-ref', 'HEAD', 'refs/heads/main') run_git('config', '--local', 'user.name', 'Your Name') run_git('config', '--local', 'user.email', 'you@example.com') run_git('config', '--local', 'commit.gpgsign', 'false') run_git('config', '--local', 'tag.gpgsign', 'false') touch('A', 'B') run_git('add', 'A', 'B') @pytest.fixture def app_context(): """Create a repository in a temporary directory and return its ApplicationContext""" tmp_directory = tempfile.mkdtemp('-cola-test') current_directory = os.getcwd() os.chdir(tmp_directory) initialize_repo() context = Mock() context.git = git.create() context.git.set_worktree(core.getcwd()) context.cfg = gitcfg.create(context) context.model = main.create(context) context.cfg.reset() gitcmds.reset() yield context os.chdir(current_directory) shutil.rmtree(tmp_directory, onerror=remove_readonly) git-cola-3.12.0/test/i18n_test.py000066400000000000000000000032131417222504200164410ustar00rootroot00000000000000"""Tests for the i18n translation module""" from __future__ import absolute_import, division, print_function, unicode_literals import pytest from cola import i18n from cola.i18n import N_ from cola.compat import uchr @pytest.fixture(autouse=True) def i18n_context(): """Perform cleanup/teardown of the i18n module""" yield i18n.uninstall() def test_translates_noun(): """Test that strings with @@noun are translated""" i18n.install('ja_JP') expect = uchr(0x30B3) + uchr(0x30DF) + uchr(0x30C3) + uchr(0x30C8) actual = N_('Commit@@verb') assert expect == actual def test_translates_verb(): """Test that strings with @@verb are translated""" i18n.install('de_DE') expect = 'Commit aufnehmen' actual = N_('Commit@@verb') assert expect == actual def test_translates_english_noun(): """Test that English strings with @@noun are properly handled""" i18n.install('en_US.UTF-8') expect = 'Commit' actual = N_('Commit@@noun') assert expect == actual def test_translates_english_verb(): """Test that English strings with @@verb are properly handled""" i18n.install('en_US.UTF-8') expect = 'Commit' actual = N_('Commit@@verb') assert expect == actual def test_translates_random_english(): """Test that random English strings are passed through as-is""" i18n.install('en_US.UTF-8') expect = 'Random' actual = N_('Random') assert expect == actual def test_translate_push_pull_french(): i18n.install('fr_FR') expect = 'Tirer' actual = N_('Pull') assert expect == actual expect = 'Pousser' actual = N_('Push') assert expect == actual git-cola-3.12.0/test/icons_test.py000066400000000000000000000006621417222504200170020ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, unicode_literals from cola import compat from cola import core from cola import icons def test_from_filename_unicode(): filename = compat.uchr(0x400) + '.py' expect = 'file-code.svg' actual = icons.basename_from_filename(filename) assert expect == actual actual = icons.basename_from_filename(core.encode(filename)) assert expect == actual git-cola-3.12.0/test/main_model_test.py000066400000000000000000000144301417222504200177710ustar00rootroot00000000000000# pylint: disable=redefined-outer-name from __future__ import absolute_import, division, print_function, unicode_literals import os import pytest from cola import core from cola import git from cola.models import main from . import helper from .helper import app_context from .helper import Mock # These assertions make flake8 happy. It considers them unused imports otherwise. assert app_context is not None REMOTE = 'server' LOCAL_BRANCH = 'local' REMOTE_BRANCH = 'remote' @pytest.fixture def mock_context(): """Return a Mock context for testing""" context = Mock() context.git = git.create() return context def test_project(app_context): """Test the 'project' attribute.""" project = os.path.basename(core.getcwd()) app_context.model.set_worktree(core.getcwd()) assert app_context.model.project == project def test_local_branches(app_context): """Test the 'local_branches' attribute.""" helper.commit_files() app_context.model.update_status() assert app_context.model.local_branches == ['main'] def test_remote_branches(app_context): """Test the 'remote_branches' attribute.""" app_context.model.update_status() assert app_context.model.remote_branches == [] helper.commit_files() helper.run_git('remote', 'add', 'origin', '.') helper.run_git('fetch', 'origin') app_context.model.update_status() assert app_context.model.remote_branches == ['origin/main'] def test_modified(app_context): """Test the 'modified' attribute.""" helper.write_file('A', 'change') app_context.model.update_status() assert app_context.model.modified == ['A'] def test_unstaged(app_context): """Test the 'unstaged' attribute.""" helper.write_file('A', 'change') helper.write_file('C', 'C') app_context.model.update_status() assert app_context.model.unstaged == ['A', 'C'] def test_untracked(app_context): """Test the 'untracked' attribute.""" helper.write_file('C', 'C') app_context.model.update_status() assert app_context.model.untracked == ['C'] def test_remotes(app_context): """Test the 'remote' attribute.""" helper.run_git('remote', 'add', 'origin', '.') app_context.model.update_status() assert app_context.model.remotes == ['origin'] def test_currentbranch(app_context): """Test the 'currentbranch' attribute.""" helper.run_git('checkout', '-b', 'test') app_context.model.update_status() assert app_context.model.currentbranch == 'test' def test_tags(app_context): """Test the 'tags' attribute.""" helper.commit_files() helper.run_git('tag', 'test') app_context.model.update_status() assert app_context.model.tags == ['test'] def test_remote_args_fetch(mock_context): # Fetch (args, kwargs) = main.remote_args( mock_context, REMOTE, local_branch=LOCAL_BRANCH, remote_branch=REMOTE_BRANCH, ) assert args == [REMOTE, 'remote:local'] assert kwargs['verbose'] assert 'tags' not in kwargs assert 'rebase' not in kwargs def test_remote_args_fetch_tags(mock_context): # Fetch tags (args, kwargs) = main.remote_args( mock_context, REMOTE, tags=True, local_branch=LOCAL_BRANCH, remote_branch=REMOTE_BRANCH, ) assert args == [REMOTE, 'remote:local'] assert kwargs['verbose'] assert kwargs['tags'] assert 'rebase' not in kwargs def test_remote_args_pull(mock_context): # Pull (args, kwargs) = main.remote_args( mock_context, REMOTE, pull=True, local_branch='', remote_branch=REMOTE_BRANCH, ) assert args == [REMOTE, 'remote'] assert kwargs['verbose'] assert 'rebase' not in kwargs assert 'tags' not in kwargs def test_remote_args_pull_rebase(mock_context): # Rebasing pull (args, kwargs) = main.remote_args( mock_context, REMOTE, pull=True, rebase=True, local_branch='', remote_branch=REMOTE_BRANCH, ) assert args == [REMOTE, 'remote'] assert kwargs['verbose'] assert kwargs['rebase'] assert 'tags' not in kwargs def test_remote_args_push(mock_context): # Push, swap local and remote (args, kwargs) = main.remote_args( mock_context, REMOTE, local_branch=REMOTE_BRANCH, remote_branch=LOCAL_BRANCH, ) assert args == [REMOTE, 'local:remote'] assert kwargs['verbose'] assert 'tags' not in kwargs assert 'rebase' not in kwargs def test_remote_args_push_tags(mock_context): # Push, swap local and remote (args, kwargs) = main.remote_args( mock_context, REMOTE, tags=True, local_branch=REMOTE_BRANCH, remote_branch=LOCAL_BRANCH, ) assert args == [REMOTE, 'local:remote'] assert kwargs['verbose'] assert kwargs['tags'] assert 'rebase' not in kwargs def test_remote_args_push_same_remote_and_local(mock_context): (args, kwargs) = main.remote_args( mock_context, REMOTE, tags=True, local_branch=LOCAL_BRANCH, remote_branch=LOCAL_BRANCH, push=True, ) assert args == [REMOTE, 'local'] assert kwargs['verbose'] assert kwargs['tags'] assert 'rebase' not in kwargs def test_remote_args_push_set_upstream(mock_context): (args, kwargs) = main.remote_args( mock_context, REMOTE, tags=True, local_branch=LOCAL_BRANCH, remote_branch=LOCAL_BRANCH, push=True, set_upstream=True, ) assert args == [REMOTE, 'local'] assert kwargs['verbose'] assert kwargs['tags'] assert kwargs['set_upstream'] assert 'rebase' not in kwargs def test_remote_args_rebase_only(mock_context): (_, kwargs) = main.remote_args( mock_context, REMOTE, pull=True, rebase=True, ff_only=True ) assert kwargs['rebase'] assert 'ff_only' not in kwargs def test_run_remote_action(mock_context): def passthrough(*args, **kwargs): return (args, kwargs) (args, kwargs) = main.run_remote_action( mock_context, passthrough, REMOTE, local_branch=LOCAL_BRANCH, remote_branch=REMOTE_BRANCH, ) assert args == (REMOTE, 'remote:local') assert kwargs['verbose'] assert 'tags' not in kwargs assert 'rebase' not in kwargs git-cola-3.12.0/test/models_selection_test.py000066400000000000000000000005741417222504200212210ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, unicode_literals from cola.models import selection from .helper import Mock def test_union(): t = 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) assert expect == actual git-cola-3.12.0/test/resources_test.py000066400000000000000000000023161417222504200176770ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, unicode_literals from cola import resources from . import helper from .helper import patch @patch('cola.resources.compat') @patch('cola.resources.get_prefix') def test_command_unix(mock_prefix, mock_compat): """Test the behavior of resources.command() on unix platforms""" mock_compat.WIN32 = False mock_prefix.return_value = helper.fixture() expect = helper.fixture('bin', 'bare-cmd') actual = resources.command('bare-cmd') assert expect == actual expect = helper.fixture('bin', 'exe-cmd') actual = resources.command('exe-cmd') assert expect == actual @patch('cola.resources.compat') @patch('cola.resources.get_prefix') def test_command_win32(mock_prefix, mock_compat): """Test the behavior of resources.command() on unix platforms""" mock_compat.WIN32 = True mock_prefix.return_value = helper.fixture() expect = helper.fixture('bin', 'bare-cmd') actual = resources.command('bare-cmd') assert expect == actual # Windows will return exe-cmd.exe because the path exists. expect = helper.fixture('bin', 'exe-cmd.exe') actual = resources.command('exe-cmd') assert expect == actual git-cola-3.12.0/test/settings_test.py000066400000000000000000000051311417222504200175230ustar00rootroot00000000000000"""Test the cola.settings module""" # pylint: disable=redefined-outer-name from __future__ import absolute_import, division, print_function, unicode_literals import os import pytest from cola.settings import Settings from . import helper @pytest.fixture(autouse=True) def settings_fixture(): """Provide Settings that save into a temporary location to all tests""" filename = helper.tmp_path('settings') Settings.config_path = filename yield Settings.read() if os.path.exists(filename): os.remove(filename) def test_gui_save_restore(settings_fixture): """Test saving and restoring gui state""" settings = settings_fixture settings.gui_state['test-gui'] = {'foo': 'bar'} settings.save() settings = Settings.read() state = settings.gui_state.get('test-gui', {}) assert 'foo' in state assert state['foo'] == 'bar' def test_bookmarks_save_restore(): """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 = Settings.read() settings.add_bookmark(bookmark['path'], bookmark['name']) settings.save() settings = Settings.read(verify=mock_verify) bookmarks = settings.bookmarks assert len(settings.bookmarks) == 1 assert bookmark in bookmarks settings.remove_bookmark(bookmark['path'], bookmark['name']) bookmarks = settings.bookmarks expect = 0 actual = len(bookmarks) assert expect == actual assert bookmark not in bookmarks def test_bookmarks_removes_missing_entries(): """Test that missing entries are removed after a reload""" # verify returns False so all entries will be removed. bookmark = {'path': '.', 'name': 'does-not-exist'} settings = Settings.read(verify=lambda x: False) settings.add_bookmark(bookmark['path'], bookmark['name']) settings.remove_missing_bookmarks() settings.save() settings = Settings.read() bookmarks = settings.bookmarks expect = 0 actual = len(bookmarks) assert expect == actual assert bookmark not in bookmarks def test_rename_bookmark(): settings = Settings.read() 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] assert expect == actual git-cola-3.12.0/test/short_branch_overlapping.sh000077500000000000000000000037241417222504200217010ustar00rootroot00000000000000#!/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 git symbolic-ref HEAD refs/heads/main # Tags are used to get difference between row and generation values. # Branches main & 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.12.0/test/spellcheck_test.py000066400000000000000000000010611417222504200177760ustar00rootroot00000000000000from __future__ import absolute_import, division, print_function, unicode_literals from cola import compat from cola import spellcheck from . import helper def test_spellcheck_generator(): check = spellcheck.NorvigSpellCheck() assert_spellcheck(check) def test_spellcheck_unicode(): path = helper.fixture('unicode.txt') check = spellcheck.NorvigSpellCheck(cracklib=path) assert_spellcheck(check) def assert_spellcheck(check): for word in check.read(): assert word is not None assert isinstance(word, compat.ustr) git-cola-3.12.0/test/textwrap_test.py000066400000000000000000000116201417222504200175410ustar00rootroot00000000000000"""Test the textwrap module""" # pylint: disable=redefined-outer-name from __future__ import absolute_import, division, print_function, unicode_literals import pytest from cola import textwrap class WordWrapDefaults(object): def __init__(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 ) @pytest.fixture def wordwrap(): """Provide default word wrap options for tests""" return WordWrapDefaults() def test_word_wrap(wordwrap): wordwrap.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""" assert expect == wordwrap.wrap(text) def test_word_wrap_dashes(wordwrap): wordwrap.limit = 4 text = '123-5' expect = '123-5' assert expect == wordwrap.wrap(text) def test_word_wrap_leading_spaces(wordwrap): wordwrap.limit = 4 expect = '1234\n5' assert expect == wordwrap.wrap('1234 5') assert expect == wordwrap.wrap('1234 5') assert expect == wordwrap.wrap('1234 5') assert expect == wordwrap.wrap('1234 5') assert expect == wordwrap.wrap('1234 5') expect = '123\n4' assert expect == wordwrap.wrap('123 4') assert expect == wordwrap.wrap('123 4') assert expect == wordwrap.wrap('123 4') assert expect == wordwrap.wrap('123 4') assert expect == wordwrap.wrap('123 4') def test_word_wrap_double_dashes(wordwrap): wordwrap.limit = 4 text = '12--5' expect = '12--\n5' actual = wordwrap.wrap(text, break_on_hyphens=True) assert expect == actual expect = '12--5' actual = wordwrap.wrap(text, break_on_hyphens=False) assert expect == actual def test_word_wrap_many_lines(wordwrap): wordwrap.limit = 2 text = """ aa bb cc dd""" expect = """ aa bb cc dd""" actual = wordwrap.wrap(text) assert expect == actual def test_word_python_code(wordwrap): wordwrap.limit = 78 text = """ if True: print "hello world" else: print "hello world" """ expect = text actual = wordwrap.wrap(text) assert expect == actual def test_word_wrap_spaces(wordwrap): wordwrap.limit = 2 text = ' ' * 6 expect = '' actual = wordwrap.wrap(text) assert expect == actual def test_word_wrap_special_tag(wordwrap): wordwrap.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 """ actual = wordwrap.wrap(text) assert expect == actual def test_word_wrap_space_at_start_of_wrap(wordwrap): 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""" wordwrap.limit = 20 actual = wordwrap.wrap(inputs) assert expect == actual def test_word_wrap_keeps_tabs_at_start(wordwrap): inputs = """\tfirst line\n\n\tsecond line""" expect = """\tfirst line\n\n\tsecond line""" wordwrap.limit = 20 actual = wordwrap.wrap(inputs) assert expect == actual def test_word_wrap_keeps_twospace_indents(wordwrap): inputs = """first line\n\n* branch:\n line1\n line2\n""" expect = """first line\n\n* branch:\n line1\n line2\n""" wordwrap.limit = 20 actual = wordwrap.wrap(inputs) assert expect == actual def test_word_wrap_ranges(): text = 'a bb ccc dddd\neeeee' expect = 'a\nbb\nccc\ndddd\neeeee' actual = textwrap.word_wrap(text, 8, 2) assert expect == actual expect = 'a bb\nccc\ndddd\neeeee' actual = textwrap.word_wrap(text, 8, 4) assert expect == actual text = 'a bb ccc dddd\n\teeeee' expect = 'a bb\nccc\ndddd\n\t\neeeee' actual = textwrap.word_wrap(text, 8, 4) assert expect == actual def test_triplets(): text = 'xx0 xx1 xx2 xx3 xx4 xx5 xx6 xx7 xx8 xx9 xxa xxb' expect = 'xx0 xx1 xx2 xx3 xx4 xx5 xx6\nxx7 xx8 xx9 xxa xxb' actual = textwrap.word_wrap(text, 8, 27) assert expect == actual expect = 'xx0 xx1 xx2 xx3 xx4 xx5\nxx6 xx7 xx8 xx9 xxa xxb' actual = textwrap.word_wrap(text, 8, 26) assert expect == actual actual = textwrap.word_wrap(text, 8, 25) assert expect == actual actual = textwrap.word_wrap(text, 8, 24) assert expect == actual actual = textwrap.word_wrap(text, 8, 23) assert expect == actual expect = 'xx0 xx1 xx2 xx3 xx4\nxx5 xx6 xx7 xx8 xx9\nxxa xxb' actual = textwrap.word_wrap(text, 8, 22) assert expect == actual git-cola-3.12.0/test/tmp/000077500000000000000000000000001417222504200150525ustar00rootroot00000000000000git-cola-3.12.0/test/tmp/.gitignore000066400000000000000000000000001417222504200170300ustar00rootroot00000000000000git-cola-3.12.0/test/utils_test.py000066400000000000000000000054631417222504200170330ustar00rootroot00000000000000"""Tests the cola.utils module.""" from __future__ import absolute_import, division, print_function, unicode_literals import os from cola import core from cola import utils def test_basename(): """Test the utils.basename function.""" assert utils.basename('bar') == 'bar' assert utils.basename('/bar') == 'bar' assert utils.basename('/bar ') == 'bar ' assert utils.basename('foo/bar') == 'bar' assert utils.basename('/foo/bar') == 'bar' assert utils.basename('foo/foo/bar') == 'bar' assert utils.basename('/foo/foo/bar') == 'bar' assert utils.basename('/foo/foo//bar') == 'bar' assert utils.basename('////foo //foo//bar') == 'bar' def test_dirname(): """Test the utils.dirname function.""" assert utils.dirname('bar') == '' assert utils.dirname('/bar') == '' assert utils.dirname('//bar') == '' assert utils.dirname('///bar') == '' assert utils.dirname('foo/bar') == 'foo' assert utils.dirname('foo//bar') == 'foo' assert utils.dirname('foo /bar') == 'foo ' assert utils.dirname('/foo//bar') == '/foo' assert utils.dirname('/foo /bar') == '/foo ' assert utils.dirname('//foo//bar') == '/foo' assert utils.dirname('///foo///bar') == '/foo' def test_add_parents(): """Test the utils.add_parents() function.""" paths = set(['foo///bar///baz']) path_set = utils.add_parents(paths) assert 'foo/bar/baz' in path_set assert 'foo/bar' in path_set assert 'foo' in path_set assert 'foo///bar///baz' not in path_set # Ensure that the original set is unchanged expect = set(['foo///bar///baz']) assert expect == paths def test_tmp_filename_gives_good_file(): first = utils.tmp_filename('test') second = utils.tmp_filename('test') assert not core.exists(first) assert not core.exists(second) assert first != second assert os.path.basename(first).startswith('git-cola-test') assert os.path.basename(second).startswith('git-cola-test') def test_strip_one_abspath(): expect = 'bin/git' actual = utils.strip_one('/usr/bin/git') assert expect == actual def test_strip_one_relpath(): expect = 'git' actual = utils.strip_one('bin/git') assert expect == actual def test_strip_one_nested_relpath(): expect = 'bin/git' actual = utils.strip_one('local/bin/git') assert expect == actual def test_strip_one_basename(): expect = 'git' actual = utils.strip_one('git') assert expect == actual def test_select_directory(): filename = utils.tmp_filename('test') expect = os.path.dirname(filename) actual = utils.select_directory([filename]) assert expect == actual def test_select_directory_prefers_directories(): filename = utils.tmp_filename('test') expect = '.' actual = utils.select_directory([filename, '.']) assert expect == actual git-cola-3.12.0/tox.ini000066400000000000000000000012171417222504200146070ustar00rootroot00000000000000[tox] minversion = 3.2 envlist = python # https://github.com/jaraco/skeleton/issues/6 tox_pip_extensions_ext_venv_update = true # Ensure that a late version of pip is used even on tox-venv. requires = tox-pip-version>=0.0.6 tox-venv [testenv] sitepackages = true deps = -rrequirements/requirements.txt -rrequirements/requirements-dev.txt pip_version = pip whitelist_externals = make commands = make test {posargs} make flake8 {posargs} usedevelop = True extras = testing [testenv:pylint] sitepackages = true deps = {[testenv]deps} whitelist_externals = make commands = make pylint {posargs} make pylint3k {posargs}