@@ -58,9 +58,11 @@ fn do_rebase(
5858 . rebase ( Some ( & branch_commit) , Some ( & first_parent) , None , None )
5959 . context ( "starting rebase" ) ?;
6060
61- apply_diff_in_rebase ( repo , rebase , diff ) ?;
61+ let mut branches = RepoBranches :: for_repo ( repo ) ?;
6262
63- match do_rebase_inner ( repo, rebase, fixup_message) {
63+ apply_diff_in_rebase ( repo, rebase, diff, & mut branches) ?;
64+
65+ match do_rebase_inner ( repo, rebase, fixup_message, branches) {
6466 Ok ( _) => {
6567 rebase. finish ( None ) ?;
6668 Ok ( ( ) )
@@ -81,6 +83,7 @@ fn apply_diff_in_rebase(
8183 repo : & Repository ,
8284 rebase : & mut Rebase ,
8385 diff : & Diff ,
86+ branches : & mut RepoBranches ,
8487) -> Result < ( ) , anyhow:: Error > {
8588 match rebase. next ( ) {
8689 Some ( ref res) => {
@@ -94,11 +97,11 @@ fn apply_diff_in_rebase(
9497 // TODO: Support squash amends
9598
9699 let rewrit_id = target_commit. amend ( None , None , None , None , None , Some ( & tree) ) ?;
97- repo. reset (
98- & repo. find_object ( rewrit_id , None ) ? ,
99- git2 :: ResetType :: Soft ,
100- None ,
101- ) ?;
100+ let rewrit_object = repo. find_object ( rewrit_id , None ) ? ;
101+ let rewrit_commit_id = repo. find_commit ( rewrit_object . id ( ) ) ? . id ( ) ;
102+ branches . retarget_branches ( target_commit . id ( ) , rewrit_commit_id , rebase ) ? ;
103+
104+ repo . reset ( & rewrit_object , git2 :: ResetType :: Soft , None ) ?;
102105 }
103106 None => bail ! ( "Unable to start rebase: no first step in rebase" ) ,
104107 } ;
@@ -110,16 +113,10 @@ fn do_rebase_inner(
110113 repo : & Repository ,
111114 rebase : & mut Rebase ,
112115 fixup_message : Option < & str > ,
116+ mut branches : RepoBranches ,
113117) -> Result < ( ) , anyhow:: Error > {
114118 let sig = repo. signature ( ) ?;
115119
116- let mut branches: HashMap < Oid , Branch > = HashMap :: new ( ) ;
117- for ( branch, _type) in repo. branches ( Some ( git2:: BranchType :: Local ) ) ?. flatten ( ) {
118- let oid = branch. get ( ) . peel_to_commit ( ) ?. id ( ) ;
119- // TODO: handle multiple branches pointing to the same commit
120- branches. insert ( oid, branch) ;
121- }
122-
123120 while let Some ( ref res) = rebase. next ( ) {
124121 use git2:: RebaseOperationType :: * ;
125122
@@ -130,15 +127,7 @@ fn do_rebase_inner(
130127 let message = commit. message ( ) ;
131128 if message. is_some ( ) && message != fixup_message {
132129 let new_id = rebase. commit ( None , & sig, None ) ?;
133- if let Some ( branch) = branches. get_mut ( & commit. id ( ) ) {
134- // Don't retarget the last branch, rebase.finish does that for us
135- // TODO: handle multiple branches
136- if rebase. operation_current ( ) != Some ( rebase. len ( ) - 1 ) {
137- branch
138- . get_mut ( )
139- . set_target ( new_id, "git-instafix retarget historical branch" ) ?;
140- }
141- }
130+ branches. retarget_branches ( commit. id ( ) , new_id, rebase) ?;
142131 }
143132 }
144133 Some ( Fixup ) | Some ( Squash ) | Some ( Exec ) | Some ( Edit ) | Some ( Reword ) => {
@@ -152,6 +141,39 @@ fn do_rebase_inner(
152141 Ok ( ( ) )
153142}
154143
144+ struct RepoBranches < ' a > ( HashMap < Oid , Branch < ' a > > ) ;
145+
146+ impl < ' a > RepoBranches < ' a > {
147+ fn for_repo ( repo : & ' a Repository ) -> Result < RepoBranches < ' a > , anyhow:: Error > {
148+ let mut branches: HashMap < Oid , Branch > = HashMap :: new ( ) ;
149+ for ( branch, _type) in repo. branches ( Some ( git2:: BranchType :: Local ) ) ?. flatten ( ) {
150+ let oid = branch. get ( ) . peel_to_commit ( ) ?. id ( ) ;
151+ // TODO: handle multiple branches pointing to the same commit
152+ branches. insert ( oid, branch) ;
153+ }
154+ Ok ( RepoBranches ( branches) )
155+ }
156+
157+ /// Move branches whos commits have moved
158+ fn retarget_branches (
159+ & mut self ,
160+ original_commit : Oid ,
161+ target_commit : Oid ,
162+ rebase : & mut Rebase < ' _ > ,
163+ ) -> Result < ( ) , anyhow:: Error > {
164+ if let Some ( branch) = self . 0 . get_mut ( & original_commit) {
165+ // Don't retarget the last branch, rebase.finish does that for us
166+ // TODO: handle multiple branches
167+ if rebase. operation_current ( ) != Some ( rebase. len ( ) - 1 ) {
168+ branch
169+ . get_mut ( )
170+ . set_target ( target_commit, "git-instafix retarget historical branch" ) ?;
171+ }
172+ }
173+ Ok ( ( ) )
174+ }
175+ }
176+
155177fn commit_parent < ' a > ( commit : & ' a Commit ) -> Result < Commit < ' a > , anyhow:: Error > {
156178 match commit. parents ( ) . next ( ) {
157179 Some ( c) => Ok ( c) ,
0 commit comments