I would like to avoid calling porcelain commands from my scripts, but is there a way to get some of the behavior of git checkout <commit>
using only plumbing commands like checkout-index
? I'm particularly interested in the effect on the working copy: assuming everything is clean, checkout
deletes files that were tracked in the old HEAD and absent in the new one. checkout-index
doesn't seem to have any concept of deleting files. The closest thing I can think of would be to call
git diff-tree -p <old> <new> | git apply
but computing the whole diff seems unnecessarily expensive. Is there a better way?
Git divides commands into porcelain and plumbing. Porcelain is the ceramic material usually used to make sinks or toilets, while plumbing is the actual pipes carrying the water. The porcelain fixtures provide a human-friendly interface to the plumbing.
Force a Checkout You can pass the -f or --force option with the git checkout command to force Git to switch branches, even if you have un-staged changes (in other words, the index of the working tree differs from HEAD ). Basically, it can be used to throw away local changes.
You're looking for the two-tree git read-tree -um
. It uses a base tree, (generally you feed it HEAD
), a target tree, and (implicitly) the index and worktree. The table describing its behavior was hard for me to understand so I have my own cheatsheet for it, a reformatted one that makes more sense to me, anyway. At any rate, it implements git checkout
.
git read-tree -um H M # `I` is the (implicit) index, GIT_INDEX_FILE
Legend
H Original tree (usually HEAD:)
I Indexed tree
M Merge target tree
H->I \
H->M } status in second relative to first
I->M /
"-" file exists in neither
new exists only in second
deleted exists only in first
same exists in both, unchanged
changed exists in both, different
(blank) irrelevant or all cases not otherwise given
keep keep current version
fail whole command fails, no changes
delete delete worktree file
H->I H->M I->M
same keep
deleted changed fail
deleted deleted delete
deleted same delete unless Index empty, else use M
same keep
same changed worktree clean: use M; dirty: fail
same deleted worktree clean: deleted; dirty: fail
new - keep
new new changed fail
changed changed changed fail
changed deleted fail
note: "index empty" identifies an initial checkout, where HEAD has been
set but never loaded. git can't currently distinguish between a
delete-everything index and an initial-checkout index.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With