Table of Contents
- Local Branch Operation
- List up Repository Branches
- List up Branches with the last updatetime
- Switch/Create Branch Locally
- Create a New Branch Locally from a Specified Branch
- Rename a Local Branch Name
- Delete a Local Branch
- Restore a branch after its deletion in Git
- Check the Upstream Branch
- Set up an upstream branch to a local branch
- Check the Nearest Branch
- Local Branch Operation: Compare and Merge
- Remote Branch Operation
- Remote Branch Operation:
git clone
- References
Local Branch Operation
List up Repository Branches
▶ Local Branch一覧の取得
1
2
3
4
5
% git branch
develop
feature_add_cross_validation
* feature_add_visualize_module
main
▶ Remote Branch一覧の表示
origin/HEAD
はclone
した後に作業ディレクトリにチェックアウトするブランチを示したものgit clone
後のGitHub のデフォルトのブランチの最新位置に基本的に出現する
1
2
3
4
5
6
7
% git branch -r
origin/HEAD -> origin/main
origin/develop
origin/add_cross_validation
origin/add_visualize_module
origin/main
origin/project/ad_hoc_analysis
▶ Local/Remote Branch一覧の表示
1
2
3
4
5
6
7
8
9
10
11
% git branch -a
develop
feature_add_cross_validation
* feature_add_visualize_module
main
origin/HEAD -> origin/main
origin/develop
origin/add_cross_validation
origin/add_visualize_module
origin/main
origin
List up Branches with the last updatetime
- branchをcommit-baseの更新日時順(最新が上)で表示する
git branch
のoptionが利用可能とする
1
% git branch --sort=-committerdate --format='%(refname:short)%09%(committername)%09%(objectname:short)%09%(committerdate:iso-strict)' | tr '\t' '|'| column -s '|' -t
formatについてはgit-for-each-refと同様なものが使用可能です.
--sort=-committerdate |
branchをcommit更新順(最新が上)にsortする |
--sort=committerdate |
branchをcommit更新順(最新が下)にsortする |
%(objectname:short) |
commit-hashをshortで表示, defaultはlong |
なお, .gitconfig
にて引数optionが使用可能にするため, 以下のようにalias指定をしている:
1
2
[alias]
branch-update = "!f(){ git branch --sort=-committerdate --format='%(refname:short)%09%(committername)%09%(objectname:short)%09%(committerdate:iso-strict)' $1| tr '\t' '|'| column -s '|' -t;};f"
Switch/Create Branch Locally
- ブランチ移動は
git switch
コマンドを用いる git checkout
でも可能だが, 公式はgit switch
推奨- ブランチ作成 & 移動したい場合は
-c
オプションを加える
1
2
3
4
% git switch existing_branch
Switched to branch 'existing_branch'
% git switch -c non_existing_branch
Switched to a new branch 'non_existing_branch'
▶ 作成されていないブランチを指定しまった場合
1
2
% git switch test
fatal: invalid reference: test
▶ 作成済みのブランチ名を指定してgit switch -c
の場合
1
2
% git switch -c non_existing_branch
fatal: a branch named 'non_existing_branch' already exists
Create a New Branch Locally from a Specified Branch
▶ Syntax
1
% git switch -c <new branch> <rerefence branch>
<rerefence branch>
はremote branchも指定可能
▶ Example
1
2
3
4
5
% git switch -c foo2 foo
Switched to a new branch 'foo2'
% git switch -c hoge2 origin/hoge
branch 'hoge2' set up to track 'origin/hoge'.
Switched to a new branch 'hoge2'
Rename a Local Branch Name
git branch
コマンドと -m
オプションを用いてブランチ名を変更することが出来ます.
1
% git branch -m <new_branch_name>
Delete a Local Branch
- Upstream branchに編集記録が最新版までmergeされているローカルブランチを消去する場合に使用可能
1
2
3
4
% git branch --delete non-existing-branch
Deleted branch non-existing-branch (was 1d6ed41).
% git branch -d <branch>
Deleted branch <branch> (was 1d6ed42).
複数の場合は
1
% git branch --delete <branch> <branch> <branch>
upstream branchにmergeされていない場合は次のようなエラーが返ってくる
1
2
3
% git branch -d hoge
error: The branch 'hoge' is not fully merged.
If you are sure you want to delete it, run 'git branch -D hoge'.
強制的に消去したい場合は
1
2
% git branch -D hoge
Deleted branch hoge (was eb79802).
Restore a branch after its deletion in Git
▶ What I Want
- 誤って削除してしまったbranchをlocalで復旧させたい
- branchを削除してから別ブランチですでに作業を開始してしまっている状況を考える
- 復元後も, 昔の作業履歴が確認できるようにしたい
▶ How to Solve the problem
git reflog
は, すでに消去された履歴自体も確認できるコマンドgit reflog
で消去してしまったbranchからcheckoutしたcommit-hash
- 上記で取得した
commit-hash
を参照する形でgit switch -c
を実行
▶ Example
non_existing_branch
というbranchを消去してしまったあと, main
branchで作業を開始してし
まった状況を考えます.
main
branchへ移動した直後にnon_existing_branch
を消去してしまいます.
1
2
% git switch main
% git branch --delete non_existing_branch
消去したあと, main
branchで適当に作業します
1
2
3
4
5
% touch hoge.txt
% echo unkounko > hoge.txt
% git add hoge.txt
% git commit -m "DOC: Add hoge.txt about the family secret"
% git push
このタイミングで, ``non_existing_branchを消去するのはやばかったと発覚しました.
慌てずに,
git reflog`コマンドでブランチ消去直前のcommit-hashを確認します.
1
2
3
% git reflog
c65bac9 (HEAD -> main, origin/main) HEAD@{0}: commit: DOC: Add hoge.txt about the family secret
9fb60c5 HEAD@{1}: checkout: moving from non_existing_branch to main
checkoutタイミングの履歴が9fb60c5
で残っていることがわかります.
なお, このcommit-hashはgit log
では確認できません( = git reflog
とgit log
の違い)
最後にこのcommit-hashを用いて, branchを復元します.
1
% git switch -c non_existing_branch 9fb60c5
Check the Upstream Branch
▶ What I Want
- local repositoryとupstream branchの対応関係を知りたい
▶ How
1
2
3
4
5
6
7
8
% git branch -vv
branch_A 214c991 [origin/branch_A: ahead 1, behind 3] FIX readme
branch_B a387619 [origin/non_existing_branch] add yml
hoge f5663c5 [origin/hoge] hoge test
* hoge2 4a1e30f Update hoge2.txt
hoge3 376ef7c [origin/hoeg3: gone] add hoge
main 16a340c [origin/main] a
non_existing_branch a387619 [origin/non_existing_branch] add yml
- 対応していないブランチ(上では
hoge2
)では[origin/<remote branch name>]
が出力されない
Set up an upstream branch to a local branch
▶ What I Want
- upstream branchが設定されていないlocal branchに対して, upstream branchを指定したい
▶ How
1
2
% git branch -u <remote branch>
% git branch <local branch> -u <remote branch>
<local branch>
を省略した場合は, 現在のbranchに対してupstream branchを設定する
Check the Nearest Branch
▶ What I Want
- カレントブランチの派生元ブランチ名を取得する
- Merge後は, 直近のMerge元を派生元ブランチとして参照する
▶ Setup
.gitconfig
ファイルにてエイリアスを以下のように設定
1
2
[alias]
nearest = "!git show-branch -a| grep '*' | grep -v `git rev-parse --abbrev-ref HEAD`| head -n1| sed 's/.*\\[\\(.*\\)\\].*/\\1/'| sed 's/[\\^~].*//' #"
!
はシェルコマンドを入力しますよ, という指示語
▶ How to Use it
develop
ブランチから派生したfeature_model
ブランチに現在いるとするfeature_model
ブランチの派生元ブランチとしてdevelop
ブランチ名が出力されてほしい
1
2
3
4
5
6
7
% git branch
develop
feature_cv
* feature_model
main
% git nearest
develop
Local Branch Operation: Compare and Merge
Compare the current branch with the Selected Branches
▶ What I Want
- 選択したブランチと比較した時, conflictを引き起こすファイル及び差分箇所を確認したい
- コマンド実行中に, ファイルの編集も実現可能
▶ Requirements
.gitconfig
に以下のラインを追記
1
2
3
4
[diff]
tool = vscode
[difftool "vscode"]
cmd = code --wait --diff $LOCAL $REMOTE
▶ How
1
% git difftool <the selected branch> <path>
- 左側にthe selected branch, 右側にthe current branchのファイルが表示される
- the current branchのファイルは編集 & 保存が可能
<path>
指定時は, その対象ファイルのみの差分を表示<path>
を指定しなかった場合は, 差分全てを表示
Undo a Merge Commit
▶ What I Want
- merge commitを取り消す
▶ How
merge commitを取り消すには2つの方法があります:
方針 | 効果 |
---|---|
git reset --merge |
Branch Historyを強制的に書き換える(= merge commitの痕跡を履歴から消す) |
git revert |
merge変更自体は打ち消すが, merge commitの履歴は残る |
本来mergeされるべきではなかったbranchがmergeされたときに実施するundoなので, 基本的には
git reset --merge
を用いることが良いと考えています. 実際に, Linusも次のように言っています:
1
2
3
4
5
6
7
8
9
10
11
12
13
Reverting a regular commit just effectively undoes what that commit did, and is fairly straightforward.
But reverting a merge commit also undoes the _data_ that the commit changed,
but it does absolutely nothing to the effects on _history_ that the merge had.
So the merge will still exist, and it will still be seen as joining the two
branches together, and future merges will see that merge as the last shared
state – and the revert that reverted the merge brought in will not affect that at all.
So a "revert" undoes the data changes, but it's very much not an "undo" in the
sense that it doesn't undo the effects of a commit on the repository history.
So if you think of "revert" as "undo", then you're going to always miss this
part of reverts. Yes, it undoes the data, but no, it doesn't undo history.
▶ How to do git reset --merge
in order to undo the merge
1
% git reset --merge <commit-hash>
git reset –merge
はtracked filesに加えられたuncommitedな変更についての情報を残してくれるため,
全てを参照地点までの情報まで戻してしまうgit reset --hard
に対してsafer versionと一般的に言われています.
documentを確認してみると,
1
2
3
4
5
6
7
8
--hard Matches the working tree and index to that of the tree being
switched to. Any changes to tracked files in the working tree since
<commit> are lost.
--merge
Resets the index to match the tree recorded by the named commit, and
updates the files that are different between the named commit and
the current commit in the working tree.
▶ Check the difference between --hard
and --marge
--hard
と --marge
はtracked fileのuncommittedな変更について情報を残すか残さないかの違いです.
それを確認するため以下の状況を作ります:
main
とmerge_test
の2つのbranchmain
へmerge_test
をmergeする前に、tracked-fileのREADME.md
に「good bye」という文字列を加える- good byeをstashしてから,
merge_test
で適当に作業,main
へ戻る - good byeをstashからpopしてから
merge_test
をmain
へmerge
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
% mkdir test
% cd ./test
% git init
% touch README.md
% git commit -m "initial commit"
% git switch -c merge_test
% touch merge_log.txt
% echo test > merge_log.txt
% git add merge_log.tx
% git commit -m "DOC: Additing merge_log"
% git switch main
% echo hello world > README.md
% git add README.md
% git commit -m "DOC: updating README"
% echo good bye >> README.md
% git stash
% git switch merge_test
% echo 'hope this line will disappear'
% echo 'hope this line will disappear' > merge_log.txt
% git add merge_log.txt
% git commit -m "DOC: updating merge_log"
% git switch main
% git stash pop
% git merge merge_test
このとき, --hard
と --marge
で以下のような挙動の違いが発生します:
1
2
3
4
5
## stashされたgood byeは残る
% git reset --merge ORIG_HEAD
## stashされたgood byeが消える
% git reset --hard ORIG_HEAD
Remote Branch Operation
Get/Switch to a remote branch: git switch
version
▶ What I Want to Do
- リモートブランチ(
project/adhoc_analysis
)をローカルにチェックアウトしたい
▶ How
- リモートの追跡ブランチを更新
git switch
(リモート側にすでにブランチが存在するので-c
は必要なし)
1
2
3
4
5
6
7
8
9
% git branch -r
origin/HEAD -> origin/main
origin/develop
origin/add_cross_validation
origin/add_visualize_module
origin/main
origin/project/ad_hoc_analysis
% git fetch --all
% git switch project/adhoc_analysis
▶ REMARKS
- 内部的にLocal側に新しくリモートと同じブランチ名のブランチが作成, からのswitchとなる
Get/Switch to a remote branch: git fetch
version
▶ What I Want to Do
- リモートブランチ(
project/adhoc_analysis
)をローカルにbranch nameを指定して取り込みたい
▶ How
1
% git fetch <remote> <remote-branchname>:<local-branchname>
Delete Remote Branch
1
2
3
% git push <remote> --delete <branch>
## 同義
% git push <remote> :<old_branch_name>
- コロン(=
:
)の前に何も指定しないことで,「空」をpushするという挙動になる
▶ 複数の場合
1
% git push origin --delete <branch1> <branch2> <branch3>
Refresh the list of remote branches
▶ What I Want
- To update the local list of remote branches
▶ How: remote updateで実施する場合
1
% git remote update origin --prune
▶ How: fetchで実施する場合(推奨)
1
% git fetch -p
Rename Remote Branch
▶ Syntax
1
2
% git switch -c <new_branch_name> <old_branch_name>
% git push <remote> :<old_branch_name> <new_branch_name>
▶ REMARKS
- branchのrenameというよりかは, ローカルで別名で作った同一内容ブランチをremoteへ反映し直すという挙動
- remote branchの消去と新しいbranchのpushを同時に実施しているだけ
Remote Branch Operation: git clone
git clone to a specified folder
1
% git clone <repo> <directory>
<repo>
: リポジトリURL<directory>
: レポジトリ内容を格納するローカル上の空フォルダ- 事前に空フォルダを作成する必要はない
- パスには絶対パス, 相対パスどちらでも指定可能
▶ REMARKS
directory
を中身の入ったフォルダを指定すると以下のようなerrorが返ってくる:
1
2
% git clone hogehoge pokochin
fatal: destination path 'pokochin' already exists and is not an empty directory.
git clone a specified branch only
1
% git clone -b <branch> <repo>
<branch>
: branch name<repo>
: リポジトリURL-b
は--branch
optionのこと
Install Private Python Packages via git clone
-
: installしたいversionを指定 -
: レポジトリのローカルにおける保存先
1
% git clone -b <branch-name> <repository url> <local-folder-path>
Then, pip経由の場合は編集可能性を考慮して -e
オプションを付与してインストール
1
% pip install -e <folder-name>
Poetry経由の場合は
1
% poetry add --editable <folder-name>
References
▶ git config
▶ git sparse checkout
▶ git branch operation tips
- stackoverflow > How can I use the new
git switch
syntax to create a new branch? - stackoverflow > Can I recover a branch after its deletion in Git?
- git documentation > Linus explains the revert and the reset
(注意:GitHub Accountが必要となります)