Git: send commit to another branch so I can work a

2019-02-26 14:57发布

I have 2 branches, the main one and the one I'm working on a parallel release.

A --> B --> C (master)
  \
   -> E --> F (parallel)

The parallel branch will always merge from master. Always. And modify upon it.

A --> B --> C --> D --> H  (master)
  \           \ *merge*
   -> E --> F --> G --> J  (parallel)

This is easy to do if I switch branches.

But, if I'm working on parallel, can I do this without switching branches? The problem with switching is that it takes a long time to go back and forth (specially on Unity 3D)!

So say I'm on F, while master is still on A. Then I wanted to make few commits on master B and C then merge them into G. How would I do it, again, without switching branches?

3条回答
我只想做你的唯一
2楼-- · 2019-02-26 15:39

There is (nowadays) a much easier solution utilising git worktree: You will get additional worktrees (i.e. checkouts), but sharing the same repository data.

The manpage states:

A git repository can support multiple working trees, allowing you to check out more than one branch at a time.

That means you do not need to switch branches but just change directories when "switching" your activities from master to parallel or vice-versa. Since there is no additional (cloned) repository, there is no overhead in managing it like push, merge or fetch operations as well as no configuration hassle.

Add an additional worktree for branch parallel:

git worktree add path/to/new-worktree parallel
查看更多
女痞
3楼-- · 2019-02-26 15:40

To work simultaneously on two branches, push between paralleled clones.

# one-time setup: 
new=parallel-master
git clone . ../$new -b master
git remote add $new ../$new

Switch to master:

cd ../parallel-master
# work work commit commit lalala

Switch back:

git push origin master
cd ../main

and that's all it takes, git merge works normally. If you're ever going to merge from parallel to master, just push the other way before switching, it works the same both ways.

查看更多
The star\"
4楼-- · 2019-02-26 15:55

What you want could possibly be achieved using low-level (plumbing) Git commands and a separate work tree and the index.

As explained in the git(1) manual page, through the usage of environment variables it's possible to make a separate work tree for a given Git repository, basically:

$ mkdir foo && cd $_
$ export GIT_DIR=/path/to/the/repo/.git
$ export GIT_INDEX_FILE="$(pwd)/.index"
$ git read-tree master
$ git checkout-index -a -u

Now update the files in the work tree and stage the changes (git add etc) and then

$ editor /tmp/COMMIT_MSG
$ git update-ref refs/heads/master $(git commit-tree $(git write-tree) -p $(git rev-parse master) </tmp/COMMIT_MSG)

This:

  1. Creates a tree from the index (git write-tree) and writes its SHA-1 name to stdout.
  2. Obtains the SHA-1 name of the commit pointed to by the branch "master".
  3. Creates a commit object using the SHA-1 name of the commit obtained on the previous step as the parent commit. The name of the commit object is printed to stdout.
  4. Updates the branch "master" to point to that new commit object.

This operates on a pretty low level using only the plumbing commands but not touch HEAD in the repository and hence allows to work normally in the original work tree.

This is scriptable but is too cumbersome so I'd just try to use the git-new-workdir script available in the contrib section of the Git proper — it sets up a separate work tree linked to the original repository excluding the crucial stuff like HEAD which might disrupt the work in the original work tree. So you could create the new work tree, check out "master" into it, record new commits on it then safely merge them in the original work tree which has "parallel" checked in.

查看更多
登录 后发表回答