my git tricks
Tags: git, devops
Published: 2023-01-12 21:25:27

# intro

one of the things I've learned since stepping back from coding, is that git never gives up on you. it's always necessary having a solid foundation of git when working in IT, whatever your role is. I decided to start this page (maybe pages in the future) mainly for my personal use. if this comes useful to other even better.

# what's on the menu today

we can say it's something that is normally not recommended, but that may be useful in some specific cases.
let's say you are progressing on your tasks, and you have a list of commits ready to be submitted to git server. at this point you realize there is something wrong in one of them. yes, of course you can add the fix on top, staging it and create a new commit but in some cases you need to keep the history as clean as possible, and modifying the wrong commit is the only solution you have.

## how to modify the content of one commit

the easiest case would be editing the last commit of the history. this is a simple job and it can be done thanks to the soft reset. 

`git reset --soft HEAD~` 

the command will send the last commit back to staging, and you are now able to apply the changes required.

what if the commit is not the last one, but one in the middle?

we can consider the following history, with three very simple commits. 

```
$ git log --oneline 
8e7390d (HEAD -> main) third commit
26f3ff5 second commit
85c87d4 first commit
7acf898 (origin/main, origin/HEAD) Initial commit
```

if you need to edit the second one, on the condition of not adding a new commit on top of the history, the rebase with the interactive subcommand argument is for you!

## git rebase interactively

`git rebase -i` 

in the first place, the command shows the commits history

```
pick 85c87d4 first commit
pick 26f3ff5 second commit
pick 8e7390d third commit
```   

and once you found the commit you want to modify, the only thing to do is to change the prefix `pick` into `edit`. you will end up with this

```
$ git status 
interactive rebase in progress; onto 7acf898
Last commands done (2 commands done):
   pick 85c87d4 first commit
   edit 26f3ff5 second commit
Next command to do (1 remaining command):
   pick 8e7390d third commit
  (use "git rebase --edit-todo" to view and edit)
You are currently editing a commit while rebasing branch 'main' on '7acf898'.
  (use "git commit --amend" to amend the current commit)
  (use "git rebase --continue" once you are satisfied with your changes)

nothing to commit, working tree clean
```

now you are able to update your code, and apply the changes to the *second commit* just staging the file 

`git add <file>`

and finalizing the rebase:

`git rebase --continue`.

one point of focus here: in case the changes affect code touched by other commits you risk to have one or more conflicts to resolve. no panic, once fixed, mark them as resolved with `git add/rm <conflicted_files>`, then you can execute `git rebase --continue` safely.

at the end of the rebase, the *second commit* contains the changes and the git history is intact.

alternatively, there is another workflow to get the same result. you can implement the changes directly on top of the branches and staging them. thanks to the fixup and the rebase (how you can't love the rebase) it's possible to place the changes in one specific commit. let's see how

```
git add <files_changed>
git commit --fixup=<commit_hash>
git rebase -i origin/<branch> --autosquash
```
   
since the fixup creates a new commit, we need to take the patch of the changes introduced into the fixup commit and re-apply them on top of the original commit ( the *second commit* ). this is why we use again the rebase with --autosquash ( from git-rebase page: the commit marked for squashing comes right after the commit to be modified, and change the action of the moved commit from pick to ~~squash or~~ fixup ).    

this was the trick of the day. and you, have you already used one of these two workflows? which one do you prefer? any other suggestion?