How to turn a set of fixed commits (stored in reflog) into real commits

I was engaged in refactoring and just constantly correcting it every time I made some worthy progress. It went very well, and I realized that it would be nice to show people how I dealt with such a huge refactoring (a lot of tiny steps, just pushing the code around, with a green set of tests at every point).

All commits are in my reflog . Is there a way to turn each of these fixed commits into its own real commit (sorry, I don’t know the terminology) so that users can see each step, and not just aggregated on lines 81 and 57? I don’t need unique messages for commits or anything else, they are just recorded in the history.

This is still in my local repo.

+4
source share
3 answers

Reconstructing a reflog may not be as complicated as it was at the beginning. You can regenerate reflog in separate branches, or you can use git read-tree to create a single newbranch containing the reflog part.

One solution for each branch:

Suppose you need different branches for each commit. Copy your repository first. You are about to modify your reflog in this process so that you can also use the catchy version. Secondly, review your reflog and find the commit you want to start with. It will look like HEAD@ {n} . Suppose it was HEAD@ {49} . Then try the script, replacing head -50 with head -<n + 1> , whatever you do in your case:

 #!/bin/sh reflog=$(git reflog | head -50 | awk '{ print $1 }') i=0 for ref in $reflog; do git checkout -B "reflog_$i" $ref i=$(expr $i + 1) done 

This captures the reflog commit history once, and then repeats it, generating reflog_$i branches along the path. You can select, merge or manipulate them as you want. If it's just for presentation, you can write a short script that does a git checkout on branches, runs a test suite and shows all the greenery. Remember, reflog_1 is the most recent story; reflog_<n+1> is the oldest.

 #!/bin/sh for i in $(seq 50 1); do git checkout "reflog_$i" ./test-suite.sh done 

Throw it on the projector when you explain your fixing method, and this will be a pleasant backdrop.

If you want to merge all the branches, you can run this ruby ​​script to apply them in order (or create an equivalent in any language convenient for you). Let me reiterate that you must have a backup of your directory because it is quite destructive.

 #!/usr/bin/env ruby n = 50 n.downto 0 do |i| system " git read-tree reflog_#{i} git commit -m 'Refactoring #{n - i}' git checkout -- . git br -D refog_#{i} " end 

Putting all commits on one branch using git read-tree

Copy the repository first. Then use the script as shown below. For the discussion in the first solution, change the two <n + 1> to whatever depth you want in your reflog, plus one. Pay attention to the additional channel on sed . You must use it or something like that so that reflog is applied to newbranch in reverse chronological order. Of course, this can be done without using both awk and sed , but this works:

 #!/bin/sh reflog=$(git reflog | head -<n + 1> | awk '{ print $1 }' | sed -n '1!G;h;$p') git checkout -B newbranch HEAD@ {<n + 1>} for ref in $reflog; do git read-tree "$ref" git commit --no-verify -m "Adding commit $ref" git checkout -- . done 

The end result will be newbranch , which should contain all the commits between HEAD@ {0} and HEAD@ {n} , based on commit HEAD@ {n+1} .

+2
source

It is possible, but probably difficult.

Each time you did --amend , you essentially “discarded” the previous commit and replaced it with a new modified commit that contains the previous changes plus everything that was changed.

So:

 A<--B (master) 

now commit --amend:

  ---B / A<--C (master) 

now commit -amend again:

  --B / A<--D (master) \ --C 

Records B and C still exist. However, they do not indicate anything, and eventually garbage will be collected.

So, to get the desired graph:

 git checkout master git reset --hard A git cherry-pick B git cherry-pick C git cherry-pick D 

Leaves:

 A<--B'<--C'<--D' (master) 

(Note the prime (apostrophe) character indicating that they are new commits with new hashes)

Now, the only thing I don't know about is whether you will have conflicts or not. I believe that you, since each of the last commits contains some of the same changes as the previous ones, given that they have been changed. If so, you will have to solve them.

Keep in mind that when using git, if you try this and it doesn’t work, returning to where you are right now is simple:

 git reset --hard D 
+1
source

You can make a new branch from the first reflog entry, and then for each reflog, git entry check the tree on the workspace and then commit it.

This way you should not have any conflicts because you are essentially only rewriting the workspace tree with the new reflog tree.

0
source

All Articles