Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
709eed1
feat: add command to open all the changed files in git
devvaannsh Jul 12, 2026
e9664b6
feat: add branch name in the git panel toolbar
devvaannsh Jul 12, 2026
a681837
feat: add git branch toggle button in the git toolbar
devvaannsh Jul 12, 2026
78bbc43
fix: git branch button size inconsistent
devvaannsh Jul 12, 2026
7dd9ec0
feat: make git branch toggle button in git panel responsive
devvaannsh Jul 12, 2026
cfc6c78
fix: use translatable strings for git branch status labels
devvaannsh Jul 14, 2026
e249ab1
fix: align branch dropdown with git panel branch button
devvaannsh Jul 14, 2026
b9b9f54
refactor: truncate branch name once for sidebar and panel
devvaannsh Jul 14, 2026
87a9022
fix: escape branch name in sidebar branch indicator
devvaannsh Jul 14, 2026
295ce1c
feat: confirm before opening a large number of changed files
devvaannsh Jul 14, 2026
5beadb9
fix: skip open changed files confirmation when files are already open
devvaannsh Jul 14, 2026
0e6e8d7
fix: don't switch the viewed file when opening all changed files
devvaannsh Jul 14, 2026
cd488f4
fix: track branch name as data instead of comparing sidebar text
devvaannsh Jul 14, 2026
9a45db6
feat: move branch dropdown between sidebar and git panel anchors on c…
devvaannsh Jul 14, 2026
bc5d7b1
chore: auto update api docs
devvaannsh Jul 15, 2026
937e18f
feat: git branch dropdown better styling
devvaannsh Jul 15, 2026
a8abbdd
fix: init git only after all git modules load to not miss git events
devvaannsh Jul 15, 2026
b0a65ba
fix: close remotes dropdown when branch dropdown opens and vice versa
devvaannsh Jul 15, 2026
1f1fc09
fix: ignore stale git branch refresh after project switch
devvaannsh Jul 15, 2026
0083008
fix: remove git remote button focus ring and align caret with text
devvaannsh Jul 15, 2026
3d31250
feat: git remotes dropdown consistent with branch dropdown
devvaannsh Jul 15, 2026
6eb5b96
fix: don't fail push result parsing when pre-push hooks print to stdout
devvaannsh Jul 15, 2026
9c78251
fix: don't show git file history of closed or non repo files
devvaannsh Jul 15, 2026
ed6385a
feat: show message in git history when there is nothing to show
devvaannsh Jul 15, 2026
69905fd
feat: show not a git repository message in the git panel
devvaannsh Jul 15, 2026
4afa15b
fix: bottom panel resizer appearing over the open git remotes dropdown
devvaannsh Jul 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/API-Reference/command/Commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -980,6 +980,12 @@ Opens git settings
## CMD\_GIT\_CLOSE\_UNMODIFIED
Closes unmodified files

**Kind**: global variable
<a name="CMD_GIT_OPEN_CHANGED_FILES"></a>

## CMD\_GIT\_OPEN\_CHANGED\_FILES
Opens all modified/untracked files

**Kind**: global variable
<a name="CMD_GIT_CHECKOUT"></a>

Expand Down
3 changes: 3 additions & 0 deletions src/command/Commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,9 @@ define(function (require, exports, module) {
/** Closes unmodified files */
exports.CMD_GIT_CLOSE_UNMODIFIED = "git-close-unmodified-files";

/** Opens all modified/untracked files */
exports.CMD_GIT_OPEN_CHANGED_FILES = "git-open-changed-files";

/** Checks out a branch or commit */
exports.CMD_GIT_CHECKOUT = "git-checkout";

Expand Down
17 changes: 13 additions & 4 deletions src/extensions/default/Git/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,19 @@
}

AppInit.appReady(function () {
Main.init().then((enabled)=>{
if(!enabled) {
BracketsEvents.disableAll();
}
function initMain() {

Check warning on line 43 in src/extensions/default/Git/main.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Move function 'initMain' to the outer scope.

See more on https://sonarcloud.io/project/issues?id=phcode-dev_phoenix&issues=AZ9ltx4emiViUTSp8A1m&open=AZ9ltx4emiViUTSp8A1m&pullRequest=3022
Main.init().then((enabled)=>{
if(!enabled) {
BracketsEvents.disableAll();
}
});
}
// Main.init emits events like GIT_ENABLED that the modules above listen
// for. They load asynchronously, so init must wait for them or events
// fired before they finish loading are lost (Eg. empty remotes picker).
require(modules, initMain, function (err) {
console.error("Git modules failed to load, initializing git anyway", err);
initMain();
});
});

Expand Down
145 changes: 112 additions & 33 deletions src/extensions/default/Git/src/Branch.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
currentEditor,
$dropdown;

let lastRenderedBranchName = null;
let $dropdownAnchor = null;

function renderList(branches) {
branches = branches.map(function (name) {
return {
Expand Down Expand Up @@ -303,7 +306,9 @@
function attachCloseEvents() {
$("html").on("click", closeDropdown);
$("#project-files-container").on("scroll", closeDropdown);
$("#git-panel .table-container").on("scroll", closeDropdown);
$("#titlebar .nav").on("click", closeDropdown);
$("#git-panel .git-remotes").on("click", closeDropdown);

currentEditor = EditorManager.getCurrentFullEditor();
if (currentEditor) {
Expand All @@ -316,7 +321,9 @@
function detachCloseEvents() {
$("html").off("click", closeDropdown);
$("#project-files-container").off("scroll", closeDropdown);
$("#git-panel .table-container").off("scroll", closeDropdown);
$("#titlebar .nav").off("click", closeDropdown);
$("#git-panel .git-remotes").off("click", closeDropdown);

if (currentEditor) {
currentEditor._codeMirror.off("focus", closeDropdown);
Expand All @@ -325,22 +332,85 @@
// $(window).off("keydown", keydownHook);

$dropdown = null;
$dropdownAnchor = null;
}

function _positionDropdownBelow($toggle) {
// two margins to account for the preceding project dropdown as well
const marginLeft = (parseInt($toggle.css("margin-left"), 10) * 2) || 0;

const toggleOffset = $toggle.offset();

$dropdown
.css({
left: toggleOffset.left - marginLeft + 3,
top: toggleOffset.top + $toggle.outerHeight() - 3
})
.appendTo($("body"));

// fix so it doesn't overflow the screen
const maxHeight = $dropdown.parent().height(),
height = $dropdown.height(),
topOffset = $dropdown.position().top;
if (height + topOffset >= maxHeight - 10) {
$dropdown.css("bottom", "10px");
}
}

function _positionDropdownAbove($anchor) {
const anchorOffset = $anchor.offset();

$dropdown
.css({
left: anchorOffset.left,
// #git-branch-dropdown carries a negative margin-left meant for the
// sidebar toggle alignment, neutralize it so left matches the anchor
"margin-left": 0,
// the .dropdown-menu class positions with "top: 100%", it has to be
// explicitly overridden or the bottom positioning below is over-constrained
top: "auto",
bottom: $(window).height() - anchorOffset.top + 3,
// grow upwards from the anchor instead of the default top-left origin
"transform-origin": "0 100%"
})
.appendTo($("body"));

// fix so it doesn't overflow the screen
if ($dropdown.height() >= anchorOffset.top - 10) {
$dropdown.css("top", "10px");
}

const rightOverflow = $dropdown.offset().left + $dropdown.outerWidth() - ($(window).width() - 10);
if (rightOverflow > 0) {
$dropdown.css("left", anchorOffset.left - rightOverflow);
}
}

function toggleDropdown(e) {
e.stopPropagation();
$("#git-panel .btn-group.open").removeClass("open");
// currentTarget is only valid while the event is being dispatched,
// so it has to be captured before the async branch listing below
const $anchor = $(e.currentTarget);

// If the dropdown is already visible, close it
// clicking the anchor that opened the dropdown closes it, clicking the
// other anchor moves the dropdown there
if ($dropdown) {
const sameAnchor = $dropdownAnchor && $dropdownAnchor[0] === $anchor[0];
closeDropdown();
return;
if (sameAnchor) {
return;
}
}

Menus.closeAll();

Git.getBranches().catch(function (err) {
ErrorHandler.showError(err, Strings.ERROR_GETTING_BRANCH_LIST);
}).then(function (branches = []) {
if ($dropdown) {
return;
}
branches = branches.reduce(function (arr, branch) {
if (!branch.currentBranch && !branch.remote) {
arr.push(branch.name);
Expand All @@ -349,25 +419,12 @@
}, []);

$dropdown = $(renderList(branches));
const $toggle = $("#git-branch-dropdown-toggle");
// two margins to account for the preceding project dropdown as well
const marginLeft = (parseInt($toggle.css("margin-left"), 10) * 2) || 0;

const toggleOffset = $toggle.offset();

$dropdown
.css({
left: toggleOffset.left - marginLeft + 3,
top: toggleOffset.top + $toggle.outerHeight() - 3
})
.appendTo($("body"));

// fix so it doesn't overflow the screen
var maxHeight = $dropdown.parent().height(),
height = $dropdown.height(),
topOffset = $dropdown.position().top;
if (height + topOffset >= maxHeight - 10) {
$dropdown.css("bottom", "10px");
$dropdownAnchor = $anchor;
if ($anchor.closest("#git-panel").length) {
// the git panel sits at the bottom of the screen, open upwards from there
_positionDropdownAbove($anchor);
} else {
_positionDropdownBelow($("#git-branch-dropdown-toggle"));
}

PopUpManager.addPopUp($dropdown, detachCloseEvents, true, {closeCurrentPopups: true});
Expand Down Expand Up @@ -409,10 +466,9 @@
return;
}

var branchInHead = m[1],
branchInUi = $gitBranchName.text();
const branchInHead = m[1];

if (branchInHead !== branchInUi) {
if (branchInHead !== lastRenderedBranchName) {
refresh();
}
});
Expand All @@ -421,25 +477,34 @@
function refresh() {
if ($gitBranchName.length === 0) { return; }

const projectRoot = Utils.getProjectRoot();
function isStale() {
return Utils.getProjectRoot() !== projectRoot;
}

// show info that branch is refreshing currently
$gitBranchName
.text("\u2026")
.parent()
.show();
Panel.setBranchName("\u2026", "");

return Git.getGitRoot().then(function (gitRoot) {
var projectRoot = Utils.getProjectRoot(),
isRepositoryRootOrChild = gitRoot && projectRoot.indexOf(gitRoot) === 0;
if (isStale()) { return; }
var isRepositoryRootOrChild = gitRoot && projectRoot.indexOf(gitRoot) === 0;

Check failure on line 494 in src/extensions/default/Git/src/Branch.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Unexpected var, use let or const instead.

See more on https://sonarcloud.io/project/issues?id=phcode-dev_phoenix&issues=AZ9ltxz5miViUTSp8A1k&open=AZ9ltxz5miViUTSp8A1k&pullRequest=3022

$gitBranchName.parent().toggle(isRepositoryRootOrChild);

if (!isRepositoryRootOrChild) {
Preferences.set("currentGitRoot", projectRoot);
Preferences.set("currentGitSubfolder", "");

lastRenderedBranchName = null;
$gitBranchName
.off("click")
.text("not a git repo");
.text(Strings.GIT_NOT_A_REPO);
Panel.setBranchName(Strings.GIT_NOT_A_REPO, "");
$("#git-panel .git-panel-branch").removeClass("clickable").off("click");
Panel.disable("not-repo");

return;
Expand All @@ -454,6 +519,7 @@
return Git.getCurrentBranchName().then(function (branchName) {

Git.getMergeInfo().then(function (mergeInfo) {
if (isStale()) { return; }

if (mergeInfo.mergeMode) {
branchName += "|MERGING";
Expand All @@ -471,28 +537,41 @@

EventEmitter.emit(Events.REBASE_MERGE_MODE, mergeInfo.rebaseMode, mergeInfo.mergeMode);

var MAX_LEN = 18;
const MAX_LEN = 18;

lastRenderedBranchName = branchName;
const tooltip = StringUtils.format(Strings.ON_BRANCH, branchName);
const html = `<i class="fas fa-code-branch"></i> ${
branchName.length > MAX_LEN ? branchName.substring(0, MAX_LEN) + "\u2026" : branchName
}`;
const displayName = branchName.length > MAX_LEN
? branchName.substring(0, MAX_LEN) + "\u2026"
: branchName;
// branch names may contain characters like "<", so set them
// as text and never as html
$gitBranchName
.html(html)
.text(" " + displayName)
.prepend('<i class="fas fa-code-branch"></i>')
.attr("title", tooltip)
.off("click")
.on("click", toggleDropdown);
Panel.setBranchName(displayName, tooltip);
$("#git-panel .git-panel-branch")
.addClass("clickable")
.off("click")
.on("click", toggleDropdown);
Panel.enable();

}).catch(function (err) {
ErrorHandler.showError(err, Strings.ERROR_READING_GIT_STATE);
});

}).catch(function (ex) {
if (isStale()) { return; }
if (ErrorHandler.contains(ex, "unknown revision")) {
lastRenderedBranchName = null;
$gitBranchName
.off("click")
.text("no branch");
.text(Strings.GIT_NO_BRANCH);
Panel.setBranchName(Strings.GIT_NO_BRANCH, "");
$("#git-panel .git-panel-branch").removeClass("clickable").off("click");
Panel.enable();
} else {
throw ex;
Expand Down
1 change: 1 addition & 0 deletions src/extensions/default/Git/src/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ define(function (require, exports) {
exports.CMD_GIT_CLONE_WITH_URL = Commands.CMD_GIT_CLONE_WITH_URL;
exports.CMD_GIT_SETTINGS_COMMAND_ID = Commands.CMD_GIT_SETTINGS_COMMAND_ID;
exports.CMD_GIT_CLOSE_UNMODIFIED = Commands.CMD_GIT_CLOSE_UNMODIFIED;
exports.CMD_GIT_OPEN_CHANGED_FILES = Commands.CMD_GIT_OPEN_CHANGED_FILES;
exports.CMD_GIT_CHECKOUT = Commands.CMD_GIT_CHECKOUT;
exports.CMD_GIT_RESET_HARD = Commands.CMD_GIT_RESET_HARD;
exports.CMD_GIT_RESET_SOFT = Commands.CMD_GIT_RESET_SOFT;
Expand Down
Loading
Loading