Split a git branch or commit by file type -


i have branch containing html , javascript code. cross cutting reasons, need submit mass change html first @ later date js. @ moment have single branch both kinds of changes it.

how can sort commit 2 smaller commits (or branches) file type?

you can't change existing commit, can make new commits parent same commit existing "committed much" commit.

before start, make sure have clean work tree ("nothing commit"). way no git reset or whatever can lose anything. if necessary can make new commit might need zorg~2 instead of zorg~1 (see diagrams below). able retrieve saved items commit later.

draw have right now

as usual git, start drawing (at least part(s) of) commit graph. on branch now, means have branch name pointing tip-most commit, , commit pointing parent commit, , on:

...--a--b--c--d   <-- zorg 

where zorg current branch , presumably d too-big-commit , c commit before has neither set of changes. (if had make more commits, perhaps commit d 1 or more steps back; if so, adjust numbers below.)

hint: use git log --graph --oneline --decorate (with or without --all well) git draw graph (though draws vertically, more-recent stuff @ top, instead of horizontally newer stuff towards right).

draw like have instead

you cannot change d can make new commits e , f, can arrange way:

...--a--b--c--d     <-- ... we'll fill in later ...             \              e--f   <-- ... likewise ... 

or way:

             f      <-- ...             / ...--a--b--c--d     <-- ...             \              e      <-- ... 

commit d continue "too big" commit while e might have html changes , f might have js changes. (if f built on e, have both changes , matches commit d in terms of contents. if f built on c, has only js changes. it's decide how arrange these.)

each ... filled in branch name. can leave existing branch name alone , invent 1 or 2 new branch names, , that's i'll show first.

doing manually

let's want 2 new branch names, , e , f each have c parent (so, not c--e--f). git being git, there many ways this, 1 easy 1 create them git checkout -b, creates new branch names , switches on them (so git status says you're on new branch). git checkout -b command takes optional commit specifier, commit have in index , work-tree once new branch created. want both e , f spring forth c, want create new branch "at" commit c:

git checkout -b zorg-html zorg~1 

the name zorg identifies commit d. adding ~ suffix means "from commit, step across first-parent links many times in number". since number 1 (one), we'll step 1 parent, takes d c. means name zorg-html point commit c, , we'll on new branch.

now we're on zorg-html (at commit c) want replace html files. right version of files in commit d, pointed-to name zorg. easy-but-hard way files is:

git checkout zorg -- first_file second_file third_file ... 

which—this bit crazy of git checkout—this time doesn't change branches @ all, instead extracts specific named files (the list of file names after -- part) specified commit (zorg, i.e., commit d).

if files named ending in .html , no .html file not html file, easy version of easy way is:

git checkout zorg -- '*.html' '**/*.html' 

that is, every file named whatever.html top level directory, , every file named whatever.html in number of sub-directories, out of zorg commit (commit d, again).

this kind of git checkout writes updated files both index , work-tree, @ point can git commit result.

now, create commit f, repeat whole process:

git checkout -b zorg-js zorg~1  # new zorg-js branch starting @ c git checkout zorg -- '*.js' '**/*.js' git commit 

(assuming, before html files, every js file named .js , no file named .js other js file). , have:

             f      <-- zorg-js             / ...--a--b--c--d     <-- zorg             \              e      <-- zorg-html 

obviously can choose better names of these branches.

if wish make commit f come after commit e, omit git checkout -b create new branch , switch commit c. leave on branch zorg-html @ commit e when extract .js files , make commit f, f's parent e, , have:

...--a--b--c--d     <-- zorg             \              e--f   <-- zorg-html # zorg-html bad name 

you can stop here if wanted simple recipes. if want learn lots of ways deal , other issues, read on.

what if want e--f on zorg itself?

no problem. git being git, there multiple ways this. instance, can rename zorg before start:

git branch -m zorg gary-oldman 

now have this:

a--b--c--d   <-- gary-oldman 

and can safely create new zorg.

of course, upstream setting sticks renamed branch. no big deal, can use git branch --set-upstream-to set new upstreams each branch.

of course, git being git, there's yet way it! can create new branch name now, pointing commit d, remember long need it—you'll need 2 git checkout commands. can git reset branch name zorg points commit c:

git checkout zorg  # make sure zorg current branch git branch temp    # save tip commit under new name git reset --hard zorg~1  # , move zorg commit c 

now make new commits, move name zorg forward name temp still remember commit d you:

a--b--c--d   <-- temp        \         e    <-- zorg 

now access commit d use name temp, , re-find commit c use temp~1.

note if have commits "past" d (such 1 made save work done after html , js changes):

a--b--c--d--h--i--j   <-- temp, or zorg, or whatever 

you can still of this. it's now, name commit c, need either sha-1 hash "true name" (which never changes, hard type in correctly—mouse cut-and-paste helpful here), or count tip. here temp might name commit j, , temp~1 commit i, , temp~2 h; temp~3 d , temp~4 c. once you're done splitting commits, can cherry-pick remaining commits.

using git rebase -i

git being git, there yet way this, useful if there commits after d, commit split. particular 1 requires comfort git, in end shortest , fastest method. start git rebase -i rebase commit d (and later commits) onto c, (or are) already; change pick line d read edit.

git drops rebase session commit d made. want git reset head~1 (or git reset --mixed head~1; --mixed default) commit c. sets current commit—we're in detached head mode, adjusts head itself—to c , resets index match c, leaves work-tree set d. selectively git add files want: .html ones. use method (find ... | xargs git add or git add '*.html' '**/*.html' instance) add these, , git commit result. git add remaining files , git commit again, , git rebase --continue copy remaining commits , move branch label tip-most resulting commit.


Comments

Popular posts from this blog

jOOQ update returning clause with Oracle -

java - Warning equals/hashCode on @Data annotation lombok with inheritance -

java - BasicPathUsageException: Cannot join to attribute of basic type -