Git recipes
Pavlo Myroniuk June 22, 2024 #recipes #gitRecently I lectured in my company about git
and resolving specific situations with it. It inspired me to write this article. I know that there is tons of info about git
and related stuff. I wanted to make this one as a comprehensive set of instructions about resolving concrete git situations.
Note. This page can be changed and improved in the future (I'll try to save the backward compatibility)!
How to read this page
You can read it in any order. If you are interested only in some particular scenario, then read only the corresponding section. All sections are independent from each other and you can start reading anywhere.
The required git
knowledge level to read this article is pretty low. If you know what are commit, branch, and index (stage), then everything is good.
Goals
- Explain how to resolve common
git
tasks I face at work every time. - Improve your
git
knowledge. - Dispel the fear of working with
git
in uncommon cases (if you have one).
Non-goals
- Explain how
git
works inside. There is a great section in the book about git internals: Git Internals. - Propagate to work with
git
only from the terminal. If the GUI is enough for you to perform all needed tasks, then it's great! The less we interact withgit
, the lower the probability of having problems with it π. - Write zero to pro guide. It's just impossible π.
- Replace the Oh Shit, Git!?! page. The Oh-Shit-Git purpose is to quickly resolve common problems. But my purpose is to offer guides for common tasks.
Recipes
I want to leave a few clarifications before I write recipes.
HEAD
. How does Git know what branch youβre currently on? It keeps a special pointer calledHEAD
. 3.1 Git Branching - Branches in a Nutshell. What is HEAD in Git?~<number>
and^<number>
is the same in many cases, but not always. Read this SO answer for more details: https://stackoverflow.com/a/2222920/9123725.
Last commit to index
So, you want to "undo" the last commit but save changes. The git
has a git reset
command for that:
As a result, you'll not have the last commit and all changes will be in the stage. And yes, you can enter any number of commits instead of 1
. If you want changes to be untracked, then use the save command but with the --mixed
parameter:
Discard last commit
I know that it's a bad idea, but if you really want, then this is how you can discard the last commit:
Note. If you regret your decision, then you can restore lost commit with its hash:
If you don't know its hash, then try to find it with git reflog
.
Edit last commit
Actually, you only need the git commit --amend
to do it. git commit
has a lot of flags and possible use cases, but I list here only common ones so you can copy and use them.
If you have any changes in the stage, then they will be added to commit after running git commit --amend
. For example:
Now the last commit contains changes we made in README.md
file. The --no-edit
arg means do not edit the commit message. If you want to edit the commit message, then use the -m
arg and just nothing (git
will ask you for the message). It's also possible to alter the commit author, date, and so on:
# Reset commit author saving commit date. This command is helpful when you've changed the `.gitconfig` file.
Run git commit --help
for more flags.
Edit any commit in branch
Lets say you want to edit 5th commit starting from the current one (5th parent). You can use the git rebase
with its interactive mode to do it:
The git
will open a text file with a list of 5 commits (parent commits). Now you need to write edit
instead of pick
for commit you want to edit. Safe this file and clone the editor. The rebasing will stop in the specified commit.
Now all you need is to edit selected commit and continue rebasing:
- Check this recipe to know how to edit the commit: Edit last commit.
- Continue rebasing:
Example
I want to edit the the parent commit:
So, I type git rebase -i HEAD~2
and edit the opened text file:
When I save the file and close the editor, I see (git status
) that rebasing has stopped in the needed commit (1
on the screenshot) and git even shows me helpful commands (2
on the screenshot):
I edit files as I want, commit changes, and continue rebasing:
That's all! Nothing complicated π.
Split commit into two
Oh, it is an easy one. Usually, I do it in two steps:
- "Undo" the last commit but save changes. Last commit to index.
- Create two different commits with
git add
andgit commit
.
# "Undo" last commit and save its changes. Changes will not be indexed after this command.
# First commit:
# Second commit
You can split one commit into multiple ones with this approach. If you need to split another commit in your branch (one of the parent commits), use the git rebase -i
and git reset
commands. More info: Edit any commit in branch.
Split branch into a few pull requests
π π π΅βπ«
The algorithm is simple:
- Decide how to split. How many branched you'll have and what commits you'll move to what branches.
- If you need to split some commits in order to move them to separate branches, then read the Split commit into two recipe, and go to the step 1. Otherwise, go to step 2.
- Create needed branches in the base commit of the current branch.
- Use
git checkout
andgit cherry-pick
commands to apply commits to corresponding branches.
Untrack file
If you want git
to ignore some file, then just add it to the .gitignore
file. For example:
But if this file was tracked by the git
before, then this is not enough. You also need to run:
More info you can read in this SO answer: How to stop tracking and ignore changes to a file in Git?
Just my notes
Commands below are my notes for quick access:
# last commit with date
|
# one commit changes
# move last 10 commits from HEAD to another_branch.
# note. this command will not move the another_branch itself. just adds commits on top of it
# author and commiter
# print any file in any commit. more info: https://juplo.de/cat-any-file-in-any-commit-with-git/
Conclusion
There are no any smart conclusions. But I have stupid ones π:
- Make small atomic commits. The smaller your commits are, the better. It's easier to work with such commits. Moreover, everything committed in
git
always stays inside of it and can always be restored.
There are a lot of other git
commands. I just listed the most common situations for me.
I just leave it here: HN: Nobody really understands git.
Doc, references, code
- The Pro GIT book.
- Oh Shit, Git!?!.