How to partially cherry-pick a commit in git

There are times when you need to cherry-pick a commit from another branch. Then there are times when you only need parts of that commit.

Following is how you can partly cherry-pick a commit to get only the changes that you need.

Get the patch for the entire commit. Include the -n for no commit so that it does not add it as a commit to your branch

git cherry-pick -n <commit>

Then unstage the the changes from the cherry-picked commit so that you can choose which lines/hunks that you want to include

git reset

From here you can either git add -p to specify specific files or use git gui or some other tool to selectively stage and commit lines or hunks of the current set of changes.

Then just use git commit to commit your changes and reset the rest that you do not want and you are done.

How to set up a locally hosted git server and create new repositories

You may have code and configurations that are required to stay on premise. As a result, you will need to setup your own git server and create and manage repositories locally. Following is an overview of how to set that up.

We will leave aside server setup, configuration, and networking and assume that we have a machine on which we will host the repos, git-server, and machines that will clone, pull, and push updates, clients.

Setting up the git-server

On the git-server add git-shell to the list of valid shells.

echo $(which git-shell) >> /etc/shells

Add a git user with a specific shell and setup the directory in which all of the repos will be stored.

useradd --shell $(which git-shell) --home-dir /home/git git
mkdir -p /home/git/.ssh
chown -R git: /home/git/.ssh
touch /home/git/.ssh/authorized_keys
chown -R git: /home/git/.ssh
chmod 600 /home/git/.ssh/authorized_keys
chmod 700 /home/git/.ssh
mkdir -p /var/lib/git_repo
chown git: /var/lib/git_repo
chmod 700 /var/lib/git_repo

Adding a new user

To add a new user that can commit to and pull repos via ssh concatenate their public ssh key to /home/git/.ssh/authorized_keys.

Creating a new repository

As root on the git-server

export GIT_REPO=<new-repo-name>.git
sudo -u git mkdir /var/lib/git_repo/$GIT_REPO
cd /var/lib/git_repo/$GIT_REPO && sudo -u git git init --bare

As an authorized git user on the client machine

mkdir example && cd example
git init
echo "# README" >> README.md
git add README.md
git commit -m 'Initial commit'
git remote add origin git@hpdl01:/var/lib/git_repo/<new-repo-name>.git
git push origin master

Now you can clone with

git clone git@hpdl01:/var/lib/git_repo/example.git

git Cheat Sheet

A handful of handy git commands that I don’t use all that often but want to keep track of:

Stashing

Stash a single file

git stash push -m 'message here' -- path/to/file

Drop a specific stash

First figure out the id of the stash you want to drop with git stash list, then issue the following command

git stash drop stash@{n}

Add all untracked files across the entire repository

git add -A

Editing Commits

Changing author of already pushed commit

If you need to change the author of a commit that has already pushed, interactive rebase is your friend

First, determine a commit on top of which you want to rebase the commit, or a series of commits. I usually just use the commit that the series of commits is based off of (the root of the branch).

In that case you can just rebase it against that branch (but the hash of a commit before the commit you want to edit works just as well)

git rebase -i main

Your editor will open and you will be able to mark the commit that you want to edit. Change the pick token for that commit to edit and save:quit from your editor. Git will then start rebasing each commit onto the branch/commit you specified and will stop when it reaches the commit you flagged for editing.

At this point, issue the following command (updating the specific email address and author name)

git commit --amend --author="Ryan Chapin <rchapin@nbinteractive.com>" --no-edit

And then issue the commit to continue rebasing the remainder of the commits.

Undo last commit and keep changes

Sometimes you mistakenly commit things that you are not ready to commit. Run the following

git reset --soft HEAD~1

This command will

  1. git reset: move the current branch’s pointer (HEAD) to a specific commit
  2. --soft: ensure that the changes from the undone commit are preserved in your staging area and working directory as uncommitted local modifications.
  3. HEAD~1: is the reference to the commit just before the current one – the parent of HEAD

gitk

gitk is a GUI git client that has a lot of nice features and is easy to use

See orphaned branches and commits

Run gitk with the following command. Running git log with the same arguments will enable you to see the same commits, but it is much easier to browse and see with gitk.

gitk --all --reflog &

Diffing

Viewing more or less context with git diff

The default number of lines displayed above and below a change is three. To increase or decrease the number of lines displayed in the diff use the -U flag as follows, which will display 10 lines before and after the changes.

git diff -U10

Finding changes to a specific file

git log --follow --patch -- <file-path>

Reverting

When reverting your un-staged changes to your current branch you are checking out the revision from the base branch.

Reverting Changes in an entire subdirectory

git checkout <base-branch> -- path/to/directory

Changing URLs

Changing the remote URL

git remote set-url origin ssh://git@<host>:<path>/REPOSITORY.git

Git Merge Conflict Resolution Cheat Sheet

Some of git’s nomenclature can be confusing, especially since it is context dependent. Following are some TLDR;s for dealing with resolving merge conflicts in different scenarios.

–ours vs –theirs

The meaning of --ours vs --theirs can depend on whether you are doing a rebase or a merge.

Assuming that the feature branch is checked out

git merge developgit rebase develop
To keep changes from develop--theirs--ours
To keep changes from feature--ours--theirs

If, during a rebase there is a conflict and you know you want to take ALL of the changes from the branch you are rebasing onto, or ALL of the changes from the feature branch you can do the following (note that --ours vs --theirs follows the same semantics as described in the table above):

# Take all changes from the branch on which you are rebasing
git checkout --ours <path-to-file>

# Or, if you want to take all of the changes from the feature branch
git checkout --theirs <path-to-file>

# Then you can
git add <path-to-file>
git rebase --continue

Current Change vs. Incoming Change When Rebasing

Sometimes you may also see “Incoming” vs. “Current” changes when rebasing a feature branch. Assuming that the feature branch is checked out

git rebase develop
To keep changes from developAccept Current Change
To keep changes from featureAccept Incoming Change

If,

[SOLVED] Deleting remote git branch; By default, deleting the current branch is denied, because the next remote: ‘git clone’ won’t result in any file checked out, causing confusion

This is a common error encountered where you are renaming your default branch for the repository. If you have a repo hosted on GitHub or some other third-party service, there is likely some way in the GUI to change the default branch for a repo.

If you are hosting your own internal git repository you will need to SSH to that server and “checkout” a different branch from the one that you are trying to delete. In reality, the remote repository has a branch “checked out”. To change it, ssh to the remote host and cd into the <project>.git dir and run the following command to see the current branch

git symbolic-ref HEAD

This will show you the current branch that is “checked out”. To change it run

git symbolic-ref <new-branch>

Once you have done that, you can delete the old default branch.