git: Fill the commit message buffer from MERGE_MSG (#24843)

This PR uses the template merge message in `.git/MERGE_MSG` to populate
the commit message buffer in the git panel. This is done:

- when the commit message buffer is first created
- when the list of merge heads in .git changes, only if the buffer
doesn't already have some text in it

Hopefully this strikes a good balance between convenience and not
stomping on the user's toes.

Release Notes:

- N/A
This commit is contained in:
Cole Miller 2025-02-15 13:29:45 -05:00 committed by GitHub
parent 394bb8f4e6
commit 4ff1173047
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 48 additions and 12 deletions

View file

@ -40,6 +40,7 @@ pub struct Repository {
pub worktree_id: WorktreeId,
pub repository_entry: RepositoryEntry,
pub git_repo: GitRepo,
pub merge_message: Option<String>,
update_sender: mpsc::UnboundedSender<(Message, oneshot::Sender<Result<()>>)>,
}
@ -138,22 +139,29 @@ impl GitStore {
worktree.update(cx, |worktree, cx| {
let snapshot = worktree.snapshot();
for repo in snapshot.repositories().iter() {
let git_repo = worktree
let git_data = worktree
.as_local()
.and_then(|local_worktree| local_worktree.get_local_repo(repo))
.map(|local_repo| local_repo.repo().clone())
.map(GitRepo::Local)
.map(|local_repo| {
(
GitRepo::Local(local_repo.repo().clone()),
local_repo.merge_message.clone(),
)
})
.or_else(|| {
let client = client.clone()?;
let project_id = project_id?;
Some(GitRepo::Remote {
project_id,
client,
worktree_id: worktree.id(),
work_directory_id: repo.work_directory_id(),
})
Some((
GitRepo::Remote {
project_id,
client,
worktree_id: worktree.id(),
work_directory_id: repo.work_directory_id(),
},
None,
))
});
let Some(git_repo) = git_repo else {
let Some((git_repo, merge_message)) = git_data else {
continue;
};
let worktree_id = worktree.id();
@ -169,10 +177,24 @@ impl GitStore {
if self.active_index == Some(index) {
new_active_index = Some(new_repositories.len());
}
// Update the statuses but keep everything else.
// Update the statuses and merge message but keep everything else.
let existing_handle = handle.clone();
existing_handle.update(cx, |existing_handle, _| {
existing_handle.update(cx, |existing_handle, cx| {
existing_handle.repository_entry = repo.clone();
if matches!(git_repo, GitRepo::Local { .. })
&& existing_handle.merge_message != merge_message
{
if let (Some(merge_message), Some(buffer)) =
(&merge_message, &existing_handle.commit_message_buffer)
{
buffer.update(cx, |buffer, cx| {
if buffer.is_empty() {
buffer.set_text(merge_message.as_str(), cx);
}
})
}
existing_handle.merge_message = merge_message;
}
});
existing_handle
} else {
@ -182,6 +204,7 @@ impl GitStore {
repository_entry: repo.clone(),
git_repo,
update_sender: self.update_sender.clone(),
merge_message,
commit_message_buffer: None,
})
};
@ -751,6 +774,7 @@ impl Repository {
buffer_store: Entity<BufferStore>,
cx: &mut Context<Self>,
) -> Task<Result<Entity<Buffer>>> {
let merge_message = self.merge_message.clone();
cx.spawn(|repository, mut cx| async move {
let buffer = buffer_store
.update(&mut cx, |buffer_store, cx| buffer_store.create_buffer(cx))?
@ -763,6 +787,12 @@ impl Repository {
})?;
}
if let Some(merge_message) = merge_message {
buffer.update(&mut cx, |buffer, cx| {
buffer.set_text(merge_message.as_str(), cx)
})?;
}
repository.update(&mut cx, |repository, _| {
repository.commit_message_buffer = Some(buffer.clone());
})?;

View file

@ -576,6 +576,7 @@ pub struct LocalRepositoryEntry {
/// Absolute path to the .git file, if we're in a git worktree.
pub(crate) dot_git_worktree_abs_path: Option<Arc<Path>>,
pub current_merge_head_shas: Vec<String>,
pub merge_message: Option<String>,
}
impl sum_tree::Item for LocalRepositoryEntry {
@ -3524,6 +3525,7 @@ impl BackgroundScannerState {
dot_git_dir_abs_path: actual_dot_git_dir_abs_path.into(),
dot_git_worktree_abs_path,
current_merge_head_shas: Default::default(),
merge_message: None,
};
self.snapshot
@ -5491,6 +5493,10 @@ impl BackgroundScanner {
&local_repository.work_directory_id,
|entry| {
entry.current_merge_head_shas = merge_head_shas;
entry.merge_message = std::fs::read_to_string(
local_repository.dot_git_dir_abs_path.join("MERGE_MSG"),
)
.ok();
entry.status_scan_id += 1;
},
);