可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have the branch master
which tracks the remote branch origin/master
.
I want to rename them to master-old
both locally and on the remote. Is that possible? For other users who tracked origin/master
(and who always updated their local master
branch via git pull
), what would happen after I renamed the remote branch? Would their git pull
still work or would it throw an error that it couldn't find origin/master
anymore?
Then, further on, I want to create a new master
branch (both locally and remote). Again, after I did this, what would happen now if the other users do git pull
?
I guess all this would result in a lot of trouble. Is there a clean way to get what I want? Or should I just leave master
as it is and create a new branch master-new
and just work there further on?
回答1:
The closest thing to renaming is deleting and then re-creating on the remote. For example:
git branch -m master master-old
git push remote :master # delete master
git push remote master-old # create master-old on remote
git checkout -b master some-ref # create a new local master
git push remote master # create master on remote
However this has a lot of caveats. First, no existing checkouts will know about the rename - git does not attempt to track branch renames. If the new master
doesn't exist yet, git pull will error out. If the new master
has been created. the pull will attempt to merge master
and master-old
. So it's generally a bad idea unless you have the cooperation of everyone who has checked out the repository previously.
Note: Newer versions of git will not allow you to delete the master branch remotely by default. You can override this by setting the receive.denyDeleteCurrent
configuration value to warn
or ignore
on the remote repository. Otherwise, if you're ready to create a new master right away, skip the git push remote :master
step, and pass --force
to the git push remote master
step. Note that if you're not able to change the remote's configuration, you won't be able to completely delete the master branch!
This caveat only applies to the current branch (usually the master
branch); any other branch can be deleted and recreated as above.
回答2:
Assuming you are currently on master
:
git push origin master:master-old # 1
git branch master-old origin/master-old # 2
git reset --hard $new_master_commit # 3
git push -f origin # 4
- First make a
master-old
branch in the origin
repository, based off of the master
commit in the local repository.
- Create a new local branch for this new
origin/master-old
branch (which will automatically be set up properly as a tracking branch).
- Now point your local
master
to whichever commit you want it to point to.
- Finally, force-change
master
in the origin
repository to reflect your new local master
.
(If you do it in any other way, you need at least one more step to ensure that master-old
is properly set up to track origin/master-old
. None of the other solutions posted at the time of this writing include that.)
回答3:
With Git v1.7, I think this has changed slightly. Updating your local branch's tracking reference to the new remote is now very easy.
git branch -m old_branch new_branch # Rename branch locally
git push origin :old_branch # Delete the old branch
git push --set-upstream origin new_branch # Push the new branch, set local branch to track the new remote
回答4:
git checkout -b new-branch-name
git push remote-name new-branch-name :old-branch-name
You may have to manually switch to new-branch-name
before deleting old-branch-name
回答5:
There are many ways to rename the branch, but I am going to focus on the bigger problem: "how to allow clients to fast-forward and not have to mess with their branches locally".
First a quick picture:
This is something actually easy to do; but don't abuse it.
The whole idea hinges on merge commits; as they allow fast-forward, and link histories of a branch with another.
renaming the branch:
# rename the branch "master" to "master-old"
# this works even if you are on branch "master"
git branch -m master master-old
creating the new "master" branch:
# create master from new starting point
git branch master <new-master-start-point>
creating a merge commit to have a parent-child history:
# now we've got to fix the new branch...
git checkout master
# ... by doing a merge commit that obsoletes
# "master-old" hence the "ours" strategy.
git merge -s ours master-old
and voila.
git push origin master
This works because creating a merge
commit allows fast-forwarding the branch to a new revision.
using a sensible merge commit message:
renamed branch "master" to "master-old" and use commit ba2f9cc as new "master"
-- this is done by doing a merge commit with "ours" strategy which obsoletes
the branch.
these are the steps I did:
git branch -m master master-old
git branch master ba2f9cc
git checkout master
git merge -s ours master-old
回答6:
I'm assuming you're still asking about the same situation as in your previous question. That is, master-new will not contain master-old in its history.* If you call master-new "master", you will effectively have rewritten history. It does not matter how you get into a state in which master is not a descendant of a previous position of master, simply that it is in that state.
Other users attempting to pull while master does not exist will simply have their pulls fail (no such ref on remote), and once it exists again in a new place, their pulls will have to attempt to merge their master with the new remote master, just as if you merged master-old and master-new in your repository. Given what you're trying to do here, the merge would have conflicts. (If they were resolved, and the result was pushed back into the repository, you'd be in an even worse state - both versions of history there.)
To answer your question simply: you should accept that sometimes there will be mistakes in your history. This is okay. It happens to everyone. There are reverted commits in the git.git repository. The important thing is that once we publish history, it is something everyone can trust.
*If it did, this would be equivalent to pushing some changes onto master, and then creating a new branch where it used to be. No problem.
回答7:
The selected answer failed when I tried it. It throws an error: refusing to delete the current branch: refs/heads/master
. I guess I'll post what works for me:
git checkout master # if not in master already
git branch placeholder # create placeholder branch
git checkout placeholder # checkout to placeholder
git push remote placeholder # push placeholder to remote repository
git branch -d master # remove master in local repository
git push remote :master # remove master from remote repository.
The trick is to checkout to the placeholder right before pushing it to remote repository. The rest is self explanatory, deleting the master branch and push it to the remote repository should works now. Excerpted from here.
回答8:
Good. My 2 cents. How about loggin in at the server, going to the git directory and renaming the branch in the bare repository. This does not have all the problems associated with reuploading the same branch. Actually, the 'clients' will automatically recognize the modified name and change their remote reference. Afterwards (or before) you can also modify the local name of the branch.
回答9:
What about:
git checkout old-branch-name
git push remote-name new-branch-name
git push remote-name :old-branch-name
git branch -m new-branch-name
回答10:
This is the simplest and most 'readable' way I know of:
'Move' local branch using -m
git branch -m my_old_branch_name my_new_branch_name
Push the 'moved' branch to the remote, set 'upstream' using -u
git push origin -u my_new_branch_name
(setting 'upstream' essentially 'connects' your local branch to the remote, so that things like fetch, pull and push will work)
Delete the old branch from the remote
git push origin -D <old_name>
(your local branch is already gone, because you 'moved' it in the 1st step)
回答11:
OK, renaming a branch both locally and on the remote is pretty easy!...
If you on the branch, you can easily do:
git branch -m <branch>
or if not, you need to do:
git branch -m <your_old_branch> <your_new_branch>
Then, push deletion to the remote like this:
git push origin <your_old_branch>
Now you done, if you get upstream error while you trying to push, simply do:
git push --set-upstream origin <your_new_branch>
I also create the image below to show the steps in real command line, just follow the steps and you would be good:
回答12:
You may do the following:
git -m master master-old #rename current master
git checkout -b master #create a new branch master
git push -f origin master #force push to master
But force pushing is a bad idea if other people are sharing this repository. Force push will cause their revision history to conflict with the new one.
回答13:
The following can be saved to the shell script to do the job:
For example:
remote="origin"
if [ "$#" -eq 0 ] # if there are no arguments, just quit
then
echo "Usage: $0 oldName newName or $0 newName" >&2
exit 1
elif
[ "$#" -eq 1 ] # if only one argument is given, rename current branch
then
oldBranchName="$(git branch | grep \* | cut -d ' ' -f2)" #save current branch name
newBranchName=$1
else
oldBranchName=$1
newBranchName=$2
fi
git branch -m $oldBranchName $newBranchName
git push $remote :$oldBranchName #delete old branch on remote
git push --set-upstream $remote $newBranchName # add new branch name on remote and track it
Please note that here default remote name "origin" is hard-coded, you can extend the script to make if configurable!
Then this script can be used with bash aliases, git aliases or in, for example, sourcetree custom actions.
回答14:
I believe the key is the realization that you are performing a double rename: master
to master-old
and also master-new
to master
.
From all the other answers I have synthesized this:
doublerename master-new master master-old
where we first have to define the doublerename
Bash function:
# doublerename NEW CURRENT OLD
# - arguments are branch names
# - see COMMIT_MESSAGE below
# - the result is pushed to origin, with upstream tracking info updated
doublerename() {
local NEW=$1
local CUR=$2
local OLD=$3
local COMMIT_MESSAGE="Double rename: $NEW -> $CUR -> $OLD.
This commit replaces the contents of '$CUR' with the contents of '$NEW'.
The old contents of '$CUR' now lives in '$OLD'.
The name '$NEW' will be deleted.
This way the public history of '$CUR' is not rewritten and clients do not have
to perform a Rebase Recovery.
"
git branch --move $CUR $OLD
git branch --move $NEW $CUR
git checkout $CUR
git merge -s ours $OLD -m $COMMIT_MESSAGE
git push --set-upstream --atomic origin $OLD $CUR :$NEW
}
This is similar to a history-changing git rebase
in that the branch contents is quite different, but it differs in that the clients can still safely fast-forward with git pull master
.
回答15:
git update-ref newref oldref
git update-ref -d oldref newref