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
d0fe68d
feat: add command to open all the changed files in git
devvaannsh Jul 12, 2026
b7b268b
feat: add branch name in the git panel toolbar
devvaannsh Jul 12, 2026
e2dc132
feat: add git branch toggle button in the git toolbar
devvaannsh Jul 12, 2026
f93e24b
fix: git branch button size inconsistent
devvaannsh Jul 12, 2026
783ed2d
feat: make git branch toggle button in git panel responsive
devvaannsh Jul 12, 2026
2d8d2b6
fix: use translatable strings for git branch status labels
devvaannsh Jul 14, 2026
1b8abaa
fix: align branch dropdown with git panel branch button
devvaannsh Jul 14, 2026
a8bd174
refactor: truncate branch name once for sidebar and panel
devvaannsh Jul 14, 2026
a8de32b
fix: escape branch name in sidebar branch indicator
devvaannsh Jul 14, 2026
337b7a0
feat: confirm before opening a large number of changed files
devvaannsh Jul 14, 2026
a1efb7b
fix: skip open changed files confirmation when files are already open
devvaannsh Jul 14, 2026
3e8ce8b
fix: don't switch the viewed file when opening all changed files
devvaannsh Jul 14, 2026
2d655b7
fix: track branch name as data instead of comparing sidebar text
devvaannsh Jul 14, 2026
55f4e1f
feat: move branch dropdown between sidebar and git panel anchors on c…
devvaannsh Jul 14, 2026
015d0ff
chore: auto update api docs
devvaannsh Jul 15, 2026
6606f5e
feat: git branch dropdown better styling
devvaannsh Jul 15, 2026
e230b08
fix: init git only after all git modules load to not miss git events
devvaannsh Jul 15, 2026
c249c14
fix: close remotes dropdown when branch dropdown opens and vice versa
devvaannsh Jul 15, 2026
a64fd50
fix: ignore stale git branch refresh after project switch
devvaannsh Jul 15, 2026
18d7b73
fix: remove git remote button focus ring and align caret with text
devvaannsh Jul 15, 2026
9623839
feat: git remotes dropdown consistent with branch dropdown
devvaannsh Jul 15, 2026
965695b
fix: don't fail push result parsing when pre-push hooks print to stdout
devvaannsh Jul 15, 2026
c1ee2bb
fix: don't show git file history of closed or non repo files
devvaannsh Jul 15, 2026
1fef7c7
feat: show message in git history when there is nothing to show
devvaannsh Jul 15, 2026
2fab690
feat: show not a git repository message in the git panel
devvaannsh Jul 15, 2026
d9d808e
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