2

I have a local branch in which I did some development, the commit history is pretty bad so I am going back and rebasing to tidy up and leave it in a sensible state before pushing.

Say I have commits A, B, C, D, E. In commit B I have added some useful code that I want to keep but I also added some debug code. I then later removed the debug code in D. What is the best approach to use to remove this entirely from the history (the code isn't of any use so I don't want it in the history if possible)?

I have tried rebasing at A, rewriting the commit at B without the code but then C and D need manual intervention at each rebase step. Is it best to split B,D into B-keep and B-remove and D-keep and D-remove then remove the two commits? Is there other ways to clean up when code has been added then removed?

I want to end up with history that looks like A, B(useful), C, D(useful), E which I then may squash to A, B, E for example, at this stage I just want to remove the debug code from the history.

LogicTom
  • 93
  • 1
  • 9

3 Answers3

0

Applying to your Q update:

You can use this tool to loop over the commits and remove the unwanted commits. https://rtyley.github.io/bfg-repo-cleaner/

Read the example section on how to use it.

It's much faster than git filter-branch but has the same effect.


Some other options:

Read here in details about each options: How to move HEAD back to a previous location? (Detached head)

git rebase -i

Edit each commit you want to clean and remove your code from it. It's useful if you don't have too many commits, if you do - use the filter-branch or 'bfg-repo-cleaner'

git checkout

git checkout <commit_id>

git reflog

You can always use the reflog as well

git reflog
git checkout HEAD@{...}

This will get you back to your desired commit


git reset HEAD --hard <commit_id>

"Move" your head back to the desired commit.

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.
  • Note: (Since Git 2.7)
    you can also use the git rebase --no-autostash as well.

git checkout

git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

This will checkout new branch pointing to the desired commit

Community
  • 1
  • 1
CodeWizard
  • 128,036
  • 21
  • 144
  • 167
  • I've added a little to the end of the question but I don't see how the above gets me where I want to be. – LogicTom Jan 10 '16 at 07:30
0

The usual fix is using git filter-branch, combine with sed, to delete line matching a pattern:

# find out the desired file and execute sed on it to find out
# where is the debug code inside the file
git filter-branch --tree-filter "find . -type f -exec sed -i -e 's/pattern with debug/d' {} \;" -- A~..

You can refine the find criteria, to find only files with a certain extension (--name '*.java')

That will remove the debug code from history, without needing manual intervention for intermediate commits.
Of course, that will rewrite the SHA1 for all concerned commits, forcing you to do a git push --force, so if you are not alone working one that repo, do communicate the impending reset of your branch to the other collaborators.

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 1
    This assumes that the "debug code" can be easily detected through a pattern. If the debug code is complex/over multiple lines, that won't be as easy. – VonC Jan 10 '16 at 07:35
  • In this case (complex code or few patterns) its better to use squash. – CodeWizard Jan 10 '16 at 07:39
0

If commit D it is just removing debug code from commit B then you can reorder commits and squash using rebase -i, for example, when you starting rebasing you will see here:

pick c9a8ee8 B
pick f533903 C
pick c66cc92 D
pick 647ab90 E

Now you need to move commit D after commit B, you just need to edit text content:

pick c9a8ee8 B
pick c66cc92 D
pick f533903 C
pick 647ab90 E

And finally you need to change pick to squash for commit D, here is how it will looks:

pick c9a8ee8 B
squash c66cc92 D
pick f533903 C
pick 647ab90 E

After finishing rebasing, commit D will be part of commit B.

Ivan M.
  • 164
  • 1
  • 1
  • 4