Commit a file to a Different Branch Without Checkout
Solution 1
It's not possible.
The changes you commit are related to the current working copy. If you want to commit to another branch it means that you could commit changes from your working copy, but base them from another copy state.
This is not a natural way of versioning your work, and this is why you need to make different steps (stash changes, checkout the branch, pop stash and commit) to accomplish it.
As for your specific use case, a simple way is to keep two copies of your work, one checked out at master
branch, and the other at pages
branch.
In the pages
working copy, add the master
copy as a remote repo.
- You commit pages on
master
- Pull from
master
on thepages
copy - push to GitHub
- reset the master branch at its previous state.
Solution 2
It can be done by reimplementing git commit.
This can be done with various call to git hash-object
But this is hard to achieve.
Please read progit chapter 9 for more details and a full example of how to simulate a commit.
Solution 3
As several others have said, it is literally possible, but impractical.
However, as of Git 2.5 (with some important fixes in 2.6 and minor ones since then), there is a practical method for doing this using git worktree add
.
Let's say, for instance, that you want to work on branches main
and doc
"at the same time", or branches develop
and test
"at the same time", but the two branches in question deliberately contain different things. (For instance, the doc
branch has documentation that exists outside or alongside the code, or the test
branch has tests that will be run against the code, but not distributed, or which are expected to have failures for which tests are deliberately skipped on the develop
side, or whatever.)
Instead of just:
git clone -b develop <source> theclone
followed by working in theclone
with constant switching back and forth between the two branches, you would:
git clone -b develop <source> theclone
but then:
cd theclone
git worktree add ../ct test # check out branch test in ../ct
or just:
git worktree add ../test # check out branch test in ../test
Now you can run your tests in ../test
while developing in theclone
. You can merge and/or rebase changes from one branch to the other in the usual way: the underlying repository is already shared, so no git push
or git fetch
is required. You simply have both branches checked out, into two separate work-trees, named theclone
and test
from the top level.
Solution 4
So long as you don't have anything in your current index that differs from your HEAD
that you want to keep you can so something like this. (If you do want to keep your index you could temporarily export the GIT_INDEX_FILE
environment variable to point at a temporary file for the duration of these commands.)
# Reset index and HEAD to otherbranch
git reset otherbranch
# make commit for otherbranch
git add file-to-commit
git commit "edited file"
# force recreate otherbranch to here
git branch -f otherbranch
# Go back to where we were before
# (two commits ago, the reset and the commit)
git reset HEAD@{2}
We've never actually checked out otherbranch
and our working tree files haven't been touched.
Solution 5
I made a little tool that does exactly this: https://github.com/qwertzguy/git-quick
It let's you edit specific files from another branch without checking out the other branch completely (just the files you want to edit) and commit them. All this without ever affecting your working copy or staging area.
Behind the scenes it uses a combination of git worktree and sparse checkout. The source is fairly small, so you can read through.
Comments
-
Schneems almost 2 years
Is it possible to commit a file in a git branch with out checking out that branch? If so how?
Essentially I want to be able to save a file in my github pages branch without switching branches all the time. Any thoughts?
Update: It's not possible to do what I want (see comments below for use case). What I ended up doing is programmatically cloning my current directory to a tmp directory, then checking out my branch in that tmp directory (doesn't affect my working directory) and committing my files to the tmp directory clone. When I'm done, I push back to my working directory and delete the tmp directory. Sucks, but it's the only way to commit files to another branch without changing the current working branch of the working directory. If anyone has a better solution, please feel free to add it below. If it's better than 'it cannot be done', I'll accept yours.
-
Schneems over 12 yearsIt's possible to read files from a different branch without checking it out, so I was hoping there would be a way to write to a different branch without checkout. While i understand this isn't 'natural' i'm using GIT as a data store and not as pure version control in this situation. I have a workaround (see my comment above) but it is rather gross and prone to errors.
-
CharlesB over 12 yearsJust curious: why maintain a separate pages branch?
-
Schneems over 12 yearspages.github.com it's a way to serve html content such as docs or a demo page directly using github. It has to be in a separate branch because thats the way github wrote it. While the data (docs in this case) is related to the project it shouldn't necessarilly be in the main branch for a number of reasons, overwhelming the commit messages of master with changes unrelated to code being one of them.
-
jbenet over 11 yearsSee answer by Charles Bailey below!
-
user541686 about 6 yearsHow is this answer correct? The changes you commit have nothing to do with your working copy. They're based entirely on what is added to the index. You can delete everything in your work tree and still
git commit
as if nothing had happened, because git only looks at the index. -
StingyJack almost 4 yearsThis is not a natural way of versioning your work - its a natural way of wanting to backup work in progress periodically without having to fuss with branch switching and cherry picking
-
TTT almost 4 yearsI wonder if this solves a related problem as to why you don't want to checkout another branch (or clone a copy of the repo): Suppose you have a very large repo and "otherbranch" is wildly different from your current branch (but still relatively close to the merge-base), and you want to add a minor hotfix to it. Checking out otherbranch, making the change, and going back to your working branch could set you back quite some time. Is it correct to assume that reset --mixed as presented in this approach would be significantly faster than checking out a very old branch?
-
TTT almost 4 yearsThis really ought to be the accepted answer. Today I had to create a branch from a tag from a year ago, and then add one commit to it. I tested it both ways. The branch differed from my current head by 72,000 files, and it took me 2.5 minutes to checkout. (Going back only took 1.5 minutes.) Then I tried your way and it only took about 15 seconds each way, most of which was the time it spent printing out the list of files. For larger repos, file sizes, and/or slower hard drives (mine's a speedy SSD), the difference would likely be more drastic. This is a great solution!
-
Moberg over 3 yearsQuestion title says
Without Checkout
. This answer usescheckout
.