-2

I want to Squash all commit in the branch, while preserve their commit messages into the squashed commit. For example here, I want to squash [8015a49, 38a7b5a, 4c7e9e2, 49a7b5a] commits into one but keeping till 70d79f9 unchanged.

*   8015a49 - (HEAD -> dev, origin/dev) Merge branch 'feature/0' into dev (3 seconds ago)
|\
| * 49a7b5a - Fix me. (1 minutes ago)
| * 38a7b5a - Use 2 space in the code. (3 minutes ago)
| * 4c7e9e2 - Add minor improvements. (12 hours ago)
|/
* 70d79f9 - Replace ipfs with ipfsid. (2 days ago)
* 10d79f9 - Add README.md. (3 days ago)

After:

* 1234567 - New Squashed commit (1 second aga) // [8015a49, 38a7b5a, 4c7e9e2, 49a7b5a] 
* 70d79f9 - Replace ipfs with ipfsid. (2 days ago)
* 10d79f9 - Add README.md. (3 days ago)

When I tried following answer for How to squash my last x commits together?, git reset --soft HEAD~1 ; 70d79f9 also take place in the squash in between all the commits in the branch also considered.

My approach:

git fetch --all --quiet
git reset --soft HEAD~1 
output_1=$(git log -1 --pretty=%B)
output_2=$(git log --pretty=%B --reverse HEAD..HEAD@{1})
output="$output_1\n\n$output_2"
message=$(echo -e "$output" | awk 'NF{$1=$1};!NF||!seen[$0]++')
git commit --amend --quiet --no-verify --edit -m "$message"
alper
  • 2,919
  • 9
  • 53
  • 102
  • Please check this question/answer to see how to rebase going back to the first commit: https://stackoverflow.com/questions/22992543/how-do-i-git-rebase-the-first-commit – Tim Biegeleisen Jun 22 '22 at 10:24
  • I don't want to rebase to the first commit. I just want to rebase till the latest branch started and squash all the commits inside a branch – alper Jun 22 '22 at 10:29
  • 2
    `git reset --soft HEAD~1` should work *unless* you run it more than once. Given that you want to preserve commit `70d79f9` as is, you can also `git reset --soft 70d79f9` and then commit, and that will work even if you run `git reset` more than once here. – torek Jun 22 '22 at 12:28
  • @torek Some answer use `git commit --amend` in https://stackoverflow.com/questions/5189560/how-to-squash-my-last-x-commits-together ; after `git reset --soft HEAD~1` should I also do `--amend` during commit in order to update the squashed commit by merging messages of the squashed commits? – alper Jun 22 '22 at 19:04
  • Aha: `--amend` means, loosely, *reset back once more and commit* and that's where your extra reset came from. (Technically `--amend` means "set the parent(s) of this new commit to be the same as the parent(s) of the current commit, rather than setting it to be the current commit". This technical distinction is visible only in a few cases, such as if you amend a *merge commit*, if you abort your `git commit --amend` operation, or if you use another Terminal window to peek at the Git repository in the middle of the operation.) – torek Jun 23 '22 at 06:17
  • (Since `8015a49` is a merge commit, you would be able to see this effect if you used `git commit --amend` on it: you'd still have a merge commit but the new one would have a different hash ID. The old one would still exist, but be hard to find: `git log 8015a49` would find it, for instance, but regular `git log` wouldn't.) – torek Jun 23 '22 at 06:19
  • @torek Thanks for the clear explanation. Daily I do a lot `git squash` I am just curious what is the right way to do it. Could be a different question like after the reset is using `git commit` instead of `git commit --amend` would not affect the git commit hash? – alper Jun 23 '22 at 09:14
  • 1
    The hash ID of a commit is (1) unique and (2) computed in the same way by all Git software, so that every repository will use the *same* hash ID for a shared commit, and a *different* hash ID for any other commit. As a result, Git uses a cryptographic hash function to compute the hash ID. This function is exquisitely sensitive to every bit (as in computer bit) of data *in* the commit. If you change anything *about* the commit, what you get is a new and different commit with a different hash ID. The old commit still exists, unchanged. You literally *can't* change it. – torek Jun 23 '22 at 09:40
  • 1
    This is similar to (not exactly the same as) the ideas behind cryptocurrencies (though they use stronger hashes, plus other things). So if you find a way to preserve the hash ID even though you've replaced some part of the commit, you could perhaps get steal all the e-currency. :-) More seriously, see [How does the newly found SHA-1 collision affect Git?](https://stackoverflow.com/q/42433126/1256452) – torek Jun 23 '22 at 09:43
  • @torek I got it now, after `git reset --soft HEAD~1` any `git commit` with or without `—amend` would create a new commit with its new hash and the history will remain but just hidden in the public eye. Stealing all the e-currency would bring `great power and great responsibility` I cannot handle it :-) I think GitHub might delete the squashed commits https://stackoverflow.com/a/34594815/2402577 with the help of garbage collector but I am not 100% sure. – alper Jun 23 '22 at 11:29
  • GitHub have an administrative policy set to never delete any commits (never run `git gc`, more or less), which they need because of they way they implemented their "fork a repository" software. As such, if you ever need GitHub to remove a commit (because it has some sensitive data in it) you must contact GitHub support to get them to do it manually. – torek Jun 23 '22 at 11:36

1 Answers1

2

The problem is because of what you stated in a comment:

I was doing git reset --soft HEAD~1 and then git commit --amend --quiet --no-verify --edit ; which may end up changing modifying 70d79f9 as well

Why did you add --amend to your commit command? If you use --amend you are instructing Git to change your current commit, which in this case would be 70d79f9. You essentially squashed everything into that commit. Remove the --amend option and you'll get a new commit like you intended.

TTT
  • 22,611
  • 8
  • 63
  • 69
  • I had to do `--amend` to squash last two commits like if there is not branch between and when I have to squash last two commit `--amend` always work on my end after `git reset --soft HEAD~1 ` ; so when I am squashing branches I should not use `--amend` right? – alper Jun 22 '22 at 18:54
  • Isn't it idea of squash to let git to change the current commit? – alper Jun 22 '22 at 18:58
  • 1
    @alper Whether you should use amend is not related to whether or not you are squashing. Amend just says modify the current commit instead of creating a new one. You said you wanted to keep `70d79f9` and squash everything after that. So as was mentioned in the comments and the Q/A you linked to, you should reset to `70d79f9` and then make a *new* commit (don't amend). If you wanted to use amend, then you should reset to the commit you wish to amend (in this case it's `4c7e9e2`), and then you would commit with `--amend`. (The end result would be the same either way.) – TTT Jun 22 '22 at 20:42