git - How do I reword a commit (message) that is the parent of two branches? -


suppose have repo this

$ git log --oneline --graph  *   3e0a28f merge branch 'other_branch' |\   | * d4fd67a add else | *   d0f16bf merge branch 'master' other_branch | |\   | |/   |/|    * | 3684fe5 make change in master | * 45b3ecb make change |/   * b2a9034 added text, reword me * 7b1ac57 initial commit 

d0f16bf involves fixing merge conflicts. (3684fe5 , 45b3ecb modify same line). want reword b2a9034

$ git rebase -i b2a9034^ [detached head a9bd978] added text, reworded  1 file changed, 2 insertions(+) error: not apply 3684fe5... make change in master  when have resolved problem, run "git rebase --continue". if prefer skip patch, run "git rebase --skip" instead. check out original branch , stop rebasing, run "git rebase --abort". not apply 3684fe570517de37e1ce7661e3821372e1eee967... make change in master 

is there way reword b2a9034 without fixing merge conflicts again?

when "reword" assume mean "change commit message, not committed files" (the git rebase -i meaning).

git's "swiss-army chainsaw" command, git filter-branch, has option this. (of course, filter-branch difficult use, hence "swiss-army chainsaw" appellation.)

specifically, filter-branch has --msg-filter, allows copying commits while making changes message:

this filter rewriting commit messages. argument evaluated in shell original commit message on standard input; standard output used new commit message.

what means can keep existing message commits not rewrite target, , edit or replace 1 target, using suitable --msg-filter, such as:

git filter-branch ... \     --msg-filter 'if [ $git_commit == b2a9034... ]; \         cat $home/new_msg; else cat; fi' \     ... 

this filter copies message as-is (cat) unless it's 1 targeted commit, in case ignores stdin message , prints instead contents of prepared-in-advance $home/new_msg file. can of course write valid shell script instead, sure preserve exact original message of other commits.

you need fill in full commit id here (or use prefix matching it's wiser fill in full id). full id partial one, easiest method use git rev-parse:

$ git rev-parse b2a9034 b2a9034...                  <-- full 40 char sha-1 comes out $  

you need fill in rest of ... parts git filter-branch, nontrivial.

since filter-branch slow, want limit smallish number of commits. can git rev-list arguments: filter-branch pass them on git rev-list , copy commits listed. thus, can test out first:

$ git rev-list ^b2a9034^ branch1 branch2 

here 2 branches names of branches branch-tips want rewritten (probably 1 of them master, based on text above). first argument, ^b2a9034^, should cause git rev-list omit parent commit of b2a9034 , earlier commits. (the first ^ character "not" operator git rev-list , second parent-following operator of gitrevisions. can bit confusing alternative spelling ^b2a9034~1, has same meaning, doesn't use ^ in 2 different ways. i'm not sure how less confusing in end, though.)

(if repository has few commits, rev-limiting not important.)

finally, note that, filter-branch documentation says:

the command rewrite positive refs mentioned in command line (e.g. if pass a..b, b rewritten). ...

what phrase means not obvious me until understood git's internals, , there, how filter-branch does. internally, git ever adds things, git filter-branch copies existing commits new ones. if new commit same original commit, copy bit-for-bit identical original, original sha-1 copy, meaning nothing added , nothing changes. if change anything, though, new, different sha-1 id.

this means filter branch runs along copying commits, "copies" commits prior 1 being modified , gets original sha-1 again. hits first (and maybe only) 1 want changed, , gets new sha-1. original commit remains in repository there's new copy new sha-1.

once that's happened, subsequent commits filter-branch copies have @ least 1 change made, if none of filters change them. in particular, have (at least 1 of) parent id(s), new id. first new child commit has new parent id gets new id too; child commit has pick new id; , on.

the end result new copies of commits give new chain of commit-ids ending new commit id (in case two) branch(es) you're filtering. git must save ids new branch-tips. when documentation says "only b rewritten", means filter-branch update refs/heads/b—the file holds id of tip of branch b—to have final sha-1 of copied branch-tip.

thus, listing, say, ^b2a9034^ master develop, you've provided 2 "positive refs", namely refs/heads/master , refs/heads/develop, , 2 filter-branch update. ^b2a9034^ "negative ref" ("exclude b2a9034^ , earlier) , hence filter-branch nothing after passing git rev-list.


Comments

Popular posts from this blog

javascript - Karma not able to start PhantomJS on Windows - Error: spawn UNKNOWN -

c# - Display ASPX Popup control in RowDeleteing Event (ASPX Gridview) -

Nuget pack csproj using nuspec -