Git push error '[remote rejected] master -> master (branch is currently checked out)'

前端 未结 30 2723
半阙折子戏
半阙折子戏 2020-11-22 00:07

Yesterday, I posted a question on how to clone a Git repository from one of my machines to another, How can I \'git clone\' from another machine?.

I am now

30条回答
  •  眼角桃花
    2020-11-22 00:23

    Summary

    You cannot push to the one checked out branch of a repository because it would mess with the user of that repository in a way that will most probably end with loss of data and history. But you can push to any other branch of the same repository.

    As bare repositories never have any branch checked out, you can always push to any branch of a bare repository.

    There are multiple solutions, depending on your needs.

    Solution 1: Use a Bare Repostiory

    As suggested, if on one machine, you don't need the working directory, you can move to a bare repository. To avoid messing with the repository, you can just clone it:

    machine1$ cd ..
    machine1$ mv repo repo.old
    machine1$ git clone --bare repo.old repo
    

    Now you can push all you want to the same address as before.

    Solution 2: Push to a Non-Checked-Out Branch

    But if you need to check out the code on your remote , then you can use a special branch to push. Let's say that in your local repository you have called your remote origin and you're on branch master. Then you could do

    machine2$ git push origin master:master+machine2
    

    Then you need to merge it when you're in the origin remote repo:

    machine1$ git merge master+machine2
    

    Autopsy of the Problem

    When a branch is checked out, committing will add a new commit with the current branch's head as its parent and move the branch's head to be that new commit.

    So

    A ← B
        ↑
    [HEAD,branch1]
    

    becomes

    A ← B ← C
            ↑
        [HEAD,branch1]
    

    But if someone could push to that branch inbetween, the user would get itself in what git calls detached head mode:

    A ← B ← X
        ↑   ↑
    [HEAD] [branch1]
    

    Now the user is not in branch1 anymore, without having explicitly asked to check out another branch. Worse, the user is now outside any branch, and any new commit will just be dangling:

          [HEAD]
            ↓
            C
          ↙
    A ← B ← X
            ↑
           [branch1]
    

    Hypothetically, if at this point, the user checks out another branch, then this dangling commit becomes fair game for Git's garbage collector.

提交回复
热议问题