Compare commits

...

994 commits

Author SHA1 Message Date
leo
932baeec53
Merge branch 'release/v2025.21' 2025-06-09 09:30:45 +08:00
leo
637e133f47
version: Release 2025.21
Signed-off-by: leo <longshuang@msn.cn>
2025-06-09 09:30:36 +08:00
github-actions[bot]
a1e76e9bea doc: Update translation status and sort locale files 2025-06-09 01:27:28 +00:00
AquariusStar
a8541a780e
localization: update translate Russian (#1404) 2025-06-09 09:27:10 +08:00
Sina Hinderks
d55f19586f
fix: issue tracker rule over keyword in subject (#1403)
Some teams use issue tracker numbers in front of the commit message
subject, followed by a colon.  It was not possible to use an issue
tracker rule in such cases, since the issue tracker number would be
interpreted as a keyword due to the colon and therefore displayed in
bold face instead of as a link into the issue tracker.
2025-06-09 09:26:27 +08:00
leo
a22c39519f
code_style: remove unnecessary code
Some checks failed
Continuous Integration / Build (push) Has been cancelled
Continuous Integration / Prepare version string (push) Has been cancelled
Continuous Integration / Package (push) Has been cancelled
Signed-off-by: leo <longshuang@msn.cn>
2025-06-08 11:54:54 +08:00
leo
84fb39f97a
code_review: PR #1402
- it's unnecessary to implement `IEnumerable` interface
- we should check `IsIntersecting` before creating `InlineElement` to avoid unnecessary works suck as running `git cat-file -t <hash>`
- sort whold list after all elements have been added to avoid unnecessary memmove in `Insert`

Signed-off-by: leo <longshuang@msn.cn>
2025-06-08 11:09:20 +08:00
Sina Hinderks
fe54d30b70
refactor: collecting inlines for subjects (#1402)
Instead of checking intersections of inline elements yourself before adding an inline element, the new class `InlineElementCollector` prevents intersections internally.

Additionally the inline elements are sorted by the new class, so it's no longer necessary to do this after adding the inline elements.
2025-06-08 08:47:03 +08:00
leo
ba4c0f0cd2
enhance: scroll to home when active revision file changed
Some checks are pending
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Continuous Integration / Build (push) Waiting to run
Signed-off-by: leo <longshuang@msn.cn>
2025-06-07 20:53:34 +08:00
leo
2478d2953b
code_style: remove unnecessary code in DiffContext
Signed-off-by: leo <longshuang@msn.cn>
2025-06-07 20:42:45 +08:00
leo
74f52fb266
enhance: only show syntax-highlighting toggle if current revision content is a text file
Signed-off-by: leo <longshuang@msn.cn>
2025-06-07 20:27:52 +08:00
leo
f830b68f6a
ux: change foreground for some labels
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Signed-off-by: leo <longshuang@msn.cn>
2025-06-07 12:20:09 +08:00
leo
d323a2064e
feature: supports RGBA16 pixel format
Signed-off-by: leo <longshuang@msn.cn>
2025-06-07 12:00:16 +08:00
leo
203c50350e
fix: wrong pfim image format
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Signed-off-by: leo <longshuang@msn.cn>
2025-06-06 20:50:37 +08:00
leo
47012e29dc
fix: file extensions are case-insensitive
Some checks failed
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Localization Check / localization-check (push) Has been cancelled
Signed-off-by: leo <longshuang@msn.cn>
2025-06-06 18:47:36 +08:00
leo
8db033be99
code_review: PR #1392
- fix the issue that not all channel takes 8 bits
- if `PixelFormatTranscoder.Transcode` supports the same pixel formats, let it converts pixels automatically

Signed-off-by: leo <longshuang@msn.cn>
2025-06-06 18:23:10 +08:00
Henrik Andersson
a2ca071f08
feature: .dds image support (#1392)
* Added Pfim as 3rdparty lib

* Added support for parsing showing dds and tga images using Pfim

---------

Co-authored-by: Snimax <snimax@live.se>
2025-06-06 16:44:40 +08:00
Nathan Baulch
7bba40d03f
typos: (#1397) 2025-06-06 12:10:55 +08:00
leo
0c22409b7b
ux: new sort by time icon (#1393)
Signed-off-by: leo <longshuang@msn.cn>
2025-06-06 11:37:56 +08:00
leo
f63fe8637b
feature: use different icon for sort mode (#1393)
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Localization Check / localization-check (push) Waiting to run
Signed-off-by: leo <longshuang@msn.cn>
2025-06-06 11:22:30 +08:00
github-actions[bot]
08665e45c1 doc: Update translation status and sort locale files 2025-06-06 02:45:35 +00:00
leo
3bb20868fc
refactor: remove unnecessary sort by name (descending) for tags (#1393)
Signed-off-by: leo <longshuang@msn.cn>
2025-06-06 10:45:18 +08:00
leo
ac55bed812
enhance: revision file viewer
- show current file path
- add a toggle button to use global syntax highlighting setting (sometimes TextMateSharp will crash this app)

Signed-off-by: leo <longshuang@msn.cn>
2025-06-06 10:07:58 +08:00
leo
f003f67129
fix: should use file.SHA instead of _commit.SHA to query submodule's commit
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Signed-off-by: leo <longshuang@msn.cn>
2025-06-05 21:54:09 +08:00
Göran W
f04b0c5d97
fix: prevent exception on repo with no commits/branches
Signed-off-by: leo <longshuang@msn.cn>
2025-06-05 21:28:32 +08:00
Göran W
406ace9e79
enhance: activate TabsDropdownItem on Tapped instead of DoubleTapped
Signed-off-by: leo <longshuang@msn.cn>
2025-06-05 21:28:10 +08:00
leo
464fe74580
code_review: commit b969ac161a
- The return code of `AutoRemoveInvalidNode`  is never used
- It's not necessary to sort all nodes after re-scan default clone dir. Because `FindOrAddNodeByRepositoryPath` makes sure added node is ordered
- Add a new parameter `save` to `FindOrAddNodeByRepositoryPath` method, and disable it while scanning. Instead, we will save it after scan finished.

Signed-off-by: leo <longshuang@msn.cn>
2025-06-05 21:27:19 +08:00
Göran W
b969ac161a
enhance: unify sorting of RepositoryNode tree, unconditional sort & save after rescan 2025-06-05 21:19:25 +08:00
Göran W
88c38b4139
enhance: unified all file-path normalization - use char-replace, trim trailing slash 2025-06-05 21:17:18 +08:00
Göran W
54c05ac35a
fix: remove trailing slash in paths, to avoid failing comparisons.
This is needed since DirectoryInfo.Fullname (and .FullPath) will not "normalize" trailing slashes, so direct equality tests are error-prone.
This fixes a bug in ScanRepositories.GetUnmanagedRepositories(), where not all Git repo folders were added.
(Also, corrected a variable name from 'founded' to 'found'.)
2025-06-05 21:15:28 +08:00
Göran W
75c32c1a01
typo: corrected spelling error in App.GetLauncher() method 2025-06-05 21:15:28 +08:00
leo
a023a9259b
refactor: rewrite lfs pointer detection and image loading
Signed-off-by: leo <longshuang@msn.cn>
2025-06-05 21:06:31 +08:00
leo
eebadd67a1
feature: remember the last active tab index in lfs-image diff view
Some checks are pending
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Continuous Integration / Build (push) Waiting to run
Signed-off-by: leo <longshuang@msn.cn>
2025-06-05 09:18:19 +08:00
leo
f716c5ee1e
refactor: use existing QueryFileContent command
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Signed-off-by: leo <longshuang@msn.cn>
2025-06-04 21:30:08 +08:00
leo
ed496a41fb
feature: supports to view image diff when lfs object points to a image
Signed-off-by: leo <longshuang@msn.cn>
2025-06-04 20:53:42 +08:00
leo
06a77502bc
fix: crash when clicking Previous Difference without visual lines (#1385)
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Always scroll to top when the state of `Show All Lines` changed

Signed-off-by: leo <longshuang@msn.cn>
2025-06-04 13:13:28 +08:00
leo
c2187edbe9
fix: running git command in UIThread via context menu entry blocks whole app (#1384)
Some checks failed
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Localization Check / localization-check (push) Has been cancelled
Signed-off-by: leo <longshuang@msn.cn>
2025-06-03 23:36:15 +08:00
github-actions[bot]
d85f82e171 doc: Update translation status and sort locale files 2025-06-03 13:38:04 +00:00
leo
f7c10d0b33
feature: supports to load avatar from local image and save it to disk
Signed-off-by: leo <longshuang@msn.cn>
2025-06-03 21:37:47 +08:00
leo
25e272fa55
ux: layout of filter mode toggle buttons
Signed-off-by: leo <longshuang@msn.cn>
2025-06-03 20:28:44 +08:00
leo
98041c803e
feature: supports re-order custom actions (#1346)
Signed-off-by: leo <longshuang@msn.cn>
2025-06-03 20:24:30 +08:00
leo
ee2e7d0127
enhance: ignores $ char when measuring contents in NamedHighlightedTextBlock
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Signed-off-by: leo <longshuang@msn.cn>
2025-06-03 14:12:23 +08:00
leo
6517e78ab6
enhance: enable StaysOpenOnClick for filter mode in graph context menu item
Signed-off-by: leo <longshuang@msn.cn>
2025-06-03 14:06:53 +08:00
leo
bf43dd828a
ux: new style for ref's Visibility in Graph context menu item
Signed-off-by: leo <longshuang@msn.cn>
2025-06-03 12:34:49 +08:00
leo
cd009bda6b
ux: enable Use monospace font only in text editor by default
Signed-off-by: leo <longshuang@msn.cn>
2025-06-03 10:15:58 +08:00
leo
cd8ff2e9bf
Merge branch 'master' into develop
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
2025-06-03 09:27:51 +08:00
leo
0594196dee
Merge branch 'release/v2025.20' 2025-06-03 09:27:03 +08:00
leo
425395da29
version: Release 2025.20
Signed-off-by: leo <longshuang@msn.cn>
2025-06-03 09:26:57 +08:00
leo
6e501b1ee4
feature!: now SourceGit requires git >= 2.25.1
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Localization Check / localization-check (push) Waiting to run
Signed-off-by: leo <longshuang@msn.cn>
2025-06-02 22:38:00 +08:00
leo
7b05b011aa
fix: USE THEIRS for AU conflict and USE MINE for UA conflict
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Signed-off-by: leo <longshuang@msn.cn>
2025-06-02 13:03:38 +08:00
leo
f1052c3efc
refactor: use git reset --hard HEAD to discard all changes and use git restore --staged to unstage changes in text diff view
Signed-off-by: leo <longshuang@msn.cn>
2025-06-02 12:50:58 +08:00
leo
78f9ae2fa9
refactor: rewrite git restore integration
Signed-off-by: leo <longshuang@msn.cn>
2025-06-02 12:14:22 +08:00
leo
80df53cf04
ux: move hunk-based operation button away from scrollbar (#1382)
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Signed-off-by: leo <longshuang@msn.cn>
2025-06-01 20:04:15 +08:00
leo
57004c4baf
code_style: run dotnet format
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Signed-off-by: leo <longshuang@msn.cn>
2025-06-01 11:23:04 +08:00
leo
fa004ce31b
enhance: unstaged renamed file should use git restore --staged <path> <org_path> instead of git restore --staged <path>
Signed-off-by: leo <longshuang@msn.cn>
2025-06-01 11:19:41 +08:00
leo
6620bd193e
ux: remove tooltip for USE THEIRS and USE MINE button
Signed-off-by: leo <longshuang@msn.cn>
2025-06-01 11:09:31 +08:00
leo
26307e2343
refactor: new tooltip for change
Signed-off-by: leo <longshuang@msn.cn>
2025-06-01 10:34:24 +08:00
leo
db5bb0aec9
fix: must convert the relative path to absolute before send it to first instance (#1376)
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Signed-off-by: leo <longshuang@msn.cn>
2025-05-31 21:26:01 +08:00
leo
dd432c63e8
enhance: when counting commits in Statistics, if the authors have the same e-mail address, the commits are considered to be from the same person (#1380)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-31 18:52:15 +08:00
github-actions[bot]
b94f26a937 doc: Update translation status and sort locale files
Some checks failed
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Localization Check / localization-check (push) Has been cancelled
2025-05-31 04:15:23 +00:00
Javier J. Martínez M.
8e5d5b946e
localization: update spanish translations (#1379)
add missing translations
2025-05-31 12:15:06 +08:00
leo
a9734ea8e9
code_style: remove unused code
Signed-off-by: leo <longshuang@msn.cn>
2025-05-31 11:33:22 +08:00
github-actions[bot]
e22f0f8513 doc: Update translation status and sort locale files
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Localization Check / localization-check (push) Waiting to run
2025-05-30 10:20:10 +00:00
leo
8b17f3b1f4
localization: change Compare with HEAD to Compare with <current_branch_name>
Signed-off-by: leo <longshuang@msn.cn>
2025-05-30 18:19:46 +08:00
leo
7934496cff
feature: reset non-active branch to selected commit should not depends on upstream
Signed-off-by: leo <longshuang@msn.cn>
2025-05-30 17:56:06 +08:00
leo
188408fdfc
project: remove duplicated attributes in csproj
Signed-off-by: leo <longshuang@msn.cn>
2025-05-30 17:21:49 +08:00
leo
bc5deac9fe
fix: OpenFolderPickerAsync raise exception when selected a drive root such as E:\
Signed-off-by: leo <longshuang@msn.cn>
2025-05-30 17:12:56 +08:00
leo
1bd2044589
ux: show conflict description in change status icon
Some checks are pending
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Continuous Integration / Build (push) Waiting to run
Signed-off-by: leo <longshuang@msn.cn>
2025-05-30 11:20:43 +08:00
leo
f0c77ffeb8
code_style: run dotnet format
Signed-off-by: leo <longshuang@msn.cn>
2025-05-30 11:16:07 +08:00
leo
60cd210b80
fix: using theirs or mine does not work if it is deleted by ours or theirs
Signed-off-by: leo <longshuang@msn.cn>
2025-05-30 11:13:29 +08:00
leo
75015d550c
ux: show conflict short format in changes view
Signed-off-by: leo <longshuang@msn.cn>
2025-05-30 10:42:02 +08:00
leo
e40ca4bbe0
refactor: use git restore instead of git reset to unstage local changes (#1373)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-30 09:43:45 +08:00
leo
46231a759c
code_style: run dotnet format
Some checks failed
Continuous Integration / Build (push) Has been cancelled
Continuous Integration / Prepare version string (push) Has been cancelled
Localization Check / localization-check (push) Has been cancelled
Continuous Integration / Package (push) Has been cancelled
Signed-off-by: leo <longshuang@msn.cn>
2025-05-28 15:17:05 +08:00
leo
fbc8edcc13
feature: show conflict reason
Signed-off-by: leo <longshuang@msn.cn>
2025-05-28 14:20:56 +08:00
github-actions[bot]
3437f5f4a9 doc: Update translation status and sort locale files 2025-05-28 02:19:23 +00:00
leo
40bf69bff3
ux: move some buttons to page switcher (#1370)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-28 10:18:34 +08:00
leo
2aac6779a5
fix: squash should not change the original author
Signed-off-by: leo <longshuang@msn.cn>
2025-05-28 09:50:14 +08:00
cdammanintopix
9affca1fb2
fix: arguments order for checkout command (#1368)
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
2025-05-27 17:43:33 +08:00
Gadfly
729e06d5c0
fix: SaveAsPatch for untracked changes in stash (#1366)
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
2025-05-26 22:50:29 +08:00
leo
826619e7c9
fix: new added file in stash changes may not come from untracked file but from staged files (#1358)
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Signed-off-by: leo <longshuang@msn.cn>
2025-05-26 22:13:10 +08:00
github-actions[bot]
056b90a5ae doc: Update translation status and sort locale files
Some checks failed
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Continuous Integration / Build (push) Waiting to run
Localization Check / localization-check (push) Has been cancelled
2025-05-26 04:28:23 +00:00
leo
0641a22230
feature: allow to reset author when --amend is enabled for committing 2025-05-26 12:28:00 +08:00
leo
d3bc85418e
Merge branch 'master' into develop 2025-05-26 09:56:00 +08:00
leo
4887252870
Merge branch 'release/v2025.19' 2025-05-26 09:45:48 +08:00
leo
860f6f2369
version: Release 2025.19
Signed-off-by: leo <longshuang@msn.cn>
2025-05-26 09:45:43 +08:00
leo
cfc80d41a1
fix: sometimes track status is not correct because the local branch name is ambiguous to git
Signed-off-by: leo <longshuang@msn.cn>
2025-05-26 09:42:46 +08:00
leo
ac26d5bb06
fix: can not squash and fixup until first picked/edit/reword commit in interactive rebase exists list (#1362)
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Localization Check / localization-check (push) Waiting to run
Signed-off-by: leo <longshuang@msn.cn>
2025-05-25 13:46:27 +08:00
github-actions[bot]
d7c3bb7150 doc: Update translation status and sort locale files 2025-05-25 05:05:31 +00:00
AquariusStar
39d955b033
localization: update russian translate (#1363) 2025-05-25 13:05:14 +08:00
leo
0e35c56529
enhance: disable squash and fixup for the first commit in interactive rebase list (#1362)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-25 13:03:36 +08:00
leo
22339ab619
enhance: allow to use arrow keys to select changes up/down after stage/unstage previous selected changes by hotkey (#1361)
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Signed-off-by: leo <longshuang@msn.cn>
2025-05-24 21:29:48 +08:00
leo
ef53dd0025
refactor: use a new Models.ChangeState.Conflicted to represent all the unmerged file state (#1359)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-24 20:25:05 +08:00
Göran W
30d4c1008a
enhance: don't show unmerged files in STAGED area (#1359)
Unmerged files (i.e unresolved conflicts) should only appear in the Unstaged area, and not "duplicated" in the Staged area.

Motivation:
* The user-friendly git-status command does not show these as "Changes to be committed".
* If they appear in the Staged area, they are quite redundant since the Diff view will just show "No changes or only EOL changes".
* Some other Git UIs (like Fork) don't show these as Staged items either.

NOTE: According to docs for the git-status "Short Format" (and --porcelain=v1), the XY fields for Unmerged paths do NOT actually represent the Index & Working-tree states, instead they represent the states introduced by each HEAD in the merge (i.e Ours & Theirs, relative to Base).
2025-05-24 19:42:10 +08:00
leo
ca33107a45
code_review: PR #1360
Signed-off-by: leo <longshuang@msn.cn>
2025-05-24 19:26:17 +08:00
Göran W
4363b8b6aa
refactor: add new constant Models.Commit.EmptyTreeSHA1 (#1360) 2025-05-24 19:23:28 +08:00
Göran W
f3fe90b2e1
fix: IsConflictResolved check should not be done for submodules (#1356)
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
A submodule conflict is not resolved until it's Staged.
2025-05-24 09:40:17 +08:00
leo
e28b75b860
enhance: include stdout in error popup when git process (in Exec mode, we do not need to parse its output) exit with non-zero code
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Signed-off-by: leo <longshuang@msn.cn>
2025-05-23 16:12:40 +08:00
leo
3377886bab
enhance: filter hint: blocks
Signed-off-by: leo <longshuang@msn.cn>
2025-05-23 14:13:48 +08:00
leo
4807cd5eb2
fix: if font family name contains '#', make sure we have that built-in font
Signed-off-by: leo <longshuang@msn.cn>
2025-05-23 13:32:02 +08:00
github-actions[bot]
d21b790784 doc: Update translation status and sort locale files
Some checks failed
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Localization Check / localization-check (push) Has been cancelled
2025-05-23 04:25:41 +00:00
Javier J. Martínez M.
764ae31239
localization: update spanish translations (#1355)
* localization: update spanish translations

add missing translations

* Update es_ES.axaml

Quickfix for `Text.DeinitSubmodule.Force` translation
2025-05-23 12:25:29 +08:00
github-actions[bot]
38d67d7f17 doc: Update translation status and sort locale files 2025-05-23 03:28:10 +00:00
leo
76a197aae7
feature: supports to overwrite existing branch while creating new branch (#1349)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-23 11:27:45 +08:00
leo
594ffc0d1a
localization: fix typo in en_US for Text.DeinitSubmodule.Force
Signed-off-by: leo <longshuang@msn.cn>
2025-05-23 10:38:44 +08:00
leo
fb1f5638ce
code_style: simpfy context menu creation for blame editor
Signed-off-by: leo <longshuang@msn.cn>
2025-05-23 10:31:11 +08:00
leo
492da8dd57
fix: blame highlight background did not update when using scrollbar (#1354)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-23 10:27:48 +08:00
leo
0ae39faad1
enhance: do not show hint: messages in error popup, but leave it in git command logs (#1348)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-23 10:05:09 +08:00
leo
c112549b69
refactor: query branch head after operation finished to avoid branch head mismatch
Signed-off-by: leo <longshuang@msn.cn>
2025-05-23 09:40:15 +08:00
Göran W
9fb8af51ff
code_style: move hardcoded brush/strings (for outlier Conflict-icon) into named constants (#1350)
This makes code more consistent and gives better overview of all the icons.
(Potentially, this special/outlier icon could be moved into the existing arrays as an extra ChangeState enum-value.)
2025-05-23 09:18:05 +08:00
leo
1ee7d1184e
enhance: only refresh submodules when it is needed (#1344)
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Signed-off-by: leo <longshuang@msn.cn>
2025-05-22 11:02:54 +08:00
Göran W
44c83ef342
enhance: added more FileSystemWatcher patterns, to improve handling (#1345)
Skip files frequently updated by Git fsmonitor--daemon and Visual Studio, to ease debugging and for early exit.
Check for HEAD and ORIG_HEAD under .git/modules/<submodule>/, to improve handling of submodules.
Check for MERGE_HEAD and AUTO_MERGE under .git/, to improve handling of submodules.
2025-05-22 09:11:28 +08:00
leo
c3ac59ee1a
enhance: refresh submodules after .gitmodules file changed
Some checks failed
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Localization Check / localization-check (push) Has been cancelled
Signed-off-by: leo <longshuang@msn.cn>
2025-05-21 20:51:29 +08:00
leo
c73f775aa5
enhance: mark submodule having local changes even if there are only untracked files (#1344)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-21 20:47:10 +08:00
M-L-Ml
afbd0d7135
fix: typo in name SetupExternalTools (#1343) 2025-05-21 20:35:22 +08:00
github-actions[bot]
bf39673b21 doc: Update translation status and sort locale files 2025-05-21 12:34:51 +00:00
leo
b0c0c46441
feature: supports to de-initialize a submodule (#1272)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-21 20:34:33 +08:00
leo
1fef7a7baa
perf: only update uninited or outdated submodules
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Localization Check / localization-check (push) Waiting to run
Signed-off-by: leo <longshuang@msn.cn>
2025-05-21 17:51:00 +08:00
github-actions[bot]
1872740265 doc: Update translation status and sort locale files 2025-05-21 09:18:49 +00:00
leo
09d0122e26
refactor: rewrite git pull command
If we do not provide pulling remote branch, it will auto fetch all branches first.

Signed-off-by: leo <longshuang@msn.cn>
2025-05-21 17:18:25 +08:00
github-actions[bot]
7728f4ffbf doc: Update translation status and sort locale files 2025-05-21 08:54:46 +00:00
leo
936160ea5c
feature: supports --recurse-submodules on pull (#1342)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-21 16:54:23 +08:00
leo
d73ae83b01
feature: supports to use relative path in remote URL (#1339)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-21 16:29:33 +08:00
leo
5e05c008fc
refactor: simplfy the regex to check remote's URL with HTTP/HTTPS/GIT protocol
Signed-off-by: leo <longshuang@msn.cn>
2025-05-21 15:09:36 +08:00
leo
598ba6d9f6
refactor: rewrite Remote.IsValidURL (#1339)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-21 14:48:21 +08:00
leo
3232e6f313
fix: on Windows, the correct file protocol url format is file:///<driver>:/path/to/file_or_dir (#1339)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-21 14:18:06 +08:00
leo
0a6b1faa65
feature: support git:// protocol (#1339)
Some checks are pending
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Continuous Integration / Build (push) Waiting to run
Signed-off-by: leo <longshuang@msn.cn>
2025-05-21 09:36:41 +08:00
leo
71b90a82b6
refactor: remove validation for relative path while adding submodule (#1339)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-21 09:27:02 +08:00
leo
d304c50e7f
enhance: show custom action output in popup
Some checks are pending
Localization Check / localization-check (push) Waiting to run
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Signed-off-by: leo <longshuang@msn.cn>
2025-05-21 00:16:19 +08:00
leo
438aa76695
feature: support to use relative path as submodule's url when adding new submodule (#1339)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-21 00:10:10 +08:00
leo
ece51fbd32
fix: remove binding error in debug mode (#1338)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-20 23:02:45 +08:00
leo
224f7a949a
fix: since can not been used in HotKey property and ⌘+⌥+D has been used to show Dock, change the hotkey to open external merge tool to Ctrl+Shift+D/⌘+⇧+D
Signed-off-by: leo <longshuang@msn.cn>
2025-05-20 23:01:21 +08:00
leo
e6fdc778b7
fix: remove binding error in debug mode (#1338)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-20 21:48:58 +08:00
leo
53c6fc8999
fix: remove binding error in debug mode (#1338)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-20 21:44:28 +08:00
leo
f0d1d460a9
fix: remove binding error in debug mode (#1338)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-20 21:35:14 +08:00
leo
3386cb177b
refactor: rewrite git flow init
Signed-off-by: leo <longshuang@msn.cn>
2025-05-20 21:26:41 +08:00
leo
4d5be9f280
refactor: rewrite git-flow integration
Signed-off-by: leo <longshuang@msn.cn>
2025-05-20 21:08:00 +08:00
leo
6fa454ace8
fix!: same hotkey for opening external diff tool and discard block (#1337)
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Localization Check / localization-check (push) Waiting to run
Signed-off-by: leo <longshuang@msn.cn>
2025-05-20 17:32:06 +08:00
leo
75b7724d44
refactor: implement IDisposable instead of calling custom Cleanup
Signed-off-by: leo <longshuang@msn.cn>
2025-05-20 17:24:00 +08:00
leo
550493b572
enhance: prevent requesting worktree files more than once time
Signed-off-by: leo <longshuang@msn.cn>
2025-05-20 16:49:00 +08:00
leo
eb183589f5
enhance: prevent requesting revision files more than once time
Signed-off-by: leo <longshuang@msn.cn>
2025-05-20 16:32:57 +08:00
github-actions[bot]
d56c6a5030 doc: Update translation status and sort locale files 2025-05-20 04:24:40 +00:00
leo
f9b6116a76
feature: supports reset branch to selected commit without checkout (#1247) (#1318)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-20 12:24:07 +08:00
Gadfly
12d2b7721c
fix: Trim and normalize commit message history line endings (#1335)
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
2025-05-20 10:56:02 +08:00
leo
119b0fe95c
feature: log output of custom action if Wait for action exit enabled (#1334)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-20 09:17:00 +08:00
github-actions[bot]
1dfb629cef doc: Update translation status and sort locale files
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Localization Check / localization-check (push) Waiting to run
2025-05-19 04:22:07 +00:00
leo
0e2bb1b276
feature: show commit changes count (#1306)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-19 12:21:50 +08:00
leo
57ee1f7dbd
fix: wrong hotkey tip for open Preferences window
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Signed-off-by: leo <longshuang@msn.cn>
2025-05-19 10:55:25 +08:00
leo
aaf53ac694
enhance: try to cancel switcher first then other popup
Signed-off-by: leo <longshuang@msn.cn>
2025-05-19 10:08:37 +08:00
leo
736991198f
Merge branch 'master' into develop 2025-05-19 09:45:11 +08:00
leo
7dd1389c25
Merge branch 'release/v2025.18' 2025-05-19 09:43:59 +08:00
leo
341ac26576
version: Release 2025.18
Signed-off-by: leo <longshuang@msn.cn>
2025-05-19 09:43:48 +08:00
leo
aff003fd6d
enhance: cleanup unused resources
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Localization Check / localization-check (push) Waiting to run
Signed-off-by: leo <longshuang@msn.cn>
2025-05-18 22:00:35 +08:00
qiufengshe
b78f6b0ea8
perf: minimize temporary strings for better performance (#1332) 2025-05-18 20:52:05 +08:00
leo
5e85f6fefe
enhance: auto-select the first page by default
Signed-off-by: leo <longshuang@msn.cn>
2025-05-18 20:47:38 +08:00
github-actions[bot]
52991351af doc: Update translation status and sort locale files 2025-05-18 12:34:17 +00:00
leo
4b849d9d5c
ux: update workspace/page switcher popup layout
Signed-off-by: leo <longshuang@msn.cn>
2025-05-18 20:33:55 +08:00
github-actions[bot]
6b083dcd3e doc: Update translation status and sort locale files 2025-05-18 11:36:39 +00:00
leo
9614b995d8
refactor: workspace/page switcher (#1330)
- add `Switch Tab` popup
- change hotkey to open `Preferences` to `Ctrl+,/⌘+,`
- change hotkey to open `Switch Workspace` to `Ctrl+Shift+P/⌘+⇧+P`
- change hotkey to open `Switch Tab` to `Ctrl+P/⌘+P`

Signed-off-by: leo <longshuang@msn.cn>
2025-05-18 19:36:17 +08:00
github-actions[bot]
36c2e083cc doc: Update translation status and sort locale files
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Localization Check / localization-check (push) Waiting to run
2025-05-18 07:02:46 +00:00
AquariusStar
fd35e0817d
localization: update russian translate (#1331) 2025-05-18 15:02:30 +08:00
github-actions[bot]
d429a6426a doc: Update translation status and sort locale files
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Localization Check / localization-check (push) Waiting to run
2025-05-17 12:14:32 +00:00
leo
4c1ba717a7
refactor: rewrite workspace switcher (#1267)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-17 20:14:09 +08:00
github-actions[bot]
bd553405c2 doc: Update translation status and sort locale files 2025-05-17 10:37:25 +00:00
leo
f121975a28
code_review: PR #1328
* remove hotkey to open workspace dropdown menu
* call orignal `ViewModels.Launcher.SwitchWorkspace` directly in view
* add missing translation for Chinese

Signed-off-by: leo <longshuang@msn.cn>
2025-05-17 18:37:02 +08:00
github-actions[bot]
ea320d2cdf doc: Update translation status and sort locale files
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Localization Check / localization-check (push) Waiting to run
2025-05-17 05:17:22 +00:00
popara
01945f231e
Added workspaces shortcuts (#1328)
- added Alt+Space for opening Workspaces context menu (which can then be navigated normally with arrows)
- added Alt+1 through Alt+9 for switching to corresponding workspace
2025-05-17 13:17:10 +08:00
github-actions[bot]
506dbc218c doc: Update translation status and sort locale files 2025-05-17 05:12:20 +00:00
Javier J. Martínez M.
d3a740fb95
localization: update spanish translations (#1329)
add missing translations
2025-05-17 13:12:01 +08:00
leo
d3d0e7b15c
ux: thinner border for default avatar
Some checks are pending
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Signed-off-by: leo <longshuang@msn.cn>
2025-05-17 08:13:19 +08:00
Gadfly
879b84ac20
enhance: Show the stderr content from QueryLocalChanges (#1327) 2025-05-17 07:58:47 +08:00
github-actions[bot]
7f86ad9f22 doc: Update translation status and sort locale files 2025-05-16 12:08:16 +00:00
Leonardo
0c9cb41e68
localization: new keys translated to italian (#1323) 2025-05-16 20:08:04 +08:00
leo
86f27c5e58
refactor: generate hash based default avatar instead of simple label (#1322)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-16 17:55:02 +08:00
leo
1f0ab2bfec
refactor: simpfy SourceGit.Views.BranchTreeNodeIcon
Signed-off-by: leo <longshuang@msn.cn>
2025-05-16 13:43:41 +08:00
leo
fd935259aa
refactor: build tags view data in viewmodels instead of views
Signed-off-by: leo <longshuang@msn.cn>
2025-05-16 12:22:52 +08:00
github-actions[bot]
f46bbd01cd doc: Update translation status and sort locale files 2025-05-16 03:32:09 +00:00
leo
ed1351b1f7
feature: supports to show submodules as tree or list (#1307)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-16 11:31:53 +08:00
leo
d299469613
ux: show tooltip at right of hovered item in repository's left side bar (#1317)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-16 10:47:38 +08:00
leo
e4490d87dc
code_review: PR #1314
Signed-off-by: leo <longshuang@msn.cn>
2025-05-16 09:45:26 +08:00
Martin Smith
85b223a3d0
Task/UI usability tweaks (#1314)
* Allow About to center in parent
* About closes on Escape
* ConfirmEmptyCommit dialog closes on Escape
* Ignore Dev file
* Missed condition

---------

Co-authored-by: Martin Smith <martin.smith@purplebricks.com>
2025-05-16 09:27:42 +08:00
github-actions[bot]
6c62789c4c doc: Update translation status and sort locale files 2025-05-16 01:20:43 +00:00
AquariusStar
85e08f5eea
localization: update russian localization (#1319) 2025-05-16 09:20:31 +08:00
leo
463d161ac7
refactor: show submodule as tree instead of list (#1307) 2025-05-14 17:55:28 +08:00
github-actions[bot]
5ec51eefb9 doc: Update translation status and sort locale files 2025-05-14 08:02:08 +00:00
leo
bc5c4670de
feature: supports to use Ctrl+D/⌘+D to open in external diff/merge tool (#1312) 2025-05-14 16:01:47 +08:00
leo
d3363429df
ux: new style for submodule tooltip (#1307) 2025-05-14 15:49:42 +08:00
github-actions[bot]
f83b6c24ae doc: Update translation status and sort locale files 2025-05-14 06:27:00 +00:00
leo
61bb0f7dc7
feature: show submodule's URL in tooltip (#1307) 2025-05-14 14:26:33 +08:00
leo
20a239621b
fix: can not open submodule that has not been initialized 2025-05-14 11:48:44 +08:00
github-actions[bot]
9e91494a20 doc: Update translation status and sort locale files 2025-05-14 03:36:15 +00:00
leo
d71189c705
feature: tooltip for submodule list item (#1307) 2025-05-14 11:35:34 +08:00
leo
55232aeddd
project: ignore custom script files
Signed-off-by: leo <longshuang@msn.cn>
2025-05-13 22:55:24 +08:00
leo
6bf930a9e0
feature: show tags count in tags tree (#1306)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-13 22:50:10 +08:00
Göran W
5b72b15cf2
feature: show remote's URL in tooltip for relevant BranchTreeNodes (#1310) 2025-05-13 22:36:10 +08:00
leo
0e61a0196b
fix: right caption buttons should not visible on macOS (#1311)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-13 22:34:53 +08:00
leo
7bb4e355bd
feature: show branches count in branch tree (#1306) 2025-05-13 19:28:52 +08:00
leo
57d15dc6d3
fix: git submodule status may return lines that start as U character (#1307) 2025-05-13 18:11:51 +08:00
leo
65808e5f58
fix: filter with local branch should not include invalid upstream (gone) (#1308) 2025-05-13 17:59:51 +08:00
leo
cf7b61dd71
refactor: new way to display item count 2025-05-13 17:50:47 +08:00
leo
ac1bd7ca85
ux: hide tag message if it's the same with its name (#1305) 2025-05-13 14:22:41 +08:00
leo
142ee5a327
ux: use localized text instead of hard-coded string annotated (#1305) 2025-05-13 13:01:15 +08:00
leo
afc8a772dd
ux: new style for tag's tooltip (#1305) 2025-05-13 12:26:33 +08:00
leo
8a45e25106
refactor: rewrite custom WM_NCHITTEST implementation on Windows 2025-05-13 10:19:51 +08:00
leo
4e41a6207a
enhance: display tag's name instead of nothing while showing tooltip of tag without message 2025-05-13 10:01:41 +08:00
Göran W
a5c25cf9fe
enhance: add border around tag name, makes tooltip work as for branches
(cherry picked from commit 6a5e6d12d70f52e5777cc4edc4022fed870151d4)
2025-05-13 09:38:09 +08:00
leo
11a9d7fdd8
enhance: force using --no-sign to ignore tag.gpgsign configuration while creating lightweight tag
Signed-off-by: leo <longshuang@msn.cn>
2025-05-13 09:24:00 +08:00
leo
ef4b639f8e
code_style: move platform dependent code to initialize window to namespace SourceGit.Native
Signed-off-by: leo <longshuang@msn.cn>
2025-05-12 21:52:50 +08:00
leo
c62b4a031f
perf: return HTCLIENT directly when window is fullscreen or maximized
Signed-off-by: leo <longshuang@msn.cn>
2025-05-12 18:09:25 +08:00
leo
af9cf6ba6a
ux: force using 4 * RenderScaling as resize border size on Windows
Signed-off-by: leo <longshuang@msn.cn>
2025-05-12 17:57:49 +08:00
leo
641098ffb2
ux: better content padding for maximized window on Windows
Signed-off-by: leo <longshuang@msn.cn>
2025-05-12 16:27:54 +08:00
leo
fcad8eeadc
Merge branch 'master' into develop 2025-05-12 09:24:48 +08:00
leo
01625ada1a
Merge branch 'release/v2025.17' 2025-05-12 09:23:46 +08:00
leo
88dc12275a
version: Release 2025.17
Signed-off-by: leo <longshuang@msn.cn>
2025-05-12 09:22:28 +08:00
Bailey Allen
bac21c5714
enhance: added support for kitty terminal on macOS and Linux. (#1300) 2025-05-12 09:17:20 +08:00
github-actions[bot]
19a51f227b doc: Update translation status and sort locale files 2025-05-12 01:13:27 +00:00
Javier J. Martínez M.
b6d618a6d7
localization: update spanish translations (#1302)
* localization: update spanish translations

add missing translations

* localization: update spanish translations

add missing translations
2025-05-12 09:13:13 +08:00
github-actions[bot]
2573553e01 doc: Update translation status and sort locale files 2025-05-12 01:12:59 +00:00
AquariusStar
9dd0beb61f
localization: update russian translate (#1301) 2025-05-12 09:12:49 +08:00
leo
029fd6933f
refactor: new way to discard selected or all local changes
This modification aims to solve the problem that the deleted submodule cannot be discarded.

Signed-off-by: leo <longshuang@msn.cn>
2025-05-09 22:57:46 +08:00
leo
0f6c8976af
refactor: rewrite checkout/create branch with submodules
Signed-off-by: leo <longshuang@msn.cn>
2025-05-09 18:12:30 +08:00
leo
e446e97f28
fix: remove testing code for git checkout command
Signed-off-by: leo <longshuang@msn.cn>
2025-05-09 17:22:17 +08:00
leo
3e530de9cc
enhance: update submodules individually (#1272)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-09 17:12:12 +08:00
leo
6cf1b20ea6
refactor: context menu for commit change and revision file
Signed-off-by: leo <longshuang@msn.cn>
2025-05-09 14:11:15 +08:00
github-actions[bot]
321ccf9622 doc: Update translation status and sort locale files 2025-05-09 02:47:52 +00:00
leo
ebe0e61367
feature: support to enable --squash and --push option while finishing git-flow branches (#1290)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-09 10:47:36 +08:00
leo
e8bf58f6c3
code_review: PR #1292
Use syntax `String.AsSpan(int start, int len)` instead of `String.AsSpan().Slice(int start, int len)`

Signed-off-by: leo <longshuang@msn.cn>
2025-05-09 09:30:00 +08:00
qiufengshe
15ee2dac91
perf: minimize temporary strings for better performance (#1292) 2025-05-09 09:19:33 +08:00
github-actions[bot]
5d1601086f doc: Update translation status and sort locale files 2025-05-09 01:16:10 +00:00
AquariusStar
3eaa24a993
localization: update and fix translation russian (#1291) 2025-05-09 09:15:59 +08:00
leo
6986e1ac24
code_style: calculate bounds only when it is needed
Signed-off-by: leo <longshuang@msn.cn>
2025-05-08 13:42:21 +08:00
leo
2c8370fa92
refactor: get graph clip width from grid column definition directly
Signed-off-by: leo <longshuang@msn.cn>
2025-05-08 13:39:27 +08:00
leo
008708f07c
ux: use larger font size for commit ref label
Signed-off-by: leo <longshuang@msn.cn>
2025-05-08 13:13:22 +08:00
leo
832fcd7487
fix: offset of commit graph does not look quite right (#1287)
This is because that when using `VirtualizingStackPanel`, the `Bounds.Height` of `ListBoxItem` may not be the same with its `Height` setted in axaml.

Signed-off-by: leo <longshuang@msn.cn>
2025-05-08 12:22:23 +08:00
leo
6df38ad970
ux: new style for inline code in commit subject
Signed-off-by: leo <longshuang@msn.cn>
2025-05-07 20:23:06 +08:00
github-actions[bot]
0a7b973388 doc: Update translation status and sort locale files 2025-05-07 11:08:51 +00:00
Christopher Göttfert
6b050fa557
localization: updated german translations (#1284) 2025-05-07 19:08:39 +08:00
leo
417ab3ecc2
ux: layout for revision compare targets
Signed-off-by: leo <longshuang@msn.cn>
2025-05-07 09:52:26 +08:00
leo
a413df6f89
code_style: run dotnet format
Signed-off-by: leo <longshuang@msn.cn>
2025-05-06 20:56:45 +08:00
leo
ddf643c081
ux: new style for revision/branch compare targets
Signed-off-by: leo <longshuang@msn.cn>
2025-05-06 20:52:43 +08:00
leo
bbc840a5cb
perf: set/update TimeToSort while creating branch nodes
Signed-off-by: leo <longshuang@msn.cn>
2025-05-06 19:26:06 +08:00
github-actions[bot]
c8e21673e4 doc: Update translation status and sort locale files 2025-05-06 10:24:59 +00:00
leo
e45e37d305
feature: supports sort branches by committer date (#1192)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-06 18:24:34 +08:00
github-actions[bot]
b7fa04d141 doc: Update translation status and sort locale files 2025-05-06 07:52:23 +00:00
leo
93a5d7baea
feature: supports to visit remote repository in web browser (#1265)
- combine `Open in File Manager`, `Open in Terminal` and `Open with external editor` into one dropdown menu
- add `Visit $REMOTE in Browser`

Signed-off-by: leo <longshuang@msn.cn>
2025-05-06 15:51:57 +08:00
leo
e4e2f7b3a7
ux: use smaller font size for inline code in commit subject
Signed-off-by: leo <longshuang@msn.cn>
2025-05-06 14:49:54 +08:00
leo
eae6d10784
enhance: only log exception in popup task (#1281)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-06 12:17:48 +08:00
github-actions[bot]
4bc5b90e6b
doc: Update translation status and sort locale files
(cherry picked from commit 15445d02379020144239886bc87380ae38c2018a)
2025-05-06 12:02:19 +08:00
leo
df29edd8f0
feature: make --recurse-submdoules an option while trying to checkout branch with submodules (#1272)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-06 12:01:58 +08:00
leo
054bbf7e0c
enhance: do not override core.autocrlf configure while reading file diff (#1278)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-06 09:39:03 +08:00
leo
ce00fa6c88
Merge branch 'master' into develop 2025-05-06 09:23:20 +08:00
leo
a960e14368
Merge branch 'release/v2025.16' 2025-05-06 09:22:58 +08:00
leo
867edd9453
version: Release 2025.16
Signed-off-by: leo <longshuang@msn.cn>
2025-05-06 09:22:49 +08:00
github-actions[bot]
aee4ce6387 doc: Update translation status and sort locale files 2025-05-06 01:17:55 +00:00
Javier J. Martínez M.
d92d279fbe
localization: update spanish translations (#1279)
add missing translations
2025-05-06 09:17:45 +08:00
github-actions[bot]
5e080279ce doc: Update translation status and sort locale files 2025-05-04 09:36:42 +00:00
AquariusStar
704c6f589d
localization: update and fix translation russian (#1276) 2025-05-04 17:36:30 +08:00
broknecho
666275c747
feature: add Meld as an option for external merge tool on Windows (#1275) 2025-05-04 11:24:11 +08:00
leo
c0c52695a3
code_style: remove unused code
Signed-off-by: leo <longshuang@msn.cn>
2025-05-03 21:31:10 +08:00
Alen Šiljak
c529fab869
feature: close repository configuration dialog when user pressed Esc (#1269) 2025-05-03 21:18:24 +08:00
leo
4b2983b330
fix: commit detail panel is overlapping history when resizing (#1273)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-03 21:09:43 +08:00
leo
8c1d397480
fix: inline blocks is not sorted in order (#1274)
Signed-off-by: leo <longshuang@msn.cn>
2025-05-03 20:52:40 +08:00
leo
007acb3fa6
project: remove unused scripts
Signed-off-by: leo <longshuang@msn.cn>
2025-04-30 21:40:01 +08:00
leo
3b0c57be84
feature: supports to re-order workspaces (#1261)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-30 21:39:03 +08:00
github-actions[bot]
61bc42612e doc: Update translation status and sort locale files 2025-04-30 13:06:53 +00:00
leo
fe677d40c1
feature: supports search commits by change content (#1263)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-30 21:05:53 +08:00
leo
9bde797b24
fix: make sure the new pattern is appended as a new line (#1264)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-30 20:41:00 +08:00
leo
7501588c95
enhance: quit application after main window has been closed
Signed-off-by: leo <longshuang@msn.cn>
2025-04-30 15:03:14 +08:00
leo
80aead3a17
feature: add dirty state indicator icon to repository tab (#1227)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-30 11:01:39 +08:00
leo
847a1e727b
refactor: enable --ignore-cr-at-eol in diff by default
Signed-off-by: leo <longshuang@msn.cn>
2025-04-30 09:26:34 +08:00
leo
98dd37a9bc
localization: update tranlation for Text.Diff.IgnoreWhitespace
This is because that in `git diff` command the `--ignore-all-space` option will also ignore line-ending changes (`--ignore-cr-at-eol`)

Signed-off-by: leo <longshuang@msn.cn>
2025-04-29 22:49:20 +08:00
leo
95ea0a6ba6
ux: Ignore Whitespace and EOL Changes should always be visible (#1260)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-29 22:21:38 +08:00
leo
b9dc5a8164
feature: parse url in commit message (#1133)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-29 18:08:35 +08:00
leo
63803c9b88
feature: show command running time in logs window (#1253)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-29 16:36:05 +08:00
leo
825b74c2a3
refactor: use String.AsSpan(int, int) instead of String.AsSpan().Slice(int, int)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-29 09:44:06 +08:00
qiufengshe
48bb8e91de
perf: minimize temporary strings for better performance (#1255) 2025-04-29 09:33:14 +08:00
leo
53a55467f1
enhance: ignore submodule changes when deal with local changes before pull/checkout/create branch (#1256)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-29 09:27:09 +08:00
leo
5681bf489d
fix: empty dialog when generating commit message with AI (#1257)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-29 09:14:24 +08:00
leo
226bc434f5
ux: make log window resizable (#1253)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-28 16:53:51 +08:00
leo
30d42b11e2
enhance: wait a while after branch changed (#1254)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-28 16:19:40 +08:00
leo
2698427cd0
fix: popup running animation did not update after switch back from another page
Signed-off-by: leo <longshuang@msn.cn>
2025-04-28 11:57:36 +08:00
leo
b4f1f35e67
Merge branch 'master' into develop 2025-04-28 09:17:40 +08:00
leo
92f215d039
Merge branch 'release/v2025.15' 2025-04-28 09:16:44 +08:00
leo
2e1cf76c82
version: Release 2025.15
Signed-off-by: leo <longshuang@msn.cn>
2025-04-28 09:16:37 +08:00
leo
951ea8f088
fix: use subject as context menu item header to fix vertical alignment (#1251)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-27 11:20:44 +08:00
Chiahong
21cb87cec5
localization: update zh_TW.axaml (#1249) 2025-04-27 09:38:28 +08:00
github-actions[bot]
f39048df77 doc: Update translation status and sort locale files 2025-04-27 01:38:20 +00:00
AquariusStar
bbdeecdcc6
locallization: update russian translate (#1248) 2025-04-27 09:38:09 +08:00
leo
d2e688908c
ux: use different inline code background for different themes
Signed-off-by: leo <longshuang@msn.cn>
2025-04-25 21:26:21 +08:00
leo
91acf0a32a
enhance: fore invalidate measure after data context of BisectStateIndicator changed
Signed-off-by: leo <longshuang@msn.cn>
2025-04-25 20:55:11 +08:00
leo
d44d2b9770
ux: use a outer border to hold tooltip of commit message in FileHistories view (#1232)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-25 18:50:56 +08:00
cdammanintopix
f09367a614
fix: Append UserName to the SourceGitIPCChannel NamedPipeServerStream to allow multiple users usage on the same server (#1244) (#1246) 2025-04-25 16:56:28 +08:00
leo
00e56ce9d1
fix: System.NullReferenceException raised after popup stop (success or not) running
Signed-off-by: leo <longshuang@msn.cn>
2025-04-25 15:56:37 +08:00
leo
22d4f26bc3
code_style: run dotnet format
Signed-off-by: leo <longshuang@msn.cn>
2025-04-25 14:31:14 +08:00
leo
a94c7f55ce
ux: remove tips in commit list
Signed-off-by: leo <longshuang@msn.cn>
2025-04-25 13:37:11 +08:00
leo
1d16925e74
enhance: stop render next inline elements when it is out of bounds
Signed-off-by: leo <longshuang@msn.cn>
2025-04-25 13:30:00 +08:00
leo
8c4362a98d
feature: subject presenter supports inline codeblock
Signed-off-by: leo <longshuang@msn.cn>
2025-04-25 13:24:13 +08:00
leo
9efbc7dd7a
localization: update translations for Chinese
Signed-off-by: leo <longshuang@msn.cn>
2025-04-24 10:04:57 +08:00
github-actions[bot]
c519381645 doc: Update translation status and sort locale files 2025-04-24 02:00:26 +00:00
leo
6590812634
localization: update translations for Chinese
Signed-off-by: leo <longshuang@msn.cn>
2025-04-24 10:00:07 +08:00
github-actions[bot]
ad6ed1512b doc: Update translation status and sort locale files 2025-04-24 01:22:43 +00:00
Javier J. Martínez M.
f73e0687a1
localization: update spanish translations (#1241)
add missing translations. `Bisect`/`Bisecting` stays the same because they reference command names.
2025-04-24 09:22:32 +08:00
qiufengshe
ea680782fe
perf: minimize temporary strings for better performance (#1240)
(cherry picked from commit f4dad2bf551ead5640a500297a4a6f408aef1350)
2025-04-23 21:15:58 +08:00
leo
7e282b13fa
code_style: run dotnet format
Signed-off-by: leo <longshuang@msn.cn>
2025-04-23 20:59:39 +08:00
leo
1386ca30e3
fix: typo in conventional commit type (#1239)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-23 20:52:41 +08:00
github-actions[bot]
2107676058 doc: Update translation status and sort locale files 2025-04-23 07:34:37 +00:00
leo
f72f1894c3
feature: supports to enable --ignore-cr-at-eol in diff by default
Signed-off-by: leo <longshuang@msn.cn>
2025-04-23 15:34:21 +08:00
github-actions[bot]
586ff39da1 doc: Update translation status and sort locale files 2025-04-23 02:39:41 +00:00
AquariusStar
9bdbf47522
localization: update russian localization (#1233) 2025-04-23 10:39:30 +08:00
leo
17c08d42a0
enhance: ignore all sub-directories those names start with '.' (#1234)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-23 10:38:01 +08:00
leo
fafa2a53ae
enhance: show commit full message tooltip when hover commit subject in FileHistories view (#1232)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-23 10:33:49 +08:00
leo
7890f7abbf
refactor: use PointerPressed event instead of ListBox.SelectionChanged event to navigate to commit (#1230)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-23 10:17:14 +08:00
leo
345ad06aba
refactor: diff for staged file with --amend enabled (#1231)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-22 19:20:27 +08:00
leo
78f4809875
fix: no changes were displayed when try to amend a commit without parent (branch first commit) (#1231)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-22 19:04:40 +08:00
leo
87ebe3741d
fix: for init-commit, app will crash with COMMIT & PUSH due to local branch has not been updated (#1229)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-22 18:45:14 +08:00
leo
f2000b4a84
enhance: show git log without command itself for git bisect
Signed-off-by: leo <longshuang@msn.cn>
2025-04-22 17:51:55 +08:00
leo
9a6c671a96
refactor: --ignore-cr-at-eol is not necessary when --ignore-all-space is enabled
Signed-off-by: leo <longshuang@msn.cn>
2025-04-22 16:50:46 +08:00
leo
34e0ea3bcb
enhance: raise bisect error manually
Signed-off-by: leo <longshuang@msn.cn>
2025-04-22 16:07:23 +08:00
leo
7be37424e1
fix: modal dialog did not take focus after show (#1225)
Co-authored-by: Gadfly <gadfly@gadfly.vip>
Signed-off-by: leo <longshuang@msn.cn>
2025-04-22 16:02:27 +08:00
github-actions[bot]
a42df87b9c doc: Update translation status and sort locale files 2025-04-22 07:45:38 +00:00
leo
df5294bcb7
feature: git bisect support
Signed-off-by: leo <longshuang@msn.cn>
2025-04-22 15:45:15 +08:00
leo
9eae1eeb81
ux: add InputGesture for hotkeys dialog
Signed-off-by: leo <longshuang@msn.cn>
2025-04-22 11:05:39 +08:00
leo
4c3698b171
feature: use F1 to quick open the Keyboard Shortcuts Reference dialog (#1225)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-22 10:30:19 +08:00
qiufengshe
9f18cbca5b
minimize temporary strings for better performance (#1224)
* minimize temporary strings for better performance

* minimize temporary strings for better performance

(cherry picked from commit c9e6a8d4c2d7b5fe03ee13af0a79c5334c23b1c0)
2025-04-22 10:23:20 +08:00
leo
6882ae069f
enhance: do not show tooltip if the ower window is deactived (#1218)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-22 10:22:02 +08:00
leo
9c53894cb4
ux: add an empty icon if there are no git command logs available
Signed-off-by: leo <longshuang@msn.cn>
2025-04-21 18:48:01 +08:00
leo
06d033464d
code_style: move commit link parser to Models.CommitLink.Get
Signed-off-by: leo <longshuang@msn.cn>
2025-04-21 17:27:07 +08:00
leo
750ca8ec61
refactor: use custom view locator to create new window/dialog (#1216)
Signed-off-by: leo <longshuang@msn.cn>
(cherry picked from commit 3e6f2b25f15b263e2b84922abc5cf6d621d62a83)
2025-04-21 15:32:21 +08:00
leo
86113701f3
Merge branch 'master' into develop 2025-04-21 09:49:51 +08:00
leo
387b68cdfe
Merge branch 'release/v2025.14' 2025-04-21 09:49:02 +08:00
leo
550c108f84
version: Release 2025.14
Signed-off-by: leo <longshuang@msn.cn>
2025-04-21 09:48:52 +08:00
qiufengshe
232482ca92
minimize temporary strings for better performance (#1215)
(cherry picked from commit b4fa80c0939ca198bff8e858a4dc241efd31d558)
2025-04-21 09:44:26 +08:00
heartacker
b4db88a663
chore: update Avalonia package references to version 11.2.8 (#1220) 2025-04-21 09:43:44 +08:00
leo
41416a6bed
refactor: use DataTemplates instead of create NamedHighlightedTextBlock manually for menu item (#1216)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-20 11:05:24 +08:00
leo
5fd074a9b6
refactor: use view locator instead of creating views manually in viewmodels (#1213)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-19 11:14:19 +08:00
leo
413669741d
enhance: ensure sourcegit_rebase_jobs.json only being used when orig-head and onto are both matched
Signed-off-by: leo <longshuang@msn.cn>
2025-04-18 12:49:19 +08:00
leo
75b4a4b294
enhance: record more git command logs
Signed-off-by: leo <longshuang@msn.cn>
2025-04-18 11:29:59 +08:00
leo
d254b557a9
docs: update README.md
Signed-off-by: leo <longshuang@msn.cn>
2025-04-18 10:25:53 +08:00
leo
892f3b8032
code_style: move SourceGit.CommandExtensions to SourceGit.ViewModels.CommandExtensions
Signed-off-by: leo <longshuang@msn.cn>
2025-04-18 10:24:20 +08:00
leo
afe5d4b969
ux: show an icon to draw user's attention to LOCAL CHANGES when there is an in-progress operation (#1210)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-18 09:59:34 +08:00
lwray-renesas
4d31392085
Fixed tooltip
Tooltip for chosing mine was wrong.
Was --theirs when should be --ours.

(cherry picked from commit 26a471933c)
2025-04-18 09:47:31 +08:00
leo
de31d4bad4
ux: layout of git command log item
Signed-off-by: leo <longshuang@msn.cn>
2025-04-17 21:17:54 +08:00
github-actions[bot]
5bd7dd428d doc: Update translation status and sort locale files 2025-04-17 12:04:02 +00:00
leo
4c1a04477e
refactor: enhanced copy commit information context menu (#1209)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-17 20:03:46 +08:00
leo
090b64d68d
refactor: notification popup uses the same text presenter with git command log viewer (#1149)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-17 18:21:55 +08:00
leo
231010abc6
ux: custom style for command line in git command log
Signed-off-by: leo <longshuang@msn.cn>
2025-04-17 17:45:49 +08:00
leo
3358ff9aee
enhance: disable hyper link and email link in git command logs
Signed-off-by: leo <longshuang@msn.cn>
2025-04-17 17:24:56 +08:00
leo
104a3f0bbf
code_style: run dotnet format
Signed-off-by: leo <longshuang@msn.cn>
2025-04-17 16:35:18 +08:00
github-actions[bot]
a06d1183d7 doc: Update translation status and sort locale files 2025-04-17 08:32:08 +00:00
leo
9f493abd1a
enhance: add context menu for selected log
Signed-off-by: leo <longshuang@msn.cn>
2025-04-17 16:31:30 +08:00
github-actions[bot]
349844cf2a doc: Update translation status and sort locale files 2025-04-17 08:07:57 +00:00
leo
021aab8408
enhance: add a button to clear all git command logs
Signed-off-by: leo <longshuang@msn.cn>
2025-04-17 16:07:40 +08:00
leo
c1e31ac4e3
ci: try to remove zlib1g-dev:arm64
Signed-off-by: leo <longshuang@msn.cn>
2025-04-17 15:48:02 +08:00
github-actions[bot]
2a43efde07 doc: Update translation status and sort locale files 2025-04-17 05:34:40 +00:00
Javier J. Martínez M.
33ae6a9989
localization: update spanish translations (#1206)
add missing translations
modify instances of `stagear` with `hacer stage`
2025-04-17 13:34:27 +08:00
leo
0e967ffc8e
fix: pressing Alt+Enter to commit and push in a repository that has no remotes will crash (#1205)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-17 13:30:41 +08:00
github-actions[bot]
c231772298 doc: Update translation status and sort locale files 2025-04-17 05:24:26 +00:00
leo
8b39df32cc
feature: git command logs
Signed-off-by: leo <longshuang@msn.cn>
2025-04-17 13:23:56 +08:00
leo
928a0ad3c5
feature: add wip (work in progress) type (#1200)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-16 19:39:24 +08:00
leo
9606f128e4
enhance: remember commit message when exiting (#1166)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-16 16:36:23 +08:00
leo
67255a5529
ux: reduce combobox item height
Signed-off-by: leo <longshuang@msn.cn>
2025-04-16 15:42:44 +08:00
leo
cac4b7edf6
enhance: conventional commit message helper (#1200)
- add `build`, `ci`, `pref`
- re-design helper dialog

Signed-off-by: leo <longshuang@msn.cn>
2025-04-16 15:40:26 +08:00
leo
fa44fa773c
ux: re-design welcome (repositories manager) page (#1202)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-16 11:54:50 +08:00
leo
db46de0261
enhance: append character U+26D4 to line when \ No newline at end of file is found in git diff output (#1197)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-16 11:41:40 +08:00
leo
e9036b5fb9
ux: re-design commit message input box
Signed-off-by: leo <longshuang@msn.cn>
2025-04-16 10:22:54 +08:00
leo
9ba0b595d9
enhance: remember the last state of Ignore Whitespace Change and EOF in text diff view (#1198)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-15 17:58:26 +08:00
github-actions[bot]
cf763b47c6 doc: Update translation status and sort locale files 2025-04-15 09:47:30 +00:00
leo
539d3f6eca
ux: re-design commit message input box (#1169)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-15 17:47:12 +08:00
leo
03216fc31e
code_style: run dotnet format and re-order codes
Signed-off-by: leo <longshuang@msn.cn>
2025-04-15 16:30:50 +08:00
leo
3cc463d24b
enhance: use Environment.Exit(0) instead of IClassicDesktopStyleApplicationLifetime.Shutdown to stop for non-first instance of SourceGit
Signed-off-by: leo <longshuang@msn.cn>
2025-04-15 16:24:48 +08:00
leo
33a463ce59
feature: allow to view contribution chart based on selected author (#1196)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-15 16:08:38 +08:00
leo
90b37663ed
refactor: use lock file instead of named mutex since the second one may not work on other platforms
Signed-off-by: leo <longshuang@msn.cn>
2025-04-15 14:36:12 +08:00
leo
9ebde1943e
project: downgrade AvaloniaUI to 11.2.6 to fix duplicated characters when input to textbox (#1195)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-15 11:15:13 +08:00
leo
be3f418680
fix: no diff content shows with new files (#1193)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-15 11:03:34 +08:00
leo
a97f163860
readme: update translation tips
Signed-off-by: leo <longshuang@msn.cn>
2025-04-15 10:53:53 +08:00
github-actions[bot]
c1839199ee doc: Update translation status and sort locale files 2025-04-15 02:42:33 +00:00
leo
7d5ffaf867
code_style: keep all translations ordered by key
Signed-off-by: leo <longshuang@msn.cn>
2025-04-15 10:42:16 +08:00
github-actions[bot]
f0d4cfc9f9 doc: Update translation status and sort locale files 2025-04-15 02:30:43 +00:00
Oleksii Borovyk
70494485ab
Added ukrainian translation (#1191)
(cherry picked from commit b40bfeb98f35da080a1b3935e801e422858faf14)
2025-04-15 10:30:24 +08:00
leo
c4c04b8b01
enhance: bring window into view after receive IPC message
Signed-off-by: leo <longshuang@msn.cn>
2025-04-15 10:19:57 +08:00
leo
e2da44c8fd
enhance: use Mutex to force running SourceGit in singleton mode
Signed-off-by: leo <longshuang@msn.cn>
2025-04-15 09:35:16 +08:00
leo
0acbe3e487
enhance: use PipeOptions.FirstPipeInstance to create NamedPipeServerStream
Signed-off-by: leo <longshuang@msn.cn>
2025-04-14 23:55:42 +08:00
leo
05982e6dc0
style: re-design style for disabled primary button
Signed-off-by: leo <longshuang@msn.cn>
2025-04-14 23:23:40 +08:00
leo
e5dc211c35
refactor: simpfy IPC code
Signed-off-by: leo <longshuang@msn.cn>
2025-04-14 23:17:04 +08:00
Gadfly
1e0fd63543
localization: add translation sorting and formatting (#1186)
* doc: Update translation status and missing keys

* localization: add translation sorting and formatting

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-04-14 22:07:24 +08:00
Gadfly
3b1018e0e2
fix: update visible staged changes retrieval in WorkingCopy (#1187)
* doc: Update translation status and missing keys

* fix: update visible staged changes retrieval in WorkingCopy

* fix: prevent unintended amend behavior when changing current branch

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-04-14 22:05:05 +08:00
leo
7d20f97f4e
code_review: PR #1185
- make `SourceGit` running in singleton mode
- `TrySendArgsToExistingInstance` should not be called before `BuildAvaloniaApp().StartWithClassicDesktopLifetime(args)` since we may want to launch `SourceGit` as a core editor.
- avoid `preference.json` to be saved by multiple instances.
- move IPC code to models.

Signed-off-by: leo <longshuang@msn.cn>
2025-04-14 22:03:51 +08:00
Massimo
09c0edef8e
feat: implement IPC for opening repositories in new tabs (#1185)
* refactor: improve diff handling for EOL changes and enhance text diff display

- Updated `Diff.cs` to streamline whitespace handling in diff arguments.
- Enhanced `DiffContext.cs` to check for EOL changes when old and new hashes differ, creating a text diff if necessary.
- Added support for showing end-of-line symbols in `TextDiffView.axaml.cs` options.

* localization: update translations to include EOF handling in ignore whitespace messages

- Modified the ignore whitespace text in multiple language files to specify that EOF changes are also ignored.
- Ensured consistency across all localization files for the patch application feature.

* revert: Typo in DiffResult comment

* revert: update diff arguments to ignore CR at EOL in whitespace handling (like before changes)

* revert: update translations to remove EOF references in Text.Apply.IgnoreWS and fixed typo in Text.Diff.IgnoreWhitespace (EOF => EOL)

* feat: add workspace-specific default clone directory functionality

- Implemented logic in Clone.cs to set ParentFolder based on the active workspace's DefaultCloneDir if available, falling back to the global GitDefaultCloneDir.
- Added DefaultCloneDir property to Workspace.cs to store the default clone directory for each workspace.
- Updated ConfigureWorkspace.axaml to include a TextBox and Button for setting the DefaultCloneDir in the UI.
- Implemented folder selection functionality in ConfigureWorkspace.axaml.cs to allow users to choose a directory for cloning.
- This closes issue #1145

* feat: implement IPC for opening repositories in new tabs

- Added functionality to send repository paths to an existing instance of the application using named pipes.
- Introduced a new preference option to open repositories in a new tab instead of a new window.
- Updated UI to include a checkbox for the new preference.
- Enhanced the handling of IPC server lifecycle based on the new preference setting.
- This closes issue #1184

---------

Co-authored-by: mpagani <massimo.pagani@unitec-group.com>
2025-04-14 19:16:15 +08:00
github-actions[bot]
558eb7c9ac doc: Update translation status and missing keys 2025-04-14 09:03:23 +00:00
leo
b7aa49403b
code_review: PR #1183
- code style in `Clone` constructor
- re-design workspace configuration dialog

Signed-off-by: leo <longshuang@msn.cn>
2025-04-14 17:03:08 +08:00
Massimo
f14a666091
feat: add workspace-specific default clone directory functionality (#1183)
* refactor: improve diff handling for EOL changes and enhance text diff display

- Updated `Diff.cs` to streamline whitespace handling in diff arguments.
- Enhanced `DiffContext.cs` to check for EOL changes when old and new hashes differ, creating a text diff if necessary.
- Added support for showing end-of-line symbols in `TextDiffView.axaml.cs` options.

* localization: update translations to include EOF handling in ignore whitespace messages

- Modified the ignore whitespace text in multiple language files to specify that EOF changes are also ignored.
- Ensured consistency across all localization files for the patch application feature.

* revert: Typo in DiffResult comment

* revert: update diff arguments to ignore CR at EOL in whitespace handling (like before changes)

* revert: update translations to remove EOF references in Text.Apply.IgnoreWS and fixed typo in Text.Diff.IgnoreWhitespace (EOF => EOL)

* feat: add workspace-specific default clone directory functionality

- Implemented logic in Clone.cs to set ParentFolder based on the active workspace's DefaultCloneDir if available, falling back to the global GitDefaultCloneDir.
- Added DefaultCloneDir property to Workspace.cs to store the default clone directory for each workspace.
- Updated ConfigureWorkspace.axaml to include a TextBox and Button for setting the DefaultCloneDir in the UI.
- Implemented folder selection functionality in ConfigureWorkspace.axaml.cs to allow users to choose a directory for cloning.
- This closes issue #1145

---------

Co-authored-by: mpagani <massimo.pagani@unitec-group.com>
2025-04-14 16:41:34 +08:00
leo
e89dbd8f43
code_review: PR #1177
- use `Command.ReadToEnd` instead of `Command.Exec` to avoid git trims line endings.
- use `StringBuilder.Append('\n')` instead of `StringBuilder.AppendLine()` to restore original line endings (we split the original diff output by `\n` not `\r')
- there's no need to show file content (the `StreamReader.ReadLine()` will trim line endings)

Signed-off-by: leo <longshuang@msn.cn>
2025-04-14 16:06:52 +08:00
Massimo
81820e7034
refactor: improve diff handling for EOL changes and enhance text diff… (#1177)
* refactor: improve diff handling for EOL changes and enhance text diff display

- Updated `Diff.cs` to streamline whitespace handling in diff arguments.
- Enhanced `DiffContext.cs` to check for EOL changes when old and new hashes differ, creating a text diff if necessary.
- Added support for showing end-of-line symbols in `TextDiffView.axaml.cs` options.

* localization: update translations to include EOF handling in ignore whitespace messages

- Modified the ignore whitespace text in multiple language files to specify that EOF changes are also ignored.
- Ensured consistency across all localization files for the patch application feature.

* revert: Typo in DiffResult comment

* revert: update diff arguments to ignore CR at EOL in whitespace handling (like before changes)

* revert: update translations to remove EOF references in Text.Apply.IgnoreWS and fixed typo in Text.Diff.IgnoreWhitespace (EOF => EOL)

---------

Co-authored-by: mpagani <massimo.pagani@unitec-group.com>
2025-04-14 15:18:45 +08:00
leo
e7f0217a7b
refactor: move binding for ToolTip.IsOpen from code to axaml
Signed-off-by: leo <longshuang@msn.cn>
2025-04-14 11:51:40 +08:00
leo
0cb2ca78fe
code_review: PR #1180
- replace `SetNeedNavigateToUpstreamHead` with `NavigateToBranchDelayed`
- navigate to current HEAD instead of original source HEAD after merge

Signed-off-by: leo <longshuang@msn.cn>
2025-04-14 11:35:50 +08:00
Gadfly
17cf402c78
enhance: navigate to upstream head after fetch, pull, and merge (#1180) 2025-04-14 10:42:34 +08:00
leo
245de9b458
fix: tooltip did not hide after pointer move out (#1178)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-14 10:40:24 +08:00
leo
e76328ff38
Merge branch 'master' into develop 2025-04-14 09:56:48 +08:00
leo
61a1b130f2
Merge branch 'release/v2025.13' 2025-04-14 09:55:55 +08:00
leo
69d8d963ea
version: Release 2025.13
Signed-off-by: leo <longshuang@msn.cn>
2025-04-14 09:55:49 +08:00
leo
48835ca043
project: upgrade AvaloniaUI to 11.2.7
Signed-off-by: leo <longshuang@msn.cn>
2025-04-14 09:53:59 +08:00
github-actions[bot]
241f92a290 doc: Update translation status and missing keys 2025-04-14 01:47:39 +00:00
AquariusStar
12b1204809
update russian localization (#1181) 2025-04-14 09:47:23 +08:00
leo
cd5a682194
refactor: directly use --exclude=HEAD instead of --exclude=HEA[D]
Signed-off-by: leo <longshuang@msn.cn>
2025-04-11 15:44:02 +08:00
leo
18888de081
refactor: rewrite histories filter to support ref name that contains non-ascii characters (#1175)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-11 15:39:51 +08:00
github-actions[bot]
13af0a43ed doc: Update translation status and missing keys 2025-04-11 04:31:25 +00:00
leo
af350c2fcd
code_review: PR #1174
- keeps all keys in locale files in order
- add தமிழ் (Tamil)

Signed-off-by: leo <longshuang@msn.cn>
2025-04-11 12:31:09 +08:00
தமிழ் நேரம்
accccb5ea3
தமிழ் (Tamil) translation file added (#1174)
* Tamil file added

220

* 0

* Tamil file added

220

0

(cherry picked from commit 355db34db382d17e0b8f0bb6f05b8e2e2f2963d9)
2025-04-11 12:22:48 +08:00
github-actions[bot]
cfabfb7368 doc: Update translation status and missing keys 2025-04-11 02:02:56 +00:00
leo
1799de4907
code_review: PR #1173
- rename c-style `file_arg` to `fileArg`
- add missing translations for zh_CN and zh_TW
- re-design conflict view and add tooltip for `USE THEIRS` and `USE MINE`
- re-order unstaged toolbar buttons

Signed-off-by: leo <longshuang@msn.cn>
2025-04-11 10:02:33 +08:00
github-actions[bot]
a99ab37797 doc: Update translation status and missing keys 2025-04-11 01:33:18 +00:00
Göran W
47824dc27a
Add button for running external mergetool on ALL conflicts (#1173)
* Make a few non-translated strings localizable (in Conflict view)

* Add button and wiring to run mergetool on all conflicts

* Corrected spelling and wording in related code and exception msg
2025-04-11 09:33:07 +08:00
leo
3b18ee0b37
code_style: remove unused code
Signed-off-by: leo <longshuang@msn.cn>
2025-04-08 20:20:20 +08:00
github-actions[bot]
5d90c2ed60 doc: Update translation status and missing keys 2025-04-08 12:06:21 +00:00
leo
768b324356
ux: if there are no local changes, show different confirm message (#1143)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-08 20:06:00 +08:00
github-actions[bot]
8b5f491e34 doc: Update translation status and missing keys 2025-04-08 12:01:06 +00:00
leo
506af95963
enhance: new confirm empty commit dialog (#1143)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-08 20:00:42 +08:00
leo
898a8bc69a
ux: resize confirm commit dialog
Signed-off-by: leo <longshuang@msn.cn>
2025-04-08 18:05:53 +08:00
leo
da38b72ee5
ux: disable commit button when commit message is empty
Signed-off-by: leo <longshuang@msn.cn>
2025-04-08 18:03:40 +08:00
leo
7cda7211f1
refactor: statistics dialog
- use `%aN+%aE` instead of `%aN` to get commit author
- show user avatar in statistics dialog

Signed-off-by: leo <longshuang@msn.cn>
2025-04-07 21:20:59 +08:00
Göran W
1555abd027
Added new ExternalMerger - Plastic SCM (#1162)
Motivation:
https://m-pixel.com/how-to-use-plastic-scms-merge-tool-with-p4v/
2025-04-07 20:22:53 +08:00
github-actions[bot]
7fedef396f doc: Update translation status and missing keys 2025-04-07 12:19:19 +00:00
leo
2c5ee4fa99
localization: add keys deleted by sorter tools back
Signed-off-by: leo <longshuang@msn.cn>
2025-04-07 20:19:00 +08:00
github-actions[bot]
f29402ceec doc: Update translation status and missing keys 2025-04-07 12:05:43 +00:00
leo
f5c213060e
localization: keep all keys in order and remove duplicated keys in fr_FR (#1161)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-07 20:05:24 +08:00
leo
3275dd07d2
enhance: auto stash and re-apply local changes before squashing (#1141)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-07 16:04:10 +08:00
github-actions[bot]
67fb0b300f doc: Update translation status and missing keys 2025-04-07 06:43:08 +00:00
leo
3049730dd5
feature: add Preferred Merge Mode in repository configure (#1156)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-07 14:42:46 +08:00
leo
ad9021e892
enhance: allow using + character in branch name (#1152)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-07 14:07:58 +08:00
leo
39f7f119dd
doc: always show current translation status in develop branch
Signed-off-by: leo <longshuang@msn.cn>
2025-04-07 12:06:06 +08:00
leo
3431ed4bab
Merge branch 'master' into develop 2025-04-07 12:02:24 +08:00
leo
f3d99d64bf
Merge branch 'release/v2025.12' 2025-04-07 12:00:59 +08:00
leo
b65c697e5b
version: Release 2025.12
Signed-off-by: leo <longshuang@msn.cn>
2025-04-07 12:00:45 +08:00
github-actions[bot]
48f8b6116a doc: Update translation status and missing keys 2025-04-07 03:48:59 +00:00
leo
fa02c65da5
code_review: PR #1153
- use a single filter for both unstage and staged files
- show confirm dialog if staged files are displayed partially

Signed-off-by: leo <longshuang@msn.cn>
2025-04-07 11:48:38 +08:00
Göran W
a37c6b29ec
In Local Changes, added filter-box in Staged area, to match Unstaged area (#1153)
Also added minimal handling (RaiseException) if trying to commit with active filter (might commit more changes than visible, so disallow).
Minor unification in unstageChanges() to make it more similar to StageChanges().
2025-04-07 10:37:58 +08:00
leo
ac7b02590b
enhance: add comma between date and time (#1150)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-07 10:23:37 +08:00
leo
8c9cf05c1d
fix: renamed files are missing in commit changes and stash changes (#1151)
Signed-off-by: leo <longshuang@msn.cn>
2025-04-07 10:14:02 +08:00
leo
c615d04038
doc: update README.md for Japanese support
Signed-off-by: leo <longshuang@msn.cn>
2025-04-07 09:54:48 +08:00
github-actions[bot]
17d285d9bf doc: Update translation status and missing keys 2025-04-07 01:53:35 +00:00
Sousi Omine
ef106e6909
Add Japanese localization (#1157)
* Initial Japanese translation

Only a small part was translated

* Unspecified words will be in English

When new words are added, they will be displayed in English even if Japanese support is delayed.

* Expanded translation scope

* Expanded translation scope

* Proceed with translation with a focus on overall settings

* Re-translated the outdated settings screen

* Add items that only exist in the latest en_US and remove items that do not exist in en_US

* A lot of translation work done

* A lot more translation work has been done

* ja_JP.axaml has been translated into Japanese

* Fixed three incomplete parts of the Japanese translation
2025-04-07 09:53:20 +08:00
github-actions[bot]
cbc7079e59 doc: Update translation status and missing keys 2025-04-07 01:45:21 +00:00
UchiTesting
904432a8f1
style(locale): Add a few translations to the French locale (#1158) 2025-04-07 09:45:02 +08:00
github-actions[bot]
7ef4cca1f5 doc: Update translation status and missing keys 2025-04-02 09:20:43 +00:00
Javier J. Martínez M.
2deb79f8ce
localization: update spanish translations (#1142)
add literal translation for 'CopyFullPath' string
2025-04-02 17:20:33 +08:00
leo
8e55ba1b47
enhance: avoid unhandled exceptions in timer
Signed-off-by: leo <longshuang@msn.cn>
2025-03-31 19:06:10 +08:00
leo
55be1ad1ca
Merge branch 'master' into develop 2025-03-31 09:30:56 +08:00
leo
1138ba304d
Merge branch 'release/2025.11' 2025-03-31 09:30:18 +08:00
leo
ae5fa6a793
version: Release 2025.11
Signed-off-by: leo <longshuang@msn.cn>
2025-03-31 09:29:56 +08:00
leo
0045e06d78
project: upgrade AvaloniaUI to 11.2.6
Signed-off-by: leo <longshuang@msn.cn>
2025-03-31 09:29:07 +08:00
qiufengshe
07d99f5fd2
enhance: get email hash code opimization (#1137)
(cherry picked from commit 839b92a284d6b103894f6a8a39e5ce1f99bb12fa)
2025-03-31 09:22:57 +08:00
github-actions[bot]
9ee3a00fba doc: Update translation status and missing keys 2025-03-31 01:21:15 +00:00
AquariusStar
1482a005bb
localization: update and fix translation russian (#1136) 2025-03-31 09:20:54 +08:00
github-actions[bot]
ce7196490a doc: Update translation status and missing keys 2025-03-28 10:02:16 +00:00
leo
276d000bcf
refactor: change Copy File Name to Copy Full Path for selected file or change (#1132)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-28 18:01:53 +08:00
github-actions[bot]
b26c8a64ad doc: Update translation status and missing keys 2025-03-28 04:20:55 +00:00
leo
56ebc182f2
enhance: try to reinstate not onl the working tree's change, but also the index's ones (#1135)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-28 12:20:36 +08:00
Gadfly
1575ae977e
fix: improve font family name handling by collapsing multiple spaces (#1131) 2025-03-27 20:22:46 +08:00
Gadfly
4153eec1a8
chore: Update DEB package configuration with installed size (#1130) 2025-03-26 12:15:15 +08:00
github-actions[bot]
fc37677546 doc: Update translation status and missing keys 2025-03-26 01:30:58 +00:00
leo
4fb853d1fd
localization: add translation Text.Configure.IssueTracker.AddSampleAzure for Chinese (#1128)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-26 09:30:41 +08:00
github-actions[bot]
dccf53e518 doc: Update translation status and missing keys 2025-03-26 01:27:21 +00:00
Iacopo Sbalchiero
ca0fb7ae10
Adding template for Azure DevOps workitems (#1128)
* feat: add Azure DevOps issue tracker integration

* localization: add Azure DevOps sample rule to issue tracker in multiple languages
2025-03-26 09:27:10 +08:00
leo
f37ac904b9
enhance: do not create crash log for unobserved task exceptions (#1121)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-25 10:33:39 +08:00
github-actions[bot]
467089aec5 doc: Update translation status and missing keys 2025-03-25 01:51:33 +00:00
Javier J. Martínez M.
380e6713b5
localization: update spanish translations (#1124) 2025-03-25 09:51:22 +08:00
leo
fc85dd3269
enhance: improve Repository.Open() performance (#1121)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-24 19:37:39 +08:00
leo
0a877c6730
project: upgrade OpenAI and Azure.AI.OpenAI to 2.2.0-beta.4
Signed-off-by: leo <longshuang@msn.cn>
2025-03-24 10:03:27 +08:00
leo
166c925eee
Merge branch 'master' into develop 2025-03-24 09:45:30 +08:00
leo
7581d761cc
Merge branch 'release/v2025.10' 2025-03-24 09:44:50 +08:00
leo
88bb603dc9
version: Release 2025.10
Signed-off-by: leo <longshuang@msn.cn>
2025-03-24 09:44:41 +08:00
leo
d335cac167
enhance: only raise BlockNavigationChangedEvent when UseBlockNavigation enabled
Signed-off-by: leo <longshuang@msn.cn>
2025-03-21 18:00:46 +08:00
leo
9590f96a44
enhance: clear highlight chunk while scrolling out of TextArea.TextView
Signed-off-by: leo <longshuang@msn.cn>
2025-03-21 17:46:11 +08:00
leo
03f49ccff0
refactor: text diff view block navigation
Signed-off-by: leo <longshuang@msn.cn>
2025-03-21 17:35:59 +08:00
leo
39f4cd1732
ci: move all translation status to TRANSLATION.md and do not modify README.md while checking localization
Signed-off-by: leo <longshuang@msn.cn>
2025-03-21 10:54:47 +08:00
leo
cdc0fbb753
doc: update README.md
Signed-off-by: leo <longshuang@msn.cn>
2025-03-21 10:23:52 +08:00
leo
8c1e1a3e6a
fix: text diff view scrolling issue introduced by AvaloniaEdit 11.2.0 (commit 7caa03a09b)
- `SyncScrollOffset` does not update in `side-by-side` mode while scrolling
- Highlighted chunk is not cleared when scroll by drag scrollbar

Signed-off-by: leo <longshuang@msn.cn>
2025-03-21 10:09:43 +08:00
github-actions[bot]
56253e95c3 doc: Update translation status and missing keys 2025-03-21 01:31:07 +00:00
Ilian Delagrange
5467703a6e
localization: add missing french translations (#1113)
Co-authored-by: Ilian Delagrange <ilian@MacBook-Air-de-Ilian.local>
2025-03-21 09:30:57 +08:00
leo
7cd5814410
enhance: better regex for output of Commands.CompareRevisions
Signed-off-by: leo <longshuang@msn.cn>
2025-03-20 21:18:51 +08:00
leo
38d87fa1a1
feature: use git stash show -u --name-status <stash_name> command to query changes in selected stash if git >= 2.32.0
Signed-off-by: leo <longshuang@msn.cn>
2025-03-20 21:12:08 +08:00
leo
65dbfd336d
refactor: it's not necessary to store untracked file list for selected stash
Signed-off-by: leo <longshuang@msn.cn>
2025-03-20 20:53:30 +08:00
leo
891e1b2ec8
ux: show name of stash instead of SHA which is useless to user
Signed-off-by: leo <longshuang@msn.cn>
2025-03-20 19:56:06 +08:00
github-actions[bot]
c349ac10f3 doc: Update translation status and missing keys 2025-03-20 03:11:14 +00:00
leo
145273b4a7
refactor: move Show tags in commit graph to Preferences (#1109)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-20 11:10:48 +08:00
leo
a5bdcab341
code_style: move dynamic context menu creation to view models
Signed-off-by: leo <longshuang@msn.cn>
2025-03-20 09:38:02 +08:00
github-actions[bot]
673b335a2a doc: Update translation status and missing keys 2025-03-20 01:14:21 +00:00
AquariusStar
f7197e08eb
localization: update russian localization (#1111) 2025-03-20 09:14:07 +08:00
github-actions[bot]
f02a7b9858 doc: Update translation status and missing keys 2025-03-18 13:40:50 +00:00
leo
2512d3be7a
feature: allow to hide tags in graph (#1109)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-18 21:40:31 +08:00
leo
ae1e46b586
fix: layout horizontal not working since 2025.9 after switching away from history screen (#1108)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-18 19:47:54 +08:00
leo
822452a20c
enhance: show inner exception message if possible when check update failed
Signed-off-by: leo <longshuang@msn.cn>
2025-03-18 15:55:32 +08:00
leo
760e44877b
fix: wrong split char
Signed-off-by: leo <longshuang@msn.cn>
2025-03-18 12:15:00 +08:00
leo
695db2a319
code_style: run dotnet format
Signed-off-by: leo <longshuang@msn.cn>
2025-03-17 20:57:18 +08:00
leo
8d47bd5cd9
refactor: use --format=<format> instead of --pretty=format:<format>
Signed-off-by: leo <longshuang@msn.cn>
2025-03-17 20:46:01 +08:00
leo
808302ce84
code_review: PR #1106
- Use new syntex `[...]` instead of `new char[] {...}` to create char arrays
- Use `string.ReplaceLineEndings('\n').Split('\n')` instead of `string.Split(['\n', '\r'], StringSplitOptions.RemoveEmptyEntries)` because that the `Signer` part may be missing

Signed-off-by: leo <longshuang@msn.cn>
2025-03-17 20:35:31 +08:00
Gadfly
b930066b5a
fix: improve line splitting to handle both LF and CRLF line endings (#1106) 2025-03-17 19:59:28 +08:00
leo
a0cddaea80
feature: support --ff-only option for git merge command
Signed-off-by: leo <longshuang@msn.cn>
2025-03-17 19:53:47 +08:00
github-actions[bot]
2b95ea2ab1 doc: Update translation status and missing keys 2025-03-17 09:15:30 +00:00
Leonardo
c9fe373dda
add missing key and fix untranslated one (#1104) 2025-03-17 17:15:17 +08:00
leo
398b14695c
enhance: the git dir of worktree's owner repository may not named .git
Signed-off-by: leo <longshuang@msn.cn>
2025-03-17 17:10:59 +08:00
github-actions[bot]
5845ef3eb6 doc: Update translation status and missing keys 2025-03-17 09:06:42 +00:00
leo
3e8bba0d0b
ux: re-design About page
Signed-off-by: leo <longshuang@msn.cn>
2025-03-17 17:06:26 +08:00
leo
7031693489
refactor: pass dirs to watcher directly
Signed-off-by: leo <longshuang@msn.cn>
2025-03-17 16:30:16 +08:00
leo
b4ab4afd3a
code_review: PR #1103
Since we only use `$GIT_COMMON_DIR` in filesystem watcher, it is unnecessary to store this value in `Repository`, and we can query the `$GIT_COMMON_DIR` only when it looks like a worktree

Signed-off-by: leo <longshuang@msn.cn>
2025-03-17 16:19:59 +08:00
Gadfly
cea8a90680
refactor: use $GIT_COMMON_DIR instead of cut $GIT_DIR/worktrees (#1103) 2025-03-17 15:56:13 +08:00
github-actions[bot]
265aaa1d67 doc: Update translation status and missing keys 2025-03-17 07:30:48 +00:00
leo
cdd1926e2f
refactor: rewrite git apply implementation
- Do not translate commandline options for `git`
- Re-design combox layout for `git apply` popup

Signed-off-by: leo <longshuang@msn.cn>
2025-03-17 15:30:32 +08:00
leo
ddfc868df3
ux: re-design merge option style
Signed-off-by: leo <longshuang@msn.cn>
2025-03-17 15:08:49 +08:00
leo
10fd0f9d15
doc: fix typo
Signed-off-by: leo <longshuang@msn.cn>
2025-03-17 12:02:32 +08:00
leo
99a45335fe
doc: group third-party components by types
Signed-off-by: leo <longshuang@msn.cn>
2025-03-17 12:01:29 +08:00
leo
8f8385072c
doc: add third-party components
Signed-off-by: leo <longshuang@msn.cn>
2025-03-17 11:56:38 +08:00
Gadfly
a480ba0139
docs: Add third-party components and licenses section
(cherry picked from commit 95c697248755f7b6de4d2d0bfdaa9de1e572c9f6)
2025-03-17 11:47:51 +08:00
Gadfly
4b41029768
fix: use better JSP grammar file and add licensing information (#1102) 2025-03-17 11:31:50 +08:00
leo
6273c01d71
fix: git rev-list raises errors after selected commit in Histories page (#1101)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-17 10:55:54 +08:00
Gadfly
450dadf76c
feat: Add JSP grammar support and improve TextMateHelper file type handling (#1100)
- Extend grammar support by allowing multiple file extensions per grammar and adding JSP file type handling.
- Add a new JSON grammar file for JavaServer Pages (JSP) syntax highlighting.
2025-03-17 10:12:44 +08:00
leo
7caa03a09b
project: upgrade AvaloniaEdit to 11.2.0
Signed-off-by: leo <longshuang@msn.cn>
2025-03-17 09:57:52 +08:00
leo
d9cf849b9f
Merge branch 'master' into develop 2025-03-17 09:38:30 +08:00
leo
6fd6bbb6b5
Merge branch 'release/v2025.09' 2025-03-17 09:37:49 +08:00
leo
34f8618989
version: Release 2025.09
Signed-off-by: leo <longshuang@msn.cn>
2025-03-17 09:37:40 +08:00
leo
84979b20b3
ux: force using VertialAlignment="Center" for sign info of commit (#1098)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-17 09:32:31 +08:00
Gadfly
66517fd4bf
enhance: add tooltips to various UI elements for better accessibility (#1097)
* enhance: add tooltips to various UI elements for better accessibility

* refactor: simplify user string conversion
2025-03-16 11:23:42 +08:00
github-actions[bot]
a46e52582f doc: Update translation status and missing keys 2025-03-14 08:57:15 +00:00
Asurada
db504241ea
feat: add translation for "1 hour ago" in multiple languages (#1096) 2025-03-14 16:57:03 +08:00
leo
c3e1fb93b6
refactor: fix maxOS PATH env
Signed-off-by: leo <longshuang@msn.cn>
2025-03-14 10:54:09 +08:00
leo
c8bee2f6ba
code_review: PR #1093
Merge deleting branch and tag on remote into `SourceGit.Commands.Push(repo, remote, refname, isDelete)`

Signed-off-by: leo <longshuang@msn.cn>
2025-03-14 09:36:34 +08:00
Michael Pakhantsov
9645b65db6
Explicitly provided fully qualified reference for the git branch, becase can be exists a tag and a branch with identical names (#1093)
Fix push command for branch deletion

Updated the `push` command to use `--delete refs/heads/{name}` instead of `--delete {name}` for clearer branch reference when deleting a remote branch.

Co-authored-by: Michael Pakhantsov <michae.pakhantsov@gmail.com>
2025-03-14 09:26:59 +08:00
leo
67f4330dd4
code_style: arrange methods in App.axaml.cs
Signed-off-by: leo <longshuang@msn.cn>
2025-03-13 15:23:43 +08:00
leo
9560496c7b
code_review: PR #1092
- Remove `SourceGit.ViewModels.Preference.FixFontFamilyName` (it is not necessary any more)
- Use `string.Join` instead of `StringBuilder` to make the logic more clear

Signed-off-by: leo <longshuang@msn.cn>
2025-03-13 15:17:20 +08:00
Gadfly
b9b684a83d
fix: improve font string processing in SetFonts method (#1092) 2025-03-13 15:05:30 +08:00
github-actions[bot]
519bdf1ddc doc: Update translation status and missing keys 2025-03-13 02:22:09 +00:00
leo
0e261cffd2
refactor: rewrite the way to deal with uncommitted local changes when checkout/pull/create branch (#1085)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-13 10:21:54 +08:00
leo
e430e847ff
enhance: auto convert spaces with dashes while renaming a branch (#1088)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-13 09:50:42 +08:00
Gadfly
7331167be2
fix: schedule DWM frame extension to next render frame on Windows 10 (#1087)
The DwmExtendFrameIntoClientArea call needs to be posted to the next render frame to ensure the window handle is fully initialized and avoid potential race conditions.
2025-03-13 09:38:08 +08:00
Morgan Courbet
f07832c385
docs: fix typo in README.md
(cherry picked from commit 59fd2aaab1)
2025-03-13 09:24:43 +08:00
leo
e4f5c34e0c
code_style: remove whitespaces
Signed-off-by: leo <longshuang@msn.cn>
2025-03-12 17:58:57 +08:00
leo
eaa322dfab
enhance: re-design commit search result display (#1083)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-12 17:57:31 +08:00
leo
77d8afe056
refactor: reduce the times to call RefreshLayout
Signed-off-by: leo <longshuang@msn.cn>
2025-03-12 15:10:43 +08:00
leo
0476a825ef
code_style: move some code from Histories.axaml to separate files
Signed-off-by: leo <longshuang@msn.cn>
2025-03-12 14:58:59 +08:00
leo
bb2284c4c9
refactor: re-write commit searching (part 3)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-12 11:53:24 +08:00
leo
ee7ccc0391
refactor: re-write commit searching (part 2)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-12 11:05:19 +08:00
leo
231f3bf668
enhance: use --ancestry-path=<commit_oid> to reduce unnecessary outpus while querying children commits
Signed-off-by: leo <longshuang@msn.cn>
2025-03-12 10:11:00 +08:00
leo
f5d6e1264d
refactor: use List<T> instead of AvaloniaList<T> since it is not used for bindings
Signed-off-by: leo <longshuang@msn.cn>
2025-03-11 23:01:34 +08:00
leo
64a41dce39
refactor: rewrite searching commit by file path
Signed-off-by: leo <longshuang@msn.cn>
2025-03-11 20:55:39 +08:00
leo
fa4d9d24e9
enhance: hide suggestion popups when window is deactived (#963)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-11 20:22:32 +08:00
leo
91c5c96afc
fix: accessing dummy in multi-threads throws exception
Signed-off-by: leo <longshuang@msn.cn>
2025-03-11 20:05:34 +08:00
leo
2fc03025ee
fix: file suggestion popup did not show while searching commit by file path
Signed-off-by: leo <longshuang@msn.cn>
2025-03-11 19:52:50 +08:00
leo
471452646b
refactor: use System.Threading.CancellationToken instead of SourceGit.Commands.Command.CancelToken to cancel fetching information of selected commit
Signed-off-by: leo <longshuang@msn.cn>
2025-03-11 16:53:51 +08:00
leo
f23e3478e6
fix: do not save preference in design mode
Signed-off-by: leo <longshuang@msn.cn>
2025-03-11 11:41:37 +08:00
leo
54d49a9eda
fix: app crashes when close a repository on read-only drive (#1080)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-11 09:36:13 +08:00
leo
5f2bd8ad94
ux: layout for Preferences window
Signed-off-by: leo <longshuang@msn.cn>
2025-03-11 09:27:32 +08:00
leo
f54c8877d7
Merge pull request #1079 from AquariusStar/develop_translation_russian
update russian localization
2025-03-11 09:21:20 +08:00
Михаил Усоцкий
f496d15f70 update russian localization 2025-03-10 20:15:29 +03:00
leo
cf8cff6b64
code_style: add ViewModels.Repository.GetCustomAction(scope)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-10 21:30:04 +08:00
leo
5c279b4b56
feature: add global configuration for custom action (#1077)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-10 21:19:38 +08:00
leo
0f9087fac6
code_review: PR #1078
- Remove `ForceEnglishLocale` because we want all `git` outputs in English
- Remove locale settings for `ExecuteCustomAction`

Signed-off-by: leo <longshuang@msn.cn>
2025-03-10 20:08:42 +08:00
Gadfly
860f52153b
fix: Force English locale in branch query command. (#1078) 2025-03-10 20:05:37 +08:00
leo
b4fbc2372b
enhance: show commit info tip when hover SHA in conflict view
Signed-off-by: leo <longshuang@msn.cn>
2025-03-10 20:02:09 +08:00
leo
2b2f070c4a
enhance: use --no-optional-locks parameter for git status command
Signed-off-by: leo <longshuang@msn.cn>
2025-03-10 18:29:11 +08:00
leo
e65cb50495
fix: use \ as path delim on Windows when executing custom actions (#1077)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-10 17:48:02 +08:00
Gadfly
cdae9168ed
ci(windows): maintain SourceGit folder structure (#1076) 2025-03-10 15:44:39 +08:00
leo
2e51e8939b
Merge branch 'master' into develop 2025-03-10 12:34:34 +08:00
leo
e3cc987682
Merge branch 'develop' 2025-03-10 12:33:20 +08:00
Gadfly
c1c0e7b2a0
enhance: Save Preferences after switched Workspace and closed Preferences (#1073) 2025-03-10 12:04:19 +08:00
leo
df6cbcaa28
fix: app crashed after enable Show children in the commit details (#1072)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-10 11:33:38 +08:00
leo
855466686d
ux: show conflict sources when it comes from a stash or patch (#1067)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-10 10:22:49 +08:00
leo
bfc3f37e47
Merge branch 'master' into develop 2025-03-10 09:37:40 +08:00
leo
18d3b9560b
Merge branch 'release/v2025.08' 2025-03-10 09:36:44 +08:00
leo
82fdd2e9d4
version: Release 2025.08
Signed-off-by: leo <longshuang@msn.cn>
2025-03-10 09:36:36 +08:00
Gadfly
6ba26770c4
ci: enhance Linux and Windows package workflow (#1071)
* ci: fix Linux packaging workflow with specific Ubuntu 20.04 image

* ci: use Compress-Archive in Windows try to prevent Defender false positives
2025-03-10 09:28:13 +08:00
github-actions[bot]
978801c9ff doc: Update translation status and missing keys 2025-03-10 01:27:39 +00:00
AquariusStar
2fb1d7e14a
update and fix translation russian (#1070) 2025-03-10 09:27:25 +08:00
Gustav Andersson
89f655c84d
fix: Show detached HEAD (#1060) 2025-03-07 16:16:15 +08:00
leo
0860245674
code_style: simple window do not using DataContext
Signed-off-by: leo <longshuang@msn.cn>
2025-03-07 15:44:50 +08:00
leo
43fed8e04d
refactor: re-write About window
Signed-off-by: leo <longshuang@msn.cn>
2025-03-07 15:15:47 +08:00
leo
83f23583be
enhance: supports to navigate to target commit while resolving conflicts
Signed-off-by: leo <longshuang@msn.cn>
2025-03-07 12:22:47 +08:00
leo
ca6d41ee60
enhance: try to get stopped at revision info from .git/rebase-merge/head
Signed-off-by: leo <longshuang@msn.cn>
2025-03-07 11:39:15 +08:00
github-actions[bot]
773e27fda7 doc: Update translation status and missing keys 2025-03-07 01:32:14 +00:00
Javier J. Martínez M.
14877d4d63
localization: update spanish translations (#1061)
add missing spanish translations
update previous references of `patch` as `parche`
2025-03-07 09:32:05 +08:00
leo
92fa25ae8d
ux: disable scrollbar in NumericUpDown control (#1023)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-06 15:14:05 +08:00
leo
aa0d4b4296
ux: adjust column width of commit hash and time after font size changed (#994)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-06 11:50:22 +08:00
leo
78c0d8d334
fix: both --tags and --no-tags are used in git pull command
Signed-off-by: leo <longshuang@msn.cn>
2025-03-06 10:37:50 +08:00
leo
81bbe11345
code_style: rename some variables in ParseLinksInMessage
Signed-off-by: leo <longshuang@msn.cn>
2025-03-05 17:06:45 +08:00
Gadfly
991ebe4082
ci: set ubuntu:20.04 (#1056) 2025-03-05 09:55:55 +08:00
leo
fb8d4a2542
code_review: PR #1055
- since the author and time are already shown in the blame view, use the full message as tooltip is better.
- cache the commit message in `ViewModels.Blame` since the `Tooltip` of control may change.
- querying commit message synchronously (it's very fast) to avoid similar issues in commit details panel.

Signed-off-by: leo <longshuang@msn.cn>
2025-03-05 09:54:23 +08:00
GadflyFang
269903503f
feat: Add commit Tooltip in Blame (#1055)
Fixes #993
2025-03-05 09:36:32 +08:00
leo
5e898a809e
enhance: check commit hash after intersect testing
Signed-off-by: leo <longshuang@msn.cn>
2025-03-05 09:30:55 +08:00
GadflyFang
71d0b69eee
fix: prevent kill apt process by accident (#1054) 2025-03-04 19:51:36 +08:00
leo
792e61b24f
ux: re-design the layout for Interactive Rebase window that tries to fix issue #1037
Signed-off-by: leo <longshuang@msn.cn>
2025-03-04 18:23:13 +08:00
leo
e884f27f67
code_style: re-order CommitDetail properties
Signed-off-by: leo <longshuang@msn.cn>
2025-03-04 18:02:29 +08:00
leo
e28f8611ef
ux: re-design the layout for Interactive Rebase window that tries to fix issue #1037
Signed-off-by: leo <longshuang@msn.cn>
2025-03-04 17:39:21 +08:00
github-actions[bot]
5af856b9da doc: Update translation status and missing keys 2025-03-04 09:26:48 +00:00
leo
2137ad9ec9
enhance: allow to configure editor tab width in preferences window (#1048)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-04 17:26:27 +08:00
leo
11af5d9b29
code_style: use ?: operator instead of if ... else statement
Signed-off-by: leo <longshuang@msn.cn>
2025-03-04 16:42:32 +08:00
GadflyFang
68e96f428e
fix: validate result not update #1052 (#1053) 2025-03-04 16:34:51 +08:00
GadflyFang
25e6e261a6
refactor: Improve key modifier checks and AltGr detection (#1051) 2025-03-04 16:33:43 +08:00
leo
96538b9a62
fix: there's an extra line-ending while copy multiple lines from text diff view (#1049)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-04 16:26:14 +08:00
leo
b75676a7f8
refactor: commit message
- move issue tracker and commit hash links parsing to view models
- parsing links async
- make sure matched hash is a valid commit oid
- disable `CHILDREN` row in submodule info panel

Signed-off-by: leo <longshuang@msn.cn>
2025-03-04 16:04:19 +08:00
leo
5301a368e0
ux: re-design the layout for Interactive Rebase window that tries to fix issue #1037
Signed-off-by: leo <longshuang@msn.cn>
2025-03-04 09:46:02 +08:00
leo
d4bcc60113
enhance: disable CONTINUE button while it is running (#1046)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-04 09:29:07 +08:00
leo
35ee4a47db
fix: the last selected line is missing while trying to copy multiple lines in text diff view (#1044)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-03 15:39:59 +08:00
leo
598bba5210
code_review: PR #1043
`FileModeChange` should not be changed out of UIThread

Signed-off-by: leo <longshuang@msn.cn>
2025-03-03 14:25:49 +08:00
GadflyFang
72c7f24e2f
fix: set FileModeChange after RefreshAll (#1043) 2025-03-03 14:17:03 +08:00
GadflyFang
9dffd55c2b
build: Add pre-install and pre-removal scripts for DEBIAN package (#1041)
kill sourcegit before install
2025-03-03 10:39:57 +08:00
GadflyFang
7f8372f6b5
enhance: Handle file mode changes for new/deleted file (#1040) 2025-03-03 10:38:58 +08:00
leo
4c63c4c90d
Merge branch 'master' into develop 2025-03-03 09:28:02 +08:00
leo
4418214d38
Merge branch 'release/v2025.07' 2025-03-03 09:27:04 +08:00
leo
8c48b9623e
version: Release 2025.07
Signed-off-by: leo <longshuang@msn.cn>
2025-03-03 09:26:49 +08:00
leo
25fa223c6b
enhance: better regex for remote URL (#1039)
Signed-off-by: leo <longshuang@msn.cn>
2025-03-02 10:39:04 +08:00
heartacker
8423f53ace
chore: 升级Avalonia和CommunityToolkit.Mvvm包 (#1038)
- Upgrade Avalonia packages to version 11.2.5 and CommunityToolkit.Mvvm to version 8.4.0.
2025-03-01 19:20:37 +08:00
leo
8dd0274bdd
enhance: only write MERGE_MSG when commit message is not null
Signed-off-by: leo <longshuang@msn.cn>
2025-03-01 09:21:52 +08:00
leo
5199fb2b74
enhance: do NOT remember the last selected handling method of uncommitted local changes (#977)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-28 22:14:21 +08:00
leo
c90b7afac1
feature: makes the base on branch name selectable (#1036)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-28 19:18:10 +08:00
leo
88c7d5bbc9
fix: app crashes when Return key is pressed while current action is already running (#1035)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-28 19:15:02 +08:00
leo
9cf1cba9b7
feature: apply commit message while continue merge/revert (#1027)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-28 19:08:27 +08:00
leo
639bff9ad8
code_style: run dotnet format
Signed-off-by: leo <longshuang@msn.cn>
2025-02-28 17:27:17 +08:00
leo
3e70ff94b0
fix: should not use ... to get revision range for rebasing (#1033)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-28 17:06:07 +08:00
Andre Greeff
f930967698
feat: remove IsMerged check from "Interactive Rebase" context menu conditional (#1033) 2025-02-28 17:05:49 +08:00
github-actions[bot]
109eee5668 doc: Update translation status and missing keys 2025-02-27 13:14:38 +00:00
GadflyFang
57cb9d0909
fix: Dynamic load copyright (#1030) 2025-02-27 21:14:24 +08:00
github-actions[bot]
caca1dcaaf doc: Update translation status and missing keys 2025-02-27 13:12:27 +00:00
Leonardo
337ee1a55d
localization: update italian translation (#1029) 2025-02-27 21:12:14 +08:00
leo
fc3043b93c
fix: double-clicking button trigger binded command twice (#1032)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-27 21:10:41 +08:00
leo
61d7f36be4
enhance: reset diff view context for empty commit
Signed-off-by: leo <longshuang@msn.cn>
2025-02-27 10:59:00 +08:00
leo
bdf439a742
enhance: do not show error message if it is empty
Signed-off-by: leo <longshuang@msn.cn>
2025-02-26 16:33:11 +08:00
leo
7bfb95f7ce
fix: ptyxis does not start with given working directory (#1005)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-26 16:07:18 +08:00
github-actions[bot]
c849c13fcb doc: Update translation status and missing keys 2025-02-26 07:45:04 +00:00
Javier J. Martínez M.
8f7db4e874
localization: add missing spanish translations (#1024)
* localization: add missing spanish translations

* localization: add missing spanish translations
2025-02-26 15:44:51 +08:00
leo
a7e254cac6
fix: multiple bindings for IsVisible property of Button
Signed-off-by: leo <longshuang@msn.cn>
2025-02-26 09:50:54 +08:00
leo
79306ad73b
fix: ptyxis does not start with given working directory (#1005)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-25 19:50:09 +08:00
leo
a0786bf9cc
fix: pulling with empty repository (no local branch) crashes this app (#1020)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-25 14:37:03 +08:00
leo
4d740f4731
feature: auto-select the first change when selected stash changed (#1019)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-25 11:09:12 +08:00
leo
c6747f72f9
feature: auto-select first change in commit details panel and revision/branch compare panel (#1019)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-25 10:53:42 +08:00
github-actions[bot]
1f35e83799 doc: Update translation status and missing keys 2025-02-24 13:25:13 +00:00
leo
1d037c7c57
feature: add context menu Save As Patch... for selected stash (#1018)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-24 21:24:53 +08:00
leo
4868ea1a0b
Merge branch 'master' into develop 2025-02-24 09:50:24 +08:00
leo
fb6b57bdf5
Merge branch 'release/v2025.06' 2025-02-24 09:49:41 +08:00
leo
0b7805b2ee
version: Release 2025.06
Signed-off-by: leo <longshuang@msn.cn>
2025-02-24 09:49:30 +08:00
github-actions[bot]
89e09d842d doc: Update translation status and missing keys 2025-02-24 01:45:49 +00:00
Javier J. Martínez M.
d4341c1195
localization: add missing spanish translations (#1017) 2025-02-24 09:45:39 +08:00
github-actions[bot]
74e5bcb704 doc: Update translation status and missing keys 2025-02-24 01:37:52 +00:00
leo
124bdc97f9
localization: add missing keys for zh_CN and zh_TW
Signed-off-by: leo <longshuang@msn.cn>
2025-02-24 09:37:34 +08:00
github-actions[bot]
52a53cc697 doc: Update translation status and missing keys 2025-02-24 01:32:32 +00:00
Göran W
fa4caa2186
enhance: add first/last buttons for block-nav, no wrapping (#1015) (#1016)
Added 2 new buttons (only visible in block-nav mode), with new icons and new (en_US) strings (First/Last Difference).
Implemented these new buttons, and disabled the automatic wrap-around for the prev/next buttons in block-nav mode.
2025-02-24 09:32:19 +08:00
Ikko Eltociear Ashimine
9ab602788a
docs: update README.md (#1014)
comaptible -> compatible
2025-02-24 09:28:00 +08:00
github-actions[bot]
b2ab62825e doc: Update translation status and missing keys 2025-02-21 02:48:21 +00:00
saxc
841276852a
localization: add german translations (#1011)
(cherry picked from commit fcc720480c85fe01120e555c22b6aec286ee717b)
2025-02-21 10:47:48 +08:00
leo
2b4fc64c73
fix: resolve conflict with deleted files does not work (#1009)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-21 10:26:14 +08:00
leo
9da2c787db
enhance: supports to configure fetch.prune for selected repository (#995)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-21 09:44:51 +08:00
leo
b5feabfd37
enhance: auto-set commit message while rebasing is inprogress (#1003)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-20 15:42:11 +08:00
leo
08da3ac5d8
enhance: prefer to use Default Remote in repository settings while fetching remote changes (#1008)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-20 11:12:29 +08:00
leo
731f1055bc
feat!: add ptyxis support (#1005)
BREAKING CHANGE: Index of `Custom` shell/terminal

Signed-off-by: leo <longshuang@msn.cn>
2025-02-20 11:04:57 +08:00
leo
507e502874
fix: Custom Action height is not large enough to display all contents (#1004)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-20 10:19:00 +08:00
github-actions[bot]
b57c0158c1 doc: Update translation status and missing keys 2025-02-20 02:14:51 +00:00
leo
53f591bdad
ux: add a warning icon when the tracking upstream of a local branch is gone (#1006)
Co-authored-by: Davide Tentori <dtentori@softeam.it>
2025-02-20 10:14:25 +08:00
leo
0e1dfba7ef
code_review: PR #1007
Signed-off-by: leo <longshuang@msn.cn>
2025-02-20 09:34:03 +08:00
Oleg Kosmakov
cbc2e46beb
fix: Update unstaged filed counter when unstaged files change (#1007)
* Add missing OnPropertyChanged in Cleanup

* Force unstaged count to refresh
2025-02-20 09:31:07 +08:00
leo
ce16ac63eb
enhance: submodule bookmark inherts from parent repo (#1001)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-19 19:22:36 +08:00
github-actions[bot]
68946d2140 doc: Update translation status and missing keys 2025-02-19 10:01:37 +00:00
leo
c3eca0d7fd
refactor: OpenAI integration (#996)
- Add `OpenAIResponse` to trim the `<think>...</think>` block
- Add an `Enable Streaming` option to fix the issue that some services do not support streaming output

Signed-off-by: leo <longshuang@msn.cn>
2025-02-19 18:01:16 +08:00
leo
69d107430a
project: upgrade OpenAI and Azure.AI.OpenAI to 2.2.0-beta.2
Signed-off-by: leo <longshuang@msn.cn>
2025-02-19 10:44:51 +08:00
leo
59638eb731
enhance: tag push behavior while creating and deleting (#999)
- Remember the state of `Push to all remotes after created` checkbox while creating tag
- Remember the state of `Delete from remote repositories` checkbox while deleting tag
- Change default state of `Delete from remote repositories` to `false`

Signed-off-by: leo <longshuang@msn.cn>
2025-02-19 10:35:34 +08:00
leo
5d2cd8b2fa
ux: new style for current branch (#998)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-18 18:19:19 +08:00
leo
3d4a9b86b4
ux: use bold font weight for current branch name (#997)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-18 16:54:00 +08:00
leo
af4645a4ad
project: upgrade LiveChartsCore.SkiaSharpView.Avalonia to 2.0.0-rc5.4
Signed-off-by: leo <longshuang@msn.cn>
2025-02-18 16:27:19 +08:00
leo
cf42381802
Merge branch 'master' into develop 2025-02-18 11:00:25 +08:00
leo
ed37b42a4a
Merge branch 'release/v2025.05' 2025-02-18 10:58:58 +08:00
leo
d401e898a2
version: Release 2025.05
Signed-off-by: leo <longshuang@msn.cn>
2025-02-18 10:58:30 +08:00
leo
e28abf8119
enhance: supports remove single histories filter (#987)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-18 10:04:56 +08:00
leo
14f47a9007
ux: style for current branch in branch tree (#991)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-18 09:50:01 +08:00
Arun
7ae5100fcf
chore: Convey the usage of monospace font only in text editor (#990)
Signed-off-by: Arun <visionofarun@gmail.com>
(cherry picked from commit 7ec7de7b4a933a599cfffc79382a6edd13582c85)
2025-02-18 09:32:15 +08:00
Chiahong
36178d5ecf
localization: update zh_TW.axaml (#989) 2025-02-18 09:26:44 +08:00
leo
bc66e24407
project: upgrade AvaloniaUI to 11.2.4
Signed-off-by: leo <longshuang@msn.cn>
2025-02-15 17:43:47 +08:00
github-actions[bot]
e39351b4a7 doc: Update translation status and missing keys 2025-02-14 02:43:26 +00:00
leo
9104060d79
feature: support add custom actions for selected branch (#980)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-14 10:43:08 +08:00
leo
9b07034846
code_review: PR #978
* Remove unnecessary parentheses since the name of relative path uses secondary foreground color already

Signed-off-by: leo <longshuang@msn.cn>
2025-02-13 10:46:28 +08:00
Dmitrij D. Czarkoff
588879eb7f
feat: change worktree presentation (#978)
Present the worktree name first, then relative path to the main repo.

This is more aligned with Git's own UI,  and works better with UI size constrains.
2025-02-13 10:41:08 +08:00
leo
c6aedf1193
ux: right margin of main tab bar on macOS
Signed-off-by: leo <longshuang@msn.cn>
2025-02-12 21:29:17 +08:00
leo
3302bdeb26
localization: remove duplicated keys in de_DE
Signed-off-by: leo <longshuang@msn.cn>
2025-02-12 21:25:57 +08:00
github-actions[bot]
21e4dcffd0 doc: Update translation status and missing keys 2025-02-12 02:59:19 +00:00
Christopher Göttfert
9757678dcf
localization: added missing german translations (#973)
Co-authored-by: Christopher Göttfert <Christopher.Goettfert@.uni-wuerzburg.de>
2025-02-12 10:59:00 +08:00
github-actions[bot]
19e72f8650 doc: Update translation status and missing keys 2025-02-12 02:51:20 +00:00
AquariusStar
eea55ec56f
localization: update russian localization (#971) 2025-02-12 10:51:06 +08:00
leo
21cfd17cdb
fix: do NOT quit when try to input @ via Alt Gr+Q with German ISO keyboard layout (#970)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-11 18:57:54 +08:00
leo
e9d16a5102
project: upgrade TextMateSharp to 1.0.66 (#969)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-11 16:58:32 +08:00
github-actions[bot]
1bfe1a2755 doc: Update translation status and missing keys 2025-02-11 07:15:47 +00:00
leo
011a415949
enhance: add a button to clear all notifications (#950)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-11 15:15:27 +08:00
leo
37e5926388
code_style: keep translation ordered
Signed-off-by: leo <longshuang@msn.cn>
2025-02-11 14:41:56 +08:00
leo
06df27780f
localization: update Text.Configure.CustomAction.WaitForExit for en_US
Signed-off-by: leo <longshuang@msn.cn>
2025-02-11 14:36:46 +08:00
github-actions[bot]
37fed93589 doc: Update translation status and missing keys 2025-02-11 06:34:33 +00:00
leo
af20ab2448
feature: add Wait for action done option to control whether or not to wait for the custom action execution to complete (#951)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-11 14:34:14 +08:00
leo
10fba08e43
code_review: PR #949
Signed-off-by: leo <longshuang@msn.cn>
2025-02-11 11:07:33 +08:00
Doodeletion
821063e3ec
Swap selection start and end index if selection is created from bottom to top (#967) 2025-02-11 10:57:20 +08:00
leo
aebfffee00
fix: GUI stops refreshing after manually refresh while merge tool is open (#949)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-10 20:51:36 +08:00
leo
0c8179b934
enhance: add a opened tabs selector popup (#958)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-10 20:06:44 +08:00
leo
e757e63bf7
refactor: launcher tab bar scroller visibility
Signed-off-by: leo <longshuang@msn.cn>
2025-02-10 16:42:42 +08:00
leo
59e4f0d388
refactor: update submodules when branch status changed
Signed-off-by: leo <longshuang@msn.cn>
2025-02-10 14:28:20 +08:00
GadflyFang
bead749c57
enhance: async refresh operations in Watcher (#961) 2025-02-10 14:05:27 +08:00
leo
c61ecb0bb0
Merge branch 'master' into develop 2025-02-10 10:05:55 +08:00
leo
7fc7c8fdb6
Merge branch 'release/v2025.04' 2025-02-10 10:05:23 +08:00
leo
3b76a30948
version: Release 2025.04
Signed-off-by: leo <longshuang@msn.cn>
2025-02-10 10:05:10 +08:00
GadflyFang
ef2e0a8a56
fix: Ignore the Chain-of-Thought in AI response (#952)
- Improve chat response processing to handle thinking patterns using regular expressions.
- Migrate server value by removing trailing '/chat/completions' path.
2025-02-08 17:30:27 +08:00
leo
8cc056d2af
enhance: supports searching/filtering unstaged changes (#960)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-08 17:16:56 +08:00
leo
35abeae758
project: upgrade Azure.AI.OpenAI to 2.2.0-beta.1
Signed-off-by: leo <longshuang@msn.cn>
2025-02-08 16:20:45 +08:00
leo
aa0d066944
enhance: move Create New Page button out of tab list if scroll arrow is visible (#958)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-08 14:55:55 +08:00
leo
2495911bd8
code_style: run dotnet format
Signed-off-by: leo <longshuang@msn.cn>
2025-02-08 12:08:06 +08:00
leo
1f0dd15192
fix: only o1-mini does not supports system prompt
Signed-off-by: leo <longshuang@msn.cn>
2025-02-08 11:57:10 +08:00
github-actions[bot]
6a80e54b47 doc: Update translation status and missing keys 2025-02-08 02:17:16 +00:00
leo
a915708db3
refactor: rewrite OpenAI integration
- use `OpenAI` and `Azure.AI.OpenAI`
- use `developer` role instead of `system` for OpenAI's `o1` series models
- use streaming response
- re-design `AIAssistant`

Signed-off-by: leo <longshuang@msn.cn>
2025-02-08 10:03:11 +08:00
github-actions[bot]
cf90e51887 doc: Update translation status and missing keys 2025-02-07 10:08:27 +00:00
leo
f8bc022813
ux: clarify Delete operation for tree node in welcome page (#957)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-07 18:08:07 +08:00
leo
12597fd3e3
code_style: run dotnet format
Signed-off-by: leo <longshuang@msn.cn>
2025-02-07 12:06:29 +08:00
leo
9a36e652e6
fix: add a new interface CanStartDirectly and move this check to StartPopup (#956)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-07 11:56:30 +08:00
leo
8ed7a99923
fix: COMMIT & PUSH should hide when there's no remotes available (#956)
Signed-off-by: leo <longshuang@msn.cn>
2025-02-07 11:45:18 +08:00
leo
8edd955370
code_review: PR #956
* Just use `Check` instead of a new one `AutoCheck`

Signed-off-by: leo <longshuang@msn.cn>
2025-02-07 11:36:30 +08:00
GadflyFang
2105fd450d
fix: when upstream is null show CommitAndPush and stop auto push (#955) (#956) 2025-02-07 11:30:14 +08:00
github-actions[bot]
d1f3469250 doc: Update translation status and missing keys 2025-02-06 08:34:27 +00:00
leo
7089f29b85
refactor: re-implement git stash apply
* supports `--index` option
* add an option to drop selected stash after applying
* remove `Pop` context menu for stash

Signed-off-by: leo <longshuang@msn.cn>
2025-02-06 16:33:55 +08:00
leo
dbb1df5f8b
fix: single _ will be traited as a space by image shields
Signed-off-by: leo <longshuang@msn.cn>
2025-02-06 15:34:12 +08:00
leo
e9297096df
enhance: remember last view mode in file histories view
Signed-off-by: leo <longshuang@msn.cn>
2025-02-06 13:30:56 +08:00
leo
dacbd2a791
enhance: auto-select the first revision in file histories view
Signed-off-by: leo <longshuang@msn.cn>
2025-02-06 13:13:45 +08:00
leo
38a8490d16
code_review: PR #946
Signed-off-by: leo <longshuang@msn.cn>
2025-02-06 13:07:58 +08:00
GadflyFang
9aba737d9e
feat: support compare both revision in FileHistories (#786) (#946) 2025-02-06 11:33:55 +08:00
GadflyFang
65a9406c9a
fix: adjust SHA regex pattern to min 6 chars (#944)
- Adjust the SHA regex pattern to match commit hashes with a minimum length of 6 characters instead of 10.
2025-02-06 10:55:07 +08:00
github-actions[bot]
2ee5b4707a doc: Update translation status and missing keys 2025-02-06 02:32:00 +00:00
GadflyFang
3ca4dc488c
feat: Add stash auto-restore functionality (#947) (#948) 2025-02-06 10:31:46 +08:00
GadflyFang
942f349275
enhance: enhance crash logging with detailed system info (#943)
- Enhance crash logging by adding detailed system and process information, including thread name, user, app start time, exception time, and memory usage.
2025-02-06 10:22:34 +08:00
GadflyFang
84533599f1
fix: support encoded url in remote (#938) 2025-02-06 10:22:01 +08:00
github-actions[bot]
018a32b95b doc: Update translation status and missing keys 2025-02-06 02:20:06 +00:00
leo
e784696058
enhance: add a checkbox to toggle Initialize & update submodules after clone
Signed-off-by: leo <longshuang@msn.cn>
2025-02-06 10:19:43 +08:00
GadflyFang
3af6012561
refactor: Update submodules individually to avoid failures (#925) (#936)
* refactor: Update submodules individually to avoid failures (#925)

- Remove `--recurse-submodules` flag from the clone command to simplify the cloning process.
- Refactor submodule update logic to handle updating all submodules in a loop and improve progress description handling.

* fix: Parse submodule list even if submodule status fails (#935)
2025-02-06 10:08:12 +08:00
GadflyFang
a4157e11e6
fix: Improve in-progress rebase handling (#933)
* fix: Improve in-progress rebase handling

* fix: Close merge popup even if there are conflicts (#941)
2025-02-06 10:00:35 +08:00
github-actions[bot]
c2950ad209 doc: Update translation status and missing keys 2025-02-06 02:00:25 +00:00
Leonardo
9a9f63a787
Add missing keys and general reviewing of the Italian translation (#932)
* update italian translation

* ordered italian translation and removed from md file

* revert edits in translations.md
2025-02-06 10:00:12 +08:00
GadflyFang
4f41f44a9f
fix: add --include-untracked to stash push for specific changes (#931) 2025-02-06 09:51:03 +08:00
GadflyFang
92065dee12
fix: Ensure each ImageView instance calculates its own aspect ratio (#929)
* fix: Ensure each ImageView instance calculates its own aspect ratio

- Modified ArrangeOverride methods in ImageView class to independently calculate and apply the aspect ratio based on the instance's image.

Signed-off-by: Gadfly <gadfly@gadfly.vip>

* fix: Make IgnoredWhitespace toggle button visible based on IsTextDiff

---------

Signed-off-by: Gadfly <gadfly@gadfly.vip>
2025-02-06 09:49:45 +08:00
leo
dd254ebf4f
ux: new attached property MenuItemExtension.Command for MenuItem
Signed-off-by: leo <longshuang@msn.cn>
2025-01-26 14:55:44 +08:00
Erica Buckmann
6a1026c992
feature: Add Ghostty to macOS terminals. (#928) 2025-01-26 10:42:13 +08:00
leo
fa07bb5b5a
refactor: move per-repository config Enable --prune on fetch to global git config fetch.prune (#908)
Signed-off-by: leo <longshuang@msn.cn>
2025-01-25 12:06:48 +08:00
leo
aad42a8297
feature: select the cursor line by triple-click (#927)
Signed-off-by: leo <longshuang@msn.cn>
2025-01-25 11:14:15 +08:00
leo
733ffe1af2
localization: update Text.WorkingCopy.Amend since we already add --amend as tooltip
Signed-off-by: leo <longshuang@msn.cn>
2025-01-24 17:15:05 +08:00
github-actions[bot]
4f6a878177 doc: Update translation status and missing keys 2025-01-24 06:46:07 +00:00
leo
49ee9c8e33
ux: move --signoff toggle from repository configuration window to commit options bar
Signed-off-by: leo <longshuang@msn.cn>
2025-01-24 14:45:49 +08:00
github-actions[bot]
0192e941f0 doc: Update translation status and missing keys 2025-01-24 04:11:14 +00:00
leo
37c4545875
feature: branch name allows spaces and auto replace spaces with dashes (#917) 2025-01-24 12:10:56 +08:00
leo
ab080b53b1
enhance: exclude indicators or empty blocks in diff text view while copying text (#924) 2025-01-24 11:41:11 +08:00
github-actions[bot]
cc111baf01 doc: Update translation status and missing keys 2025-01-23 08:11:28 +00:00
leo
e242119a03
fix: searching by Author & Committer does not work when the committer is different with author 2025-01-23 16:11:07 +08:00
leo
620f411e99
code_style: move RevisionTextFileView 2025-01-22 11:42:14 +08:00
leo
e033a93dd8
localization: update Text.Fetch.Force 2025-01-22 11:36:53 +08:00
github-actions[bot]
cce08fb086 doc: Update translation status and missing keys 2025-01-22 03:23:54 +00:00
leo
cd0b2326f5
localization: update en_US 2025-01-22 11:23:38 +08:00
leo
75288e7a31
ci: replacing 100% and 100.00% with for translation progress in README.md 2025-01-22 11:21:24 +08:00
leo
6ae66095c2
project: upgrade LiveChartsCore.SkiaSharpView.Avalonia to 2.0.0-rc5.1 2025-01-22 10:55:38 +08:00
leo
cb4ad63ba3
fix: discarding changes with selected changes should never be traited as Discard all changes (#904) 2025-01-22 10:52:01 +08:00
aikawayataro
90c04f1db2
fix: _ is not parsed in template variable name (#920) 2025-01-21 20:01:09 +08:00
GadflyFang
6482ef227a
fix: prevent target branch HEAD from being changed when adding worktree (#919)
* fix: prevent target branch HEAD from being changed when adding worktree

Signed-off-by: Gadfly <gadfly@gadfly.vip>

* fix: worktree path validator trigger error

Signed-off-by: Gadfly <gadfly@gadfly.vip>

---------

Signed-off-by: Gadfly <gadfly@gadfly.vip>
2025-01-21 13:58:07 +08:00
leo
38e7b69450
Merge branch 'master' into develop 2025-01-20 10:06:59 +08:00
leo
0f13c002f5
Merge branch 'release/v2025.03' 2025-01-20 10:06:00 +08:00
leo
b00c81c996
version: Release 2025.03 2025-01-20 10:05:43 +08:00
leo
8a472cb472
fix: sometimes tags did not update after deleting selected tag (#908) 2025-01-15 10:42:35 +08:00
leo
53ec53a6ee
project: upgrade LiveChartsCore.SkiaSharpView.Avalonia to 2.0.0-rc5 2025-01-14 21:26:31 +08:00
leo
1c8d4d312a
fix: SelectableTextBlock does not re-draw after Text property changed (#906) 2025-01-14 21:02:32 +08:00
leo
c8aecc00cc
ux: use Grid instead of DockPanel 2025-01-14 20:39:56 +08:00
github-actions[bot]
5b425c4ed0 doc: Update translation status and missing keys 2025-01-14 10:11:25 +00:00
Nils van Rijsinge
765286ec0b
localization: add missing de_DE keys (#905)
Configure.IssueTracker Gittee 22ba8b3acf
General.DateFormat c058b4744b
Git.SSLVerify 1596ca71a5
Repository.HistoriesLayout 26ebd5ae7e 6b5e8c588d
OnlyHighlightCurrentBranchInHistories, UseRelativeTimeInHistories 26ebd5ae7e
Tags.Order..., Tags.Sort 08a128cd87
SetUpstream 6fe4d8162b
2025-01-14 18:11:11 +08:00
leo
8ea17e57da
Merge branch 'feat-bare-repository' into develop 2025-01-14 18:08:46 +08:00
leo
6f407fb086
enhance: enable --index option in git stash pop command by default (#903) 2025-01-14 18:07:55 +08:00
leo
f2b1c06bb8
enhance: disable checkout branch via double-clicking branch tree node (#899) 2025-01-14 17:57:31 +08:00
leo
766b60d05e
enhance: disable unused context menus for bare repository (#899) 2025-01-14 17:53:26 +08:00
leo
a9327274c6
enhance: disable LOCAL CHANGES and STASHES for bare repository (#899) 2025-01-14 17:26:01 +08:00
leo
5acc6e6928
enhance: double-click commit in histories of a bare repository 2025-01-14 17:26:01 +08:00
leo
a112d212dc
enhance: disable pull/stash/apply/git-flow/git-lfs buttons in bare repository 2025-01-14 17:26:01 +08:00
leo
b9b5220590
feature: bare repository support 2025-01-14 17:26:01 +08:00
leo
cc5f3ebfa5
refactor: do not run git add for untracked file while stashing local changes (#903) 2025-01-14 17:10:06 +08:00
leo
d8168c3ba6
ux: submodule alignment 2025-01-14 16:14:19 +08:00
Vixb
99b7086cd0
doc: update default path for windows (#901)
(cherry picked from commit 4456366ea63b277665d7250709928deb1e563675)
2025-01-14 10:20:51 +08:00
Mat
011f5258ad
fix: LFS locks do not show if user name contains . character (#902) 2025-01-14 10:18:56 +08:00
leo
5f4c1bb984
enhance: do not show Initialize Repository popup for bare repositories (#891) 2025-01-13 17:42:41 +08:00
leo
632222a776
ux: add icon for quit menu item 2025-01-13 15:37:55 +08:00
wl2776
458a1ea83c
feature: Exit on Ctrl+Q (#898) 2025-01-13 15:33:13 +08:00
leo
b10e084c54
ux: context menu separator 2025-01-13 14:47:32 +08:00
github-actions[bot]
88e64a4f31 doc: Update translation status and missing keys 2025-01-13 06:42:23 +00:00
leo
10d8d3b2ef
refactor: branch compare 2025-01-13 14:42:07 +08:00
GadflyFang
59e3e4c635
docs: Update README.md with APT source config changes (#897)
- Update APT source configuration to include architecture-specific settings.

Signed-off-by: Gadfly <gadfly@gadfly.vip>
2025-01-13 12:07:24 +08:00
leo
f87bf8b4c6
Merge branch 'master' into develop 2025-01-13 10:30:08 +08:00
leo
4f3e6398b0
Merge branch 'release/v2025.02' 2025-01-13 10:29:01 +08:00
leo
001e813b7e
version: Release 2025.02 2025-01-13 10:28:31 +08:00
leo
6e6cd7a7f3
enhance: do not show Initialize Repository popup for bare repositories (#891) 2025-01-13 10:25:58 +08:00
github-actions[bot]
a205e17bf2 doc: Update translation status and missing keys 2025-01-13 02:11:41 +00:00
wl2776
6e5626f267
fix: several typos in source code (#895) 2025-01-13 10:11:28 +08:00
github-actions[bot]
91883c9f11 doc: Update translation status and missing keys 2025-01-13 02:07:46 +00:00
UchiTesting
f8e7976ec2
style(locale): Translate French locale further (#896)
- Picked a few of the 1st lines from TRANSLATION.md
- Updated a few others. Prune to Elaguer for instance.
2025-01-13 10:07:32 +08:00
leo
b26838ff68
refactor: git version related commands
* use `--pathspec-from-file=<FILE>` in `git add` command if git >= 2.25.0
* use `--pathspec-from-file=<FILE>` in `git stash push` command if git >= 2.26.0
* use `--staged` in `git stash push` command only if git >= 2.35.0
2025-01-11 17:29:38 +08:00
aikawayataro
c939308e4c
readme: add package repository instructions (#893) 2025-01-11 15:06:42 +08:00
leo
275a52eb5c
refactor: add repository 2025-01-11 11:28:37 +08:00
leo
52fba29613
readme: add doc for Linux RPM/DEB packages 2025-01-10 14:32:01 +08:00
GadflyFang
d7ba310a24
build: Update package dependencies to include broader range of ICU libraries (#890)
Signed-off-by: Gadfly <gadfly@gadfly.vip>
(cherry picked from commit d340584249b771f497f818f45a3bc542bc473cc5)
2025-01-10 12:24:37 +08:00
aikawayataro
f1acc96a72
ci: remove Buildkite, add missing dependencies, README edits (#885)
* build: add libicu dependency for deb package

* ci: remove obsolete Buildkite publish workflow

* build: add xdg-utils dependency

* readme: update Linux notes

Remove Buildkite repo instructions and fix some typos.
2025-01-10 09:29:19 +08:00
github-actions[bot]
7361b3d403 doc: Update translation status and missing keys 2025-01-10 01:25:28 +00:00
Bernat Borràs Civil
eca5639e31
localization: add missing translations for Spanish (#886) 2025-01-10 09:25:16 +08:00
github-actions[bot]
dd15f3aa45 doc: Update translation status and missing keys 2025-01-10 01:24:30 +00:00
AquariusStar
afe55a5ff5
localization: update russian localization (#887) 2025-01-10 09:24:18 +08:00
leo
810568e179
fix: typo 2025-01-09 18:14:11 +08:00
leo
b06d14fec7
refactor: SourceGit.App 2025-01-09 18:12:11 +08:00
leo
495b3a9296
refactor: issue tracker configuration (#884) 2025-01-09 12:28:07 +08:00
github-actions[bot]
f74dbdf8ed doc: Update translation status and missing keys 2025-01-09 04:04:52 +00:00
leo
22ba8b3acf
feature: add issue/pr tracker for Gitee.com (#884) 2025-01-09 12:04:36 +08:00
leo
9baa2c9fad
refactor: get owner page of repsitory dynamically 2025-01-09 09:21:58 +08:00
leo
f07e838e6f
code_style: remove used code 2025-01-08 21:46:35 +08:00
leo
a3d744f426
code_style: run dotnet format 2025-01-08 21:44:35 +08:00
leo
f06b1d5d51
refactor: merge ViewModels.PopupHost into ViewModels.LauncherPage 2025-01-08 21:36:49 +08:00
leo
0e34a77add
enhance: threadsafe way to accessing _remotes (#882) 2025-01-08 19:20:27 +08:00
leo
94c532889b
fix: auto fetch does not work if use ssh (#882) 2025-01-08 19:09:52 +08:00
leo
8018abe0a2
code_style: remove unused namespace using 2025-01-08 16:10:16 +08:00
leo
5d791b63bf
fix: crach while submodule changed (#881) 2025-01-08 12:42:30 +08:00
leo
eea3d5db6c
ux: right margin of filter toggle button (#875) 2025-01-08 11:14:17 +08:00
leo
df422b2219
fix: missing popup window shadows on Windows 10 (#879) 2025-01-08 09:40:23 +08:00
github-actions[bot]
5f7b6c3c66 doc: Update translation status and missing keys 2025-01-07 11:51:52 +00:00
leo
1596ca71a5
feature: add checkbox to enable/disable global http.sslVerify configuration (#877) 2025-01-07 19:51:27 +08:00
leo
7a217336dc
enhance: graph color allocation 2025-01-07 15:24:11 +08:00
github-actions[bot]
0391ec99b4 doc: Update translation status and missing keys 2025-01-07 04:06:26 +00:00
leo
6fe4d8162b
refactor: use popup to change tracking branch 2025-01-07 12:05:52 +08:00
leo
25a2bf603f
ux: conventional commit message builder layout 2025-01-07 10:40:35 +08:00
leo
903a3b9660
feature: add Ctrl+Enter/⌘+Enter hotkey to submit conventional commit (#874) 2025-01-07 10:36:07 +08:00
leo
85504b1487
enhance: enable text search for branch ComboBox (#784) 2025-01-07 10:29:55 +08:00
leo
8b04ab52d6
fix: Height can not be negative (#869) 2025-01-07 09:48:44 +08:00
AquariusStar
7f9be03e5c
localization: update translation russian (#872)
fix
2025-01-06 20:18:31 +08:00
github-actions[bot]
999c19052c doc: Update translation status and missing keys 2025-01-06 12:17:41 +00:00
leo
6b5e8c588d
ux: add a group header for advanced histories options 2025-01-06 20:17:20 +08:00
leo
a00e62233f
ux: reduce width of buttons in Histories toolbar 2025-01-06 17:58:43 +08:00
leo
68cfb092fc
ux: use a transparent brush for non relatives paths (#848) 2025-01-06 17:52:59 +08:00
github-actions[bot]
fffa4f9bea doc: Update translation status and missing keys 2025-01-06 09:24:41 +00:00
AquariusStar
108a212108
localization: update russian translate (#870) 2025-01-06 17:24:27 +08:00
github-actions[bot]
03b06de907 doc: Update translation status and missing keys 2025-01-06 08:16:48 +00:00
leo
08a128cd87
feature: add a button to switch tag sort method (creatordate/name asc/name des) (#865) 2025-01-06 16:16:27 +08:00
leo
84721a7258
update: icon for --reflog 2025-01-06 15:21:15 +08:00
github-actions[bot]
702e8ec34f doc: Update translation status and missing keys 2025-01-06 06:59:46 +00:00
leo
26ebd5ae7e
feature: add option to only highlight current branch in commit graph (#848)
- add a toggle button to only highlight current branch in commit graph
- re-order buttons in histories toolbar
- remove unused icons and styles
2025-01-06 14:59:27 +08:00
leo
65e820e4d5
fix: new created branch expanded state is not remembered 2025-01-06 10:41:41 +08:00
leo
68210d8a3e
ci: release title 2025-01-06 10:23:58 +08:00
leo
a5e1e5ebc8
Merge branch 'master' into develop 2025-01-06 09:55:38 +08:00
leo
0aa2aaaf9d
Merge branch 'release/v2025.01' 2025-01-06 09:54:31 +08:00
leo
1898385086
version: Release 2025.01 2025-01-06 09:54:18 +08:00
leo
0628e3d3f7
feature: clear commit message when toggle off Amend 2025-01-03 14:27:54 +08:00
leo
8ebf4d76d6
ux: use AvaloniaEdit.TextEditor to display release update detail info 2025-01-03 14:13:57 +08:00
leo
c6afc6a205
doc: add tips for translation 2025-01-03 09:31:04 +08:00
leo
4e06944c9f
fix: auto-filter does not work well (#855) 2025-01-02 20:05:04 +08:00
leo
127315528a
feature: auto-change filter branches after checkout (#855) 2025-01-02 14:19:10 +08:00
leo
2a55ba6d07
fix: Avalonia designer does not work (#858) 2025-01-02 11:19:52 +08:00
Juga Paazmaya
554ffc728d
Short list of commands needed when nothing has not yet been done (#859) 2025-01-02 09:14:19 +08:00
UchiTesting
1e75a518a6
style(locale): Translate French locale further (#857)
- "Checkout" translates to "Récupérer". Updating lines that match
- "Push" translates to "Pousser". Updating lines that match.
- Staged translates to "Présent dans l'index" but it is too long to I go simply for "Indexé".
- Translating a few extra lines
- Some of the terms mentioned above remain untranslated because it is not appropriate provided their respective context
2025-01-02 01:52:58 +08:00
github-actions[bot]
70fa80bab9 doc: Update translation status and missing keys 2025-01-01 17:52:14 +00:00
AquariusStar
4b02199c9b
update russian translate (#853)
fix and update
2025-01-02 01:52:01 +08:00
leo
4f350c84c3
ux: use Auto for commit time column 2024-12-31 14:44:19 +08:00
leo
7a02854e2d
fix: bad output file name while creating archive by tag 2024-12-31 11:19:05 +08:00
leo
87e7b792bb
refactor: date time format
- generate example dynamically
- update commit/author time in histories immediately after data time format changed
2024-12-31 10:43:00 +08:00
leo
a6420aff9b
fix: crash if the executable file can not be found 2024-12-31 09:38:46 +08:00
wl2776
addc756fbf
feature: support several more variants of git installation on MacOS (#852) 2024-12-31 09:28:00 +08:00
leo
ced1737bdc
fix: typo in DataTimeFormat 2024-12-30 20:29:50 +08:00
leo
82fc261743
feature: shows the git configured commit template in Template/Histories popup (#846) 2024-12-30 19:40:58 +08:00
leo
8d12227227
ux: show date time format string 2024-12-30 17:47:55 +08:00
leo
7d0fa3b86d
Revert "feature: ignore remote.{REMOTE}.mirror settings (#844)"
This reverts commit 093176d10b.
2024-12-30 17:34:58 +08:00
github-actions[bot]
418897c5de doc: Update translation status and missing keys 2024-12-30 09:20:17 +00:00
leo
c058b4744b
feature: allows to change DateTime format (#755) 2024-12-30 17:19:55 +08:00
leo
dc649e6142
refactor: rewrite the portable mode (#851) 2024-12-30 15:12:23 +08:00
leo
093176d10b
feature: ignore remote.{REMOTE}.mirror settings (#844)
(cherry picked from commit 9164f1b7340f68e00fea99bf9bac67734062f930)
2024-12-30 14:54:04 +08:00
leo
7f268a6557
Merge branch 'master' into develop 2024-12-30 09:22:26 +08:00
leo
2d500fc35a
Merge branch 'release/v8.45' 2024-12-30 09:21:39 +08:00
leo
bb8e66e479
version: Release 8.45 2024-12-30 09:21:25 +08:00
github-actions[bot]
cdda418c2d doc: Update translation status and missing keys 2024-12-30 01:19:01 +00:00
Bernat Borràs Civil
1f316708fd
Update spanish translation (#849)
* Add missing translations

* Add missing keys after merge

* Remove duplicated string

* Sort unsorted strings
2024-12-30 09:18:49 +08:00
AquariusStar
03d3cbe11e
update translation russian (#850)
fix
2024-12-30 09:18:12 +08:00
AquariusStar
fa46586417
localization: update (#845)
fix incorrected translated
2024-12-28 12:17:36 +08:00
Martin Garstenauer
12e8a212d4
fix: Enter key does not stage/unstage all selected items (#843) 2024-12-27 20:26:18 +08:00
leo
5081d2fba2
fix: error occurs while using WinMerge as external diff tool with Single instance mode enabled (#842) 2024-12-27 17:40:34 +08:00
wl2776
e407399d03
Fix some more messages in russian and english (#839) 2024-12-26 09:23:41 +08:00
wl2776
4254a22d79
Fix grammar in tip (#838) 2024-12-25 18:17:06 +08:00
leo
c9b00d7bfe
ci: do not use portable for windows actions 2024-12-24 14:48:04 +08:00
leo
f53b71bfe7
feature: add -p:EnablePortable=true option for dotnet publish command to store app data portable (#834) 2024-12-24 09:23:50 +08:00
leo
7028e08390
enhance: remove invalid expanded node records in repository's settings 2024-12-23 16:56:49 +08:00
leo
ec94c8c1b4
Merge branch 'master' into develop 2024-12-23 09:21:06 +08:00
leo
f3adb25c82
Merge branch 'release/v8.44' 2024-12-23 09:20:23 +08:00
leo
9603f2b5aa
version: Release 8.44 2024-12-23 09:20:00 +08:00
leo
ae2ffd5b40
fix: wrong text trimming position 2024-12-20 15:31:33 +08:00
leo
2e838840e0
localization: update Text.OpenAppDataDir 2024-12-20 14:57:33 +08:00
leo
dbf12ff88e
ux: layout of commit message template 2024-12-20 14:11:22 +08:00
leo
1862428a0f
feature: supports Warp terminal on macOS (#829)
Signed-off-by: leo <longshuang@msn.cn>
2024-12-20 10:44:06 +08:00
leo
50892f7401
ux: re-order context menu items for selected multiple branches 2024-12-20 10:00:10 +08:00
leo
fec13cdc87
ux: layout of INFORMATION page 2024-12-20 09:56:53 +08:00
leo
ed229166ee
enhance: allow wrap commit refs in INFORMATION page (#807) 2024-12-20 09:51:25 +08:00
leo
6c795e1238
project: upgrade TextMateSharp to 1.0.65 2024-12-19 19:30:17 +08:00
leo
7ee7964799
ux: use trimmed error message 2024-12-19 17:38:53 +08:00
leo
7acd6e42fe
project: upgrade Avalonia to 11.2.3 2024-12-19 17:09:20 +08:00
leo
9a6d6bb68a
ux: enable text wrap in notification panel 2024-12-19 10:01:36 +08:00
leo
37bf6dec5e
feature: remember --reflog, --first-parent, --topo-order and --date-order toggle states 2024-12-18 19:49:08 +08:00
leo
ed3e7cbfaf
ux: update unreal icon 2024-12-18 19:03:59 +08:00
github-actions[bot]
df6f2f3585 doc: Update translation status and missing keys 2024-12-18 10:54:50 +00:00
wl2776
b2ca6480b8
localization: Russian translation (#827)
add missing keys, based on TRANSLATION.md

reword some existing keys that seemed incorrect
2024-12-18 18:54:38 +08:00
leo
a899de2b98
enhance: ignore refs/*/HEAD when query refs those contains given commit 2024-12-18 17:50:19 +08:00
leo
31ad317a57
feature: remember the Include Untracked Files toggle state in local changes 2024-12-18 17:30:04 +08:00
leo
5ec8279d38
feature: remember the state of repository sidebar (#823) 2024-12-18 15:33:09 +08:00
leo
7526def448
project: rename dotnet publish option -p:SourceGitNoAot=true|false to -p:DisableAOT=true|false 2024-12-18 10:17:00 +08:00
leo
e4fb9eeb52
refactor: built-in default avatar 2024-12-18 10:00:25 +08:00
leo
cb3727b524
feature: remember --force check state in git fetch popup (#824) 2024-12-18 09:36:25 +08:00
Martin Garstenauer
39dff8a93f
ux: change text selection brush to improve readability (#825) 2024-12-18 09:25:56 +08:00
leo
23326d179a
refactor: commit hash detection in message 2024-12-17 14:39:18 +08:00
leo
6768a2c1fe
ux: new notification theme 2024-12-17 12:08:25 +08:00
leo
1c345df37d
ux: add some tooltips to checkboxes 2024-12-17 11:24:59 +08:00
leo
c768b1750e
feature: use -p:DisableUpdateDetection=true to disable built-in update detection feature (#819) 2024-12-17 10:26:35 +08:00
leo
707a227aca
ux: make Welcome page responsive (#821) 2024-12-17 09:36:06 +08:00
leo
f418b72c64
feature: use [$workspace] $repo_name ($repo_path) as main window's title (#818) 2024-12-16 15:47:33 +08:00
leo
5425fa64fe
refactor: use another way to open tooltip of SHA after getting commit info (#810) 2024-12-16 13:29:46 +08:00
github-actions[bot]
e4cfca0ffd doc: Update translation status and missing keys 2024-12-16 01:51:11 +00:00
Nils van Rijsinge
dd85760b7a
localization: add missing de_DE keys (#817)
* localization: add missing de_DE keys

BranchCM.MergeMultiBranches, CommitCM.MergeMultiple, MergeMultiple #793
CommitCM.Merge 2053ce033d
CommitDetail.Files.Search 894f3e9b03
Diff.UseBlockNavigation #703
FileCM.ResolveUsing 3b5d87391d
Hotkeys.Global.Clone bea2a39feb
InProgress.CherryPick.Head e1df5c52f1
InProgress.Merge.Operating ef40e4b738
InProgress.Rebase.StoppedAt, Repository.Skip #790
InProgress.Revert.Head 93d9a04460
Merge.Source 2504a52398
WorkingCopy.CommitToEdit c1368212df

* localization: consistently use clone with 'k'

for most other keys a more "germanized" version with a k is used rather than a c
2024-12-16 09:50:59 +08:00
leo
819602f77c
Merge branch 'master' into develop 2024-12-16 09:30:14 +08:00
leo
0e37e018ef
Merge branch 'release/v8.43' 2024-12-16 09:29:17 +08:00
leo
e1fb799fd4
version: Release 8.43 2024-12-16 09:29:06 +08:00
leo
f986e59a94
fix: tag filter hidden behind the scroll bar (#815)
Signed-off-by: leo <longshuang@msn.cn>
2024-12-14 20:25:25 +08:00
leo
0a0e2bc044
enhance: only create squash menu item if it is needed 2024-12-13 16:24:39 +08:00
leo
24b6153226
ux: context menu of selected commits
* update English translation
* re-order the menu items
2024-12-13 16:02:10 +08:00
leo
751991c816
refactor: rewrite the way reading full message of commit 2024-12-13 11:00:03 +08:00
leo
a99bd2e973
enhance: only dispatch error message if it contains valid data 2024-12-13 10:43:39 +08:00
Ezra
26923435e7
enhance: improve readability of default clone dir errors. (#813) 2024-12-13 10:08:47 +08:00
leo
02658839c2
enhance: notification popup 2024-12-13 10:08:26 +08:00
leo
6eb226eb44
fix: wrong whitespace at start of the last commit message while interactive rebasing (#790) 2024-12-12 20:01:10 +08:00
leo
59f11e9aca
fix: original FullMessage missing line-endings (#790) 2024-12-12 19:38:02 +08:00
leo
c4c7bef93c
ux: update Icons.Commit 2024-12-12 17:14:04 +08:00
leo
27afe1871f
fix: tooltip of commit sha did not close properly (#810) 2024-12-12 14:40:47 +08:00
github-actions[bot]
0ac1031c4c doc: Update translation status and missing keys 2024-12-12 02:03:49 +00:00
leo
2053ce033d
feature: supports merge selected commit to current branch (#800) 2024-12-12 10:03:34 +08:00
leo
e17b53da42
enhance: block-navigation in text diff view
* It is not necessary to re-calculate all the contents when `UseBlockNavigation` changed
* Redraw the text view after `block-navigation` has turned off
2024-12-12 09:44:55 +08:00
leo
9dd4166009
refactor: use MultiBinding instead of code to control visibility of Commit & Push button 2024-12-11 16:08:23 +08:00
leo
a10f9e0dd0
enhance: popup will be closed when cherry-pick or revert failed 2024-12-11 15:27:00 +08:00
leo
0dd6692cd8
enhance: supports --skip while reverting commits 2024-12-11 15:12:25 +08:00
leo
dcaeaef48a
refactor: re-design conflict panel 2024-12-11 11:33:20 +08:00
leo
36ecbcc4e0
enhance: supports self-host git server (#733) 2024-12-10 21:38:06 +08:00
leo
55ad194e0e
code_style: remove unused code 2024-12-10 21:09:26 +08:00
github-actions[bot]
9b88db290d doc: Update translation status and missing keys 2024-12-10 12:57:28 +00:00
leo
93d9a04460
enhance: show reverting commit in banner while reverting is in-progress 2024-12-10 20:57:10 +08:00
leo
2dd9cab695
enhance: try to use friendly name instead of commit hash 2024-12-10 20:23:46 +08:00
leo
3b5d87391d
ux: use Views.NameHighlightedTextBlock instead of plan text for FileCM.ResolveUsing 2024-12-10 16:56:05 +08:00
github-actions[bot]
767de75512 doc: Update translation status and missing keys 2024-12-10 08:44:55 +00:00
leo
feb7e96b2c
enhance: show friendly name instead of --theirs or --mine while resolving conflicts 2024-12-10 16:44:37 +08:00
leo
c8cdda3477
ux: color for in processing target 2024-12-10 16:17:12 +08:00
github-actions[bot]
3cecb3f888 doc: Update translation status and missing keys 2024-12-10 07:38:27 +00:00
leo
2504a52398
fix: wrong display when merge tag
* remove `Text.Merge.Source`  translations from `de_DE`/`es_ES`/`fr_FR`/`it_IT`/`pt_BR`/`ru_RU` because its content has been changed
2024-12-10 15:38:06 +08:00
github-actions[bot]
4dd3b7f412 doc: Update translation status and missing keys 2024-12-10 07:18:11 +00:00
leo
ef40e4b738
enhance: show source branch/tag/commit in banner while merging request in progress 2024-12-10 15:17:54 +08:00
leo
e1df5c52f1
localization: update Text.InProgress.CherryPick.Head 2024-12-10 14:13:44 +08:00
leo
33ef9a612d
fix: avoid crash if fontfamily contains consecutive whitespace (#799) 2024-12-10 12:06:36 +08:00
github-actions[bot]
0a486a90d9 doc: Update translation status and missing keys 2024-12-10 03:17:52 +00:00
leo
aee3abfffb
enhance: redesign in-progress banner (#790)
* show head for cherry-pick
* show stopped at for rebase
* supports `--skip` for cherry-pick and rebase
2024-12-10 11:17:30 +08:00
leo
1644b4c8ce
readme: remove unnecessary tips 2024-12-10 09:28:35 +08:00
Bernat Borràs Civil
967429cea6
doc: add repository instructions to readme (#797) 2024-12-10 09:27:26 +08:00
Данил Бизимов
33625b58da
readme: added appimagehub link (#798) 2024-12-10 09:26:15 +08:00
leo
64bedd2ae9
ux: layout for Views.MergeMultiple 2024-12-09 21:21:16 +08:00
github-actions[bot]
2b6210e61c doc: Update translation status and missing keys 2024-12-09 13:13:16 +00:00
leo
94daa46db9
code_review: PR #793
* do NOT modify the existing merge, and add a new constructor for `Commands.Merge` instead
* rewrite `ViewModels.MergeMultiple`
  - since `_histories.Commits.Find` may returns null, use `List<object>` instead of `List<Models.Commits>`
  - supports display merge target as both `Models.Commit` and `Models.Branch`
* rename translation key `Text.MergeMultiple.Commit` to `Text.MergeMultiple.Targets`, and add translations for zh_CN and zh_TW
* some UI/UX changes
2024-12-09 21:12:58 +08:00
github-actions[bot]
4eed9674b4 doc: Update translation status and missing keys 2024-12-09 13:04:39 +00:00
Dmitrij D. Czarkoff
dce33fdf60
feature: merge multiple heads (#793)
* feature: allow merging multiple heads
* feature: allow merging multiple branches from branch tree
2024-12-09 21:04:25 +08:00
github-actions[bot]
c9c7fb5d5b doc: Update translation status and missing keys 2024-12-09 08:44:36 +00:00
leo
ee3942fec6
code_review: PR #795
* update zh_CN and zh_TW translations
* simplify calling `Welcome.Clone`
2024-12-09 16:44:16 +08:00
github-actions[bot]
3990cc9452 doc: Update translation status and missing keys 2024-12-09 08:36:52 +00:00
Luigi Grilli
bea2a39feb
feature: added Ctrl+N/⌘+N shortcut (#795)
(cherry picked from commit 726cf0d376a9af9167145560977ec6e1bf748277)
2024-12-09 16:36:19 +08:00
leo
19307cebc0
ux: update icon for Block-Navigation 2024-12-09 16:11:20 +08:00
leo
a9011ddc2c
readme: update tooltips for Linux users 2024-12-09 10:24:59 +08:00
leo
9f5cbaba09
fix: publish-packages should depends on package and version 2024-12-09 09:56:07 +08:00
leo
a263002c83
Merge branch 'master' into develop 2024-12-09 09:36:03 +08:00
leo
4a3ef6267f
Merge branch 'release/v8.42' 2024-12-09 09:35:18 +08:00
leo
3196bd41a6
version: Release 8.42 2024-12-09 09:35:08 +08:00
github-actions[bot]
076ab95614 doc: Update translation status and missing keys 2024-12-09 01:31:58 +00:00
AquariusStar
33ff191212
localization: update (#794) 2024-12-09 09:31:45 +08:00
leo
962055dd2a
code_style: run dotnet format
Signed-off-by: leo <longshuang@msn.cn>
2024-12-08 21:51:33 +08:00
leo
723263d099
fix: wrong binding modes
Signed-off-by: leo <longshuang@msn.cn>
2024-12-08 21:47:20 +08:00
github-actions[bot]
ea130967fb doc: Update translation status and missing keys 2024-12-08 13:02:51 +00:00
leo
15d3ad355d
code_review: PR #703
* change the name of this feature to `Enable Block-Navigation`
* change the icon of the toggle button used to enable this feature
* use a new class `BlockNavigation` to hold all the data about this feature
* create `BlockNavigation` data only when it is enabled

Signed-off-by: leo <longshuang@msn.cn>
2024-12-08 21:02:30 +08:00
github-actions[bot]
0c04cccd52 doc: Update translation status and missing keys 2024-12-08 09:50:45 +00:00
Göran W
655d71b0bc
Add navigation and highlighting of change-blocks in Text Diff (#616, #717) (#703)
* Corrected misspelled local variable nextHigh(t)light

* Implemented change-block navigation

* Modified behavior of the Prev/Next Change buttons in DiffView toolbar.
* Well-defined change-blocks are pre-calculated and can be navigated between.
* Current change-block is highlighted in the Diff panel(s).
* Prev/next at start/end of range (re-)scrolls to first/last change-block
(I.e when unset, or already at first/last change-block, or at the only one.)
* Current change-block is unset in RefreshContent().

* Added safeguards for edge cases

* Added indicator of current/total change-blocks in DiffView toolbar

* Added new Icon and String (en-US) for Highlighted Diff Navigation

* Added Preference and ToggleButton for diff navigation style
2024-12-08 17:50:33 +08:00
GadflyFang
c062f27081
fix: Dispose _autoFetchTimer before _setting set to null (#792)
Signed-off-by: Gadfly <gadfly@gadfly.vip>
2024-12-06 15:09:14 +08:00
Bernat Borràs Civil
c2252266ce
Update Spanish translation (#791)
* Update spanish translation

* doc: Update translation status and missing keys

* Add missing key

(cherry picked from commit 2bf0641323325bf97d1fac9ed225228e5015a3ba)

* doc: Update translation status and missing keys

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-06 09:13:45 +08:00
leo
e18d6d65e8
ux: style of MenuItem 2024-12-05 20:43:31 +08:00
leo
75e9f1e9a4
feature: show track status in Delete Multiple Branches panel (#785) 2024-12-04 19:14:48 +08:00
leo
1ddd348a40
feature: show tracking status in Delete Branch panel if possible (#785) 2024-12-04 18:04:57 +08:00
leo
d616d0897b
refactor: relative time display mode (#777) 2024-12-04 11:25:25 +08:00
stone-w4tch3r
43928936bc
Added repositories for deb/rpm packages on buildkite (#780)
* added and used new github action for publishing packages to packagecloud

* publish-packages.yml WIP

* publish-packages.yml now uses curl push

* fix naming from packagecloud to buildkite

* Add debug logs to publish-packages.yml

* fix package path

* change repo name to sourcegit

* fixed unused code

* added --fail to curl pushes

* Remove leftowers from release.yml
2024-12-04 09:57:30 +08:00
stone-w4tch3r
abacccab00
feat: Add libicu dependency to RPM spec file (#781)
(cherry picked from commit f312895ef8c77098612645a54420539fef70a849)
(cherry picked from commit 662149045f9b37e8b8842125c82d835625055150)
2024-12-04 09:48:30 +08:00
leo
ca29a232e4
enhance: call gc after viewing commit changed 2024-12-03 10:44:27 +08:00
leo
ea0bec16da
refactor: use control instead of DataContext to get input string 2024-12-03 09:35:32 +08:00
leo
0160600c75
revert: changes about SystemAccentColor (#776)
This reverts commit db8ee3410b.
2024-12-03 09:27:16 +08:00
leo
d1a1b4b2b9
enhance: do NOT show search suggestion if input string is empty (#775) 2024-12-02 21:51:05 +08:00
github-actions[bot]
a52977baf3 doc: Update translation status and missing keys 2024-12-02 13:44:50 +00:00
leo
894f3e9b03
feature: supports searching revision files (#775) 2024-12-02 21:44:15 +08:00
leo
536f225867
feature: allow using Amend while rebasing (#773) 2024-12-02 10:38:40 +08:00
leo
f9c55a94c9
Merge branch 'master' into develop 2024-12-02 09:34:19 +08:00
439 changed files with 23615 additions and 9950 deletions

View file

@ -19,14 +19,25 @@ jobs:
os: macos-latest
runtime: osx-arm64
- name : Linux
os: ubuntu-20.04
os: ubuntu-latest
runtime: linux-x64
container: ubuntu:20.04
- name : Linux (arm64)
os: ubuntu-20.04
os: ubuntu-latest
runtime: linux-arm64
container: ubuntu:20.04
name: Build ${{ matrix.name }}
runs-on: ${{ matrix.os }}
container: ${{ matrix.container || '' }}
steps:
- name: Install common CLI tools
if: ${{ startsWith(matrix.runtime, 'linux-') }}
run: |
export DEBIAN_FRONTEND=noninteractive
ln -fs /usr/share/zoneinfo/Etc/UTC /etc/localtime
apt-get update
apt-get install -y sudo
sudo apt-get install -y curl wget git unzip zip libicu66 tzdata clang
- name: Checkout sources
uses: actions/checkout@v4
- name: Setup .NET
@ -47,7 +58,7 @@ jobs:
if: ${{ matrix.runtime == 'linux-arm64' }}
run: |
sudo apt-get update
sudo apt-get install clang llvm gcc-aarch64-linux-gnu zlib1g-dev:arm64
sudo apt-get install -y llvm gcc-aarch64-linux-gnu
- name: Build
run: dotnet build -c Release
- name: Publish

View file

@ -4,7 +4,6 @@ on:
branches: [ develop ]
paths:
- 'src/Resources/Locales/**'
- 'README.md'
workflow_dispatch:
workflow_call:
@ -32,8 +31,8 @@ jobs:
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
if [ -n "$(git status --porcelain)" ]; then
git add README.md TRANSLATION.md
git commit -m 'doc: Update translation status and missing keys'
git add TRANSLATION.md src/Resources/Locales/*.axaml
git commit -m 'doc: Update translation status and sort locale files'
git push
else
echo "No changes to commit"

View file

@ -7,12 +7,12 @@ on:
required: true
type: string
jobs:
windows-portable:
name: Package portable Windows app
runs-on: ubuntu-latest
windows:
name: Package Windows
runs-on: windows-2019
strategy:
matrix:
runtime: [win-x64, win-arm64]
runtime: [ win-x64, win-arm64 ]
steps:
- name: Checkout sources
uses: actions/checkout@v4
@ -22,10 +22,11 @@ jobs:
name: sourcegit.${{ matrix.runtime }}
path: build/SourceGit
- name: Package
shell: bash
env:
VERSION: ${{ inputs.version }}
RUNTIME: ${{ matrix.runtime }}
run: ./build/scripts/package.windows-portable.sh
run: ./build/scripts/package.windows.sh
- name: Upload package artifact
uses: actions/upload-artifact@v4
with:
@ -36,7 +37,7 @@ jobs:
with:
name: sourcegit.${{ matrix.runtime }}
osx-app:
name: Package OSX app
name: Package macOS
runs-on: macos-latest
strategy:
matrix:
@ -69,6 +70,7 @@ jobs:
linux:
name: Package Linux
runs-on: ubuntu-latest
container: ubuntu:20.04
strategy:
matrix:
runtime: [linux-x64, linux-arm64]
@ -77,9 +79,10 @@ jobs:
uses: actions/checkout@v4
- name: Download package dependencies
run: |
sudo add-apt-repository universe
sudo apt-get update
sudo apt-get install desktop-file-utils rpm libfuse2
export DEBIAN_FRONTEND=noninteractive
ln -fs /usr/share/zoneinfo/Etc/UTC /etc/localtime
apt-get update
apt-get install -y curl wget git dpkg-dev fakeroot tzdata zip unzip desktop-file-utils rpm libfuse2 file build-essential binutils
- name: Download build
uses: actions/download-artifact@v4
with:
@ -89,6 +92,7 @@ jobs:
env:
VERSION: ${{ inputs.version }}
RUNTIME: ${{ matrix.runtime }}
APPIMAGE_EXTRACT_AND_RUN: 1
run: |
mkdir build/SourceGit
tar -xf "build/sourcegit.${{ matrix.runtime }}.tar" -C build/SourceGit

View file

@ -38,7 +38,7 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ github.ref_name }}
VERSION: ${{ needs.version.outputs.version }}
run: gh release create "$TAG" -t "Release $VERSION" --notes-from-tag
run: gh release create "$TAG" -t "$VERSION" --notes-from-tag
- name: Download artifacts
uses: actions/download-artifact@v4
with:

2
.gitignore vendored
View file

@ -37,3 +37,5 @@ build/*.deb
build/*.rpm
build/*.AppImage
SourceGit.app/
build.command
src/Properties/launchSettings.json

View file

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2024 sourcegit
Copyright (c) 2025 sourcegit
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
@ -17,4 +17,4 @@ 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.
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -11,16 +11,16 @@
* Supports Windows/macOS/Linux
* Opensource/Free
* Fast
* Deutsch/English/Español/Français/Italiano/Português/Русский/简体中文/繁體中文
* Deutsch/English/Español/Français/Italiano/Português/Русский/Українська/简体中文/繁體中文/日本語/தமிழ் (Tamil)
* Built-in light/dark themes
* Customize theme
* Visual commit graph
* Supports SSH access with each remote
* GIT commands with GUI
* Clone/Fetch/Pull/Push...
* Merge/Rebase/Reset/Revert/Amend/Cherry-pick...
* Amend/Reword
* Interactive rebase (Basic)
* Merge/Rebase/Reset/Revert/Cherry-pick...
* Amend/Reword/Squash
* Interactive rebase
* Branches
* Remotes
* Tags
@ -35,11 +35,14 @@
* Revision Diffs
* Branch Diff
* Image Diff - Side-By-Side/Swipe/Blend
* Git command logs
* Search commits
* GitFlow
* Git LFS
* Bisect
* Issue Link
* Workspace
* Custom Action
* Using AI to generate commit message (C# port of [anjerodev/commitollama](https://github.com/anjerodev/commitollama))
> [!WARNING]
@ -47,24 +50,25 @@
## Translation Status
[![en_US](https://img.shields.io/badge/en__US-100%25-brightgreen)](TRANSLATION.md) [![de__DE](https://img.shields.io/badge/de__DE-99.86%25-yellow)](TRANSLATION.md) [![es__ES](https://img.shields.io/badge/es__ES-97.87%25-yellow)](TRANSLATION.md) [![fr__FR](https://img.shields.io/badge/fr__FR-97.30%25-yellow)](TRANSLATION.md) [![it__IT](https://img.shields.io/badge/it__IT-97.73%25-yellow)](TRANSLATION.md) [![pt__BR](https://img.shields.io/badge/pt__BR-99.15%25-yellow)](TRANSLATION.md) [![ru__RU](https://img.shields.io/badge/ru__RU-100.00%25-brightgreen)](TRANSLATION.md) [![zh__CN](https://img.shields.io/badge/zh__CN-100.00%25-brightgreen)](TRANSLATION.md) [![zh__TW](https://img.shields.io/badge/zh__TW-100.00%25-brightgreen)](TRANSLATION.md)
You can find the current translation status in [TRANSLATION.md](https://github.com/sourcegit-scm/sourcegit/blob/develop/TRANSLATION.md)
## How to Use
**To use this tool, you need to install Git(>=2.23.0) first.**
**To use this tool, you need to install Git(>=2.25.1) first.**
You can download the latest stable from [Releases](https://github.com/sourcegit-scm/sourcegit/releases/latest) or download workflow artifacts from [Github Actions](https://github.com/sourcegit-scm/sourcegit/actions) to try this app based on latest commits.
You can download the latest stable from [Releases](https://github.com/sourcegit-scm/sourcegit/releases/latest) or download workflow artifacts from [GitHub Actions](https://github.com/sourcegit-scm/sourcegit/actions) to try this app based on latest commits.
This software creates a folder `$"{System.Environment.SpecialFolder.ApplicationData}/SourceGit"`, which is platform-dependent, to store user settings, downloaded avatars and crash logs.
| OS | PATH |
|---------|-----------------------------------------------------|
| Windows | `C:\Users\USER_NAME\AppData\Roaming\SourceGit` |
| Windows | `%APPDATA%\SourceGit` |
| Linux | `${HOME}/.config/SourceGit` or `${HOME}/.sourcegit` |
| macOS | `${HOME}/Library/Application Support/SourceGit` |
> [!TIP]
> You can open the app data dir from the main menu.
> * You can open this data storage directory from the main menu `Open Data Storage Directory`.
> * You can create a `data` folder next to the `SourceGit` executable to force this app to store data (user settings, downloaded avatars and crash logs) into it (Portable-Mode). Only works on Windows.
For **Windows** users:
@ -75,12 +79,12 @@ For **Windows** users:
```
> [!NOTE]
> `winget` will install this software as a commandline tool. You need run `SourceGit` from console or `Win+R` at the first time. Then you can add it to the taskbar.
* You can install the latest stable by `scoope` with follow commands:
* You can install the latest stable by `scoop` with follow commands:
```shell
scoop bucket add extras
scoop install sourcegit
```
* Portable versions can be found in [Releases](https://github.com/sourcegit-scm/sourcegit/releases/latest)
* Pre-built binaries can be found in [Releases](https://github.com/sourcegit-scm/sourcegit/releases/latest)
For **macOS** users:
@ -89,7 +93,7 @@ For **macOS** users:
brew tap ybeapps/homebrew-sourcegit
brew install --cask --no-quarantine sourcegit
```
* If you want to install `SourceGit.app` from Github Release manually, you need run following command to make sure it works:
* If you want to install `SourceGit.app` from GitHub Release manually, you need run following command to make sure it works:
```shell
sudo xattr -cr /Applications/SourceGit.app
```
@ -98,22 +102,45 @@ For **macOS** users:
For **Linux** users:
* `xdg-open` must be installed to support open native file manager.
* Make sure [git-credential-manager](https://github.com/git-ecosystem/git-credential-manager/releases) is installed on your linux.
* Thanks [@aikawayataro](https://github.com/aikawayataro) for providing `rpm` and `deb` repositories, hosted on [Codeberg](https://codeberg.org/yataro/-/packages).
`deb` how to:
```shell
curl https://codeberg.org/api/packages/yataro/debian/repository.key | sudo tee /etc/apt/keyrings/sourcegit.asc
echo "deb [signed-by=/etc/apt/keyrings/sourcegit.asc, arch=amd64,arm64] https://codeberg.org/api/packages/yataro/debian generic main" | sudo tee /etc/apt/sources.list.d/sourcegit.list
sudo apt update
sudo apt install sourcegit
```
`rpm` how to:
```shell
curl https://codeberg.org/api/packages/yataro/rpm.repo | sed -e 's/gpgcheck=1/gpgcheck=0/' > sourcegit.repo
# Fedora 41 and newer
sudo dnf config-manager addrepo --from-repofile=./sourcegit.repo
# Fedora 40 and earlier
sudo dnf config-manager --add-repo ./sourcegit.repo
sudo dnf install sourcegit
```
If your distribution isn't using `dnf`, please refer to the documentation of your distribution on how to add an `rpm` repository.
* `AppImage` files can be found on [AppImage hub](https://appimage.github.io/SourceGit/), `xdg-open` (`xdg-utils`) must be installed to support open native file manager.
* Make sure [git-credential-manager](https://github.com/git-ecosystem/git-credential-manager/releases) is installed on your Linux.
* Maybe you need to set environment variable `AVALONIA_SCREEN_SCALE_FACTORS`. See https://github.com/AvaloniaUI/Avalonia/wiki/Configuring-X11-per-monitor-DPI.
* If you can NOT type accented characters, such as `ê`, `ó`, try to set the environment variable `AVALONIA_IM_MODULE` to `none`.
* If you can NOT type accented characters, such as `ê`, `ó`, try to set the environment variable `AVALONIA_IM_MODULE` to `none`.
## OpenAI
This software supports using OpenAI or other AI service that has an OpenAI comaptible HTTP API to generate commit message. You need configurate the service in `Preference` window.
This software supports using OpenAI or other AI service that has an OpenAI compatible HTTP API to generate commit message. You need configurate the service in `Preference` window.
For `OpenAI`:
* `Server` must be `https://api.openai.com/v1/chat/completions`
* `Server` must be `https://api.openai.com/v1`
For other AI service:
* The `Server` should fill in a URL equivalent to OpenAI's `https://api.openai.com/v1/chat/completions`. For example, when using `Ollama`, it should be `http://localhost:11434/v1/chat/completions` instead of `http://localhost:11434/api/generate`
* The `Server` should fill in a URL equivalent to OpenAI's `https://api.openai.com/v1`. For example, when using `Ollama`, it should be `http://localhost:11434/v1` instead of `http://localhost:11434/api/generate`
* The `API Key` is optional that depends on the service
## External Tools
@ -132,7 +159,7 @@ This app supports open repository in external tools listed in the table below.
> [!NOTE]
> This app will try to find those tools based on some pre-defined or expected locations automatically. If you are using one portable version of these tools, it will not be detected by this app.
> To solve this problem you can add a file named `external_editors.json` in app data dir and provide the path directly. For example:
> To solve this problem you can add a file named `external_editors.json` in app data storage directory and provide the path directly. For example:
```json
{
"tools": {
@ -162,6 +189,19 @@ This app supports open repository in external tools listed in the table below.
Everyone is welcome to submit a PR. Please make sure your PR is based on the latest `develop` branch and the target branch of PR is `develop`.
In short, here are the commands to get started once [.NET tools are installed](https://dotnet.microsoft.com/en-us/download):
```sh
dotnet nuget add source https://api.nuget.org/v3/index.json -n nuget.org
dotnet restore
dotnet build
dotnet run --project src/SourceGit.csproj
```
Thanks to all the people who contribute.
[![Contributors](https://contrib.rocks/image?repo=sourcegit-scm/sourcegit&columns=20)](https://github.com/sourcegit-scm/sourcegit/graphs/contributors)
## Third-Party Components
For detailed license information, see [THIRD-PARTY-LICENSES.md](THIRD-PARTY-LICENSES.md).

View file

@ -60,6 +60,8 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DEBIAN", "DEBIAN", "{F101849D-BDB7-40D4-A516-751150C3CCFC}"
ProjectSection(SolutionItems) = preProject
build\resources\deb\DEBIAN\control = build\resources\deb\DEBIAN\control
build\resources\deb\DEBIAN\preinst = build\resources\deb\DEBIAN\preinst
build\resources\deb\DEBIAN\prerm = build\resources\deb\DEBIAN\prerm
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "rpm", "rpm", "{9BA0B044-0CC9-46F8-B551-204F149BF45D}"
@ -80,7 +82,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{C54D
build\scripts\localization-check.js = build\scripts\localization-check.js
build\scripts\package.linux.sh = build\scripts\package.linux.sh
build\scripts\package.osx-app.sh = build\scripts\package.osx-app.sh
build\scripts\package.windows-portable.sh = build\scripts\package.windows-portable.sh
build\scripts\package.windows.sh = build\scripts\package.windows.sh
EndProjectSection
EndProject
Global

86
THIRD-PARTY-LICENSES.md Normal file
View file

@ -0,0 +1,86 @@
# Third-Party Licenses
This project incorporates components from the following third parties:
## Packages
### AvaloniaUI
- **Source**: https://github.com/AvaloniaUI/Avalonia
- **Version**: 11.2.5
- **License**: MIT License
- **License Link**: https://github.com/AvaloniaUI/Avalonia/blob/master/licence.md
### AvaloniaEdit
- **Source**: https://github.com/AvaloniaUI/AvaloniaEdit
- **Version**: 11.2.0
- **License**: MIT License
- **License Link**: https://github.com/AvaloniaUI/AvaloniaEdit/blob/master/LICENSE
### LiveChartsCore.SkiaSharpView.Avalonia
- **Source**: https://github.com/beto-rodriguez/LiveCharts2
- **Version**: 2.0.0-rc5.4
- **License**: MIT License
- **License Link**: https://github.com/beto-rodriguez/LiveCharts2/blob/master/LICENSE
### TextMateSharp
- **Source**: https://github.com/danipen/TextMateSharp
- **Version**: 1.0.66
- **License**: MIT License
- **License Link**: https://github.com/danipen/TextMateSharp/blob/master/LICENSE.md
### OpenAI .NET SDK
- **Source**: https://github.com/openai/openai-dotnet
- **Version**: 2.2.0-beta2
- **License**: MIT License
- **License Link**: https://github.com/openai/openai-dotnet/blob/main/LICENSE
### Azure.AI.OpenAI
- **Source**: https://github.com/Azure/azure-sdk-for-net
- **Version**: 2.2.0-beta2
- **License**: MIT License
- **License Link**: https://github.com/Azure/azure-sdk-for-net/blob/main/LICENSE.txt
## Fonts
### JetBrainsMono
- **Source**: https://github.com/JetBrains/JetBrainsMono
- **Commit**: v2.304
- **License**: SIL Open Font License, Version 1.1
- **License Link**: https://github.com/JetBrains/JetBrainsMono/blob/v2.304/OFL.txt
## Grammar Files
### haxe-TmLanguage
- **Source**: https://github.com/vshaxe/haxe-TmLanguage
- **Commit**: ddad8b4c6d0781ac20be0481174ec1be772c5da5
- **License**: MIT License
- **License Link**: https://github.com/vshaxe/haxe-TmLanguage/blob/ddad8b4c6d0781ac20be0481174ec1be772c5da5/LICENSE.md
### coc-toml
- **Source**: https://github.com/kkiyama117/coc-toml
- **Commit**: aac3e0c65955c03314b2733041b19f903b7cc447
- **License**: MIT License
- **License Link**: https://github.com/kkiyama117/coc-toml/blob/aac3e0c65955c03314b2733041b19f903b7cc447/LICENSE
### eclipse-buildship
- **Source**: https://github.com/eclipse/buildship
- **Commit**: 6bb773e7692f913dec27105129ebe388de34e68b
- **License**: Eclipse Public License 1.0
- **License Link**: https://github.com/eclipse-buildship/buildship/blob/6bb773e7692f913dec27105129ebe388de34e68b/README.md
### vscode-jsp-lang
- **Source**: https://github.com/samuel-weinhardt/vscode-jsp-lang
- **Commit**: 0e89ecdb13650dbbe5a1e85b47b2e1530bf2f355
- **License**: MIT License
- **License Link**: https://github.com/samuel-weinhardt/vscode-jsp-lang/blob/0e89ecdb13650dbbe5a1e85b47b2e1530bf2f355/LICENSE

View file

@ -1,131 +1,496 @@
### de_DE.axaml: 99.86%
# Translation Status
This document shows the translation status of each locale file in the repository.
## Details
### ![en_US](https://img.shields.io/badge/en__US-%E2%88%9A-brightgreen)
### ![de__DE](https://img.shields.io/badge/de__DE-96.38%25-yellow)
<details>
<summary>Missing Keys</summary>
<summary>Missing keys in de_DE.axaml</summary>
- Text.WorkingCopy.CommitToEdit
- Text.Avatar.Load
- Text.BranchCM.ResetToSelectedCommit
- Text.CommitDetail.Changes.Count
- Text.CreateBranch.OverwriteExisting
- Text.DeinitSubmodule
- Text.DeinitSubmodule.Force
- Text.DeinitSubmodule.Path
- Text.Diff.Submodule.Deleted
- Text.GitFlow.FinishWithPush
- Text.GitFlow.FinishWithSquash
- Text.Hotkeys.Global.SwitchWorkspace
- Text.Hotkeys.Global.SwitchTab
- Text.Hotkeys.TextEditor.OpenExternalMergeTool
- Text.Launcher.Workspaces
- Text.Launcher.Pages
- Text.Pull.RecurseSubmodules
- Text.Repository.ClearStashes
- Text.Repository.ShowSubmodulesAsTree
- Text.ResetWithoutCheckout
- Text.ResetWithoutCheckout.MoveTo
- Text.ResetWithoutCheckout.Target
- Text.Submodule.Deinit
- Text.Submodule.Status
- Text.Submodule.Status.Modified
- Text.Submodule.Status.NotInited
- Text.Submodule.Status.RevisionChanged
- Text.Submodule.Status.Unmerged
- Text.Submodule.URL
- Text.WorkingCopy.ResetAuthor
</details>
### es_ES.axaml: 97.87%
### ![es__ES](https://img.shields.io/badge/es__ES-99.88%25-yellow)
<details>
<summary>Missing Keys</summary>
<summary>Missing keys in es_ES.axaml</summary>
- Text.Avatar.Load
</details>
### ![fr__FR](https://img.shields.io/badge/fr__FR-92.26%25-yellow)
<details>
<summary>Missing keys in fr_FR.axaml</summary>
- Text.Avatar.Load
- Text.Bisect
- Text.Bisect.Abort
- Text.Bisect.Bad
- Text.Bisect.Detecting
- Text.Bisect.Good
- Text.Bisect.Skip
- Text.Bisect.WaitingForRange
- Text.BranchCM.ResetToSelectedCommit
- Text.Checkout.RecurseSubmodules
- Text.CommitCM.CopyAuthor
- Text.CommitCM.CopyCommitter
- Text.CommitCM.CopySubject
- Text.CommitDetail.Changes.Count
- Text.CommitMessageTextBox.SubjectCount
- Text.Configure.Git.PreferredMergeMode
- Text.ConfirmEmptyCommit.Continue
- Text.ConfirmEmptyCommit.NoLocalChanges
- Text.ConfirmEmptyCommit.StageAllThenCommit
- Text.ConfirmEmptyCommit.WithLocalChanges
- Text.CreateBranch.OverwriteExisting
- Text.DeinitSubmodule
- Text.DeinitSubmodule.Force
- Text.DeinitSubmodule.Path
- Text.Diff.Submodule.Deleted
- Text.GitFlow.FinishWithPush
- Text.GitFlow.FinishWithSquash
- Text.Hotkeys.Global.SwitchWorkspace
- Text.Hotkeys.Global.SwitchTab
- Text.Hotkeys.TextEditor.OpenExternalMergeTool
- Text.Launcher.Workspaces
- Text.Launcher.Pages
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Pull.RecurseSubmodules
- Text.Repository.BranchSort
- Text.Repository.BranchSort.ByCommitterDate
- Text.Repository.BranchSort.ByName
- Text.Repository.ClearStashes
- Text.Repository.Search.ByContent
- Text.Repository.ShowSubmodulesAsTree
- Text.Repository.ViewLogs
- Text.Repository.Visit
- Text.ResetWithoutCheckout
- Text.ResetWithoutCheckout.MoveTo
- Text.ResetWithoutCheckout.Target
- Text.Submodule.Deinit
- Text.Submodule.Status
- Text.Submodule.Status.Modified
- Text.Submodule.Status.NotInited
- Text.Submodule.Status.RevisionChanged
- Text.Submodule.Status.Unmerged
- Text.Submodule.URL
- Text.ViewLogs
- Text.ViewLogs.Clear
- Text.ViewLogs.CopyLog
- Text.ViewLogs.Delete
- Text.WorkingCopy.ConfirmCommitWithFilter
- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
- Text.WorkingCopy.Conflicts.UseMine
- Text.WorkingCopy.Conflicts.UseTheirs
- Text.WorkingCopy.ResetAuthor
</details>
### ![it__IT](https://img.shields.io/badge/it__IT-97.63%25-yellow)
<details>
<summary>Missing keys in it_IT.axaml</summary>
- Text.Avatar.Load
- Text.BranchCM.ResetToSelectedCommit
- Text.CommitDetail.Changes.Count
- Text.CreateBranch.OverwriteExisting
- Text.DeinitSubmodule
- Text.DeinitSubmodule.Force
- Text.DeinitSubmodule.Path
- Text.Diff.Submodule.Deleted
- Text.Hotkeys.Global.SwitchWorkspace
- Text.Hotkeys.Global.SwitchTab
- Text.Launcher.Workspaces
- Text.Launcher.Pages
- Text.Pull.RecurseSubmodules
- Text.Repository.ClearStashes
- Text.ResetWithoutCheckout
- Text.ResetWithoutCheckout.MoveTo
- Text.ResetWithoutCheckout.Target
- Text.Submodule.Deinit
- Text.WorkingCopy.ResetAuthor
</details>
### ![ja__JP](https://img.shields.io/badge/ja__JP-92.01%25-yellow)
<details>
<summary>Missing keys in ja_JP.axaml</summary>
- Text.Avatar.Load
- Text.Bisect
- Text.Bisect.Abort
- Text.Bisect.Bad
- Text.Bisect.Detecting
- Text.Bisect.Good
- Text.Bisect.Skip
- Text.Bisect.WaitingForRange
- Text.BranchCM.CompareWithCurrent
- Text.BranchCM.ResetToSelectedCommit
- Text.Checkout.RecurseSubmodules
- Text.CommitCM.CopyAuthor
- Text.CommitCM.CopyCommitter
- Text.CommitCM.CopySubject
- Text.CommitDetail.Changes.Count
- Text.CommitMessageTextBox.SubjectCount
- Text.Configure.Git.PreferredMergeMode
- Text.ConfirmEmptyCommit.Continue
- Text.ConfirmEmptyCommit.NoLocalChanges
- Text.ConfirmEmptyCommit.StageAllThenCommit
- Text.ConfirmEmptyCommit.WithLocalChanges
- Text.CreateBranch.OverwriteExisting
- Text.DeinitSubmodule
- Text.DeinitSubmodule.Force
- Text.DeinitSubmodule.Path
- Text.Diff.Submodule.Deleted
- Text.GitFlow.FinishWithPush
- Text.GitFlow.FinishWithSquash
- Text.Hotkeys.Global.SwitchWorkspace
- Text.Hotkeys.Global.SwitchTab
- Text.Hotkeys.TextEditor.OpenExternalMergeTool
- Text.Launcher.Workspaces
- Text.Launcher.Pages
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Pull.RecurseSubmodules
- Text.Repository.BranchSort
- Text.Repository.BranchSort.ByCommitterDate
- Text.Repository.BranchSort.ByName
- Text.Repository.ClearStashes
- Text.Repository.FilterCommits
- Text.Repository.Search.ByContent
- Text.Repository.ShowSubmodulesAsTree
- Text.Repository.ViewLogs
- Text.Repository.Visit
- Text.ResetWithoutCheckout
- Text.ResetWithoutCheckout.MoveTo
- Text.ResetWithoutCheckout.Target
- Text.Submodule.Deinit
- Text.Submodule.Status
- Text.Submodule.Status.Modified
- Text.Submodule.Status.NotInited
- Text.Submodule.Status.RevisionChanged
- Text.Submodule.Status.Unmerged
- Text.Submodule.URL
- Text.ViewLogs
- Text.ViewLogs.Clear
- Text.ViewLogs.CopyLog
- Text.ViewLogs.Delete
- Text.WorkingCopy.ConfirmCommitWithFilter
- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
- Text.WorkingCopy.Conflicts.UseMine
- Text.WorkingCopy.Conflicts.UseTheirs
- Text.WorkingCopy.ResetAuthor
</details>
### ![pt__BR](https://img.shields.io/badge/pt__BR-84.02%25-yellow)
<details>
<summary>Missing keys in pt_BR.axaml</summary>
- Text.AIAssistant.Regen
- Text.AIAssistant.Use
- Text.ApplyStash
- Text.ApplyStash.DropAfterApply
- Text.ApplyStash.RestoreIndex
- Text.ApplyStash.Stash
- Text.Avatar.Load
- Text.Bisect
- Text.Bisect.Abort
- Text.Bisect.Bad
- Text.Bisect.Detecting
- Text.Bisect.Good
- Text.Bisect.Skip
- Text.Bisect.WaitingForRange
- Text.BranchCM.CustomAction
- Text.BranchCM.MergeMultiBranches
- Text.BranchCM.ResetToSelectedCommit
- Text.BranchUpstreamInvalid
- Text.Checkout.RecurseSubmodules
- Text.Clone.RecurseSubmodules
- Text.CommitCM.CopyAuthor
- Text.CommitCM.CopyCommitter
- Text.CommitCM.CopySubject
- Text.CommitCM.Merge
- Text.CommitCM.MergeMultiple
- Text.CommitDetail.Changes.Count
- Text.CommitDetail.Files.Search
- Text.CommitDetail.Info.Children
- Text.CommitMessageTextBox.SubjectCount
- Text.Configure.CustomAction.Scope.Branch
- Text.Configure.CustomAction.WaitForExit
- Text.Configure.Git.PreferredMergeMode
- Text.Configure.IssueTracker.AddSampleGiteeIssue
- Text.Configure.IssueTracker.AddSampleGiteePullRequest
- Text.ConfirmEmptyCommit.Continue
- Text.ConfirmEmptyCommit.NoLocalChanges
- Text.ConfirmEmptyCommit.StageAllThenCommit
- Text.ConfirmEmptyCommit.WithLocalChanges
- Text.CopyFullPath
- Text.CreateBranch.Name.WarnSpace
- Text.CreateBranch.OverwriteExisting
- Text.DeinitSubmodule
- Text.DeinitSubmodule.Force
- Text.DeinitSubmodule.Path
- Text.DeleteRepositoryNode.Path
- Text.DeleteRepositoryNode.TipForGroup
- Text.DeleteRepositoryNode.TipForRepository
- Text.Diff.First
- Text.Diff.Last
- Text.Diff.Submodule.Deleted
- Text.Diff.UseBlockNavigation
- Text.Fetch.Force
- Text.Preference.Appearance.FontSize
- Text.Preference.Appearance.FontSize.Default
- Text.Preference.Appearance.FontSize.Editor
- Text.Preference.General.ShowChildren
- Text.FileCM.ResolveUsing
- Text.GitFlow.FinishWithPush
- Text.GitFlow.FinishWithSquash
- Text.Hotkeys.Global.Clone
- Text.Hotkeys.Global.SwitchWorkspace
- Text.Hotkeys.Global.SwitchTab
- Text.Hotkeys.TextEditor.OpenExternalMergeTool
- Text.InProgress.CherryPick.Head
- Text.InProgress.Merge.Operating
- Text.InProgress.Rebase.StoppedAt
- Text.InProgress.Revert.Head
- Text.Launcher.Workspaces
- Text.Launcher.Pages
- Text.Merge.Source
- Text.MergeMultiple
- Text.MergeMultiple.CommitChanges
- Text.MergeMultiple.Strategy
- Text.MergeMultiple.Targets
- Text.Preferences.AI.Streaming
- Text.Preferences.Appearance.EditorTabWidth
- Text.Preferences.General.DateFormat
- Text.Preferences.General.ShowChildren
- Text.Preferences.General.ShowTagsInGraph
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Preferences.Git.SSLVerify
- Text.Pull.RecurseSubmodules
- Text.Repository.BranchSort
- Text.Repository.BranchSort.ByCommitterDate
- Text.Repository.BranchSort.ByName
- Text.Repository.ClearStashes
- Text.Repository.FilterCommits
- Text.Repository.FilterCommits.Default
- Text.Repository.FilterCommits.Exclude
- Text.Repository.FilterCommits.Include
- Text.Repository.HistoriesLayout
- Text.Repository.HistoriesLayout.Horizontal
- Text.Repository.HistoriesLayout.Vertical
- Text.Repository.HistoriesOrder
- Text.Repository.HistoriesOrder.ByDate
- Text.Repository.HistoriesOrder.Topo
- Text.Repository.Notifications.Clear
- Text.Repository.OnlyHighlightCurrentBranchInHistories
- Text.Repository.Search.ByContent
- Text.Repository.ShowSubmodulesAsTree
- Text.Repository.Skip
- Text.Repository.Tags.OrderByCreatorDate
- Text.Repository.Tags.OrderByName
- Text.Repository.Tags.Sort
- Text.Repository.UseRelativeTimeInHistories
- Text.Repository.ViewLogs
- Text.Repository.Visit
- Text.ResetWithoutCheckout
- Text.ResetWithoutCheckout.MoveTo
- Text.ResetWithoutCheckout.Target
- Text.SetUpstream
- Text.SetUpstream.Local
- Text.SetUpstream.Unset
- Text.SetUpstream.Upstream
- Text.SHALinkCM.NavigateTo
- Text.Stash.AutoRestore
- Text.Stash.AutoRestore.Tip
- Text.StashCM.SaveAsPatch
- Text.Submodule.Deinit
- Text.Submodule.Status
- Text.Submodule.Status.Modified
- Text.Submodule.Status.NotInited
- Text.Submodule.Status.RevisionChanged
- Text.Submodule.Status.Unmerged
- Text.Submodule.URL
- Text.ViewLogs
- Text.ViewLogs.Clear
- Text.ViewLogs.CopyLog
- Text.ViewLogs.Delete
- Text.WorkingCopy.CommitToEdit
- Text.WorkingCopy.ConfirmCommitWithFilter
- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
- Text.WorkingCopy.Conflicts.UseMine
- Text.WorkingCopy.Conflicts.UseTheirs
- Text.WorkingCopy.ResetAuthor
- Text.WorkingCopy.SignOff
</details>
### fr_FR.axaml: 97.30%
### ![ru__RU](https://img.shields.io/badge/ru__RU-%E2%88%9A-brightgreen)
### ![ta__IN](https://img.shields.io/badge/ta__IN-92.13%25-yellow)
<details>
<summary>Missing Keys</summary>
<summary>Missing keys in ta_IN.axaml</summary>
- Text.CherryPick.AppendSourceToMessage
- Text.CherryPick.Mainline.Tips
- Text.CommitCM.CherryPickMultiple
- Text.Fetch.Force
- Text.Preference.Appearance.FontSize
- Text.Preference.Appearance.FontSize.Default
- Text.Preference.Appearance.FontSize.Editor
- Text.Preference.General.ShowChildren
- Text.Repository.CustomActions
- Text.Repository.FilterCommits
- Text.Repository.FilterCommits.Default
- Text.Repository.FilterCommits.Exclude
- Text.Repository.FilterCommits.Include
- Text.Repository.HistoriesOrder
- Text.Repository.HistoriesOrder.ByDate
- Text.Repository.HistoriesOrder.Topo
- Text.ScanRepositories
- Text.SHALinkCM.NavigateTo
- Text.WorkingCopy.CommitToEdit
- Text.Avatar.Load
- Text.Bisect
- Text.Bisect.Abort
- Text.Bisect.Bad
- Text.Bisect.Detecting
- Text.Bisect.Good
- Text.Bisect.Skip
- Text.Bisect.WaitingForRange
- Text.BranchCM.CompareWithCurrent
- Text.BranchCM.ResetToSelectedCommit
- Text.Checkout.RecurseSubmodules
- Text.CommitCM.CopyAuthor
- Text.CommitCM.CopyCommitter
- Text.CommitCM.CopySubject
- Text.CommitDetail.Changes.Count
- Text.CommitMessageTextBox.SubjectCount
- Text.Configure.Git.PreferredMergeMode
- Text.ConfirmEmptyCommit.Continue
- Text.ConfirmEmptyCommit.NoLocalChanges
- Text.ConfirmEmptyCommit.StageAllThenCommit
- Text.ConfirmEmptyCommit.WithLocalChanges
- Text.CreateBranch.OverwriteExisting
- Text.DeinitSubmodule
- Text.DeinitSubmodule.Force
- Text.DeinitSubmodule.Path
- Text.Diff.Submodule.Deleted
- Text.GitFlow.FinishWithPush
- Text.GitFlow.FinishWithSquash
- Text.Hotkeys.Global.SwitchWorkspace
- Text.Hotkeys.Global.SwitchTab
- Text.Hotkeys.TextEditor.OpenExternalMergeTool
- Text.Launcher.Workspaces
- Text.Launcher.Pages
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Pull.RecurseSubmodules
- Text.Repository.BranchSort
- Text.Repository.BranchSort.ByCommitterDate
- Text.Repository.BranchSort.ByName
- Text.Repository.ClearStashes
- Text.Repository.Search.ByContent
- Text.Repository.ShowSubmodulesAsTree
- Text.Repository.ViewLogs
- Text.Repository.Visit
- Text.ResetWithoutCheckout
- Text.ResetWithoutCheckout.MoveTo
- Text.ResetWithoutCheckout.Target
- Text.Submodule.Deinit
- Text.Submodule.Status
- Text.Submodule.Status.Modified
- Text.Submodule.Status.NotInited
- Text.Submodule.Status.RevisionChanged
- Text.Submodule.Status.Unmerged
- Text.Submodule.URL
- Text.UpdateSubmodules.Target
- Text.ViewLogs
- Text.ViewLogs.Clear
- Text.ViewLogs.CopyLog
- Text.ViewLogs.Delete
- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
- Text.WorkingCopy.Conflicts.UseMine
- Text.WorkingCopy.Conflicts.UseTheirs
- Text.WorkingCopy.ResetAuthor
</details>
### it_IT.axaml: 97.73%
### ![uk__UA](https://img.shields.io/badge/uk__UA-93.38%25-yellow)
<details>
<summary>Missing Keys</summary>
<summary>Missing keys in uk_UA.axaml</summary>
- Text.CommitDetail.Info.Children
- Text.Configure.IssueTracker.AddSampleGitLabMergeRequest
- Text.Configure.OpenAI.Preferred
- Text.Configure.OpenAI.Preferred.Tip
- Text.Fetch.Force
- Text.Preference.General.ShowChildren
- Text.Repository.FilterCommits
- Text.Repository.FilterCommits.Default
- Text.Repository.FilterCommits.Exclude
- Text.Repository.FilterCommits.Include
- Text.Repository.HistoriesOrder
- Text.Repository.HistoriesOrder.ByDate
- Text.Repository.HistoriesOrder.Topo
- Text.SHALinkCM.CopySHA
- Text.SHALinkCM.NavigateTo
- Text.WorkingCopy.CommitToEdit
- Text.Avatar.Load
- Text.Bisect
- Text.Bisect.Abort
- Text.Bisect.Bad
- Text.Bisect.Detecting
- Text.Bisect.Good
- Text.Bisect.Skip
- Text.Bisect.WaitingForRange
- Text.BranchCM.ResetToSelectedCommit
- Text.Checkout.RecurseSubmodules
- Text.CommitCM.CopyAuthor
- Text.CommitCM.CopyCommitter
- Text.CommitCM.CopySubject
- Text.CommitDetail.Changes.Count
- Text.CommitMessageTextBox.SubjectCount
- Text.ConfigureWorkspace.Name
- Text.CreateBranch.OverwriteExisting
- Text.DeinitSubmodule
- Text.DeinitSubmodule.Force
- Text.DeinitSubmodule.Path
- Text.Diff.Submodule.Deleted
- Text.GitFlow.FinishWithPush
- Text.GitFlow.FinishWithSquash
- Text.Hotkeys.Global.SwitchWorkspace
- Text.Hotkeys.Global.SwitchTab
- Text.Hotkeys.TextEditor.OpenExternalMergeTool
- Text.Launcher.Workspaces
- Text.Launcher.Pages
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Pull.RecurseSubmodules
- Text.Repository.BranchSort
- Text.Repository.BranchSort.ByCommitterDate
- Text.Repository.BranchSort.ByName
- Text.Repository.ClearStashes
- Text.Repository.Search.ByContent
- Text.Repository.ShowSubmodulesAsTree
- Text.Repository.ViewLogs
- Text.Repository.Visit
- Text.ResetWithoutCheckout
- Text.ResetWithoutCheckout.MoveTo
- Text.ResetWithoutCheckout.Target
- Text.Submodule.Deinit
- Text.Submodule.Status
- Text.Submodule.Status.Modified
- Text.Submodule.Status.NotInited
- Text.Submodule.Status.RevisionChanged
- Text.Submodule.Status.Unmerged
- Text.Submodule.URL
- Text.ViewLogs
- Text.ViewLogs.Clear
- Text.ViewLogs.CopyLog
- Text.ViewLogs.Delete
- Text.WorkingCopy.ResetAuthor
</details>
### pt_BR.axaml: 99.15%
### ![zh__CN](https://img.shields.io/badge/zh__CN-%E2%88%9A-brightgreen)
<details>
<summary>Missing Keys</summary>
- Text.CommitDetail.Info.Children
- Text.Fetch.Force
- Text.Preference.General.ShowChildren
- Text.Repository.FilterCommits
- Text.SHALinkCM.NavigateTo
- Text.WorkingCopy.CommitToEdit
</details>
### ru_RU.axaml: 100.00%
<details>
<summary>Missing Keys</summary>
</details>
### zh_CN.axaml: 100.00%
<details>
<summary>Missing Keys</summary>
</details>
### zh_TW.axaml: 100.00%
<details>
<summary>Missing Keys</summary>
</details>
### ![zh__TW](https://img.shields.io/badge/zh__TW-%E2%88%9A-brightgreen)

View file

@ -1 +1 @@
8.41
2025.21

View file

@ -12,4 +12,4 @@
dotnet publish -c Release -r $RUNTIME_IDENTIFIER -o $DESTINATION_FOLDER src/SourceGit.csproj
```
> [!NOTE]
> Please replace the `$RUNTIME_IDENTIFIER` with one of `win-x64`,`win-arm64`,`linux-x64`,`linux-arm64`,`osx-x64`,`osx-arm64`, and replece the `$DESTINATION_FOLDER` with the real path that will store the output executable files.
> Please replace the `$RUNTIME_IDENTIFIER` with one of `win-x64`,`win-arm64`,`linux-x64`,`linux-arm64`,`osx-x64`,`osx-arm64`, and replace the `$DESTINATION_FOLDER` with the real path that will store the output executable files.

View file

@ -1,7 +1,8 @@
Package: sourcegit
Version: 8.23
Version: 2025.10
Priority: optional
Depends: libx11-6, libice6, libsm6
Depends: libx11-6, libice6, libsm6, libicu | libicu76 | libicu74 | libicu72 | libicu71 | libicu70 | libicu69 | libicu68 | libicu67 | libicu66 | libicu65 | libicu63 | libicu60 | libicu57 | libicu55 | libicu52, xdg-utils
Architecture: amd64
Installed-Size: 60440
Maintainer: longshuang@msn.cn
Description: Open-source & Free Git GUI Client

View file

@ -0,0 +1,32 @@
#!/bin/sh
set -e
# summary of how this script can be called:
# * <new-preinst> `install'
# * <new-preinst> `install' <old-version>
# * <new-preinst> `upgrade' <old-version>
# * <old-preinst> `abort-upgrade' <new-version>
# for details, see http://www.debian.org/doc/debian-policy/
case "$1" in
install|upgrade)
# Check if SourceGit is running and stop it
if pgrep -f '/opt/sourcegit/sourcegit' > /dev/null; then
echo "Stopping running SourceGit instance..."
pkill -f '/opt/sourcegit/sourcegit' || true
# Give the process a moment to terminate
sleep 1
fi
;;
abort-upgrade)
;;
*)
echo "preinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -0,0 +1,35 @@
#!/bin/sh
set -e
# summary of how this script can be called:
# * <prerm> `remove'
# * <old-prerm> `upgrade' <new-version>
# * <new-prerm> `failed-upgrade' <old-version>
# * <conflictor's-prerm> `remove' `in-favour' <package> <new-version>
# * <deconfigured's-prerm> `deconfigure' `in-favour'
# <package-being-installed> <version> `removing'
# <conflicting-package> <version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
remove|upgrade|deconfigure)
if pgrep -f '/opt/sourcegit/sourcegit' > /dev/null; then
echo "Stopping running SourceGit instance..."
pkill -f '/opt/sourcegit/sourcegit' || true
# Give the process a moment to terminate
sleep 1
fi
;;
failed-upgrade)
;;
*)
echo "prerm called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -7,6 +7,8 @@ URL: https://sourcegit-scm.github.io/
Source: https://github.com/sourcegit-scm/sourcegit/archive/refs/tags/v%_version.tar.gz
Requires: libX11.so.6()(%{__isa_bits}bit)
Requires: libSM.so.6()(%{__isa_bits}bit)
Requires: libicu
Requires: xdg-utils
%define _build_id_links none

View file

@ -6,7 +6,6 @@ const repoRoot = path.join(__dirname, '../../');
const localesDir = path.join(repoRoot, 'src/Resources/Locales');
const enUSFile = path.join(localesDir, 'en_US.axaml');
const outputFile = path.join(repoRoot, 'TRANSLATION.md');
const readmeFile = path.join(repoRoot, 'README.md');
const parser = new xml2js.Parser();
@ -15,45 +14,70 @@ async function parseXml(filePath) {
return parser.parseStringPromise(data);
}
async function filterAndSortTranslations(localeData, enUSKeys, enUSData) {
const strings = localeData.ResourceDictionary['x:String'];
// Remove keys that don't exist in English file
const filtered = strings.filter(item => enUSKeys.has(item.$['x:Key']));
// Sort based on the key order in English file
const enUSKeysArray = enUSData.ResourceDictionary['x:String'].map(item => item.$['x:Key']);
filtered.sort((a, b) => {
const aIndex = enUSKeysArray.indexOf(a.$['x:Key']);
const bIndex = enUSKeysArray.indexOf(b.$['x:Key']);
return aIndex - bIndex;
});
return filtered;
}
async function calculateTranslationRate() {
const enUSData = await parseXml(enUSFile);
const enUSKeys = new Set(enUSData.ResourceDictionary['x:String'].map(item => item.$['x:Key']));
const translationRates = [];
const badges = [];
const files = (await fs.readdir(localesDir)).filter(file => file !== 'en_US.axaml' && file.endsWith('.axaml'));
// Add en_US badge first
badges.push(`[![en_US](https://img.shields.io/badge/en__US-100%25-brightgreen)](TRANSLATION.md)`);
const lines = [];
lines.push('# Translation Status');
lines.push('This document shows the translation status of each locale file in the repository.');
lines.push(`## Details`);
lines.push(`### ![en_US](https://img.shields.io/badge/en__US-%E2%88%9A-brightgreen)`);
for (const file of files) {
const locale = file.replace('.axaml', '').replace('_', '__');
const filePath = path.join(localesDir, file);
const localeData = await parseXml(filePath);
const localeKeys = new Set(localeData.ResourceDictionary['x:String'].map(item => item.$['x:Key']));
const missingKeys = [...enUSKeys].filter(key => !localeKeys.has(key));
const translationRate = ((enUSKeys.size - missingKeys.length) / enUSKeys.size) * 100;
translationRates.push(`### ${file}: ${translationRate.toFixed(2)}%\n`);
translationRates.push(`<details>\n<summary>Missing Keys</summary>\n\n${missingKeys.map(key => `- ${key}`).join('\n')}\n\n</details>`);
// Sort and clean up extra translations
const sortedAndCleaned = await filterAndSortTranslations(localeData, enUSKeys, enUSData);
localeData.ResourceDictionary['x:String'] = sortedAndCleaned;
// Add badges
const locale = file.replace('.axaml', '').replace('_', '__');
const badgeColor = translationRate === 100 ? 'brightgreen' : translationRate >= 75 ? 'yellow' : 'red';
badges.push(`[![${locale}](https://img.shields.io/badge/${locale}-${translationRate.toFixed(2)}%25-${badgeColor})](TRANSLATION.md)`);
// Save the updated file
const builder = new xml2js.Builder({
headless: true,
renderOpts: { pretty: true, indent: ' ' }
});
let xmlStr = builder.buildObject(localeData);
// Add an empty line before the first x:String
xmlStr = xmlStr.replace(' <x:String', '\n <x:String');
await fs.writeFile(filePath, xmlStr + '\n', 'utf8');
if (missingKeys.length > 0) {
const progress = ((enUSKeys.size - missingKeys.length) / enUSKeys.size) * 100;
const badgeColor = progress >= 75 ? 'yellow' : 'red';
lines.push(`### ![${locale}](https://img.shields.io/badge/${locale}-${progress.toFixed(2)}%25-${badgeColor})`);
lines.push(`<details>\n<summary>Missing keys in ${file}</summary>\n\n${missingKeys.map(key => `- ${key}`).join('\n')}\n\n</details>`)
} else {
lines.push(`### ![${locale}](https://img.shields.io/badge/${locale}-%E2%88%9A-brightgreen)`);
}
}
console.log(translationRates.join('\n\n'));
await fs.writeFile(outputFile, translationRates.join('\n\n') + '\n', 'utf8');
// Update README.md
let readmeContent = await fs.readFile(readmeFile, 'utf8');
const badgeSection = `## Translation Status\n\n${badges.join(' ')}`;
console.log(badgeSection);
readmeContent = readmeContent.replace(/## Translation Status\n\n.*\n\n/, badgeSection + '\n\n');
await fs.writeFile(readmeFile, readmeContent, 'utf8');
const content = lines.join('\n\n');
console.log(content);
await fs.writeFile(outputFile, content, 'utf8');
}
calculateTranslationRate().catch(err => console.error(err));

View file

@ -56,8 +56,15 @@ cp -f SourceGit/* resources/deb/opt/sourcegit
ln -rsf resources/deb/opt/sourcegit/sourcegit resources/deb/usr/bin
cp -r resources/_common/applications resources/deb/usr/share
cp -r resources/_common/icons resources/deb/usr/share
sed -i -e "s/^Version:.*/Version: $VERSION/" -e "s/^Architecture:.*/Architecture: $arch/" resources/deb/DEBIAN/control
dpkg-deb --root-owner-group --build resources/deb "sourcegit_$VERSION-1_$arch.deb"
# Calculate installed size in KB
installed_size=$(du -sk resources/deb | cut -f1)
# Update the control file
sed -i -e "s/^Version:.*/Version: $VERSION/" \
-e "s/^Architecture:.*/Architecture: $arch/" \
-e "s/^Installed-Size:.*/Installed-Size: $installed_size/" \
resources/deb/DEBIAN/control
# Build deb package with gzip compression
dpkg-deb -Zgzip --root-owner-group --build resources/deb "sourcegit_$VERSION-1_$arch.deb"
rpmbuild -bb --target="$target" resources/rpm/SPECS/build.spec --define "_topdir $(pwd)/resources/rpm" --define "_version $VERSION"
mv "resources/rpm/RPMS/$target/sourcegit-$VERSION-1.$target.rpm" ./

View file

@ -1,12 +0,0 @@
#!/usr/bin/env bash
set -e
set -o
set -u
set pipefail
cd build
rm -rf SourceGit/*.pdb
zip "sourcegit_$VERSION.$RUNTIME.zip" -r SourceGit

View file

@ -0,0 +1,16 @@
#!/usr/bin/env bash
set -e
set -o
set -u
set pipefail
cd build
rm -rf SourceGit/*.pdb
if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || "$OSTYPE" == "win32" ]]; then
powershell -Command "Compress-Archive -Path SourceGit -DestinationPath \"sourcegit_$VERSION.$RUNTIME.zip\" -Force"
else
zip "sourcegit_$VERSION.$RUNTIME.zip" -r SourceGit
fi

View file

@ -25,12 +25,34 @@ namespace SourceGit
private Action<object> _action = null;
}
public static readonly Command OpenPreferenceCommand = new Command(_ => OpenDialog(new Views.Preference()));
public static readonly Command OpenHotkeysCommand = new Command(_ => OpenDialog(new Views.Hotkeys()));
public static bool IsCheckForUpdateCommandVisible
{
get
{
#if DISABLE_UPDATE_DETECTION
return false;
#else
return true;
#endif
}
}
public static readonly Command OpenPreferencesCommand = new Command(_ => ShowWindow(new Views.Preferences(), false));
public static readonly Command OpenHotkeysCommand = new Command(_ => ShowWindow(new Views.Hotkeys(), false));
public static readonly Command OpenAppDataDirCommand = new Command(_ => Native.OS.OpenInFileManager(Native.OS.DataDir));
public static readonly Command OpenAboutCommand = new Command(_ => OpenDialog(new Views.About()));
public static readonly Command CheckForUpdateCommand = new Command(_ => Check4Update(true));
public static readonly Command OpenAboutCommand = new Command(_ => ShowWindow(new Views.About(), false));
public static readonly Command CheckForUpdateCommand = new Command(_ => (Current as App)?.Check4Update(true));
public static readonly Command QuitCommand = new Command(_ => Quit(0));
public static readonly Command CopyTextBlockCommand = new Command(p => CopyTextBlock(p as TextBlock));
public static readonly Command CopyTextBlockCommand = new Command(p =>
{
var textBlock = p as TextBlock;
if (textBlock == null)
return;
if (textBlock.Inlines is { Count: > 0 } inlines)
CopyText(inlines.Text);
else if (!string.IsNullOrEmpty(textBlock.Text))
CopyText(textBlock.Text);
});
}
}

View file

@ -46,11 +46,9 @@ namespace SourceGit
[JsonSerializable(typeof(Models.ExternalToolPaths))]
[JsonSerializable(typeof(Models.InteractiveRebaseJobCollection))]
[JsonSerializable(typeof(Models.JetBrainsState))]
[JsonSerializable(typeof(Models.OpenAIChatRequest))]
[JsonSerializable(typeof(Models.OpenAIChatResponse))]
[JsonSerializable(typeof(Models.ThemeOverrides))]
[JsonSerializable(typeof(Models.Version))]
[JsonSerializable(typeof(Models.RepositorySettings))]
[JsonSerializable(typeof(ViewModels.Preference))]
[JsonSerializable(typeof(ViewModels.Preferences))]
internal partial class JsonCodeGen : JsonSerializerContext { }
}

View file

@ -16,10 +16,13 @@
<ResourceInclude x:Key="fr_FR" Source="/Resources/Locales/fr_FR.axaml"/>
<ResourceInclude x:Key="it_IT" Source="/Resources/Locales/it_IT.axaml"/>
<ResourceInclude x:Key="pt_BR" Source="/Resources/Locales/pt_BR.axaml"/>
<ResourceInclude x:Key="uk_UA" Source="/Resources/Locales/uk_UA.axaml"/>
<ResourceInclude x:Key="ru_RU" Source="/Resources/Locales/ru_RU.axaml"/>
<ResourceInclude x:Key="zh_CN" Source="/Resources/Locales/zh_CN.axaml"/>
<ResourceInclude x:Key="zh_TW" Source="/Resources/Locales/zh_TW.axaml"/>
<ResourceInclude x:Key="es_ES" Source="/Resources/Locales/es_ES.axaml"/>
<ResourceInclude x:Key="ja_JP" Source="/Resources/Locales/ja_JP.axaml"/>
<ResourceInclude x:Key="ta_IN" Source="/Resources/Locales/ta_IN.axaml"/>
</ResourceDictionary>
</Application.Resources>
@ -32,10 +35,10 @@
<NativeMenu.Menu>
<NativeMenu>
<NativeMenuItem Header="{DynamicResource Text.About.Menu}" Command="{x:Static s:App.OpenAboutCommand}"/>
<NativeMenuItem Header="{DynamicResource Text.Hotkeys}" Command="{x:Static s:App.OpenHotkeysCommand}"/>
<NativeMenuItem Header="{DynamicResource Text.SelfUpdate}" Command="{x:Static s:App.CheckForUpdateCommand}"/>
<NativeMenuItem Header="{DynamicResource Text.Hotkeys}" Command="{x:Static s:App.OpenHotkeysCommand}" Gesture="F1"/>
<NativeMenuItem Header="{DynamicResource Text.SelfUpdate}" Command="{x:Static s:App.CheckForUpdateCommand}" IsVisible="{x:Static s:App.IsCheckForUpdateCommandVisible}"/>
<NativeMenuItemSeparator/>
<NativeMenuItem Header="{DynamicResource Text.Preference}" Command="{x:Static s:App.OpenPreferenceCommand}" Gesture="⌘+,"/>
<NativeMenuItem Header="{DynamicResource Text.Preferences}" Command="{x:Static s:App.OpenPreferencesCommand}" Gesture="⌘+,"/>
<NativeMenuItem Header="{DynamicResource Text.OpenAppDataDir}" Command="{x:Static s:App.OpenAppDataDirCommand}"/>
<NativeMenuItemSeparator/>
<NativeMenuItem Header="{DynamicResource Text.Quit}" Command="{x:Static s:App.QuitCommand}" Gesture="⌘+Q"/>

View file

@ -1,10 +1,13 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Avalonia;
@ -22,6 +25,7 @@ namespace SourceGit
{
public partial class App : Application
{
#region App Entry Point
[STAThread]
public static void Main(string[] args)
{
@ -34,15 +38,14 @@ namespace SourceGit
TaskScheduler.UnobservedTaskException += (_, e) =>
{
LogException(e.Exception);
e.SetObserved();
};
try
{
if (TryLaunchedAsRebaseTodoEditor(args, out int exitTodo))
if (TryLaunchAsRebaseTodoEditor(args, out int exitTodo))
Environment.Exit(exitTodo);
else if (TryLaunchedAsRebaseMessageEditor(args, out int exitMessage))
else if (TryLaunchAsRebaseMessageEditor(args, out int exitMessage))
Environment.Exit(exitMessage);
else
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
@ -75,38 +78,71 @@ namespace SourceGit
return builder;
}
public override void Initialize()
public static void LogException(Exception ex)
{
AvaloniaXamlLoader.Load(this);
if (ex == null)
return;
var pref = ViewModels.Preference.Instance;
pref.PropertyChanged += (_, _) => pref.Save();
var builder = new StringBuilder();
builder.Append($"Crash::: {ex.GetType().FullName}: {ex.Message}\n\n");
builder.Append("----------------------------\n");
builder.Append($"Version: {Assembly.GetExecutingAssembly().GetName().Version}\n");
builder.Append($"OS: {Environment.OSVersion}\n");
builder.Append($"Framework: {AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName}\n");
builder.Append($"Source: {ex.Source}\n");
builder.Append($"Thread Name: {Thread.CurrentThread.Name ?? "Unnamed"}\n");
builder.Append($"User: {Environment.UserName}\n");
builder.Append($"App Start Time: {Process.GetCurrentProcess().StartTime}\n");
builder.Append($"Exception Time: {DateTime.Now}\n");
builder.Append($"Memory Usage: {Process.GetCurrentProcess().PrivateMemorySize64 / 1024 / 1024} MB\n");
builder.Append($"---------------------------\n\n");
builder.Append(ex);
SetLocale(pref.Locale);
SetTheme(pref.Theme, pref.ThemeOverrides);
SetFonts(pref.DefaultFontFamily, pref.MonospaceFontFamily, pref.OnlyUseMonoFontInEditor);
var time = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
var file = Path.Combine(Native.OS.DataDir, $"crash_{time}.log");
File.WriteAllText(file, builder.ToString());
}
#endregion
public override void OnFrameworkInitializationCompleted()
#region Utility Functions
public static void ShowWindow(object data, bool showAsDialog)
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
var impl = (Views.ChromelessWindow target, bool isDialog) =>
{
BindingPlugins.DataValidators.RemoveAt(0);
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner })
{
if (isDialog)
target.ShowDialog(owner);
else
target.Show(owner);
}
else
{
target.Show();
}
};
if (TryLaunchedAsCoreEditor(desktop))
return;
if (TryLaunchedAsAskpass(desktop))
return;
TryLaunchedAsNormal(desktop);
if (data is Views.ChromelessWindow window)
{
impl(window, showAsDialog);
return;
}
}
public static void OpenDialog(Window window)
{
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner })
window.ShowDialog(owner);
var dataTypeName = data.GetType().FullName;
if (string.IsNullOrEmpty(dataTypeName) || !dataTypeName.Contains(".ViewModels.", StringComparison.Ordinal))
return;
var viewTypeName = dataTypeName.Replace(".ViewModels.", ".Views.");
var viewType = Type.GetType(viewTypeName);
if (viewType == null || !viewType.IsSubclassOf(typeof(Views.ChromelessWindow)))
return;
window = Activator.CreateInstance(viewType) as Views.ChromelessWindow;
if (window != null)
{
window.DataContext = data;
impl(window, showAsDialog);
}
}
public static void RaiseException(string context, string message)
@ -164,7 +200,12 @@ namespace SourceGit
var resDic = new ResourceDictionary();
var overrides = JsonSerializer.Deserialize(File.ReadAllText(themeOverridesFile), JsonCodeGen.Default.ThemeOverrides);
foreach (var kv in overrides.BasicColors)
resDic[$"Color.{kv.Key}"] = kv.Value;
{
if (kv.Key.Equals("SystemAccentColor", StringComparison.Ordinal))
resDic["SystemAccentColor"] = kv.Value;
else
resDic[$"Color.{kv.Key}"] = kv.Value;
}
if (overrides.GraphColors.Count > 0)
Models.CommitGraph.SetPens(overrides.GraphColors, overrides.GraphPenThickness);
@ -199,6 +240,9 @@ namespace SourceGit
app._fontsOverrides = null;
}
defaultFont = app.FixFontFamilyName(defaultFont);
monospaceFont = app.FixFontFamilyName(monospaceFont);
var resDic = new ResourceDictionary();
if (!string.IsNullOrEmpty(defaultFont))
resDic.Add("Fonts.Default", new FontFamily(defaultFont));
@ -294,26 +338,11 @@ namespace SourceGit
return null;
}
public static ViewModels.Launcher GetLauncer()
public static ViewModels.Launcher GetLauncher()
{
return Current is App app ? app._launcher : null;
}
public static ViewModels.Repository FindOpenedRepository(string repoPath)
{
if (Current is App app && app._launcher != null)
{
foreach (var page in app._launcher.Pages)
{
var id = page.Node.Id.Replace("\\", "/");
if (id == repoPath && page.Data is ViewModels.Repository repo)
return repo;
}
}
return null;
}
public static void Quit(int exitCode)
{
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
@ -326,94 +355,68 @@ namespace SourceGit
Environment.Exit(exitCode);
}
}
#endregion
private static void CopyTextBlock(TextBlock textBlock)
#region Overrides
public override void Initialize()
{
if (textBlock == null)
return;
AvaloniaXamlLoader.Load(this);
if (textBlock.Inlines is { Count: > 0 } inlines)
CopyText(inlines.Text);
else if (!string.IsNullOrEmpty(textBlock.Text))
CopyText(textBlock.Text);
var pref = ViewModels.Preferences.Instance;
pref.PropertyChanged += (_, _) => pref.Save();
SetLocale(pref.Locale);
SetTheme(pref.Theme, pref.ThemeOverrides);
SetFonts(pref.DefaultFontFamily, pref.MonospaceFontFamily, pref.OnlyUseMonoFontInEditor);
}
private static void LogException(Exception ex)
public override void OnFrameworkInitializationCompleted()
{
if (ex == null)
return;
var builder = new StringBuilder();
builder.Append($"Crash::: {ex.GetType().FullName}: {ex.Message}\n\n");
builder.Append("----------------------------\n");
builder.Append($"Version: {Assembly.GetExecutingAssembly().GetName().Version}\n");
builder.Append($"OS: {Environment.OSVersion.ToString()}\n");
builder.Append($"Framework: {AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName}\n");
builder.Append($"Source: {ex.Source}\n");
builder.Append($"---------------------------\n\n");
builder.Append(ex.StackTrace);
while (ex.InnerException != null)
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
ex = ex.InnerException;
builder.Append($"\n\nInnerException::: {ex.GetType().FullName}: {ex.Message}\n");
builder.Append(ex.StackTrace);
BindingPlugins.DataValidators.RemoveAt(0);
// Disable tooltip if window is not active.
ToolTip.ToolTipOpeningEvent.AddClassHandler<Control>((c, e) =>
{
var topLevel = TopLevel.GetTopLevel(c);
if (topLevel is not Window { IsActive: true })
e.Cancel = true;
});
if (TryLaunchAsCoreEditor(desktop))
return;
if (TryLaunchAsAskpass(desktop))
return;
_ipcChannel = new Models.IpcChannel();
if (!_ipcChannel.IsFirstInstance)
{
var arg = desktop.Args is { Length: > 0 } ? desktop.Args[0].Trim() : string.Empty;
if (!string.IsNullOrEmpty(arg))
{
if (arg.StartsWith('"') && arg.EndsWith('"'))
arg = arg.Substring(1, arg.Length - 2).Trim();
if (arg.Length > 0 && !Path.IsPathFullyQualified(arg))
arg = Path.GetFullPath(arg);
}
_ipcChannel.SendToFirstInstance(arg);
Environment.Exit(0);
}
else
{
_ipcChannel.MessageReceived += TryOpenRepository;
desktop.Exit += (_, _) => _ipcChannel.Dispose();
TryLaunchAsNormal(desktop);
}
}
var time = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
var file = Path.Combine(Native.OS.DataDir, $"crash_{time}.log");
File.WriteAllText(file, builder.ToString());
}
#endregion
private static void Check4Update(bool manually = false)
{
Task.Run(async () =>
{
try
{
// Fetch lastest release information.
var client = new HttpClient() { Timeout = TimeSpan.FromSeconds(5) };
var data = await client.GetStringAsync("https://sourcegit-scm.github.io/data/version.json");
// Parse json into Models.Version.
var ver = JsonSerializer.Deserialize(data, JsonCodeGen.Default.Version);
if (ver == null)
return;
// Check if already up-to-date.
if (!ver.IsNewVersion)
{
if (manually)
ShowSelfUpdateResult(new Models.AlreadyUpToDate());
return;
}
// Should not check ignored tag if this is called manually.
if (!manually)
{
var pref = ViewModels.Preference.Instance;
if (ver.TagName == pref.IgnoreUpdateTag)
return;
}
ShowSelfUpdateResult(ver);
}
catch (Exception e)
{
if (manually)
ShowSelfUpdateResult(e);
}
});
}
private static void ShowSelfUpdateResult(object data)
{
Dispatcher.UIThread.Post(() =>
{
OpenDialog(new Views.SelfUpdate() { DataContext = new ViewModels.SelfUpdate() { Data = data } });
});
}
private static bool TryLaunchedAsRebaseTodoEditor(string[] args, out int exitCode)
private static bool TryLaunchAsRebaseTodoEditor(string[] args, out int exitCode)
{
exitCode = -1;
@ -466,7 +469,7 @@ namespace SourceGit
return true;
}
private static bool TryLaunchedAsRebaseMessageEditor(string[] args, out int exitCode)
private static bool TryLaunchAsRebaseMessageEditor(string[] args, out int exitCode)
{
exitCode = -1;
@ -481,26 +484,42 @@ namespace SourceGit
return true;
var gitDir = Path.GetDirectoryName(file)!;
var jobsFile = Path.Combine(gitDir, "sourcegit_rebase_jobs.json");
if (!File.Exists(jobsFile))
return true;
var collection = JsonSerializer.Deserialize(File.ReadAllText(jobsFile), JsonCodeGen.Default.InteractiveRebaseJobCollection);
var origHeadFile = Path.Combine(gitDir, "rebase-merge", "orig-head");
var ontoFile = Path.Combine(gitDir, "rebase-merge", "onto");
var doneFile = Path.Combine(gitDir, "rebase-merge", "done");
if (!File.Exists(doneFile))
var jobsFile = Path.Combine(gitDir, "sourcegit_rebase_jobs.json");
if (!File.Exists(ontoFile) || !File.Exists(origHeadFile) || !File.Exists(doneFile) || !File.Exists(jobsFile))
return true;
var done = File.ReadAllText(doneFile).Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
if (done.Length > collection.Jobs.Count)
var origHead = File.ReadAllText(origHeadFile).Trim();
var onto = File.ReadAllText(ontoFile).Trim();
var collection = JsonSerializer.Deserialize(File.ReadAllText(jobsFile), JsonCodeGen.Default.InteractiveRebaseJobCollection);
if (!collection.Onto.Equals(onto) || !collection.OrigHead.Equals(origHead))
return true;
var job = collection.Jobs[done.Length - 1];
File.WriteAllText(file, job.Message);
var done = File.ReadAllText(doneFile).Trim().Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
if (done.Length == 0)
return true;
var current = done[^1].Trim();
var match = REG_REBASE_TODO().Match(current);
if (!match.Success)
return true;
var sha = match.Groups[1].Value;
foreach (var job in collection.Jobs)
{
if (job.SHA.StartsWith(sha))
{
File.WriteAllText(file, job.Message);
break;
}
}
return true;
}
private bool TryLaunchedAsCoreEditor(IClassicDesktopStyleApplicationLifetime desktop)
private bool TryLaunchAsCoreEditor(IClassicDesktopStyleApplicationLifetime desktop)
{
var args = desktop.Args;
if (args == null || args.Length <= 1 || !args[0].Equals("--core-editor", StringComparison.Ordinal))
@ -508,14 +527,18 @@ namespace SourceGit
var file = args[1];
if (!File.Exists(file))
{
desktop.Shutdown(-1);
else
desktop.MainWindow = new Views.StandaloneCommitMessageEditor(file);
return true;
}
var editor = new Views.StandaloneCommitMessageEditor();
editor.SetFile(file);
desktop.MainWindow = editor;
return true;
}
private bool TryLaunchedAsAskpass(IClassicDesktopStyleApplicationLifetime desktop)
private bool TryLaunchAsAskpass(IClassicDesktopStyleApplicationLifetime desktop)
{
var launchAsAskpass = Environment.GetEnvironmentVariable("SOURCEGIT_LAUNCH_AS_ASKPASS");
if (launchAsAskpass is not "TRUE")
@ -524,30 +547,159 @@ namespace SourceGit
var args = desktop.Args;
if (args?.Length > 0)
{
desktop.MainWindow = new Views.Askpass(args[0]);
var askpass = new Views.Askpass();
askpass.TxtDescription.Text = args[0];
desktop.MainWindow = askpass;
return true;
}
return false;
}
private void TryLaunchedAsNormal(IClassicDesktopStyleApplicationLifetime desktop)
private void TryLaunchAsNormal(IClassicDesktopStyleApplicationLifetime desktop)
{
Native.OS.SetupEnternalTools();
Native.OS.SetupExternalTools();
Models.AvatarManager.Instance.Start();
string startupRepo = null;
if (desktop.Args != null && desktop.Args.Length == 1 && Directory.Exists(desktop.Args[0]))
startupRepo = desktop.Args[0];
var pref = ViewModels.Preferences.Instance;
pref.SetCanModify();
_launcher = new ViewModels.Launcher(startupRepo);
desktop.MainWindow = new Views.Launcher() { DataContext = _launcher };
desktop.ShutdownMode = ShutdownMode.OnMainWindowClose;
var pref = ViewModels.Preference.Instance;
#if !DISABLE_UPDATE_DETECTION
if (pref.ShouldCheck4UpdateOnStartup())
Check4Update();
#endif
}
private void TryOpenRepository(string repo)
{
if (!string.IsNullOrEmpty(repo) && Directory.Exists(repo))
{
var test = new Commands.QueryRepositoryRootPath(repo).ReadToEnd();
if (test.IsSuccess && !string.IsNullOrEmpty(test.StdOut))
{
Dispatcher.UIThread.Invoke(() =>
{
var node = ViewModels.Preferences.Instance.FindOrAddNodeByRepositoryPath(test.StdOut.Trim(), null, false);
ViewModels.Welcome.Instance.Refresh();
_launcher?.OpenRepositoryInTab(node, null);
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: Views.Launcher wnd })
wnd.BringToTop();
});
return;
}
}
Dispatcher.UIThread.Invoke(() =>
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: Views.Launcher launcher })
launcher.BringToTop();
});
}
private void Check4Update(bool manually = false)
{
Task.Run(async () =>
{
try
{
// Fetch latest release information.
var client = new HttpClient() { Timeout = TimeSpan.FromSeconds(5) };
var data = await client.GetStringAsync("https://sourcegit-scm.github.io/data/version.json");
// Parse JSON into Models.Version.
var ver = JsonSerializer.Deserialize(data, JsonCodeGen.Default.Version);
if (ver == null)
return;
// Check if already up-to-date.
if (!ver.IsNewVersion)
{
if (manually)
ShowSelfUpdateResult(new Models.AlreadyUpToDate());
return;
}
// Should not check ignored tag if this is called manually.
if (!manually)
{
var pref = ViewModels.Preferences.Instance;
if (ver.TagName == pref.IgnoreUpdateTag)
return;
}
ShowSelfUpdateResult(ver);
}
catch (Exception e)
{
if (manually)
ShowSelfUpdateResult(new Models.SelfUpdateFailed(e));
}
});
}
private void ShowSelfUpdateResult(object data)
{
Dispatcher.UIThread.Post(() =>
{
ShowWindow(new ViewModels.SelfUpdate() { Data = data }, true);
});
}
private string FixFontFamilyName(string input)
{
if (string.IsNullOrEmpty(input))
return string.Empty;
var parts = input.Split(',');
var trimmed = new List<string>();
foreach (var part in parts)
{
var t = part.Trim();
if (string.IsNullOrEmpty(t))
continue;
// Collapse multiple spaces into single space
var prevChar = '\0';
var sb = new StringBuilder();
foreach (var c in t)
{
if (c == ' ' && prevChar == ' ')
continue;
sb.Append(c);
prevChar = c;
}
var name = sb.ToString();
var idx = name.IndexOf('#');
if (idx >= 0)
{
if (!name.Equals("fonts:Inter#Inter", StringComparison.Ordinal) &&
!name.Equals("fonts:SourceGit#JetBrains Mono", StringComparison.Ordinal))
continue;
}
trimmed.Add(name);
}
return trimmed.Count > 0 ? string.Join(',', trimmed) : string.Empty;
}
[GeneratedRegex(@"^[a-z]+\s+([a-fA-F0-9]{4,40})(\s+.*)?$")]
private static partial Regex REG_REBASE_TODO();
private Models.IpcChannel _ipcChannel = null;
private ViewModels.Launcher _launcher = null;
private ResourceDictionary _activeLocale = null;
private ResourceDictionary _themeOverrides = null;

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- This manifest is used on Windows only.
Don't remove it as it might cause problems with window transparency and embeded controls.
Don't remove it as it might cause problems with window transparency and embedded controls.
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
<assemblyIdentity version="1.0.0.0" name="SourceGit.Desktop"/>

View file

@ -1,7 +1,4 @@
using System.Collections.Generic;
using System.Text;
namespace SourceGit.Commands
namespace SourceGit.Commands
{
public class Add : Command
{
@ -12,20 +9,18 @@ namespace SourceGit.Commands
Args = includeUntracked ? "add ." : "add -u .";
}
public Add(string repo, List<Models.Change> changes)
public Add(string repo, Models.Change change)
{
WorkingDirectory = repo;
Context = repo;
Args = $"add -- \"{change.Path}\"";
}
var builder = new StringBuilder();
builder.Append("add --");
foreach (var c in changes)
{
builder.Append(" \"");
builder.Append(c.Path);
builder.Append("\"");
}
Args = builder.ToString();
public Add(string repo, string pathspecFromFile)
{
WorkingDirectory = repo;
Context = repo;
Args = $"add --pathspec-from-file=\"{pathspecFromFile}\"";
}
}
}

View file

@ -1,23 +1,12 @@
using System;
namespace SourceGit.Commands
namespace SourceGit.Commands
{
public class Archive : Command
{
public Archive(string repo, string revision, string saveTo, Action<string> outputHandler)
public Archive(string repo, string revision, string saveTo)
{
WorkingDirectory = repo;
Context = repo;
Args = $"archive --format=zip --verbose --output=\"{saveTo}\" {revision}";
TraitErrorAsOutput = true;
_outputHandler = outputHandler;
}
protected override void OnReadline(string line)
{
_outputHandler?.Invoke(line);
}
private readonly Action<string> _outputHandler;
}
}

View file

@ -1,75 +1,14 @@
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace SourceGit.Commands
namespace SourceGit.Commands
{
public partial class AssumeUnchanged
public class AssumeUnchanged : Command
{
[GeneratedRegex(@"^(\w)\s+(.+)$")]
private static partial Regex REG_PARSE();
class ViewCommand : Command
public AssumeUnchanged(string repo, string file, bool bAdd)
{
public ViewCommand(string repo)
{
WorkingDirectory = repo;
Args = "ls-files -v";
RaiseError = false;
}
var mode = bAdd ? "--assume-unchanged" : "--no-assume-unchanged";
public List<string> Result()
{
Exec();
return _outs;
}
protected override void OnReadline(string line)
{
var match = REG_PARSE().Match(line);
if (!match.Success)
return;
if (match.Groups[1].Value == "h")
{
_outs.Add(match.Groups[2].Value);
}
}
private readonly List<string> _outs = new List<string>();
WorkingDirectory = repo;
Context = repo;
Args = $"update-index {mode} -- \"{file}\"";
}
class ModCommand : Command
{
public ModCommand(string repo, string file, bool bAdd)
{
var mode = bAdd ? "--assume-unchanged" : "--no-assume-unchanged";
WorkingDirectory = repo;
Context = repo;
Args = $"update-index {mode} -- \"{file}\"";
}
}
public AssumeUnchanged(string repo)
{
_repo = repo;
}
public List<string> View()
{
return new ViewCommand(_repo).Result();
}
public void Add(string file)
{
new ModCommand(_repo, file, true).Exec();
}
public void Remove(string file)
{
new ModCommand(_repo, file, false).Exec();
}
private readonly string _repo;
}
}

13
src/Commands/Bisect.cs Normal file
View file

@ -0,0 +1,13 @@
namespace SourceGit.Commands
{
public class Bisect : Command
{
public Bisect(string repo, string subcmd)
{
WorkingDirectory = repo;
Context = repo;
RaiseError = false;
Args = $"bisect {subcmd}";
}
}
}

View file

@ -21,10 +21,17 @@ namespace SourceGit.Commands
public Models.BlameData Result()
{
var succ = Exec();
if (!succ)
var rs = ReadToEnd();
if (!rs.IsSuccess)
return _result;
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
return new Models.BlameData();
ParseLine(line);
if (_result.IsBinary)
break;
}
if (_needUnifyCommitSHA)
@ -42,13 +49,8 @@ namespace SourceGit.Commands
return _result;
}
protected override void OnReadline(string line)
private void ParseLine(string line)
{
if (_result.IsBinary)
return;
if (string.IsNullOrEmpty(line))
return;
if (line.IndexOf('\0', StringComparison.Ordinal) >= 0)
{
_result.IsBinary = true;
@ -65,7 +67,7 @@ namespace SourceGit.Commands
var commit = match.Groups[1].Value;
var author = match.Groups[2].Value;
var timestamp = int.Parse(match.Groups[3].Value);
var when = DateTime.UnixEpoch.AddSeconds(timestamp).ToLocalTime().ToString("yyyy/MM/dd");
var when = DateTime.UnixEpoch.AddSeconds(timestamp).ToLocalTime().ToString(_dateFormat);
var info = new Models.BlameLineInfo()
{
@ -87,6 +89,7 @@ namespace SourceGit.Commands
private readonly Models.BlameData _result = new Models.BlameData();
private readonly StringBuilder _content = new StringBuilder();
private readonly string _dateFormat = Models.DateTimeFormat.Active.DateOnly;
private string _lastSHA = string.Empty;
private bool _needUnifyCommitSHA = false;
private int _minSHALen = 64;

View file

@ -1,30 +1,52 @@
namespace SourceGit.Commands
using System.Text;
namespace SourceGit.Commands
{
public static class Branch
{
public static bool Create(string repo, string name, string basedOn)
public static string ShowCurrent(string repo)
{
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
cmd.Args = $"branch {name} {basedOn}";
cmd.Args = $"branch --show-current";
return cmd.ReadToEnd().StdOut.Trim();
}
public static bool Create(string repo, string name, string basedOn, bool force, Models.ICommandLog log)
{
var builder = new StringBuilder();
builder.Append("branch ");
if (force)
builder.Append("-f ");
builder.Append(name);
builder.Append(" ");
builder.Append(basedOn);
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
cmd.Args = builder.ToString();
cmd.Log = log;
return cmd.Exec();
}
public static bool Rename(string repo, string name, string to)
public static bool Rename(string repo, string name, string to, Models.ICommandLog log)
{
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
cmd.Args = $"branch -M {name} {to}";
cmd.Log = log;
return cmd.Exec();
}
public static bool SetUpstream(string repo, string name, string upstream)
public static bool SetUpstream(string repo, string name, string upstream, Models.ICommandLog log)
{
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
cmd.Log = log;
if (string.IsNullOrEmpty(upstream))
cmd.Args = $"branch {name} --unset-upstream";
@ -34,32 +56,27 @@
return cmd.Exec();
}
public static bool DeleteLocal(string repo, string name)
public static bool DeleteLocal(string repo, string name, Models.ICommandLog log)
{
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
cmd.Args = $"branch -D {name}";
cmd.Log = log;
return cmd.Exec();
}
public static bool DeleteRemote(string repo, string remote, string name)
public static bool DeleteRemote(string repo, string remote, string name, Models.ICommandLog log)
{
bool exists = new Remote(repo).HasBranch(remote, name);
if (exists)
return new Push(repo, remote, $"refs/heads/{name}", true) { Log = log }.Exec();
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
bool exists = new Remote(repo).HasBranch(remote, name);
if (exists)
{
cmd.SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
cmd.Args = $"push {remote} --delete {name}";
}
else
{
cmd.Args = $"branch -D -r {remote}/{name}";
}
cmd.Args = $"branch -D -r {remote}/{name}";
cmd.Log = log;
return cmd.Exec();
}
}

View file

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Text;
namespace SourceGit.Commands
@ -12,19 +11,37 @@ namespace SourceGit.Commands
Context = repo;
}
public bool Branch(string branch, Action<string> onProgress)
public bool Branch(string branch, bool force)
{
Args = $"checkout --recurse-submodules --progress {branch}";
TraitErrorAsOutput = true;
_outputHandler = onProgress;
var builder = new StringBuilder();
builder.Append("checkout --progress ");
if (force)
builder.Append("--force ");
builder.Append(branch);
Args = builder.ToString();
return Exec();
}
public bool Branch(string branch, string basedOn, Action<string> onProgress)
public bool Branch(string branch, string basedOn, bool force, bool allowOverwrite)
{
Args = $"checkout --recurse-submodules --progress -b {branch} {basedOn}";
TraitErrorAsOutput = true;
_outputHandler = onProgress;
var builder = new StringBuilder();
builder.Append("checkout --progress ");
if (force)
builder.Append("--force ");
builder.Append(allowOverwrite ? "-B " : "-b ");
builder.Append(branch);
builder.Append(" ");
builder.Append(basedOn);
Args = builder.ToString();
return Exec();
}
public bool Commit(string commitId, bool force)
{
var option = force ? "--force" : string.Empty;
Args = $"checkout {option} --detach --progress {commitId}";
return Exec();
}
@ -61,20 +78,5 @@ namespace SourceGit.Commands
Args = $"checkout --no-overlay {revision} -- \"{file}\"";
return Exec();
}
public bool Commit(string commitId, Action<string> onProgress)
{
Args = $"checkout --detach --progress {commitId}";
TraitErrorAsOutput = true;
_outputHandler = onProgress;
return Exec();
}
protected override void OnReadline(string line)
{
_outputHandler?.Invoke(line);
}
private Action<string> _outputHandler;
}
}

View file

@ -1,31 +1,12 @@
using System.Collections.Generic;
using System.Text;
namespace SourceGit.Commands
namespace SourceGit.Commands
{
public class Clean : Command
{
public Clean(string repo, bool includeIgnored)
public Clean(string repo)
{
WorkingDirectory = repo;
Context = repo;
Args = includeIgnored ? "clean -qfdx" : "clean -qfd";
}
public Clean(string repo, List<string> files)
{
var builder = new StringBuilder();
builder.Append("clean -qfd --");
foreach (var f in files)
{
builder.Append(" \"");
builder.Append(f);
builder.Append("\"");
}
WorkingDirectory = repo;
Context = repo;
Args = builder.ToString();
Args = "clean -qfdx";
}
}
}

View file

@ -1,18 +1,13 @@
using System;
namespace SourceGit.Commands
namespace SourceGit.Commands
{
public class Clone : Command
{
private readonly Action<string> _notifyProgress;
public Clone(string ctx, string path, string url, string localName, string sshKey, string extraArgs, Action<string> ouputHandler)
public Clone(string ctx, string path, string url, string localName, string sshKey, string extraArgs)
{
Context = ctx;
WorkingDirectory = path;
TraitErrorAsOutput = true;
SSHKey = sshKey;
Args = "clone --progress --verbose --recurse-submodules ";
Args = "clone --progress --verbose ";
if (!string.IsNullOrEmpty(extraArgs))
Args += $"{extraArgs} ";
@ -21,13 +16,6 @@ namespace SourceGit.Commands
if (!string.IsNullOrEmpty(localName))
Args += localName;
_notifyProgress = ouputHandler;
}
protected override void OnReadline(string line)
{
_notifyProgress?.Invoke(line);
}
}
}

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using Avalonia.Threading;
@ -10,11 +11,6 @@ namespace SourceGit.Commands
{
public partial class Command
{
public class CancelToken
{
public bool Requested { get; set; } = false;
}
public class ReadToEndResult
{
public bool IsSuccess { get; set; } = false;
@ -30,81 +26,51 @@ namespace SourceGit.Commands
}
public string Context { get; set; } = string.Empty;
public CancelToken Cancel { get; set; } = null;
public CancellationToken CancellationToken { get; set; } = CancellationToken.None;
public string WorkingDirectory { get; set; } = null;
public EditorType Editor { get; set; } = EditorType.CoreEditor; // Only used in Exec() mode
public string SSHKey { get; set; } = string.Empty;
public string Args { get; set; } = string.Empty;
public bool RaiseError { get; set; } = true;
public bool TraitErrorAsOutput { get; set; } = false;
public Models.ICommandLog Log { get; set; } = null;
public bool Exec()
{
Log?.AppendLine($"$ git {Args}\n");
var start = CreateGitStartInfo();
var errs = new List<string>();
var proc = new Process() { StartInfo = start };
var isCancelled = false;
proc.OutputDataReceived += (_, e) =>
{
if (Cancel != null && Cancel.Requested)
{
isCancelled = true;
proc.CancelErrorRead();
proc.CancelOutputRead();
if (!proc.HasExited)
proc.Kill(true);
return;
}
if (e.Data != null)
OnReadline(e.Data);
};
proc.ErrorDataReceived += (_, e) =>
{
if (Cancel != null && Cancel.Requested)
{
isCancelled = true;
proc.CancelErrorRead();
proc.CancelOutputRead();
if (!proc.HasExited)
proc.Kill(true);
return;
}
if (string.IsNullOrEmpty(e.Data))
return;
if (TraitErrorAsOutput)
OnReadline(e.Data);
// Ignore progress messages
if (e.Data.StartsWith("remote: Enumerating objects:", StringComparison.Ordinal))
return;
if (e.Data.StartsWith("remote: Counting objects:", StringComparison.Ordinal))
return;
if (e.Data.StartsWith("remote: Compressing objects:", StringComparison.Ordinal))
return;
if (e.Data.StartsWith("Filtering content:", StringComparison.Ordinal))
return;
if (REG_PROGRESS().IsMatch(e.Data))
return;
errs.Add(e.Data);
};
proc.OutputDataReceived += (_, e) => HandleOutput(e.Data, errs);
proc.ErrorDataReceived += (_, e) => HandleOutput(e.Data, errs);
var dummy = null as Process;
var dummyProcLock = new object();
try
{
proc.Start();
// It not safe, please only use `CancellationToken` in readonly commands.
if (CancellationToken.CanBeCanceled)
{
dummy = proc;
CancellationToken.Register(() =>
{
lock (dummyProcLock)
{
if (dummy is { HasExited: false })
dummy.Kill();
}
});
}
}
catch (Exception e)
{
if (RaiseError)
{
Dispatcher.UIThread.Invoke(() =>
{
App.RaiseException(Context, e.Message);
});
}
Dispatcher.UIThread.Post(() => App.RaiseException(Context, e.Message));
Log?.AppendLine(string.Empty);
return false;
}
@ -112,18 +78,27 @@ namespace SourceGit.Commands
proc.BeginErrorReadLine();
proc.WaitForExit();
if (dummy != null)
{
lock (dummyProcLock)
{
dummy = null;
}
}
int exitCode = proc.ExitCode;
proc.Close();
Log?.AppendLine(string.Empty);
if (!isCancelled && exitCode != 0 && errs.Count > 0)
if (!CancellationToken.IsCancellationRequested && exitCode != 0)
{
if (RaiseError)
{
Dispatcher.UIThread.Invoke(() =>
{
App.RaiseException(Context, string.Join("\n", errs));
});
var errMsg = string.Join("\n", errs).Trim();
if (!string.IsNullOrEmpty(errMsg))
Dispatcher.UIThread.Post(() => App.RaiseException(Context, errMsg));
}
return false;
}
@ -162,11 +137,6 @@ namespace SourceGit.Commands
return rs;
}
protected virtual void OnReadline(string line)
{
// Implemented by derived class
}
private ProcessStartInfo CreateGitStartInfo()
{
var start = new ProcessStartInfo();
@ -191,13 +161,12 @@ namespace SourceGit.Commands
if (!start.Environment.ContainsKey("GIT_SSH_COMMAND") && !string.IsNullOrEmpty(SSHKey))
start.Environment.Add("GIT_SSH_COMMAND", $"ssh -i '{SSHKey}'");
// Force using en_US.UTF-8 locale to avoid GCM crash
// Force using en_US.UTF-8 locale
if (OperatingSystem.IsLinux())
start.Environment.Add("LANG", "en_US.UTF-8");
// Fix macOS `PATH` env
if (OperatingSystem.IsMacOS() && !string.IsNullOrEmpty(Native.OS.CustomPathEnv))
start.Environment.Add("PATH", Native.OS.CustomPathEnv);
{
start.Environment.Add("LANG", "C");
start.Environment.Add("LC_ALL", "C");
}
// Force using this app as git editor.
switch (Editor)
@ -223,6 +192,28 @@ namespace SourceGit.Commands
return start;
}
private void HandleOutput(string line, List<string> errs)
{
line = line ?? string.Empty;
Log?.AppendLine(line);
// Lines to hide in error message.
if (line.Length > 0)
{
if (line.StartsWith("remote: Enumerating objects:", StringComparison.Ordinal) ||
line.StartsWith("remote: Counting objects:", StringComparison.Ordinal) ||
line.StartsWith("remote: Compressing objects:", StringComparison.Ordinal) ||
line.StartsWith("Filtering content:", StringComparison.Ordinal) ||
line.StartsWith("hint:", StringComparison.Ordinal))
return;
if (REG_PROGRESS().IsMatch(line))
return;
}
errs.Add(line);
}
[GeneratedRegex(@"\d+%")]
private static partial Regex REG_PROGRESS();
}

View file

@ -4,19 +4,18 @@ namespace SourceGit.Commands
{
public class Commit : Command
{
public Commit(string repo, string message, bool amend, bool signOff)
public Commit(string repo, string message, bool signOff, bool amend, bool resetAuthor)
{
_tmpFile = Path.GetTempFileName();
File.WriteAllText(_tmpFile, message);
WorkingDirectory = repo;
Context = repo;
TraitErrorAsOutput = true;
Args = $"commit --allow-empty --file=\"{_tmpFile}\"";
if (amend)
Args += " --amend --no-edit";
if (signOff)
Args += " --signoff";
if (amend)
Args += resetAuthor ? " --amend --reset-author --no-edit" : " --amend --no-edit";
}
public bool Run()

View file

@ -6,8 +6,10 @@ namespace SourceGit.Commands
{
public partial class CompareRevisions : Command
{
[GeneratedRegex(@"^(\s?[\w\?]{1,4})\s+(.+)$")]
[GeneratedRegex(@"^([MADC])\s+(.+)$")]
private static partial Regex REG_FORMAT();
[GeneratedRegex(@"^R[0-9]{0,4}\s+(.+)$")]
private static partial Regex REG_RENAME_FORMAT();
public CompareRevisions(string repo, string start, string end)
{
@ -18,18 +20,44 @@ namespace SourceGit.Commands
Args = $"diff --name-status {based} {end}";
}
public CompareRevisions(string repo, string start, string end, string path)
{
WorkingDirectory = repo;
Context = repo;
var based = string.IsNullOrEmpty(start) ? "-R" : start;
Args = $"diff --name-status {based} {end} -- \"{path}\"";
}
public List<Models.Change> Result()
{
Exec();
var rs = ReadToEnd();
if (!rs.IsSuccess)
return _changes;
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
ParseLine(line);
_changes.Sort((l, r) => string.Compare(l.Path, r.Path, StringComparison.Ordinal));
return _changes;
}
protected override void OnReadline(string line)
private void ParseLine(string line)
{
var match = REG_FORMAT().Match(line);
if (!match.Success)
{
match = REG_RENAME_FORMAT().Match(line);
if (match.Success)
{
var renamed = new Models.Change() { Path = match.Groups[1].Value };
renamed.Set(Models.ChangeState.Renamed);
_changes.Add(renamed);
}
return;
}
var change = new Models.Change() { Path = match.Groups[2].Value };
var status = match.Groups[1].Value;
@ -48,10 +76,6 @@ namespace SourceGit.Commands
change.Set(Models.ChangeState.Deleted);
_changes.Add(change);
break;
case 'R':
change.Set(Models.ChangeState.Renamed);
_changes.Add(change);
break;
case 'C':
change.Set(Models.ChangeState.Copied);
_changes.Add(change);

View file

@ -29,7 +29,7 @@ namespace SourceGit.Commands
var rs = new Dictionary<string, string>();
if (output.IsSuccess)
{
var lines = output.StdOut.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
var lines = output.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
var idx = line.IndexOf('=', StringComparison.Ordinal);

View file

@ -8,7 +8,7 @@ namespace SourceGit.Commands
{
WorkingDirectory = repo;
Context = repo;
Args = "status -uno --ignore-submodules=dirty --porcelain";
Args = "--no-optional-locks status -uno --ignore-submodules=all --porcelain";
}
public int Result()
@ -16,7 +16,7 @@ namespace SourceGit.Commands
var rs = ReadToEnd();
if (rs.IsSuccess)
{
var lines = rs.StdOut.Split('\n', StringSplitOptions.RemoveEmptyEntries);
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
return lines.Length;
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
@ -28,34 +28,48 @@ namespace SourceGit.Commands
Context = repo;
if (ignoreWhitespace)
Args = $"-c core.autocrlf=false diff --no-ext-diff --patch --ignore-cr-at-eol --ignore-all-space --unified={unified} {opt}";
Args = $"diff --no-ext-diff --patch --ignore-all-space --unified={unified} {opt}";
else if (Models.DiffOption.IgnoreCRAtEOL)
Args = $"diff --no-ext-diff --patch --ignore-cr-at-eol --unified={unified} {opt}";
else
Args = $"-c core.autocrlf=false diff --no-ext-diff --patch --ignore-cr-at-eol --unified={unified} {opt}";
Args = $"diff --no-ext-diff --patch --unified={unified} {opt}";
}
public Models.DiffResult Result()
{
Exec();
var rs = ReadToEnd();
var start = 0;
var end = rs.StdOut.IndexOf('\n', start);
while (end > 0)
{
var line = rs.StdOut.Substring(start, end - start);
ParseLine(line);
if (_result.IsBinary || _result.IsLFS)
start = end + 1;
end = rs.StdOut.IndexOf('\n', start);
}
if (start < rs.StdOut.Length)
ParseLine(rs.StdOut.Substring(start));
if (_result.IsBinary || _result.IsLFS || _result.TextDiff.Lines.Count == 0)
{
_result.TextDiff = null;
}
else
{
ProcessInlineHighlights();
if (_result.TextDiff.Lines.Count == 0)
_result.TextDiff = null;
else
_result.TextDiff.MaxLineNumber = Math.Max(_newLine, _oldLine);
_result.TextDiff.MaxLineNumber = Math.Max(_newLine, _oldLine);
}
return _result;
}
protected override void OnReadline(string line)
private void ParseLine(string line)
{
if (_result.IsBinary)
return;
if (line.StartsWith("old mode ", StringComparison.Ordinal))
{
_result.OldMode = line.Substring(9);
@ -68,8 +82,17 @@ namespace SourceGit.Commands
return;
}
if (_result.IsBinary)
if (line.StartsWith("deleted file mode ", StringComparison.Ordinal))
{
_result.OldMode = line.Substring(18);
return;
}
if (line.StartsWith("new file mode ", StringComparison.Ordinal))
{
_result.NewMode = line.Substring(14);
return;
}
if (_result.IsLFS)
{
@ -82,7 +105,7 @@ namespace SourceGit.Commands
}
else if (line.StartsWith("-size ", StringComparison.Ordinal))
{
_result.LFSDiff.Old.Size = long.Parse(line.Substring(6));
_result.LFSDiff.Old.Size = long.Parse(line.AsSpan(6));
}
}
else if (ch == '+')
@ -93,12 +116,12 @@ namespace SourceGit.Commands
}
else if (line.StartsWith("+size ", StringComparison.Ordinal))
{
_result.LFSDiff.New.Size = long.Parse(line.Substring(6));
_result.LFSDiff.New.Size = long.Parse(line.AsSpan(6));
}
}
else if (line.StartsWith(" size ", StringComparison.Ordinal))
{
_result.LFSDiff.New.Size = _result.LFSDiff.Old.Size = long.Parse(line.Substring(6));
_result.LFSDiff.New.Size = _result.LFSDiff.Old.Size = long.Parse(line.AsSpan(6));
}
return;
}
@ -128,7 +151,8 @@ namespace SourceGit.Commands
_oldLine = int.Parse(match.Groups[1].Value);
_newLine = int.Parse(match.Groups[2].Value);
_result.TextDiff.Lines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Indicator, line, 0, 0));
_last = new Models.TextDiffLine(Models.TextDiffLineType.Indicator, line, 0, 0);
_result.TextDiff.Lines.Add(_last);
}
}
else
@ -136,7 +160,8 @@ namespace SourceGit.Commands
if (line.Length == 0)
{
ProcessInlineHighlights();
_result.TextDiff.Lines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Normal, "", _oldLine, _newLine));
_last = new Models.TextDiffLine(Models.TextDiffLineType.Normal, "", _oldLine, _newLine);
_result.TextDiff.Lines.Add(_last);
_oldLine++;
_newLine++;
return;
@ -152,7 +177,8 @@ namespace SourceGit.Commands
return;
}
_deleted.Add(new Models.TextDiffLine(Models.TextDiffLineType.Deleted, line.Substring(1), _oldLine, 0));
_last = new Models.TextDiffLine(Models.TextDiffLineType.Deleted, line.Substring(1), _oldLine, 0);
_deleted.Add(_last);
_oldLine++;
}
else if (ch == '+')
@ -164,7 +190,8 @@ namespace SourceGit.Commands
return;
}
_added.Add(new Models.TextDiffLine(Models.TextDiffLineType.Added, line.Substring(1), 0, _newLine));
_last = new Models.TextDiffLine(Models.TextDiffLineType.Added, line.Substring(1), 0, _newLine);
_added.Add(_last);
_newLine++;
}
else if (ch != '\\')
@ -175,7 +202,8 @@ namespace SourceGit.Commands
{
_oldLine = int.Parse(match.Groups[1].Value);
_newLine = int.Parse(match.Groups[2].Value);
_result.TextDiff.Lines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Indicator, line, 0, 0));
_last = new Models.TextDiffLine(Models.TextDiffLineType.Indicator, line, 0, 0);
_result.TextDiff.Lines.Add(_last);
}
else
{
@ -186,11 +214,16 @@ namespace SourceGit.Commands
return;
}
_result.TextDiff.Lines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Normal, line.Substring(1), _oldLine, _newLine));
_last = new Models.TextDiffLine(Models.TextDiffLineType.Normal, line.Substring(1), _oldLine, _newLine);
_result.TextDiff.Lines.Add(_last);
_oldLine++;
_newLine++;
}
}
else if (line.Equals("\\ No newline at end of file", StringComparison.Ordinal))
{
_last.NoNewLineEndOfFile = true;
}
}
}
@ -241,6 +274,7 @@ namespace SourceGit.Commands
private readonly Models.DiffResult _result = new Models.DiffResult();
private readonly List<Models.TextDiffLine> _deleted = new List<Models.TextDiffLine>();
private readonly List<Models.TextDiffLine> _added = new List<Models.TextDiffLine>();
private Models.TextDiffLine _last = null;
private int _oldLine = 0;
private int _newLine = 0;
}

View file

@ -1,39 +1,95 @@
using System;
using System.Collections.Generic;
using System.IO;
using Avalonia.Threading;
namespace SourceGit.Commands
{
public static class Discard
{
public static void All(string repo, bool includeIgnored)
/// <summary>
/// Discard all local changes (unstaged & staged)
/// </summary>
/// <param name="repo"></param>
/// <param name="includeIgnored"></param>
/// <param name="log"></param>
public static void All(string repo, bool includeIgnored, Models.ICommandLog log)
{
new Restore(repo).Exec();
new Clean(repo, includeIgnored).Exec();
var changes = new QueryLocalChanges(repo).Result();
try
{
foreach (var c in changes)
{
if (c.WorkTree == Models.ChangeState.Untracked ||
c.WorkTree == Models.ChangeState.Added ||
c.Index == Models.ChangeState.Added ||
c.Index == Models.ChangeState.Renamed)
{
var fullPath = Path.Combine(repo, c.Path);
if (Directory.Exists(fullPath))
Directory.Delete(fullPath, true);
else
File.Delete(fullPath);
}
}
}
catch (Exception e)
{
Dispatcher.UIThread.Invoke(() =>
{
App.RaiseException(repo, $"Failed to discard changes. Reason: {e.Message}");
});
}
new Reset(repo, "HEAD", "--hard") { Log = log }.Exec();
if (includeIgnored)
new Clean(repo) { Log = log }.Exec();
}
public static void Changes(string repo, List<Models.Change> changes)
/// <summary>
/// Discard selected changes (only unstaged).
/// </summary>
/// <param name="repo"></param>
/// <param name="changes"></param>
/// <param name="log"></param>
public static void Changes(string repo, List<Models.Change> changes, Models.ICommandLog log)
{
var needClean = new List<string>();
var needCheckout = new List<string>();
var restores = new List<string>();
foreach (var c in changes)
try
{
if (c.WorkTree == Models.ChangeState.Untracked || c.WorkTree == Models.ChangeState.Added)
needClean.Add(c.Path);
else
needCheckout.Add(c.Path);
foreach (var c in changes)
{
if (c.WorkTree == Models.ChangeState.Untracked || c.WorkTree == Models.ChangeState.Added)
{
var fullPath = Path.Combine(repo, c.Path);
if (Directory.Exists(fullPath))
Directory.Delete(fullPath, true);
else
File.Delete(fullPath);
}
else
{
restores.Add(c.Path);
}
}
}
catch (Exception e)
{
Dispatcher.UIThread.Invoke(() =>
{
App.RaiseException(repo, $"Failed to discard changes. Reason: {e.Message}");
});
}
for (int i = 0; i < needClean.Count; i += 10)
if (restores.Count > 0)
{
var count = Math.Min(10, needClean.Count - i);
new Clean(repo, needClean.GetRange(i, count)).Exec();
}
for (int i = 0; i < needCheckout.Count; i += 10)
{
var count = Math.Min(10, needCheckout.Count - i);
new Restore(repo, needCheckout.GetRange(i, count), "--worktree --recurse-submodules").Exec();
var pathSpecFile = Path.GetTempFileName();
File.WriteAllLines(pathSpecFile, restores);
new Restore(repo, pathSpecFile, false) { Log = log }.Exec();
File.Delete(pathSpecFile);
}
}
}

View file

@ -8,7 +8,26 @@ namespace SourceGit.Commands
{
public static class ExecuteCustomAction
{
public static void Run(string repo, string file, string args, Action<string> outputHandler)
public static void Run(string repo, string file, string args)
{
var start = new ProcessStartInfo();
start.FileName = file;
start.Arguments = args;
start.UseShellExecute = false;
start.CreateNoWindow = true;
start.WorkingDirectory = repo;
try
{
Process.Start(start);
}
catch (Exception e)
{
Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, e.Message));
}
}
public static void RunAndWait(string repo, string file, string args, Models.ICommandLog log)
{
var start = new ProcessStartInfo();
start.FileName = file;
@ -21,13 +40,7 @@ namespace SourceGit.Commands
start.StandardErrorEncoding = Encoding.UTF8;
start.WorkingDirectory = repo;
// Force using en_US.UTF-8 locale to avoid GCM crash
if (OperatingSystem.IsLinux())
start.Environment.Add("LANG", "en_US.UTF-8");
// Fix macOS `PATH` env
if (OperatingSystem.IsMacOS() && !string.IsNullOrEmpty(Native.OS.CustomPathEnv))
start.Environment.Add("PATH", Native.OS.CustomPathEnv);
log?.AppendLine($"$ {file} {args}\n");
var proc = new Process() { StartInfo = start };
var builder = new StringBuilder();
@ -35,14 +48,14 @@ namespace SourceGit.Commands
proc.OutputDataReceived += (_, e) =>
{
if (e.Data != null)
outputHandler?.Invoke(e.Data);
log?.AppendLine(e.Data);
};
proc.ErrorDataReceived += (_, e) =>
{
if (e.Data != null)
{
outputHandler?.Invoke(e.Data);
log?.AppendLine(e.Data);
builder.AppendLine(e.Data);
}
};
@ -53,26 +66,21 @@ namespace SourceGit.Commands
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
proc.WaitForExit();
var exitCode = proc.ExitCode;
if (exitCode != 0)
{
var errMsg = builder.ToString().Trim();
if (!string.IsNullOrEmpty(errMsg))
Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, errMsg));
}
}
catch (Exception e)
{
Dispatcher.UIThread.Invoke(() =>
{
App.RaiseException(repo, e.Message);
});
Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, e.Message));
}
var exitCode = proc.ExitCode;
proc.Close();
if (exitCode != 0)
{
var errMsg = builder.ToString();
Dispatcher.UIThread.Invoke(() =>
{
App.RaiseException(repo, errMsg);
});
}
}
}
}

View file

@ -1,15 +1,11 @@
using System;
namespace SourceGit.Commands
namespace SourceGit.Commands
{
public class Fetch : Command
{
public Fetch(string repo, string remote, bool noTags, bool prune, bool force, Action<string> outputHandler)
public Fetch(string repo, string remote, bool noTags, bool force)
{
_outputHandler = outputHandler;
WorkingDirectory = repo;
Context = repo;
TraitErrorAsOutput = true;
SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
Args = "fetch --progress --verbose ";
@ -21,27 +17,15 @@ namespace SourceGit.Commands
if (force)
Args += "--force ";
if (prune)
Args += "--prune ";
Args += remote;
}
public Fetch(string repo, Models.Branch local, Models.Branch remote, Action<string> outputHandler)
public Fetch(string repo, Models.Branch local, Models.Branch remote)
{
_outputHandler = outputHandler;
WorkingDirectory = repo;
Context = repo;
TraitErrorAsOutput = true;
SSHKey = new Config(repo).Get($"remote.{remote.Remote}.sshkey");
Args = $"fetch --progress --verbose {remote.Remote} {remote.Name}:{local.Name}";
}
protected override void OnReadline(string line)
{
_outputHandler?.Invoke(line);
}
private readonly Action<string> _outputHandler;
}
}

View file

@ -6,6 +6,7 @@
{
WorkingDirectory = repo;
Context = repo;
Editor = EditorType.None;
Args = $"format-patch {commit} -1 --output=\"{saveTo}\"";
}
}

View file

@ -1,23 +1,12 @@
using System;
namespace SourceGit.Commands
namespace SourceGit.Commands
{
public class GC : Command
{
public GC(string repo, Action<string> outputHandler)
public GC(string repo)
{
_outputHandler = outputHandler;
WorkingDirectory = repo;
Context = repo;
TraitErrorAsOutput = true;
Args = "gc --prune=now";
}
protected override void OnReadline(string line)
{
_outputHandler?.Invoke(line);
}
private readonly Action<string> _outputHandler;
}
}

View file

@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Text;
using System.Threading;
using Avalonia.Threading;
namespace SourceGit.Commands
{
/// <summary>
@ -20,82 +22,78 @@ namespace SourceGit.Commands
}
}
public GenerateCommitMessage(Models.OpenAIService service, string repo, List<Models.Change> changes, CancellationToken cancelToken, Action<string> onProgress)
public GenerateCommitMessage(Models.OpenAIService service, string repo, List<Models.Change> changes, CancellationToken cancelToken, Action<string> onResponse)
{
_service = service;
_repo = repo;
_changes = changes;
_cancelToken = cancelToken;
_onProgress = onProgress;
_onResponse = onResponse;
}
public string Result()
public void Exec()
{
try
{
var summarybuilder = new StringBuilder();
var bodyBuilder = new StringBuilder();
_onResponse?.Invoke("Waiting for pre-file analyzing to completed...\n\n");
var responseBuilder = new StringBuilder();
var summaryBuilder = new StringBuilder();
foreach (var change in _changes)
{
if (_cancelToken.IsCancellationRequested)
return "";
return;
_onProgress?.Invoke($"Analyzing {change.Path}...");
responseBuilder.Append("- ");
summaryBuilder.Append("- ");
var summary = GenerateChangeSummary(change);
summarybuilder.Append("- ");
summarybuilder.Append(summary);
summarybuilder.Append("(file: ");
summarybuilder.Append(change.Path);
summarybuilder.Append(")");
summarybuilder.AppendLine();
var rs = new GetDiffContent(_repo, new Models.DiffOption(change, false)).ReadToEnd();
if (rs.IsSuccess)
{
_service.Chat(
_service.AnalyzeDiffPrompt,
$"Here is the `git diff` output: {rs.StdOut}",
_cancelToken,
update =>
{
responseBuilder.Append(update);
summaryBuilder.Append(update);
bodyBuilder.Append("- ");
bodyBuilder.Append(summary);
bodyBuilder.AppendLine();
_onResponse?.Invoke($"Waiting for pre-file analyzing to completed...\n\n{responseBuilder}");
});
}
responseBuilder.Append("\n");
summaryBuilder.Append("(file: ");
summaryBuilder.Append(change.Path);
summaryBuilder.Append(")\n");
}
if (_cancelToken.IsCancellationRequested)
return "";
return;
_onProgress?.Invoke($"Generating commit message...");
var body = bodyBuilder.ToString();
var subject = GenerateSubject(summarybuilder.ToString());
return string.Format("{0}\n\n{1}", subject, body);
var responseBody = responseBuilder.ToString();
var subjectBuilder = new StringBuilder();
_service.Chat(
_service.GenerateSubjectPrompt,
$"Here are the summaries changes:\n{summaryBuilder}",
_cancelToken,
update =>
{
subjectBuilder.Append(update);
_onResponse?.Invoke($"{subjectBuilder}\n\n{responseBody}");
});
}
catch (Exception e)
{
App.RaiseException(_repo, $"Failed to generate commit message: {e}");
return "";
Dispatcher.UIThread.Post(() => App.RaiseException(_repo, $"Failed to generate commit message: {e}"));
}
}
private string GenerateChangeSummary(Models.Change change)
{
var rs = new GetDiffContent(_repo, new Models.DiffOption(change, false)).ReadToEnd();
var diff = rs.IsSuccess ? rs.StdOut : "unknown change";
var rsp = _service.Chat(_service.AnalyzeDiffPrompt, $"Here is the `git diff` output: {diff}", _cancelToken);
if (rsp != null && rsp.Choices.Count > 0)
return rsp.Choices[0].Message.Content;
return string.Empty;
}
private string GenerateSubject(string summary)
{
var rsp = _service.Chat(_service.GenerateSubjectPrompt, $"Here are the summaries changes:\n{summary}", _cancelToken);
if (rsp != null && rsp.Choices.Count > 0)
return rsp.Choices[0].Message.Content;
return string.Empty;
}
private Models.OpenAIService _service;
private string _repo;
private List<Models.Change> _changes;
private CancellationToken _cancelToken;
private Action<string> _onProgress;
private Action<string> _onResponse;
}
}

View file

@ -1,52 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
using Avalonia.Threading;
namespace SourceGit.Commands
{
public static class GitFlow
{
public class BranchDetectResult
public static bool Init(string repo, string master, string develop, string feature, string release, string hotfix, string version, Models.ICommandLog log)
{
public bool IsGitFlowBranch { get; set; } = false;
public string Type { get; set; } = string.Empty;
public string Prefix { get; set; } = string.Empty;
}
public static bool IsEnabled(string repo, List<Models.Branch> branches)
{
var localBrancheNames = new HashSet<string>();
foreach (var branch in branches)
{
if (branch.IsLocal)
localBrancheNames.Add(branch.Name);
}
var config = new Config(repo).ListAll();
if (!config.TryGetValue("gitflow.branch.master", out string master) || !localBrancheNames.Contains(master))
return false;
if (!config.TryGetValue("gitflow.branch.develop", out string develop) || !localBrancheNames.Contains(develop))
return false;
return config.ContainsKey("gitflow.prefix.feature") &&
config.ContainsKey("gitflow.prefix.release") &&
config.ContainsKey("gitflow.prefix.hotfix");
}
public static bool Init(string repo, List<Models.Branch> branches, string master, string develop, string feature, string release, string hotfix, string version)
{
var current = branches.Find(x => x.IsCurrent);
var masterBranch = branches.Find(x => x.Name == master);
if (masterBranch == null && current != null)
Branch.Create(repo, master, current.Head);
var devBranch = branches.Find(x => x.Name == develop);
if (devBranch == null && current != null)
Branch.Create(repo, develop, current.Head);
var config = new Config(repo);
config.Set("gitflow.branch.master", master);
config.Set("gitflow.branch.develop", develop);
@ -61,104 +21,72 @@ namespace SourceGit.Commands
init.WorkingDirectory = repo;
init.Context = repo;
init.Args = "flow init -d";
init.Log = log;
return init.Exec();
}
public static string GetPrefix(string repo, string type)
public static bool Start(string repo, Models.GitFlowBranchType type, string name, Models.ICommandLog log)
{
return new Config(repo).Get($"gitflow.prefix.{type}");
}
public static BranchDetectResult DetectType(string repo, List<Models.Branch> branches, string branch)
{
var rs = new BranchDetectResult();
var localBrancheNames = new HashSet<string>();
foreach (var b in branches)
{
if (b.IsLocal)
localBrancheNames.Add(b.Name);
}
var config = new Config(repo).ListAll();
if (!config.TryGetValue("gitflow.branch.master", out string master) || !localBrancheNames.Contains(master))
return rs;
if (!config.TryGetValue("gitflow.branch.develop", out string develop) || !localBrancheNames.Contains(develop))
return rs;
if (!config.TryGetValue("gitflow.prefix.feature", out var feature) ||
!config.TryGetValue("gitflow.prefix.release", out var release) ||
!config.TryGetValue("gitflow.prefix.hotfix", out var hotfix))
return rs;
if (branch.StartsWith(feature, StringComparison.Ordinal))
{
rs.IsGitFlowBranch = true;
rs.Type = "feature";
rs.Prefix = feature;
}
else if (branch.StartsWith(release, StringComparison.Ordinal))
{
rs.IsGitFlowBranch = true;
rs.Type = "release";
rs.Prefix = release;
}
else if (branch.StartsWith(hotfix, StringComparison.Ordinal))
{
rs.IsGitFlowBranch = true;
rs.Type = "hotfix";
rs.Prefix = hotfix;
}
return rs;
}
public static bool Start(string repo, string type, string name)
{
if (!SUPPORTED_BRANCH_TYPES.Contains(type))
{
Dispatcher.UIThread.Post(() =>
{
App.RaiseException(repo, "Bad branch type!!!");
});
return false;
}
var start = new Command();
start.WorkingDirectory = repo;
start.Context = repo;
start.Args = $"flow {type} start {name}";
switch (type)
{
case Models.GitFlowBranchType.Feature:
start.Args = $"flow feature start {name}";
break;
case Models.GitFlowBranchType.Release:
start.Args = $"flow release start {name}";
break;
case Models.GitFlowBranchType.Hotfix:
start.Args = $"flow hotfix start {name}";
break;
default:
Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, "Bad git-flow branch type!!!"));
return false;
}
start.Log = log;
return start.Exec();
}
public static bool Finish(string repo, string type, string name, bool keepBranch)
public static bool Finish(string repo, Models.GitFlowBranchType type, string name, bool squash, bool push, bool keepBranch, Models.ICommandLog log)
{
if (!SUPPORTED_BRANCH_TYPES.Contains(type))
{
Dispatcher.UIThread.Post(() =>
{
App.RaiseException(repo, "Bad branch type!!!");
});
var builder = new StringBuilder();
builder.Append("flow ");
return false;
switch (type)
{
case Models.GitFlowBranchType.Feature:
builder.Append("feature");
break;
case Models.GitFlowBranchType.Release:
builder.Append("release");
break;
case Models.GitFlowBranchType.Hotfix:
builder.Append("hotfix");
break;
default:
Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, "Bad git-flow branch type!!!"));
return false;
}
var option = keepBranch ? "-k" : string.Empty;
builder.Append(" finish ");
if (squash)
builder.Append("--squash ");
if (push)
builder.Append("--push ");
if (keepBranch)
builder.Append("-k ");
builder.Append(name);
var finish = new Command();
finish.WorkingDirectory = repo;
finish.Context = repo;
finish.Args = $"flow {type} finish {option} {name}";
finish.Args = builder.ToString();
finish.Log = log;
return finish.Exec();
}
private static readonly List<string> SUPPORTED_BRANCH_TYPES = new List<string>()
{
"feature",
"release",
"bugfix",
"hotfix",
"support",
};
}
}

View file

@ -8,7 +8,14 @@ namespace SourceGit.Commands
{
var file = Path.Combine(repo, ".gitignore");
if (!File.Exists(file))
{
File.WriteAllLines(file, [pattern]);
return;
}
var org = File.ReadAllText(file);
if (!org.EndsWith('\n'))
File.AppendAllLines(file, ["", pattern]);
else
File.AppendAllLines(file, [pattern]);
}

View file

@ -0,0 +1,24 @@
using System.IO;
namespace SourceGit.Commands
{
public class IsBareRepository : Command
{
public IsBareRepository(string path)
{
WorkingDirectory = path;
Args = "rev-parse --is-bare-repository";
}
public bool Result()
{
if (!Directory.Exists(Path.Combine(WorkingDirectory, "refs")) ||
!Directory.Exists(Path.Combine(WorkingDirectory, "objects")) ||
!File.Exists(Path.Combine(WorkingDirectory, "HEAD")))
return false;
var rs = ReadToEnd();
return rs.IsSuccess && rs.StdOut.Trim() == "true";
}
}
}

View file

@ -11,7 +11,7 @@ namespace SourceGit.Commands
{
WorkingDirectory = repo;
Context = repo;
Args = $"diff 4b825dc642cb6eb9a060e54bf8d69288fbee4904 {commit} --numstat -- \"{path}\"";
Args = $"diff {Models.Commit.EmptyTreeSHA1} {commit} --numstat -- \"{path}\"";
RaiseError = false;
}

View file

@ -0,0 +1,17 @@
namespace SourceGit.Commands
{
public class IsCommitSHA : Command
{
public IsCommitSHA(string repo, string hash)
{
WorkingDirectory = repo;
Args = $"cat-file -t {hash}";
}
public bool Result()
{
var rs = ReadToEnd();
return rs.IsSuccess && rs.StdOut.Trim().Equals("commit");
}
}
}

View file

@ -10,5 +10,10 @@
Context = repo;
Args = $"diff -a --ignore-cr-at-eol --check {opt}";
}
public bool Result()
{
return ReadToEnd().IsSuccess;
}
}
}

View file

@ -7,26 +7,18 @@ namespace SourceGit.Commands
{
public partial class LFS
{
[GeneratedRegex(@"^(.+)\s+(\w+)\s+\w+:(\d+)$")]
[GeneratedRegex(@"^(.+)\s+([\w.]+)\s+\w+:(\d+)$")]
private static partial Regex REG_LOCK();
class SubCmd : Command
{
public SubCmd(string repo, string args, Action<string> onProgress)
public SubCmd(string repo, string args, Models.ICommandLog log)
{
WorkingDirectory = repo;
Context = repo;
Args = args;
TraitErrorAsOutput = true;
_outputHandler = onProgress;
Log = log;
}
protected override void OnReadline(string line)
{
_outputHandler?.Invoke(line);
}
private readonly Action<string> _outputHandler;
}
public LFS(string repo)
@ -44,35 +36,35 @@ namespace SourceGit.Commands
return content.Contains("git lfs pre-push");
}
public bool Install()
public bool Install(Models.ICommandLog log)
{
return new SubCmd(_repo, "lfs install --local", null).Exec();
return new SubCmd(_repo, "lfs install --local", log).Exec();
}
public bool Track(string pattern, bool isFilenameMode = false)
public bool Track(string pattern, bool isFilenameMode, Models.ICommandLog log)
{
var opt = isFilenameMode ? "--filename" : "";
return new SubCmd(_repo, $"lfs track {opt} \"{pattern}\"", null).Exec();
return new SubCmd(_repo, $"lfs track {opt} \"{pattern}\"", log).Exec();
}
public void Fetch(string remote, Action<string> outputHandler)
public void Fetch(string remote, Models.ICommandLog log)
{
new SubCmd(_repo, $"lfs fetch {remote}", outputHandler).Exec();
new SubCmd(_repo, $"lfs fetch {remote}", log).Exec();
}
public void Pull(string remote, Action<string> outputHandler)
public void Pull(string remote, Models.ICommandLog log)
{
new SubCmd(_repo, $"lfs pull {remote}", outputHandler).Exec();
new SubCmd(_repo, $"lfs pull {remote}", log).Exec();
}
public void Push(string remote, Action<string> outputHandler)
public void Push(string remote, Models.ICommandLog log)
{
new SubCmd(_repo, $"lfs push {remote}", outputHandler).Exec();
new SubCmd(_repo, $"lfs push {remote}", log).Exec();
}
public void Prune(Action<string> outputHandler)
public void Prune(Models.ICommandLog log)
{
new SubCmd(_repo, "lfs prune", outputHandler).Exec();
new SubCmd(_repo, "lfs prune", log).Exec();
}
public List<Models.LFSLock> Locks(string remote)
@ -82,7 +74,7 @@ namespace SourceGit.Commands
var rs = cmd.ReadToEnd();
if (rs.IsSuccess)
{
var lines = rs.StdOut.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
var match = REG_LOCK().Match(line);
@ -101,21 +93,21 @@ namespace SourceGit.Commands
return locks;
}
public bool Lock(string remote, string file)
public bool Lock(string remote, string file, Models.ICommandLog log)
{
return new SubCmd(_repo, $"lfs lock --remote={remote} \"{file}\"", null).Exec();
return new SubCmd(_repo, $"lfs lock --remote={remote} \"{file}\"", log).Exec();
}
public bool Unlock(string remote, string file, bool force)
public bool Unlock(string remote, string file, bool force, Models.ICommandLog log)
{
var opt = force ? "-f" : "";
return new SubCmd(_repo, $"lfs unlock --remote={remote} {opt} \"{file}\"", null).Exec();
return new SubCmd(_repo, $"lfs unlock --remote={remote} {opt} \"{file}\"", log).Exec();
}
public bool Unlock(string remote, long id, bool force)
public bool Unlock(string remote, long id, bool force, Models.ICommandLog log)
{
var opt = force ? "-f" : "";
return new SubCmd(_repo, $"lfs unlock --remote={remote} {opt} --id={id}", null).Exec();
return new SubCmd(_repo, $"lfs unlock --remote={remote} {opt} --id={id}", log).Exec();
}
private readonly string _repo;

View file

@ -1,23 +1,36 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SourceGit.Commands
{
public class Merge : Command
{
public Merge(string repo, string source, string mode, Action<string> outputHandler)
public Merge(string repo, string source, string mode)
{
_outputHandler = outputHandler;
WorkingDirectory = repo;
Context = repo;
TraitErrorAsOutput = true;
Args = $"merge --progress {source} {mode}";
}
protected override void OnReadline(string line)
public Merge(string repo, List<string> targets, bool autoCommit, string strategy)
{
_outputHandler?.Invoke(line);
}
WorkingDirectory = repo;
Context = repo;
private readonly Action<string> _outputHandler = null;
var builder = new StringBuilder();
builder.Append("merge --progress ");
if (!string.IsNullOrEmpty(strategy))
builder.Append($"--strategy={strategy} ");
if (!autoCommit)
builder.Append("--no-commit ");
foreach (var t in targets)
{
builder.Append(t);
builder.Append(' ');
}
Args = builder.ToString();
}
}
}

View file

@ -13,15 +13,18 @@ namespace SourceGit.Commands
cmd.Context = repo;
cmd.RaiseError = true;
// NOTE: If no <file> names are specified, 'git mergetool' will run the merge tool program on every file with merge conflicts.
var fileArg = string.IsNullOrEmpty(file) ? "" : $"\"{file}\"";
if (toolType == 0)
{
cmd.Args = $"mergetool \"{file}\"";
cmd.Args = $"mergetool {fileArg}";
return cmd.Exec();
}
if (!File.Exists(toolPath))
{
Dispatcher.UIThread.Post(() => App.RaiseException(repo, $"Can NOT found external merge tool in '{toolPath}'!"));
Dispatcher.UIThread.Post(() => App.RaiseException(repo, $"Can NOT find external merge tool in '{toolPath}'!"));
return false;
}
@ -32,7 +35,7 @@ namespace SourceGit.Commands
return false;
}
cmd.Args = $"-c mergetool.sourcegit.cmd=\"\\\"{toolPath}\\\" {supported.Cmd}\" -c mergetool.writeToTemp=true -c mergetool.keepBackup=false -c mergetool.trustExitCode=true mergetool --tool=sourcegit \"{file}\"";
cmd.Args = $"-c mergetool.sourcegit.cmd=\"\\\"{toolPath}\\\" {supported.Cmd}\" -c mergetool.writeToTemp=true -c mergetool.keepBackup=false -c mergetool.trustExitCode=true mergetool --tool=sourcegit {fileArg}";
return cmd.Exec();
}
@ -51,7 +54,7 @@ namespace SourceGit.Commands
if (!File.Exists(toolPath))
{
Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, $"Can NOT found external diff tool in '{toolPath}'!"));
Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, $"Can NOT find external diff tool in '{toolPath}'!"));
return false;
}

View file

@ -1,33 +1,18 @@
using System;
namespace SourceGit.Commands
namespace SourceGit.Commands
{
public class Pull : Command
{
public Pull(string repo, string remote, string branch, bool useRebase, bool noTags, bool prune, Action<string> outputHandler)
public Pull(string repo, string remote, string branch, bool useRebase)
{
_outputHandler = outputHandler;
WorkingDirectory = repo;
Context = repo;
TraitErrorAsOutput = true;
SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
Args = "pull --verbose --progress --tags ";
Args = "pull --verbose --progress ";
if (useRebase)
Args += "--rebase ";
if (noTags)
Args += "--no-tags ";
if (prune)
Args += "--prune ";
Args += "--rebase=true ";
Args += $"{remote} {branch}";
}
protected override void OnReadline(string line)
{
_outputHandler?.Invoke(line);
}
private readonly Action<string> _outputHandler;
}
}

View file

@ -1,16 +1,11 @@
using System;
namespace SourceGit.Commands
namespace SourceGit.Commands
{
public class Push : Command
{
public Push(string repo, string local, string remote, string remoteBranch, bool withTags, bool checkSubmodules, bool track, bool force, Action<string> onProgress)
public Push(string repo, string local, string remote, string remoteBranch, bool withTags, bool checkSubmodules, bool track, bool force)
{
_outputHandler = onProgress;
WorkingDirectory = repo;
Context = repo;
TraitErrorAsOutput = true;
SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
Args = "push --progress --verbose ";
@ -26,7 +21,7 @@ namespace SourceGit.Commands
Args += $"{remote} {local}:{remoteBranch}";
}
public Push(string repo, string remote, string tag, bool isDelete)
public Push(string repo, string remote, string refname, bool isDelete)
{
WorkingDirectory = repo;
Context = repo;
@ -36,14 +31,7 @@ namespace SourceGit.Commands
if (isDelete)
Args += "--delete ";
Args += $"{remote} refs/tags/{tag}";
Args += $"{remote} {refname}";
}
protected override void OnReadline(string line)
{
_outputHandler?.Invoke(line);
}
private readonly Action<string> _outputHandler = null;
}
}

View file

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace SourceGit.Commands
{
public partial class QueryAssumeUnchangedFiles : Command
{
[GeneratedRegex(@"^(\w)\s+(.+)$")]
private static partial Regex REG_PARSE();
public QueryAssumeUnchangedFiles(string repo)
{
WorkingDirectory = repo;
Args = "ls-files -v";
RaiseError = false;
}
public List<string> Result()
{
var outs = new List<string>();
var rs = ReadToEnd();
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
var match = REG_PARSE().Match(line);
if (!match.Success)
continue;
if (match.Groups[1].Value == "h")
outs.Add(match.Groups[2].Value);
}
return outs;
}
}
}

View file

@ -14,22 +14,52 @@ namespace SourceGit.Commands
{
WorkingDirectory = repo;
Context = repo;
Args = "branch -l --all -v --format=\"%(refname)%00%(objectname)%00%(HEAD)%00%(upstream)%00%(upstream:trackshort)\"";
Args = "branch -l --all -v --format=\"%(refname)%00%(committerdate:unix)%00%(objectname)%00%(HEAD)%00%(upstream)%00%(upstream:trackshort)\"";
}
public List<Models.Branch> Result()
public List<Models.Branch> Result(out int localBranchesCount)
{
localBranchesCount = 0;
var branches = new List<Models.Branch>();
var rs = ReadToEnd();
if (!rs.IsSuccess)
return branches;
var lines = rs.StdOut.Split('\n', StringSplitOptions.RemoveEmptyEntries);
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
var remoteHeads = new Dictionary<string, string>();
foreach (var line in lines)
{
var b = ParseLine(line);
if (b != null)
{
branches.Add(b);
if (!b.IsLocal)
remoteHeads.Add(b.FullName, b.Head);
else
localBranchesCount++;
}
}
foreach (var b in branches)
{
if (b.IsLocal && !string.IsNullOrEmpty(b.Upstream))
{
if (remoteHeads.TryGetValue(b.Upstream, out var upstreamHead))
{
b.IsUpstreamGone = false;
if (b.TrackStatus == null)
b.TrackStatus = new QueryTrackStatus(WorkingDirectory, b.Head, upstreamHead).Result();
}
else
{
b.IsUpstreamGone = true;
if (b.TrackStatus == null)
b.TrackStatus = new Models.BranchTrackStatus();
}
}
}
return branches;
@ -38,7 +68,7 @@ namespace SourceGit.Commands
private Models.Branch ParseLine(string line)
{
var parts = line.Split('\0');
if (parts.Length != 5)
if (parts.Length != 6)
return null;
var branch = new Models.Branch();
@ -72,13 +102,16 @@ namespace SourceGit.Commands
}
branch.FullName = refName;
branch.Head = parts[1];
branch.IsCurrent = parts[2] == "*";
branch.Upstream = parts[3];
branch.CommitterDate = ulong.Parse(parts[1]);
branch.Head = parts[2];
branch.IsCurrent = parts[3] == "*";
branch.Upstream = parts[4];
branch.IsUpstreamGone = false;
if (branch.IsLocal && !string.IsNullOrEmpty(parts[4]) && !parts[4].Equals("=", StringComparison.Ordinal))
branch.TrackStatus = new QueryTrackStatus(WorkingDirectory, branch.Name, branch.Upstream).Result();
else
if (!branch.IsLocal ||
string.IsNullOrEmpty(branch.Upstream) ||
string.IsNullOrEmpty(parts[5]) ||
parts[5].Equals("=", StringComparison.Ordinal))
branch.TrackStatus = new Models.BranchTrackStatus();
return branch;

View file

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
namespace SourceGit.Commands
{
@ -9,22 +10,26 @@ namespace SourceGit.Commands
WorkingDirectory = repo;
Context = repo;
_commit = commit;
Args = $"rev-list -{max} --parents --branches --remotes ^{commit}";
Args = $"rev-list -{max} --parents --branches --remotes --ancestry-path ^{commit}";
}
public IEnumerable<string> Result()
public List<string> Result()
{
Exec();
return _lines;
}
var rs = ReadToEnd();
var outs = new List<string>();
if (rs.IsSuccess)
{
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
if (line.Contains(_commit))
outs.Add(line.Substring(0, 40));
}
}
protected override void OnReadline(string line)
{
if (line.Contains(_commit))
_lines.Add(line.Substring(0, 40));
return outs;
}
private string _commit;
private List<string> _lines = new List<string>();
}
}

View file

@ -6,7 +6,7 @@ namespace SourceGit.Commands
{
WorkingDirectory = repo;
Context = repo;
Args = $"show --no-show-signature --pretty=format:%B -s {sha}";
Args = $"show --no-show-signature --format=%B -s {sha}";
}
public string Result()

View file

@ -7,7 +7,7 @@
WorkingDirectory = repo;
Context = repo;
const string baseArgs = "show --no-show-signature --pretty=format:\"%G?%n%GS%n%GK\" -s";
const string baseArgs = "show --no-show-signature --format=%G?%n%GS%n%GK -s";
const string fakeSignersFileArg = "-c gpg.ssh.allowedSignersFile=/dev/null";
Args = $"{(useFakeSignersFile ? fakeSignersFileArg : string.Empty)} {baseArgs} {sha}";
}
@ -18,7 +18,7 @@
if (!rs.IsSuccess)
return null;
var raw = rs.StdOut.Trim();
var raw = rs.StdOut.Trim().ReplaceLineEndings("\n");
if (raw.Length <= 1)
return null;
@ -29,7 +29,6 @@
Signer = lines[1],
Key = lines[2]
};
}
}
}

View file

@ -6,13 +6,11 @@ namespace SourceGit.Commands
{
public class QueryCommits : Command
{
public QueryCommits(string repo, bool useTopoOrder, string limits, bool needFindHead = true)
public QueryCommits(string repo, string limits, bool needFindHead = true)
{
var order = useTopoOrder ? "--topo-order" : "--date-order";
WorkingDirectory = repo;
Context = repo;
Args = $"log {order} --no-show-signature --decorate=full --pretty=format:%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s {limits}";
Args = $"log --no-show-signature --decorate=full --format=%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s {limits}";
_findFirstMerged = needFindHead;
}
@ -20,20 +18,20 @@ namespace SourceGit.Commands
{
string search = onlyCurrentBranch ? string.Empty : "--branches --remotes ";
if (method == Models.CommitSearchMethod.ByUser)
if (method == Models.CommitSearchMethod.ByAuthor)
{
search += $"-i --author=\"{filter}\" --committer=\"{filter}\"";
search += $"-i --author=\"{filter}\"";
}
else if (method == Models.CommitSearchMethod.ByFile)
else if (method == Models.CommitSearchMethod.ByCommitter)
{
search += $"-- \"{filter}\"";
search += $"-i --committer=\"{filter}\"";
}
else
else if (method == Models.CommitSearchMethod.ByMessage)
{
var argsBuilder = new StringBuilder();
argsBuilder.Append(search);
var words = filter.Split(new[] { ' ', '\t', '\r' }, StringSplitOptions.RemoveEmptyEntries);
var words = filter.Split([' ', '\t', '\r'], StringSplitOptions.RemoveEmptyEntries);
foreach (var word in words)
{
var escaped = word.Trim().Replace("\"", "\\\"", StringComparison.Ordinal);
@ -43,10 +41,18 @@ namespace SourceGit.Commands
search = argsBuilder.ToString();
}
else if (method == Models.CommitSearchMethod.ByFile)
{
search += $"-- \"{filter}\"";
}
else
{
search = $"-G\"{filter}\"";
}
WorkingDirectory = repo;
Context = repo;
Args = $"log -1000 --date-order --no-show-signature --decorate=full --pretty=format:%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s " + search;
Args = $"log -1000 --date-order --no-show-signature --decorate=full --format=%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s {search}";
_findFirstMerged = false;
}
@ -122,7 +128,7 @@ namespace SourceGit.Commands
Args = $"log --since=\"{_commits[^1].CommitterTimeStr}\" --format=\"%H\"";
var rs = ReadToEnd();
var shas = rs.StdOut.Split('\n', StringSplitOptions.RemoveEmptyEntries);
var shas = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
if (shas.Length == 0)
return;

View file

@ -3,18 +3,18 @@ using System.Collections.Generic;
namespace SourceGit.Commands
{
public class QueryCommitsWithFullMessage : Command
public class QueryCommitsForInteractiveRebase : Command
{
public QueryCommitsWithFullMessage(string repo, string args)
public QueryCommitsForInteractiveRebase(string repo, string on)
{
_boundary = $"----- BOUNDARY OF COMMIT {Guid.NewGuid()} -----";
WorkingDirectory = repo;
Context = repo;
Args = $"log --date-order --no-show-signature --decorate=full --pretty=format:\"%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%B%n{_boundary}\" {args}";
Args = $"log --date-order --no-show-signature --decorate=full --format=\"%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%B%n{_boundary}\" {on}..HEAD";
}
public List<Models.CommitWithMessage> Result()
public List<Models.InteractiveCommit> Result()
{
var rs = ReadToEnd();
if (!rs.IsSuccess)
@ -29,7 +29,7 @@ namespace SourceGit.Commands
switch (nextPartIdx)
{
case 0:
_current = new Models.CommitWithMessage();
_current = new Models.InteractiveCommit();
_current.Commit.SHA = line;
_commits.Add(_current);
break;
@ -52,16 +52,28 @@ namespace SourceGit.Commands
_current.Commit.CommitterTime = ulong.Parse(line);
break;
default:
if (line.Equals(_boundary, StringComparison.Ordinal))
nextPartIdx = -1;
var boundary = rs.StdOut.IndexOf(_boundary, end + 1, StringComparison.Ordinal);
if (boundary > end)
{
_current.Message = rs.StdOut.Substring(start, boundary - start - 1);
end = boundary + _boundary.Length;
}
else
_current.Message += line;
{
_current.Message = rs.StdOut.Substring(start);
end = rs.StdOut.Length - 2;
}
nextPartIdx = -1;
break;
}
nextPartIdx++;
start = end + 1;
if (start >= rs.StdOut.Length - 1)
break;
end = rs.StdOut.IndexOf('\n', start);
}
@ -76,8 +88,8 @@ namespace SourceGit.Commands
_current.Commit.Parents.AddRange(data.Split(separator: ' ', options: StringSplitOptions.RemoveEmptyEntries));
}
private List<Models.CommitWithMessage> _commits = new List<Models.CommitWithMessage>();
private Models.CommitWithMessage _current = null;
private List<Models.InteractiveCommit> _commits = [];
private Models.InteractiveCommit _current = null;
private string _boundary = "";
}
}

View file

@ -1,21 +0,0 @@
namespace SourceGit.Commands
{
public class QueryCurrentRevisionFiles : Command
{
public QueryCurrentRevisionFiles(string repo)
{
WorkingDirectory = repo;
Context = repo;
Args = "ls-tree -r --name-only HEAD";
}
public string[] Result()
{
var rs = ReadToEnd();
if (rs.IsSuccess)
return rs.StdOut.Split('\n', System.StringSplitOptions.RemoveEmptyEntries);
return [];
}
}
}

View file

@ -35,5 +35,39 @@ namespace SourceGit.Commands
return stream;
}
public static Stream FromLFS(string repo, string oid, long size)
{
var starter = new ProcessStartInfo();
starter.WorkingDirectory = repo;
starter.FileName = Native.OS.GitExecutable;
starter.Arguments = $"lfs smudge";
starter.UseShellExecute = false;
starter.CreateNoWindow = true;
starter.WindowStyle = ProcessWindowStyle.Hidden;
starter.RedirectStandardInput = true;
starter.RedirectStandardOutput = true;
var stream = new MemoryStream();
try
{
var proc = new Process() { StartInfo = starter };
proc.Start();
proc.StandardInput.WriteLine("version https://git-lfs.github.com/spec/v1");
proc.StandardInput.WriteLine($"oid sha256:{oid}");
proc.StandardInput.WriteLine($"size {size}");
proc.StandardOutput.BaseStream.CopyTo(stream);
proc.WaitForExit();
proc.Close();
stream.Position = 0;
}
catch (Exception e)
{
App.RaiseException(repo, $"Failed to query file content: {e}");
}
return stream;
}
}
}

View file

@ -0,0 +1,26 @@
using System.IO;
namespace SourceGit.Commands
{
public class QueryGitCommonDir : Command
{
public QueryGitCommonDir(string workDir)
{
WorkingDirectory = workDir;
Args = "rev-parse --git-common-dir";
RaiseError = false;
}
public string Result()
{
var rs = ReadToEnd().StdOut;
if (string.IsNullOrEmpty(rs))
return null;
rs = rs.Trim();
if (Path.IsPathRooted(rs))
return rs;
return Path.GetFullPath(Path.Combine(WorkingDirectory, rs));
}
}
}

View file

@ -1,6 +1,9 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Avalonia.Threading;
namespace SourceGit.Commands
{
public partial class QueryLocalChanges : Command
@ -13,144 +16,150 @@ namespace SourceGit.Commands
{
WorkingDirectory = repo;
Context = repo;
Args = $"status -u{UNTRACKED[includeUntracked ? 1 : 0]} --ignore-submodules=dirty --porcelain";
Args = $"--no-optional-locks status -u{UNTRACKED[includeUntracked ? 1 : 0]} --ignore-submodules=dirty --porcelain";
}
public List<Models.Change> Result()
{
Exec();
return _changes;
}
protected override void OnReadline(string line)
{
var match = REG_FORMAT().Match(line);
if (!match.Success)
return;
var change = new Models.Change() { Path = match.Groups[2].Value };
var status = match.Groups[1].Value;
switch (status)
var outs = new List<Models.Change>();
var rs = ReadToEnd();
if (!rs.IsSuccess)
{
case " M":
change.Set(Models.ChangeState.None, Models.ChangeState.Modified);
break;
case " T":
change.Set(Models.ChangeState.None, Models.ChangeState.TypeChanged);
break;
case " A":
change.Set(Models.ChangeState.None, Models.ChangeState.Added);
break;
case " D":
change.Set(Models.ChangeState.None, Models.ChangeState.Deleted);
break;
case " R":
change.Set(Models.ChangeState.None, Models.ChangeState.Renamed);
break;
case " C":
change.Set(Models.ChangeState.None, Models.ChangeState.Copied);
break;
case "M":
change.Set(Models.ChangeState.Modified);
break;
case "MM":
change.Set(Models.ChangeState.Modified, Models.ChangeState.Modified);
break;
case "MT":
change.Set(Models.ChangeState.Modified, Models.ChangeState.TypeChanged);
break;
case "MD":
change.Set(Models.ChangeState.Modified, Models.ChangeState.Deleted);
break;
case "T":
change.Set(Models.ChangeState.TypeChanged);
break;
case "TM":
change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.Modified);
break;
case "TT":
change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.TypeChanged);
break;
case "TD":
change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.Deleted);
break;
case "A":
change.Set(Models.ChangeState.Added);
break;
case "AM":
change.Set(Models.ChangeState.Added, Models.ChangeState.Modified);
break;
case "AT":
change.Set(Models.ChangeState.Added, Models.ChangeState.TypeChanged);
break;
case "AD":
change.Set(Models.ChangeState.Added, Models.ChangeState.Deleted);
break;
case "D":
change.Set(Models.ChangeState.Deleted);
break;
case "R":
change.Set(Models.ChangeState.Renamed);
break;
case "RM":
change.Set(Models.ChangeState.Renamed, Models.ChangeState.Modified);
break;
case "RT":
change.Set(Models.ChangeState.Renamed, Models.ChangeState.TypeChanged);
break;
case "RD":
change.Set(Models.ChangeState.Renamed, Models.ChangeState.Deleted);
break;
case "C":
change.Set(Models.ChangeState.Copied);
break;
case "CM":
change.Set(Models.ChangeState.Copied, Models.ChangeState.Modified);
break;
case "CT":
change.Set(Models.ChangeState.Copied, Models.ChangeState.TypeChanged);
break;
case "CD":
change.Set(Models.ChangeState.Copied, Models.ChangeState.Deleted);
break;
case "DR":
change.Set(Models.ChangeState.Deleted, Models.ChangeState.Renamed);
break;
case "DC":
change.Set(Models.ChangeState.Deleted, Models.ChangeState.Copied);
break;
case "DD":
change.Set(Models.ChangeState.Deleted, Models.ChangeState.Deleted);
break;
case "AU":
change.Set(Models.ChangeState.Added, Models.ChangeState.Unmerged);
break;
case "UD":
change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Deleted);
break;
case "UA":
change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Added);
break;
case "DU":
change.Set(Models.ChangeState.Deleted, Models.ChangeState.Unmerged);
break;
case "AA":
change.Set(Models.ChangeState.Added, Models.ChangeState.Added);
break;
case "UU":
change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Unmerged);
break;
case "??":
change.Set(Models.ChangeState.Untracked, Models.ChangeState.Untracked);
break;
default:
return;
Dispatcher.UIThread.Post(() => App.RaiseException(Context, rs.StdErr));
return outs;
}
_changes.Add(change);
}
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
var match = REG_FORMAT().Match(line);
if (!match.Success)
continue;
private readonly List<Models.Change> _changes = new List<Models.Change>();
var change = new Models.Change() { Path = match.Groups[2].Value };
var status = match.Groups[1].Value;
switch (status)
{
case " M":
change.Set(Models.ChangeState.None, Models.ChangeState.Modified);
break;
case " T":
change.Set(Models.ChangeState.None, Models.ChangeState.TypeChanged);
break;
case " A":
change.Set(Models.ChangeState.None, Models.ChangeState.Added);
break;
case " D":
change.Set(Models.ChangeState.None, Models.ChangeState.Deleted);
break;
case " R":
change.Set(Models.ChangeState.None, Models.ChangeState.Renamed);
break;
case " C":
change.Set(Models.ChangeState.None, Models.ChangeState.Copied);
break;
case "M":
change.Set(Models.ChangeState.Modified);
break;
case "MM":
change.Set(Models.ChangeState.Modified, Models.ChangeState.Modified);
break;
case "MT":
change.Set(Models.ChangeState.Modified, Models.ChangeState.TypeChanged);
break;
case "MD":
change.Set(Models.ChangeState.Modified, Models.ChangeState.Deleted);
break;
case "T":
change.Set(Models.ChangeState.TypeChanged);
break;
case "TM":
change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.Modified);
break;
case "TT":
change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.TypeChanged);
break;
case "TD":
change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.Deleted);
break;
case "A":
change.Set(Models.ChangeState.Added);
break;
case "AM":
change.Set(Models.ChangeState.Added, Models.ChangeState.Modified);
break;
case "AT":
change.Set(Models.ChangeState.Added, Models.ChangeState.TypeChanged);
break;
case "AD":
change.Set(Models.ChangeState.Added, Models.ChangeState.Deleted);
break;
case "D":
change.Set(Models.ChangeState.Deleted);
break;
case "R":
change.Set(Models.ChangeState.Renamed);
break;
case "RM":
change.Set(Models.ChangeState.Renamed, Models.ChangeState.Modified);
break;
case "RT":
change.Set(Models.ChangeState.Renamed, Models.ChangeState.TypeChanged);
break;
case "RD":
change.Set(Models.ChangeState.Renamed, Models.ChangeState.Deleted);
break;
case "C":
change.Set(Models.ChangeState.Copied);
break;
case "CM":
change.Set(Models.ChangeState.Copied, Models.ChangeState.Modified);
break;
case "CT":
change.Set(Models.ChangeState.Copied, Models.ChangeState.TypeChanged);
break;
case "CD":
change.Set(Models.ChangeState.Copied, Models.ChangeState.Deleted);
break;
case "DD":
change.ConflictReason = Models.ConflictReason.BothDeleted;
change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
break;
case "AU":
change.ConflictReason = Models.ConflictReason.AddedByUs;
change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
break;
case "UD":
change.ConflictReason = Models.ConflictReason.DeletedByThem;
change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
break;
case "UA":
change.ConflictReason = Models.ConflictReason.AddedByThem;
change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
break;
case "DU":
change.ConflictReason = Models.ConflictReason.DeletedByUs;
change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
break;
case "AA":
change.ConflictReason = Models.ConflictReason.BothAdded;
change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
break;
case "UU":
change.ConflictReason = Models.ConflictReason.BothModified;
change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
break;
case "??":
change.Set(Models.ChangeState.None, Models.ChangeState.Untracked);
break;
}
if (change.Index != Models.ChangeState.None || change.WorkTree != Models.ChangeState.None)
outs.Add(change);
}
return outs;
}
}
}

View file

@ -20,9 +20,12 @@ namespace SourceGit.Commands
if (!output.IsSuccess)
return rs;
var lines = output.StdOut.Split('\n');
var lines = output.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
if (line.EndsWith("/HEAD", StringComparison.Ordinal))
continue;
if (line.StartsWith("refs/heads/", StringComparison.Ordinal))
rs.Add(new() { Name = line.Substring("refs/heads/".Length), Type = Models.DecoratorType.LocalBranchHead });
else if (line.StartsWith("refs/remotes/", StringComparison.Ordinal))

View file

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace SourceGit.Commands
@ -17,27 +18,31 @@ namespace SourceGit.Commands
public List<Models.Remote> Result()
{
Exec();
return _loaded;
}
var outs = new List<Models.Remote>();
var rs = ReadToEnd();
if (!rs.IsSuccess)
return outs;
protected override void OnReadline(string line)
{
var match = REG_REMOTE().Match(line);
if (!match.Success)
return;
var remote = new Models.Remote()
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
Name = match.Groups[1].Value,
URL = match.Groups[2].Value,
};
var match = REG_REMOTE().Match(line);
if (!match.Success)
continue;
if (_loaded.Find(x => x.Name == remote.Name) != null)
return;
_loaded.Add(remote);
var remote = new Models.Remote()
{
Name = match.Groups[1].Value,
URL = match.Groups[2].Value,
};
if (outs.Find(x => x.Name == remote.Name) != null)
continue;
outs.Add(remote);
}
return outs;
}
private readonly List<Models.Remote> _loaded = new List<Models.Remote>();
}
}

View file

@ -0,0 +1,21 @@
namespace SourceGit.Commands
{
public class QueryRevisionByRefName : Command
{
public QueryRevisionByRefName(string repo, string refname)
{
WorkingDirectory = repo;
Context = repo;
Args = $"rev-parse {refname}";
}
public string Result()
{
var rs = ReadToEnd();
if (rs.IsSuccess && !string.IsNullOrEmpty(rs.StdOut))
return rs.StdOut.Trim();
return null;
}
}
}

View file

@ -0,0 +1,27 @@
using System.Collections.Generic;
namespace SourceGit.Commands
{
public class QueryRevisionFileNames : Command
{
public QueryRevisionFileNames(string repo, string revision)
{
WorkingDirectory = repo;
Context = repo;
Args = $"ls-tree -r -z --name-only {revision}";
}
public List<string> Result()
{
var rs = ReadToEnd();
if (!rs.IsSuccess)
return [];
var lines = rs.StdOut.Split('\0', System.StringSplitOptions.RemoveEmptyEntries);
var outs = new List<string>();
foreach (var line in lines)
outs.Add(line);
return outs;
}
}
}

View file

@ -12,7 +12,7 @@ namespace SourceGit.Commands
{
WorkingDirectory = repo;
Context = repo;
Args = $"ls-tree {sha}";
Args = $"ls-tree -z {sha}";
if (!string.IsNullOrEmpty(parentFolder))
Args += $" -- \"{parentFolder}\"";
@ -20,11 +20,27 @@ namespace SourceGit.Commands
public List<Models.Object> Result()
{
Exec();
var rs = ReadToEnd();
if (rs.IsSuccess)
{
var start = 0;
var end = rs.StdOut.IndexOf('\0', start);
while (end > 0)
{
var line = rs.StdOut.Substring(start, end - start);
Parse(line);
start = end + 1;
end = rs.StdOut.IndexOf('\0', start);
}
if (start < rs.StdOut.Length)
Parse(rs.StdOut.Substring(start));
}
return _objects;
}
protected override void OnReadline(string line)
private void Parse(string line)
{
var match = REG_FORMAT().Match(line);
if (!match.Success)

View file

@ -8,7 +8,7 @@ namespace SourceGit.Commands
{
WorkingDirectory = repo;
Context = repo;
Args = $"show --no-show-signature --decorate=full --pretty=format:%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s -s {sha}";
Args = $"show --no-show-signature --decorate=full --format=%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s -s {sha}";
}
public Models.Commit Result()

View file

@ -6,87 +6,87 @@ namespace SourceGit.Commands
{
public partial class QueryStagedChangesWithAmend : Command
{
[GeneratedRegex(@"^:[\d]{6} ([\d]{6}) ([0-9a-f]{40}) [0-9a-f]{40} ([ACDMTUX])\d{0,6}\t(.*)$")]
[GeneratedRegex(@"^:[\d]{6} ([\d]{6}) ([0-9a-f]{40}) [0-9a-f]{40} ([ACDMT])\d{0,6}\t(.*)$")]
private static partial Regex REG_FORMAT1();
[GeneratedRegex(@"^:[\d]{6} ([\d]{6}) ([0-9a-f]{40}) [0-9a-f]{40} R\d{0,6}\t(.*\t.*)$")]
private static partial Regex REG_FORMAT2();
public QueryStagedChangesWithAmend(string repo)
public QueryStagedChangesWithAmend(string repo, string parent)
{
WorkingDirectory = repo;
Context = repo;
Args = "diff-index --cached -M HEAD^";
Args = $"diff-index --cached -M {parent}";
_parent = parent;
}
public List<Models.Change> Result()
{
var rs = ReadToEnd();
if (rs.IsSuccess)
if (!rs.IsSuccess)
return [];
var changes = new List<Models.Change>();
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
var changes = new List<Models.Change>();
var lines = rs.StdOut.Split('\n', StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
var match = REG_FORMAT2().Match(line);
if (match.Success)
{
var match = REG_FORMAT2().Match(line);
if (match.Success)
var change = new Models.Change()
{
var change = new Models.Change()
Path = match.Groups[3].Value,
DataForAmend = new Models.ChangeDataForAmend()
{
Path = match.Groups[3].Value,
DataForAmend = new Models.ChangeDataForAmend()
{
FileMode = match.Groups[1].Value,
ObjectHash = match.Groups[2].Value,
},
};
change.Set(Models.ChangeState.Renamed);
changes.Add(change);
continue;
}
match = REG_FORMAT1().Match(line);
if (match.Success)
{
var change = new Models.Change()
{
Path = match.Groups[4].Value,
DataForAmend = new Models.ChangeDataForAmend()
{
FileMode = match.Groups[1].Value,
ObjectHash = match.Groups[2].Value,
},
};
var type = match.Groups[3].Value;
switch (type)
{
case "A":
change.Set(Models.ChangeState.Added);
break;
case "C":
change.Set(Models.ChangeState.Copied);
break;
case "D":
change.Set(Models.ChangeState.Deleted);
break;
case "M":
change.Set(Models.ChangeState.Modified);
break;
case "T":
change.Set(Models.ChangeState.TypeChanged);
break;
case "U":
change.Set(Models.ChangeState.Unmerged);
break;
}
changes.Add(change);
}
FileMode = match.Groups[1].Value,
ObjectHash = match.Groups[2].Value,
ParentSHA = _parent,
},
};
change.Set(Models.ChangeState.Renamed);
changes.Add(change);
continue;
}
return changes;
match = REG_FORMAT1().Match(line);
if (match.Success)
{
var change = new Models.Change()
{
Path = match.Groups[4].Value,
DataForAmend = new Models.ChangeDataForAmend()
{
FileMode = match.Groups[1].Value,
ObjectHash = match.Groups[2].Value,
ParentSHA = _parent,
},
};
var type = match.Groups[3].Value;
switch (type)
{
case "A":
change.Set(Models.ChangeState.Added);
break;
case "C":
change.Set(Models.ChangeState.Copied);
break;
case "D":
change.Set(Models.ChangeState.Deleted);
break;
case "M":
change.Set(Models.ChangeState.Modified);
break;
case "T":
change.Set(Models.ChangeState.TypeChanged);
break;
}
changes.Add(change);
}
}
return [];
return changes;
}
private readonly string _parent;
}
}

View file

@ -1,60 +0,0 @@
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace SourceGit.Commands
{
public partial class QueryStashChanges : Command
{
[GeneratedRegex(@"^(\s?[\w\?]{1,4})\s+(.+)$")]
private static partial Regex REG_FORMAT();
public QueryStashChanges(string repo, string sha)
{
WorkingDirectory = repo;
Context = repo;
Args = $"diff --name-status --pretty=format: {sha}^ {sha}";
}
public List<Models.Change> Result()
{
Exec();
return _changes;
}
protected override void OnReadline(string line)
{
var match = REG_FORMAT().Match(line);
if (!match.Success)
return;
var change = new Models.Change() { Path = match.Groups[2].Value };
var status = match.Groups[1].Value;
switch (status[0])
{
case 'M':
change.Set(Models.ChangeState.Modified);
_changes.Add(change);
break;
case 'A':
change.Set(Models.ChangeState.Added);
_changes.Add(change);
break;
case 'D':
change.Set(Models.ChangeState.Deleted);
_changes.Add(change);
break;
case 'R':
change.Set(Models.ChangeState.Renamed);
_changes.Add(change);
break;
case 'C':
change.Set(Models.ChangeState.Copied);
_changes.Add(change);
break;
}
}
private readonly List<Models.Change> _changes = new List<Models.Change>();
}
}

View file

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
namespace SourceGit.Commands
{
@ -8,41 +9,65 @@ namespace SourceGit.Commands
{
WorkingDirectory = repo;
Context = repo;
Args = "stash list --pretty=format:%H%n%ct%n%gd%n%s";
Args = "stash list --format=%H%n%P%n%ct%n%gd%n%s";
}
public List<Models.Stash> Result()
{
Exec();
return _stashes;
}
var outs = new List<Models.Stash>();
var rs = ReadToEnd();
if (!rs.IsSuccess)
return outs;
protected override void OnReadline(string line)
{
switch (_nextLineIdx)
var nextPartIdx = 0;
var start = 0;
var end = rs.StdOut.IndexOf('\n', start);
while (end > 0)
{
case 0:
_current = new Models.Stash() { SHA = line };
_stashes.Add(_current);
break;
case 1:
_current.Time = ulong.Parse(line);
break;
case 2:
_current.Name = line;
break;
case 3:
_current.Message = line;
break;
var line = rs.StdOut.Substring(start, end - start);
switch (nextPartIdx)
{
case 0:
_current = new Models.Stash() { SHA = line };
outs.Add(_current);
break;
case 1:
ParseParent(line);
break;
case 2:
_current.Time = ulong.Parse(line);
break;
case 3:
_current.Name = line;
break;
case 4:
_current.Message = line;
break;
}
nextPartIdx++;
if (nextPartIdx > 4)
nextPartIdx = 0;
start = end + 1;
end = rs.StdOut.IndexOf('\n', start);
}
_nextLineIdx++;
if (_nextLineIdx > 3)
_nextLineIdx = 0;
if (start < rs.StdOut.Length)
_current.Message = rs.StdOut.Substring(start);
return outs;
}
private void ParseParent(string data)
{
if (data.Length < 8)
return;
_current.Parents.AddRange(data.Split(separator: ' ', options: StringSplitOptions.RemoveEmptyEntries));
}
private readonly List<Models.Stash> _stashes = new List<Models.Stash>();
private Models.Stash _current = null;
private int _nextLineIdx = 0;
}
}

View file

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
@ -6,12 +7,12 @@ namespace SourceGit.Commands
{
public partial class QuerySubmodules : Command
{
[GeneratedRegex(@"^[\-\+ ][0-9a-f]+\s(.*)\s\(.*\)$")]
private static partial Regex REG_FORMAT1();
[GeneratedRegex(@"^[\-\+ ][0-9a-f]+\s(.*)$")]
private static partial Regex REG_FORMAT2();
[GeneratedRegex(@"^\s?[\w\?]{1,4}\s+(.+)$")]
[GeneratedRegex(@"^([U\-\+ ])([0-9a-f]+)\s(.*?)(\s\(.*\))?$")]
private static partial Regex REG_FORMAT_STATUS();
[GeneratedRegex(@"^\s?[\w\?]{1,4}\s+(.+)$")]
private static partial Regex REG_FORMAT_DIRTY();
[GeneratedRegex(@"^submodule\.(\S*)\.(\w+)=(.*)$")]
private static partial Regex REG_FORMAT_MODULE_INFO();
public QuerySubmodules(string repo)
{
@ -24,55 +25,118 @@ namespace SourceGit.Commands
{
var submodules = new List<Models.Submodule>();
var rs = ReadToEnd();
if (!rs.IsSuccess)
return submodules;
var builder = new StringBuilder();
var lines = rs.StdOut.Split('\n', System.StringSplitOptions.RemoveEmptyEntries);
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
var map = new Dictionary<string, Models.Submodule>();
var needCheckLocalChanges = false;
foreach (var line in lines)
{
var match = REG_FORMAT1().Match(line);
var match = REG_FORMAT_STATUS().Match(line);
if (match.Success)
{
var path = match.Groups[1].Value;
builder.Append($"\"{path}\" ");
submodules.Add(new Models.Submodule() { Path = path });
continue;
}
var stat = match.Groups[1].Value;
var sha = match.Groups[2].Value;
var path = match.Groups[3].Value;
match = REG_FORMAT2().Match(line);
if (match.Success)
{
var path = match.Groups[1].Value;
builder.Append($"\"{path}\" ");
submodules.Add(new Models.Submodule() { Path = path });
var module = new Models.Submodule() { Path = path, SHA = sha };
switch (stat[0])
{
case '-':
module.Status = Models.SubmoduleStatus.NotInited;
break;
case '+':
module.Status = Models.SubmoduleStatus.RevisionChanged;
break;
case 'U':
module.Status = Models.SubmoduleStatus.Unmerged;
break;
default:
module.Status = Models.SubmoduleStatus.Normal;
needCheckLocalChanges = true;
break;
}
map.Add(path, module);
submodules.Add(module);
}
}
if (submodules.Count > 0)
{
Args = $"status -uno --porcelain -- {builder}";
Args = "config --file .gitmodules --list";
rs = ReadToEnd();
if (rs.IsSuccess)
{
var modules = new Dictionary<string, ModuleInfo>();
lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
var match = REG_FORMAT_MODULE_INFO().Match(line);
if (match.Success)
{
var name = match.Groups[1].Value;
var key = match.Groups[2].Value;
var val = match.Groups[3].Value;
if (!modules.TryGetValue(name, out var m))
{
m = new ModuleInfo();
modules.Add(name, m);
}
if (key.Equals("path", StringComparison.Ordinal))
m.Path = val;
else if (key.Equals("url", StringComparison.Ordinal))
m.URL = val;
}
}
foreach (var kv in modules)
{
if (map.TryGetValue(kv.Value.Path, out var m))
m.URL = kv.Value.URL;
}
}
}
if (needCheckLocalChanges)
{
var builder = new StringBuilder();
foreach (var kv in map)
{
if (kv.Value.Status == Models.SubmoduleStatus.Normal)
{
builder.Append('"');
builder.Append(kv.Key);
builder.Append("\" ");
}
}
Args = $"--no-optional-locks status --porcelain -- {builder}";
rs = ReadToEnd();
if (!rs.IsSuccess)
return submodules;
var dirty = new HashSet<string>();
lines = rs.StdOut.Split('\n', System.StringSplitOptions.RemoveEmptyEntries);
lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
var match = REG_FORMAT_STATUS().Match(line);
var match = REG_FORMAT_DIRTY().Match(line);
if (match.Success)
{
var path = match.Groups[1].Value;
dirty.Add(path);
if (map.TryGetValue(path, out var m))
m.Status = Models.SubmoduleStatus.Modified;
}
}
foreach (var submodule in submodules)
submodule.IsDirty = dirty.Contains(submodule.Path);
}
return submodules;
}
private class ModuleInfo
{
public string Path { get; set; } = string.Empty;
public string URL { get; set; } = string.Empty;
}
}
}

View file

@ -11,7 +11,7 @@ namespace SourceGit.Commands
Context = repo;
WorkingDirectory = repo;
Args = $"tag -l --sort=-creatordate --format=\"{_boundary}%(refname)%00%(objectname)%00%(*objectname)%00%(contents:subject)%0a%0a%(contents:body)\"";
Args = $"tag -l --format=\"{_boundary}%(refname)%00%(objecttype)%00%(objectname)%00%(*objectname)%00%(creatordate:unix)%00%(contents:subject)%0a%0a%(contents:body)\"";
}
public List<Models.Tag> Result()
@ -25,15 +25,21 @@ namespace SourceGit.Commands
foreach (var record in records)
{
var subs = record.Split('\0', StringSplitOptions.None);
if (subs.Length != 4)
if (subs.Length != 6)
continue;
var message = subs[3].Trim();
var name = subs[0].Substring(10);
var message = subs[5].Trim();
if (!string.IsNullOrEmpty(message) && message.Equals(name, StringComparison.Ordinal))
message = null;
tags.Add(new Models.Tag()
{
Name = subs[0].Substring(10),
SHA = string.IsNullOrEmpty(subs[2]) ? subs[1] : subs[2],
Message = string.IsNullOrEmpty(message) ? null : message,
Name = name,
IsAnnotated = subs[1].Equals("tag", StringComparison.Ordinal),
SHA = string.IsNullOrEmpty(subs[3]) ? subs[2] : subs[3],
CreatorDate = ulong.Parse(subs[4]),
Message = message,
});
}

View file

@ -19,7 +19,7 @@ namespace SourceGit.Commands
if (!rs.IsSuccess)
return status;
var lines = rs.StdOut.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
if (line[0] == '>')

View file

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace SourceGit.Commands
{
public partial class QueryUpdatableSubmodules : Command
{
[GeneratedRegex(@"^([U\-\+ ])([0-9a-f]+)\s(.*?)(\s\(.*\))?$")]
private static partial Regex REG_FORMAT_STATUS();
public QueryUpdatableSubmodules(string repo)
{
WorkingDirectory = repo;
Context = repo;
Args = "submodule status";
}
public List<string> Result()
{
var submodules = new List<string>();
var rs = ReadToEnd();
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
var match = REG_FORMAT_STATUS().Match(line);
if (match.Success)
{
var stat = match.Groups[1].Value;
var path = match.Groups[3].Value;
if (!stat.StartsWith(' '))
submodules.Add(path);
}
}
return submodules;
}
}
}

View file

@ -1,33 +1,7 @@
using System.Collections.Generic;
using System.Text;
namespace SourceGit.Commands
namespace SourceGit.Commands
{
public class Reset : Command
{
public Reset(string repo)
{
WorkingDirectory = repo;
Context = repo;
Args = "reset";
}
public Reset(string repo, List<Models.Change> changes)
{
WorkingDirectory = repo;
Context = repo;
var builder = new StringBuilder();
builder.Append("reset --");
foreach (var c in changes)
{
builder.Append(" \"");
builder.Append(c.Path);
builder.Append("\"");
}
Args = builder.ToString();
}
public Reset(string repo, string revision, string mode)
{
WorkingDirectory = repo;

View file

@ -1,29 +1,52 @@
using System.Collections.Generic;
using System.Text;
using System.Text;
namespace SourceGit.Commands
{
public class Restore : Command
{
public Restore(string repo)
/// <summary>
/// Only used for single staged change.
/// </summary>
/// <param name="repo"></param>
/// <param name="stagedChange"></param>
public Restore(string repo, Models.Change stagedChange)
{
WorkingDirectory = repo;
Context = repo;
Args = "restore . --source=HEAD --staged --worktree --recurse-submodules";
var builder = new StringBuilder();
builder.Append("restore --staged -- \"");
builder.Append(stagedChange.Path);
builder.Append('"');
if (stagedChange.Index == Models.ChangeState.Renamed)
{
builder.Append(" \"");
builder.Append(stagedChange.OriginalPath);
builder.Append('"');
}
Args = builder.ToString();
}
public Restore(string repo, List<string> files, string extra)
/// <summary>
/// Restore changes given in a path-spec file.
/// </summary>
/// <param name="repo"></param>
/// <param name="pathspecFile"></param>
/// <param name="isStaged"></param>
public Restore(string repo, string pathspecFile, bool isStaged)
{
WorkingDirectory = repo;
Context = repo;
StringBuilder builder = new StringBuilder();
var builder = new StringBuilder();
builder.Append("restore ");
if (!string.IsNullOrEmpty(extra))
builder.Append(extra).Append(" ");
builder.Append("--");
foreach (var f in files)
builder.Append(' ').Append('"').Append(f).Append('"');
builder.Append(isStaged ? "--staged " : "--worktree --recurse-submodules ");
builder.Append("--pathspec-from-file=\"");
builder.Append(pathspecFile);
builder.Append('"');
Args = builder.ToString();
}
}

View file

@ -37,6 +37,19 @@ namespace SourceGit.Commands
return true;
}
public static bool ProcessStashChanges(string repo, List<Models.DiffOption> opts, string saveTo)
{
using (var sw = File.Create(saveTo))
{
foreach (var opt in opts)
{
if (!ProcessSingleChange(repo, opt, sw))
return false;
}
}
return true;
}
private static bool ProcessSingleChange(string repo, Models.DiffOption opt, FileStream writer)
{
var starter = new ProcessStartInfo();

View file

@ -13,12 +13,8 @@ namespace SourceGit.Commands
var isLFSFiltered = new IsLFSFiltered(repo, revision, file).Result();
if (isLFSFiltered)
{
var tmpFile = saveTo + ".tmp";
if (ExecCmd(repo, $"show {revision}:\"{file}\"", tmpFile))
{
ExecCmd(repo, $"lfs smudge", saveTo, tmpFile);
}
File.Delete(tmpFile);
var pointerStream = QueryFileContent.Run(repo, revision, file);
ExecCmd(repo, $"lfs smudge", saveTo, pointerStream);
}
else
{
@ -26,7 +22,7 @@ namespace SourceGit.Commands
}
}
private static bool ExecCmd(string repo, string args, string outputFile, string inputFile = null)
private static bool ExecCmd(string repo, string args, string outputFile, Stream input = null)
{
var starter = new ProcessStartInfo();
starter.WorkingDirectory = repo;
@ -45,21 +41,8 @@ namespace SourceGit.Commands
{
var proc = new Process() { StartInfo = starter };
proc.Start();
if (inputFile != null)
{
using (StreamReader sr = new StreamReader(inputFile))
{
while (true)
{
var line = sr.ReadLine();
if (line == null)
break;
proc.StandardInput.WriteLine(line);
}
}
}
if (input != null)
proc.StandardInput.Write(new StreamReader(input).ReadToEnd());
proc.StandardOutput.BaseStream.CopyTo(sw);
proc.WaitForExit();
var rs = proc.ExitCode == 0;

View file

@ -11,72 +11,84 @@ namespace SourceGit.Commands
Context = repo;
}
public bool Push(string message)
{
Args = $"stash push -m \"{message}\"";
return Exec();
}
public bool Push(List<Models.Change> changes, string message, bool onlyStaged, bool keepIndex)
public bool Push(string message, bool includeUntracked = true, bool keepIndex = false)
{
var builder = new StringBuilder();
builder.Append("stash push ");
if (onlyStaged)
builder.Append("--staged ");
if (includeUntracked)
builder.Append("--include-untracked ");
if (keepIndex)
builder.Append("--keep-index ");
builder.Append("-m \"");
builder.Append(message);
builder.Append("\"");
Args = builder.ToString();
return Exec();
}
public bool Push(string message, List<Models.Change> changes, bool keepIndex)
{
var builder = new StringBuilder();
builder.Append("stash push --include-untracked ");
if (keepIndex)
builder.Append("--keep-index ");
builder.Append("-m \"");
builder.Append(message);
builder.Append("\" -- ");
if (onlyStaged)
{
foreach (var c in changes)
builder.Append($"\"{c.Path}\" ");
}
else
{
var needAdd = new List<Models.Change>();
foreach (var c in changes)
{
builder.Append($"\"{c.Path}\" ");
if (c.WorkTree == Models.ChangeState.Added || c.WorkTree == Models.ChangeState.Untracked)
{
needAdd.Add(c);
if (needAdd.Count > 10)
{
new Add(WorkingDirectory, needAdd).Exec();
needAdd.Clear();
}
}
}
if (needAdd.Count > 0)
{
new Add(WorkingDirectory, needAdd).Exec();
needAdd.Clear();
}
}
foreach (var c in changes)
builder.Append($"\"{c.Path}\" ");
Args = builder.ToString();
return Exec();
}
public bool Apply(string name)
public bool Push(string message, string pathspecFromFile, bool keepIndex)
{
Args = $"stash apply -q {name}";
var builder = new StringBuilder();
builder.Append("stash push --include-untracked --pathspec-from-file=\"");
builder.Append(pathspecFromFile);
builder.Append("\" ");
if (keepIndex)
builder.Append("--keep-index ");
builder.Append("-m \"");
builder.Append(message);
builder.Append("\"");
Args = builder.ToString();
return Exec();
}
public bool PushOnlyStaged(string message, bool keepIndex)
{
var builder = new StringBuilder();
builder.Append("stash push --staged ");
if (keepIndex)
builder.Append("--keep-index ");
builder.Append("-m \"");
builder.Append(message);
builder.Append("\"");
Args = builder.ToString();
return Exec();
}
public bool Apply(string name, bool restoreIndex)
{
var opts = restoreIndex ? "--index" : string.Empty;
Args = $"stash apply -q {opts} \"{name}\"";
return Exec();
}
public bool Pop(string name)
{
Args = $"stash pop -q {name}";
Args = $"stash pop -q --index \"{name}\"";
return Exec();
}
public bool Drop(string name)
{
Args = $"stash drop -q {name}";
Args = $"stash drop -q \"{name}\"";
return Exec();
}

View file

@ -1,4 +1,4 @@
using System;
using System;
namespace SourceGit.Commands
{
@ -8,7 +8,7 @@ namespace SourceGit.Commands
{
WorkingDirectory = repo;
Context = repo;
Args = $"log --date-order --branches --remotes -{max} --pretty=format:\"%ct$%aN\"";
Args = $"log --date-order --branches --remotes -{max} --format=%ct$%aN±%aE";
}
public Models.Statistics Result()
@ -40,7 +40,7 @@ namespace SourceGit.Commands
if (dateEndIdx == -1)
return;
var dateStr = line.Substring(0, dateEndIdx);
var dateStr = line.AsSpan(0, dateEndIdx);
if (double.TryParse(dateStr, out var date))
statistics.AddCommit(line.Substring(dateEndIdx + 1), date);
}

View file

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SourceGit.Commands
{
@ -10,10 +11,9 @@ namespace SourceGit.Commands
Context = repo;
}
public bool Add(string url, string relativePath, bool recursive, Action<string> outputHandler)
public bool Add(string url, string relativePath, bool recursive)
{
_outputHandler = outputHandler;
Args = $"submodule add {url} \"{relativePath}\"";
Args = $"-c protocol.file.allow=always submodule add \"{url}\" \"{relativePath}\"";
if (!Exec())
return false;
@ -29,38 +29,38 @@ namespace SourceGit.Commands
}
}
public bool Update(string module, bool init, bool recursive, bool useRemote, Action<string> outputHandler)
public bool Update(List<string> modules, bool init, bool recursive, bool useRemote = false)
{
Args = "submodule update";
var builder = new StringBuilder();
builder.Append("submodule update");
if (init)
Args += " --init";
builder.Append(" --init");
if (recursive)
Args += " --recursive";
builder.Append(" --recursive");
if (useRemote)
Args += " --remote";
if (!string.IsNullOrEmpty(module))
Args += $" -- \"{module}\"";
builder.Append(" --remote");
if (modules.Count > 0)
{
builder.Append(" --");
foreach (var module in modules)
builder.Append($" \"{module}\"");
}
_outputHandler = outputHandler;
Args = builder.ToString();
return Exec();
}
public bool Delete(string relativePath)
public bool Deinit(string module, bool force)
{
Args = $"submodule deinit -f \"{relativePath}\"";
if (!Exec())
return false;
Args = $"rm -rf \"{relativePath}\"";
Args = force ? $"submodule deinit -f -- \"{module}\"" : $"submodule deinit -- \"{module}\"";
return Exec();
}
protected override void OnReadline(string line)
public bool Delete(string module)
{
_outputHandler?.Invoke(line);
Args = $"rm -rf \"{module}\"";
return Exec();
}
private Action<string> _outputHandler;
}
}

View file

@ -1,59 +1,51 @@
using System.Collections.Generic;
using System.IO;
using System.IO;
namespace SourceGit.Commands
{
public static class Tag
{
public static bool Add(string repo, string name, string basedOn)
public static bool Add(string repo, string name, string basedOn, Models.ICommandLog log)
{
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
cmd.Args = $"tag {name} {basedOn}";
cmd.Args = $"tag --no-sign {name} {basedOn}";
cmd.Log = log;
return cmd.Exec();
}
public static bool Add(string repo, string name, string basedOn, string message, bool sign)
public static bool Add(string repo, string name, string basedOn, string message, bool sign, Models.ICommandLog log)
{
var param = sign ? "--sign -a" : "--no-sign -a";
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
cmd.Args = $"tag {param} {name} {basedOn} ";
cmd.Log = log;
if (!string.IsNullOrEmpty(message))
{
string tmp = Path.GetTempFileName();
File.WriteAllText(tmp, message);
cmd.Args += $"-F \"{tmp}\"";
}
else
{
cmd.Args += $"-m {name}";
var succ = cmd.Exec();
File.Delete(tmp);
return succ;
}
cmd.Args += $"-m {name}";
return cmd.Exec();
}
public static bool Delete(string repo, string name, List<Models.Remote> remotes)
public static bool Delete(string repo, string name, Models.ICommandLog log)
{
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
cmd.Args = $"tag --delete {name}";
if (!cmd.Exec())
return false;
if (remotes != null)
{
foreach (var r in remotes)
{
new Push(repo, r.Name, name, true).Exec();
}
}
return true;
cmd.Log = log;
return cmd.Exec();
}
}
}

View file

@ -1,23 +0,0 @@
using System;
namespace SourceGit.Commands
{
public class UpdateRef : Command
{
public UpdateRef(string repo, string refName, string toRevision, Action<string> outputHandler)
{
_outputHandler = outputHandler;
WorkingDirectory = repo;
Context = repo;
Args = $"update-ref {refName} {toRevision}";
}
protected override void OnReadline(string line)
{
_outputHandler?.Invoke(line);
}
private Action<string> _outputHandler;
}
}

View file

@ -1,19 +0,0 @@
namespace SourceGit.Commands
{
public class Version : Command
{
public Version()
{
Args = "--version";
RaiseError = false;
}
public string Query()
{
var rs = ReadToEnd();
if (!rs.IsSuccess || string.IsNullOrWhiteSpace(rs.StdOut))
return string.Empty;
return rs.StdOut.Trim().Substring("git version ".Length);
}
}
}

View file

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace SourceGit.Commands
{
@ -20,12 +21,13 @@ namespace SourceGit.Commands
var last = null as Models.Worktree;
if (rs.IsSuccess)
{
var lines = rs.StdOut.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
if (line.StartsWith("worktree ", StringComparison.Ordinal))
{
last = new Models.Worktree() { FullPath = line.Substring(9).Trim() };
last.RelativePath = Path.GetRelativePath(WorkingDirectory, last.FullPath);
worktrees.Add(last);
}
else if (line.StartsWith("bare", StringComparison.Ordinal))
@ -54,7 +56,7 @@ namespace SourceGit.Commands
return worktrees;
}
public bool Add(string fullpath, string name, bool createNew, string tracking, Action<string> outputHandler)
public bool Add(string fullpath, string name, bool createNew, string tracking)
{
Args = "worktree add ";
@ -73,15 +75,15 @@ namespace SourceGit.Commands
if (!string.IsNullOrEmpty(tracking))
Args += tracking;
else if (!string.IsNullOrEmpty(name) && !createNew)
Args += name;
_outputHandler = outputHandler;
return Exec();
}
public bool Prune(Action<string> outputHandler)
public bool Prune()
{
Args = "worktree prune -v";
_outputHandler = outputHandler;
return Exec();
}
@ -97,22 +99,14 @@ namespace SourceGit.Commands
return Exec();
}
public bool Remove(string fullpath, bool force, Action<string> outputHandler)
public bool Remove(string fullpath, bool force)
{
if (force)
Args = $"worktree remove -f \"{fullpath}\"";
else
Args = $"worktree remove \"{fullpath}\"";
_outputHandler = outputHandler;
return Exec();
}
protected override void OnReadline(string line)
{
_outputHandler?.Invoke(line);
}
private Action<string> _outputHandler = null;
}
}

View file

@ -1,4 +1,5 @@
using Avalonia.Data.Converters;
using Avalonia.Media;
namespace SourceGit.Converters
{
@ -6,5 +7,8 @@ namespace SourceGit.Converters
{
public static readonly FuncValueConverter<bool, double> ToPageTabWidth =
new FuncValueConverter<bool, double>(x => x ? 200 : double.NaN);
public static readonly FuncValueConverter<bool, FontWeight> IsBoldToFontWeight =
new FuncValueConverter<bool, FontWeight>(x => x ? FontWeight.Bold : FontWeight.Normal);
}
}

View file

@ -23,10 +23,10 @@ namespace SourceGit.Converters
new FuncValueConverter<int, bool>(v => v != 1);
public static readonly FuncValueConverter<int, bool> IsSubjectLengthBad =
new FuncValueConverter<int, bool>(v => v > ViewModels.Preference.Instance.SubjectGuideLength);
new FuncValueConverter<int, bool>(v => v > ViewModels.Preferences.Instance.SubjectGuideLength);
public static readonly FuncValueConverter<int, bool> IsSubjectLengthGood =
new FuncValueConverter<int, bool>(v => v <= ViewModels.Preference.Instance.SubjectGuideLength);
new FuncValueConverter<int, bool>(v => v <= ViewModels.Preferences.Instance.SubjectGuideLength);
public static readonly FuncValueConverter<int, Thickness> ToTreeMargin =
new FuncValueConverter<int, Thickness>(v => new Thickness(v * 16, 0, 0, 0));

View file

@ -7,8 +7,11 @@ namespace SourceGit.Converters
{
public static class ListConverters
{
public static readonly FuncValueConverter<IList, string> Count =
new FuncValueConverter<IList, string>(v => v == null ? "0" : $"{v.Count}");
public static readonly FuncValueConverter<IList, string> ToCount =
new FuncValueConverter<IList, string>(v => v == null ? " (0)" : $" ({v.Count})");
new FuncValueConverter<IList, string>(v => v == null ? "(0)" : $"({v.Count})");
public static readonly FuncValueConverter<IList, bool> IsNullOrEmpty =
new FuncValueConverter<IList, bool>(v => v == null || v.Count == 0);

View file

@ -0,0 +1,27 @@
using System;
using System.Globalization;
using Avalonia.Data.Converters;
namespace SourceGit.Converters
{
public static class ObjectConverters
{
public class IsTypeOfConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null || parameter == null)
return false;
return value.GetType().IsAssignableTo((Type)parameter);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return new NotImplementedException();
}
}
public static readonly IsTypeOfConverter IsTypeOf = new IsTypeOfConverter();
}
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using Avalonia.Data.Converters;
@ -22,7 +22,7 @@ namespace SourceGit.Converters
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var prefixLen = home.EndsWith('/') ? home.Length - 1 : home.Length;
if (v.StartsWith(home, StringComparison.Ordinal))
return "~" + v.Substring(prefixLen);
return $"~{v.AsSpan(prefixLen)}";
return v;
});

View file

@ -1,13 +1,12 @@
using System;
using System.Globalization;
using System.Text.RegularExpressions;
using Avalonia.Data.Converters;
using Avalonia.Styling;
namespace SourceGit.Converters
{
public static partial class StringConverters
public static class StringConverters
{
public class ToLocaleConverter : IValueConverter
{
@ -68,22 +67,6 @@ namespace SourceGit.Converters
public static readonly FuncValueConverter<string, string> ToShortSHA =
new FuncValueConverter<string, string>(v => v == null ? string.Empty : (v.Length > 10 ? v.Substring(0, 10) : v));
public static readonly FuncValueConverter<string, bool> UnderRecommendGitVersion =
new(v =>
{
var match = REG_GIT_VERSION().Match(v ?? "");
if (match.Success)
{
var major = int.Parse(match.Groups[1].Value);
var minor = int.Parse(match.Groups[2].Value);
var build = int.Parse(match.Groups[3].Value);
return new Version(major, minor, build) < MINIMAL_GIT_VERSION;
}
return true;
});
public static readonly FuncValueConverter<string, string> TrimRefsPrefix =
new FuncValueConverter<string, string>(v =>
{
@ -96,9 +79,10 @@ namespace SourceGit.Converters
return v;
});
[GeneratedRegex(@"^[\s\w]*(\d+)\.(\d+)[\.\-](\d+).*$")]
private static partial Regex REG_GIT_VERSION();
public static readonly FuncValueConverter<string, bool> ContainsSpaces =
new FuncValueConverter<string, bool>(v => v != null && v.Contains(' '));
private static readonly Version MINIMAL_GIT_VERSION = new Version(2, 23, 0);
public static readonly FuncValueConverter<string, bool> IsNotNullOrWhitespace =
new FuncValueConverter<string, bool>(v => v != null && v.Trim().Length > 0);
}
}

View file

@ -2,14 +2,22 @@
{
public class ApplyWhiteSpaceMode
{
public static readonly ApplyWhiteSpaceMode[] Supported =
[
new ApplyWhiteSpaceMode("No Warn", "Turns off the trailing whitespace warning", "nowarn"),
new ApplyWhiteSpaceMode("Warn", "Outputs warnings for a few such errors, but applies", "warn"),
new ApplyWhiteSpaceMode("Error", "Raise errors and refuses to apply the patch", "error"),
new ApplyWhiteSpaceMode("Error All", "Similar to 'error', but shows more", "error-all"),
];
public string Name { get; set; }
public string Desc { get; set; }
public string Arg { get; set; }
public ApplyWhiteSpaceMode(string n, string d, string a)
{
Name = App.Text(n);
Desc = App.Text(d);
Name = n;
Desc = d;
Arg = a;
}
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
@ -17,7 +17,7 @@ namespace SourceGit.Models
{
public interface IAvatarHost
{
void OnAvatarResourceChanged(string email);
void OnAvatarResourceChanged(string email, Bitmap image);
}
public partial class AvatarManager
@ -35,7 +35,7 @@ namespace SourceGit.Models
private static AvatarManager _instance = null;
[GeneratedRegex(@"^(?:(\d+)\+)?(.+?)@users\.noreply\.github\.com$")]
[GeneratedRegex(@"^(?:(\d+)\+)?(.+?)@.+\.github\.com$")]
private static partial Regex REG_GITHUB_USER_EMAIL();
private object _synclock = new object();
@ -43,6 +43,7 @@ namespace SourceGit.Models
private List<IAvatarHost> _avatars = new List<IAvatarHost>();
private Dictionary<string, Bitmap> _resources = new Dictionary<string, Bitmap>();
private HashSet<string> _requesting = new HashSet<string>();
private HashSet<string> _defaultAvatars = new HashSet<string>();
public void Start()
{
@ -50,8 +51,8 @@ namespace SourceGit.Models
if (!Directory.Exists(_storePath))
Directory.CreateDirectory(_storePath);
var icon = AssetLoader.Open(new Uri($"avares://SourceGit/Resources/Images/github.png", UriKind.RelativeOrAbsolute));
_resources.Add("noreply@github.com", new Bitmap(icon));
LoadDefaultAvatar("noreply@github.com", "github.png");
LoadDefaultAvatar("unrealbot@epicgames.com", "unreal.png");
Task.Run(() =>
{
@ -118,7 +119,7 @@ namespace SourceGit.Models
Dispatcher.UIThread.InvokeAsync(() =>
{
_resources[email] = img;
NotifyResourceChanged(email);
NotifyResourceChanged(email, img);
});
}
@ -140,7 +141,7 @@ namespace SourceGit.Models
{
if (forceRefetch)
{
if (email.Equals("noreply@github.com", StringComparison.Ordinal))
if (_defaultAvatars.Contains(email))
return null;
if (_resources.ContainsKey(email))
@ -150,7 +151,7 @@ namespace SourceGit.Models
if (File.Exists(localFile))
File.Delete(localFile);
NotifyResourceChanged(email);
NotifyResourceChanged(email, null);
}
else
{
@ -185,22 +186,58 @@ namespace SourceGit.Models
return null;
}
public void SetFromLocal(string email, string file)
{
try
{
Bitmap image = null;
using (var stream = File.OpenRead(file))
{
image = Bitmap.DecodeToWidth(stream, 128);
}
if (image == null)
return;
if (_resources.ContainsKey(email))
_resources[email] = image;
else
_resources.Add(email, image);
_requesting.Remove(email);
var store = Path.Combine(_storePath, GetEmailHash(email));
File.Copy(file, store, true);
NotifyResourceChanged(email, image);
}
catch
{
// ignore
}
}
private void LoadDefaultAvatar(string key, string img)
{
var icon = AssetLoader.Open(new Uri($"avares://SourceGit/Resources/Images/{img}", UriKind.RelativeOrAbsolute));
_resources.Add(key, new Bitmap(icon));
_defaultAvatars.Add(key);
}
private string GetEmailHash(string email)
{
var lowered = email.ToLower(CultureInfo.CurrentCulture).Trim();
var hash = MD5.Create().ComputeHash(Encoding.Default.GetBytes(lowered));
var builder = new StringBuilder();
var hash = MD5.HashData(Encoding.Default.GetBytes(lowered));
var builder = new StringBuilder(hash.Length * 2);
foreach (var c in hash)
builder.Append(c.ToString("x2"));
return builder.ToString();
}
private void NotifyResourceChanged(string email)
private void NotifyResourceChanged(string email, Bitmap image)
{
foreach (var avatar in _avatars)
{
avatar.OnAvatarResourceChanged(email);
}
avatar.OnAvatarResourceChanged(email, image);
}
}
}

Some files were not shown because too many files have changed in this diff Show more