Skip to content

Commit 1a2e780

Browse files
committed
feat: pull and rebase record stack modifications
When `stg pull` and `stg rebase` perform their underlying `git pull` or `git rebase`, the HEAD reference is typically moved. Previously, StGit relied on a subsequent operation, typically `stg push`, to trigger the "external modification" check at transaction execute time which would record a new stack state that reflects the updated branch head. For pull and rebase, these aren't really "external" modifications since StGit is managing them. StGit now records a new stack state immediately, and with a more appropriate message when pull or rebase cause the branch head to move. This makes the `stg log` clearer. It also allows a pull or rebase to be undone with `stg undo` without having to first perform an intervening stack-modifying command.
1 parent 863f628 commit 1a2e780

File tree

5 files changed

+41
-12
lines changed

5 files changed

+41
-12
lines changed

src/cmd/pull.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -218,11 +218,17 @@ fn run(matches: &ArgMatches) -> Result<()> {
218218
stupid.user_rebase(&rebase_cmd, rebase_target)?;
219219
}
220220

221-
if !matches.get_flag("nopush") {
222-
// The above pull and rebase action may have moved the stack's branch reference,
223-
// so we initialize the stack afresh.
224-
let stack = Stack::from_branch(&repo, None)?;
221+
// The above pull and rebase action may have moved the stack's branch reference,
222+
// so we initialize the stack afresh.
223+
let stack = Stack::from_branch(&repo, None)?;
224+
let stack = if stack.is_head_top() {
225+
stack
226+
} else {
227+
// Record a new stack state with updated head since the pull moved the head.
228+
stack.log_external_mods(Some("pull"))?
229+
};
225230

231+
if !matches.get_flag("nopush") {
226232
stack.check_head_top_mismatch()?;
227233
let check_merged = matches.get_flag("merged");
228234
stack

src/cmd/rebase.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,17 @@ fn run(matches: &ArgMatches) -> Result<()> {
157157
print_info_message(matches, &format!("Rebasing to `{}`", target_commit.id()));
158158
stupid.user_rebase(&rebase_cmd, target_commit.id())?;
159159

160+
let stack = Stack::from_branch(&repo, None)?;
161+
let stack = if stack.is_head_top() {
162+
stack
163+
} else {
164+
// Record a new stack state with updated head since the head moved.
165+
stack.log_external_mods(Some("rebase"))?
166+
};
167+
160168
if matches.get_flag("interactive") {
161-
interactive_pushback(&repo, &config, matches, &applied)?;
169+
interactive_pushback(stack, &repo, &config, matches, &applied)?;
162170
} else if !matches.get_flag("nopush") {
163-
let stack = Stack::from_branch(&repo, None)?;
164171
stack.check_head_top_mismatch()?;
165172
let check_merged = matches.get_flag("merged");
166173
stack
@@ -219,12 +226,13 @@ enum Action {
219226
}
220227

221228
fn interactive_pushback(
229+
stack: Stack,
222230
repo: &git2::Repository,
223231
config: &git2::Config,
224232
matches: &ArgMatches,
225233
previously_applied: &[PatchName],
226234
) -> Result<()> {
227-
let mut stack = Stack::from_branch(repo, None)?;
235+
let mut stack = stack;
228236

229237
if stack.all_patches().next().is_none() {
230238
return Ok(());

src/stack/stack.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,17 +183,19 @@ impl<'repo> Stack<'repo> {
183183
}
184184

185185
/// Re-commit stack state with updated branch head.
186-
pub fn log_external_mods(self) -> Result<Self> {
186+
pub fn log_external_mods(self, message: Option<&str>) -> Result<Self> {
187187
let state_ref = self.repo.find_reference(&self.refname)?;
188188
let prev_state_commit = state_ref.peel_to_commit()?;
189189
let prev_state_commit_id = prev_state_commit.id();
190190
let state = self
191191
.state
192192
.advance_head(self.branch_head.clone(), prev_state_commit);
193193

194-
let message = "external modifications\n\
195-
\n\
196-
Modifications by tools other than StGit (e.g. git).\n";
194+
let message = message.unwrap_or(
195+
"external modifications\n\
196+
\n\
197+
Modifications by tools other than StGit (e.g. git).\n",
198+
);
197199
let reflog_msg = "external modifications";
198200

199201
let state_commit_id = state.commit(self.repo, None, message)?;

src/stack/transaction/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ impl<'repo> ExecuteContext<'repo> {
153153
let mut stack = if stack.is_head_top() {
154154
stack
155155
} else {
156-
stack.log_external_mods()?
156+
stack.log_external_mods(None)?
157157
};
158158

159159
// Roll back by checking out the stack top tree prior to any changes from this

t/t2103-pull-trailing.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,19 @@ test_expect_success 'Port those patches to orig tree' '
3939
)
4040
'
4141

42+
test_expect_success 'Undo pull operation' '
43+
(
44+
cd bar &&
45+
stg id {base} >before-pull &&
46+
stg pull --nopush &&
47+
stg log -n1 | grep -e "pull$" &&
48+
test_cmp_rev ! $(cat before-pull) $(stg id) &&
49+
stg undo &&
50+
stg id >after-undo &&
51+
test_cmp before-pull after-undo
52+
)
53+
'
54+
4255
test_expect_success 'Pull those patches applied upstream, without pushing' '
4356
(
4457
cd bar &&

0 commit comments

Comments
 (0)