可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.
回答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 the pages
copy
- push to GitHub
- reset the master branch at its previous state.
回答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.
回答3:
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.
回答4:
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.
回答5:
While there is currently no single command to do this, there are at least two other options.
You could use the github api to create the commit.
This post details creating a commit in a github repo.
Create github pages as a submodule.
Use a series of plumbing commands to create the commit.
The git book has a description of plumbing commands used to create a commit
note: the command is now mktree not mk-tree
回答6:
I cannot agree it is not possible. By mixing git stash push
, git stash pop
, git checkout
, git checkout
, git add
and git commit
this is possible.
How I understand problem:
You are on branch master and you made some modifications to file patched.txt
and you would like to commit this file to other branch.
What you would like to do is:
- save all changes in this repo by doing git stash
- checkout
file.txt
from stashed stack
- add file
patched
(and only this file) to new branch
- get back to state of repo before modyfing
file.txt
This can be achieved by executing following commands:
destBranch=patch
thisBranch=master
FileToPutToOtherBranch="file1.txt file2.txt 'file with space in name.txt'"
message="patched files $FileToPutToOtherBranch"
#assumption: we are on master to which modifications to file.txt should not belong
git stash &&\ #at this point we have clean repository to $thisBranch
git checkout -b $destBranch &&\
git checkout stash@{0} -- $FileToPutToOtherBranch && #if there are many files, repeat this step #create branch if does not exist (param -b)
git add $FileToPutToOtherBranch &&\ # at this point this is equal to git add . --update
git commit -m "$message" &&\
git checkout $thisBranch &&\
git stash apply &&\ # or pop if want to loose backup
git checkout $thisBranch -- $FileToPutToOtherBranch # get unpatched files from previous branch
The reason why I am using "&&" and the end is if somebody will copy&paste this snippet into terminal, even if one error occurs, next commands will be executed, which is not good. \ is for informing shell that command is continued in next line.
To proove this works I provide testing environment for this snippet
mkdir -p /tmp/gitcommitToAnyBranch && cd /tmp/gitcommitToAnyBranch &&\
git init
echo 'this is master file' > file1.txt
echo 'this is file we do not want to have modified in patch branch because it does not patches any feature' > docs.txt
git add file1.txt && git commit -m "initial commit"
echo 'now this file gets patched' > file1.txt
git status
Now, if you run my script with parameters
destBranch=patch
thisBranch=`git rev-parse --abbrev-ref HEAD`
FileToPutToOtherBranch="file1.txt"
message="patched file $FileToPutToOtherBranch"
You will have file1.txt
modified only in patch branch, for more see gitk --all
回答7:
If you accidently modified things in the wrong branch, here's some simple steps :
- Commit these changes ;
- Merge them into the right branch ;
- Checkout the branch your were on at first and reset it to the commit before ;
- Cleanup your modifications with "git checkout -- .".
Everything should be fine after this. You can also merge, reset and cleanup your modifications selectively.
回答8:
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.
回答9:
This is how I do it:
if I've acidentally committed, roll back one commit:
git reset --soft 'HEAD^'
add the files you want to add
git add .
create a new temporary branch:
git checkout -b oops-temp
commit your changes:
git commit -m "message about this commit"
checkout the branch you meant to check out:
git checkout realbranch
merge the old branch:
git merge oops-temp
delete the old branch:
git branch -D oops-temp