Git 브랜치 - Rebase하기(https://git-scm.com/book/ko/v1/Git-%EB%B8%8C%EB%9E%9C%EC%B9%98-%EB%A6%AC%EB%AA%A8%ED%8A%B8-%EB%B8%8C%EB%9E%9C%EC%B9%98)

Rebase하기

Git에서 한 브랜치에서 다른 브랜치로 합치는 방법은 두 가지가 있다. 하나는 Merge이고 다른 하나는 Rebase다. 이 절에서는 Rebase가 무엇인지, 어떻게 사용하는지, 좋은 점은 뭐고, 어떤 상황에서 사용하고 어떤 상황에서 사용하지 말아야 하는지 알아 본다.

Rebase의 기초

앞의 Merge 절에서 살펴본 예제로 다시 돌아가 보자(그림 3-27). 두 개의 나누어진 브랜치의 모습을 볼 수 있다. (브랜치를 나누면 브랜치가 생성된 시점의 커밑은 두 브랜치 양쪽에 속해진다. 가령 아래에서 c2커밑은 master브랜치와 experiment브랜치 모두에 속한다)

그림 3-27. 두 개의 브랜치로 나누어진 커밋 히스토리

이 두 브랜치를 합치는 가장 쉬운 방법은 앞에서 살펴본 대로 Merge 명령을 사용하는 것이다. 두 브랜치의 마지막 커밋 두 개(C3, C4)와 공통 조상(C2)을 사용하는 3-way Merge로 그림 3-28처럼 새로운 커밋을 만들어 낸다.

그림 3-28. 나뉜 브랜치를 Merge하기

비슷한 결과를 만드는 다른 방식으로, C3에서 변경된 사항을 패치(Patch)로 만들고 이를 다시 C4에 적용시키는 방법이 있다. Git에서는 이런 방식을Rebase라고 한다. Rebase 명령으로 한 브랜치에서 변경된 사항을 다른 브랜치에 적용할 수 있다.

위의 예제는 다음과 같은 명령으로 Rebase한다:

$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it... Applying: added staged command

rebase를 할시 C'3는 C3와 내용상 동일하지만 다른 넘버의 커밑이다.

 

실제로 일어나는 일을 설명하자면 일단 두 브랜치가 나뉘기 전인 공통 커밋으로 이동하고 나서 그 커밋부터 지금 Checkout한 브랜치가 가리키는 커밋까지 diff를 차례로 만들어 어딘가에 임시로 저장해 놓는다. Rebase할 브랜치(역주 - experiment)가 합칠 브랜치(역주 - master)가 가리키는 커밋을 가리키게 하고 아까 저장해 놓았던 변경사항을 차례대로 적용한다. 그림 3-29는 이러한 과정을 나타내고 있다.

그림 3-29. C3의 변경사항을 C4에 적용하는 Rebase 과정

그리고 나서 master 브랜치를 Fast-forward 시킨다.

그림 3-30. master 브랜치를 Fast-forward시키기

C3'로 표시된 커밋에서의 내용은 Merge 예제에서 살펴본 C5 커밋에서의 내용과 같을 것이다. Merge이든 Rebase든 둘 다 합치는 관점에서는 서로 다를 게 없다. 하지만, Rebase가 좀 더 깨끗한 히스토리를 만든다. Rebase한 브랜치의 Log를 살펴보면 히스토리가 선형적이다. 일을 병렬로 동시에 진행해도 Rebase하고 나면 모든 작업이 차례대로 수행된 것처럼 보인다.

Rebase는 보통 리모트 브랜치에 커밋을 깔끔하게 적용하고 싶을 때 사용한다. 아마 이렇게 Rebase하는 리모트 브랜치는 직접 관리하는 것이 아니라 그냥 참여하는 브랜치일 것이다. 메인 프로젝트에 패치를 보낼 준비가 되면 하는 것이 Rebase이니까 브랜치에서 하던 일을 완전히 마치고 origin/master로 Rebase한다. 프로젝트 관리자는 어떠한 통합작업도 필요 없다. 그냥 master 브랜치를 Fast-forward 시키면 된다.

Rebase를 하든지, Merge를 하든지 최종 결과물은 같고 커밋 히스토리만 다르다는 것이 중요하다. Rebase의 경우는 브랜치의 변경사항을 순서대로 다른 브랜치에 적용하면서 합치고 Merge의 경우는 두 브랜치의 최종결과만을 가지고 합친다.

좀 더 Rebase

Rebase는 단순히 브랜치를 합치는 것만 아니라 다른 용도로도 사용할 수 있다. 그림 3-31과 같은 히스토리가 있다고 하자. server 브랜치를 만들어서 서버 기능을 추가하고 그 브랜치에서 다시 client 브랜치를 만들어 클라이언트 기능을 추가한다. 마지막으로 server 브랜치로 돌아가서 몇 가지 기능을 더 추가한다.

그림 3-31. 다른 토픽 브랜치에서 갈라져 나온 토픽 브랜치

이때 테스트가 덜 된 server 브랜치는 그대로 두고 client 브랜치만 master로 합치려는 상황을 생각해보자. server와는 아무 관련이 없는 client 커밋은 C8, C9이다. 이 두 커밋을 master 브랜치에 적용하기 위해서--onto옵션을 사용하여 아래와 같은 명령을 실행한다:

$ git rebase --onto master server client

이 명령은 client 브랜치를 Checkout하고 server와 client의 공통조상 이후의 패치를 만들어 master에 적용한다. 조금 복잡하긴 해도 꽤 쓸모 있다. 그림 3-32를 보자.

그림 3-32. 다른 토픽 브랜치에서 갈라져 나온 토픽 브랜치를 Rebase하기

이제 master 브랜치로 돌아가서 Fast-forward 시킬 수 있다:

$ git checkout master
$ git merge client

그림 3-33. master 브랜치를 client 브랜치 위치로 진행 시키기

server 브랜치의 일이 다 끝나면git rebase [basebranch] [topicbranch]라는 명령으로 Checkout하지 않고 바로 server 브랜치를 master 브랜치로 rebase할 수 있다. 이 명령은 토픽(server) 브랜치를 Checkout하고 베이스(master) 브랜치에 Rebase한다:

$ git rebase master server

server 브랜치의 수정사항을 master 브랜치에 적용했다. 그 결과는 그림 3-34와 같다.

그림 3-34. master 브랜치에 server 브랜치의 수정 사항을 적용

그리고 나서 master 브랜치를 Fast-forward 시킨다:

$ git checkout master
$ git merge server

모든 것이 master 브랜치에 통합됐기 때문에 더 필요하지 않다면 client나 server 브랜치는 삭제해도 된다. 브랜치를 삭제해도 커밋 히스토리는 그림 3-35와 같이 여전히 남아 있다:

$ git branch -d client
$ git branch -d server

그림 3-35. 최종 커밋 히스토리

Rebase의 위험성

Rebase가 장점이 많은 기능이지만 단점이 없는 것은 아니니 조심해야 한다. 그 주의사항은 다음 한 문장으로 표현할 수 있다:

이미 공개 저장소에 Push한 커밋을 Rebase하지 마라

이 지침만 지키면 Rebase를 하는 데 문제 될 게 없다. 하지만, 이 주의사항을 지키지 않으면 사람들에게 욕을 먹을 것이다(역주 - 아마도 가카의 호연지기가 필요해질 것이다).

Rebase는 기존의 커밋을 그대로 사용하는 것이 아니라 내용은 같지만 다른 커밋을 새로 만든다. 새 커밋을 서버에 Push하고 동료 중 누군가가 그 커밋을 Pull해서 작업을 한다고 하자. 그런데 그 커밋을git rebase로 바꿔서 Push해버리면 동료가 다시 Push했을 때 동료는 다시 Merge해야 한다. 그리고 동료가 다시 Merge한 내용을 Pull하면 내 코드는 정말 엉망이 된다.

이미 공개 저장소에 Push한 커밋을 Rebase하면 어떤 결과가 초래되는지 예제를 통해 알아보자. 중앙 저장소에서 Clone하고 일부 수정을 하면 커밋 히스토리는 그림 3-36과 같아 진다.

그림 3-36. 저장소를 Clone하고 일부 수정함

이제 팀원 중 누군가 커밋, Merge하고 나서 서버에 Push 한다. 이 리모트 브랜치를 Fetch, Merge하면 그림 3-37과 같이 된다.

그림 3-37. Fetch한 후 Merge함

그런데 Push했던 팀원은 Merge한 일을 되돌리고 다시 Rebase한다. 서버의 히스토리를 새로 덮어씌우려면git push --force명령을 사용해야 한다. 이후에 저장소에서 Fetch하고 나면 아래 그림과 같은 상태가 된다:

그림 3-38. 한 팀원이 다른 팀원이 의존하는 커밋을 없애고 Rebase한 커밋을 다시 Push함

기존 커밋이 사라졌기 때문에 이미 처리한 일이라고 해도 다시 Merge해야 한다. Rebase는 커밋의 SHA-1 해시를 바꾸기 때문에 Git은 새로운 커밋으로 생각한다. 사실 C4는 이미 히스토리에 적용되어 있지만, Git은 모른다.

그림 3-39. 같은 Merge를 다시 한다

다른 개발자와 계속 같이 일하려면 이런 Merge도 해야만 한다. Merge하면 C4와 C4' 커밋 둘 다 히스토리에 남게 된다. 실제 내용과 메시지가 같지만 SHA-1 해시 값이 전혀 다르다.git log로 히스토리를 확인해보면 저자, 커밋 날짜, 메시지가 같은 커밋이 두 개 있을 것이다. 이렇게 되면 혼란스럽다. 게다가 이 히스토리를 서버에 Push하면 같은 커밋이 두 개 있기 때문에 다른 사람들도 혼란스러워한다.

Push하기 전에 정리하려고 Rebase하는 것은 괜찮다. 또 절대 공개하지 않고 혼자 Rebase하는 경우도 괜찮다. 하지만, 이미 공개하여 사람들이 사용하는 커밋을 Rebase하면 틀림없이 문제가 생길 것이다.


jenkins과 gitlab연동하기




Jenkins side

1.GitLab플러그인 설치


젠킨스 쪽에서 가장 먼저 해야할 것은 gitlab과의 연동을 도와주는 플러그인을 설치하는 것이다. 


 Jenkinsの管理 ->  plugin 管理】


위의 패스를 통해 들어가면 아래와 같은 화면이 나오는데, 거기서 gitlab을 검색하면 gitlab plugin을 설치할 수 있다.





2.Jenkins에 gitlab유저정보 등록하기


認証情報 -> System -> グローバルドメイン -> 認証情報の追加】


위의 패스를 통해 들어가면, 아래와 같은 화면이 나오는데, 여기에 gitlab의 유저 정보를 기입한다.

이때, gitlab쪽에서 jenkins 전용 유저아이디를 만들어 사용하면, 사용자가 겹치지 않으므로 jenkins작업에 유리하다.




3.Jenkins 프로젝트 작성


[소스코드 관리 설정]

Repository URL : 대상이 되는 gitlab의 레포지토리 주소를 적어둔다

Credentials : 2의 유저정보등록에서 미리 등록해둔 gitlab의 정보를 사용한다.

Branch : 갱신을 확인할 브랜치를 기입한다.







[빌드트리거]

1. Build when a change is pushed .. 를 선택하고, 형광팬 표시된 url은 gitlab의 webhook등록에서 사용되므로 복사해두자.






[빌드트리거]-시크릿키 생성

gitlab에서 jenkins로 webhook을 리퀘스트 할 시, 필요한 스키릿키이다. 

시크릿키도  gitlab의 webhook등록시 사용되므로 복사해 두도록하자.







4.Gitlab webhook작성



3번에서 복사해둔, URL과 시크릿키를 각각 입력한다.

입력이 끝난 후에는 test버튼을 눌러 연결을 확인해본다.

















Gitlabのrootユーザー(admin)のパスワードを忘れてしまった場合

この記事は最終更新日から1年以上が経過しています。

Gitlabのrootユーザー(admin)のパスワードを忘れてしまった場合

GitlabCEのrootユーザー(admin)のパスワードを忘れてしまったため、
コンソールから強制的にパスワードリセットを実施した時のメモです。

環境

  • CentOS67
  • GitLab 7.14.1 481c966 Check

手順

Gitlabをインストールしたアカウントかサーバのrootアカウントで
サーバへsshログインして以下コマンドを実行します。

  1. gitlab-rails console production # コンソール起動(少しが時間かかります。)
  2. user = User.where(id: 1).first # rootアカウント設定モードへ
  3. user.password = 'secret_pass' # 新パスワード設定
  4. user.password_confirmation = 'secret_pass' # 新パスワード設定(確認)
  5. user.save! # 設定の保存
  6. exit # コンソールを抜ける

実行結果

[root@gitlab_server ~]# gitlab-rails console production
Loading production environment (Rails 4.1.11)
irb(main):001:0> user = User.where(id: 1).first
=> #<User id: 1, email: "admin@example.com", 
中略
public_email: "", dashboard: 0, project_view: 0>
irb(main):002:0> user.password = 'password'
=> "password"
irb(main):003:0> user.password_confirmation = 'password'
=> "password"
irb(main):004:0> user.save!
=> true
irb(main):005:0> exit
[root@gitlab_server ~]# 

参考

How to reset your root password


https://git-scm.com/book/ko/v2/Git-%EB%8F%84%EA%B5%AC-Stashing%EA%B3%BC-Cleaning


Git 도구 - Stashing과 Cleaning

Stashing과 Cleaning

당신이 어떤 프로젝트에서 한 부분을 담당하고 있다고 하자. 그리고 여기에서 뭔가 작업하던 일이 있고 다른 요청이 들어와서 잠시 브랜치를 변경해야 할 일이 생겼다고 치자. 그런데 이런 상황에서 아직 완료하지 않은 일을 커밋하는 것이 껄끄럽다는 것이 문제다. 커밋하지 않고 나중에 다시 돌아와서 작업을 다시 하고 싶을 것이다. 이 문제는 git stash 라는 명령으로 해결할 수 있다.

Stash 명령을 사용하면 워킹 디렉토리에서 수정한 파일들만 저장한다. Stash는 Modified이면서 Tracked 상태인 파일과 Staging Area에 있는 파일들을 보관해두는 장소다. 아직 끝내지 않은 수정사항을 스택에 잠시 저장했다가 나중에 다시 적용할 수 있다(브랜치가 달라져도 말이다).

Note
git stash push 로의 이동

2017년 10월 말 Git 메일링 리스트에는 엄청난 논의가 있었습니다. 논의는 git stash save 명령을 은퇴시키고 git stash push`로 대체하는 내용에 대한 것이었습니다. `git stash push 명령의 경우 pathspec 으로 선택하여 Stash하는 옵션이 추가되었는데 git stash save 명령이 지원하지 못하는 것이었습니다.

git stash save 명령이 곧바로 삭제되는 것은 아니기에 아직 이 명령을 쓰는 것에 대해 걱정할 필요는 없지만 git stash push 명령으로 대체하는 것에 대해 생각해볼 필요가 있습니다.

하던 일을 Stash 하기

예제 프로젝트를 하나 살펴보자. 파일을 두 개 수정하고 그 중 하나는 Staging Area에 추가한다. 그리고 git status 명령을 실행하면 아래와 같은 결과를 볼 수 있다.

$ git status
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

  modified:   index.html

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

  modified:   lib/simplegit.rb

이제 브랜치를 변경해 보자. 아직 작업 중인 파일은 커밋할 게 아니라서 모두 Stash 한다. git stash 나 git stash save 를 실행하면 스택에 새로운 Stash가 만들어진다.

$ git stash
Saved working directory and index state \
  "WIP on master: 049d078 added the index file"
HEAD is now at 049d078 added the index file
(To restore them type "git stash apply")

대신 워킹 디렉토리는 깨끗해졌다.

$ git status
# On branch master
nothing to commit, working directory clean

이제 아무 브랜치나 골라서 쉽게 바꿀 수 있다. 수정하던 것을 스택에 저장했다. 아래와 같이 git stash list 를 사용하여 저장한 Stash를 확인한다.

$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert "added file_size"
stash@{2}: WIP on master: 21d80a5 added number to log

Stash 두 개는 원래 있었다. 그래서 현재 총 세 개의 Stash를 사용할 수 있다. 이제 git stash apply 를 사용하여 Stash를 다시 적용할 수 있다. git stash 명령을 실행하면 Stash를 다시 적용하는 방법도 알려줘서 편리하다. `git stash apply stash@{2}`처럼 Stash 이름을 입력하면 골라서 적용할 수 있다. 이름이 없으면 Git은 가장 최근의 Stash를 적용한다.

$ git stash apply
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

  modified:   index.html
  modified:   lib/simplegit.rb

no changes added to commit (use "git add" and/or "git commit -a")

Git은 Stash에 저장할 때 수정했던 파일들을 복원해준다. 복원할 때의 워킹 디렉토리는 Stash 할 때의 그 브랜치이고 워킹 디렉토리도 깨끗한 상태였다. 하지만 꼭 깨끗한 워킹 디렉토리나 Stash 할 때와 같은 브랜치에 적용해야 하는 것은 아니다. 어떤 브랜치에서 Stash 하고 다른 브랜치로 옮기고서 거기에 Stash를 복원할 수 있다. 그리고 꼭 워킹 디렉토리가 깨끗한 상태일 필요도 없다. 워킹 디렉토리에 수정하고 커밋하지 않은 파일들이 있을 때도 Stash를 적용할 수 있다. 만약 충돌이 있으면 알려준다.

Git은 Stash를 적용할 때 Staged 상태였던 파일을 자동으로 다시 Staged 상태로 만들어 주지 않는다. 그래서 git stash apply 명령을 실행할 때 --index 옵션을 주어 Staged 상태까지 적용한다. 그래야 원래 작업하던 상태로 돌아올 수 있다.

$ git stash apply --index
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

  modified:   index.html

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

  modified:   lib/simplegit.rb

apply 옵션은 단순히 Stash를 적용하는 것뿐이다. Stash는 여전히 스택에 남아 있다. git stash drop명령을 사용하여 해당 Stash를 제거한다.

$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert "added file_size"
stash@{2}: WIP on master: 21d80a5 added number to log
$ git stash drop stash@{0}
Dropped stash@{0} (364e91f3f268f0900bc3ee613f9f733e82aaed43)

그리고 git stash pop 이라는 명령도 있는데 이 명령은 Stash를 적용하고 나서 바로 스택에서 제거해준다.

Stash를 만드는 새로운 방법

Stash를 만드는 방법은 여러 가지다. 주로 사용하는 옵션으로 stash save 명령과 같이 쓰는 --keep-index 이다. 이 옵션을 이용하면 이미 Staging Area에 들어 있는 파일을 Stash 하지 않는다.

$ git status -s
M  index.html
 M lib/simplegit.rb

$ git stash --keep-index
Saved working directory and index state WIP on master: 1b65b17 added the index file
HEAD is now at 1b65b17 added the index file

$ git status -s
M  index.html

추적하지 않는 파일과 추적 중인 파일을 같이 Stash 하는 일도 꽤 빈번하다. 기본적으로 git stash 는 추적 중인 파일만 저장한다. 추적 중이지 않은 파일을 같이 저장하려면 Stash 명령을 사용할 때 --include-untracked 나 -u 옵션을 붙여준다.

$ git status -s
M  index.html
 M lib/simplegit.rb
?? new-file.txt

$ git stash -u
Saved working directory and index state WIP on master: 1b65b17 added the index file
HEAD is now at 1b65b17 added the index file

$ git status -s
$

끝으로 --patch 옵션을 붙이면 Git은 수정된 모든 사항을 저장하지 않는다. 대신 대화형 프롬프트가 뜨며 변경된 데이터 중 저장할 것과 저장하지 않을 것을 지정할 수 있다.

$ git stash --patch
diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index 66d332e..8bb5674 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -16,6 +16,10 @@ class SimpleGit
         return `#{git_cmd} 2>&1`.chomp
       end
     end
+
+    def show(treeish = 'master')
+      command("git show #{treeish}")
+    end

 end
 test
Stash this hunk [y,n,q,a,d,/,e,?]? y

Saved working directory and index state WIP on master: 1b65b17 added the index file

Stash를 적용한 브랜치 만들기

보통 Stash에 저장하면 한동안 그대로 유지한 채로 그 브랜치에서 계속 새로운 일을 한다. 그러면 이제 저장한 Stash를 적용하는 것이 문제가 된다. 수정한 파일에 Stash를 적용하면 충돌이 일어날 수도 있고 그러면 또 충돌을 해결해야 한다. 필요한 것은 Stash 한 것을 쉽게 다시 테스트하는 것이다. git stash branch <브랜치> 명령을 실행하면 Stash 할 당시의 커밋을 Checkout 한 후 새로운 브랜치를 만들고 여기에 적용한다. 이 모든 것이 성공하면 Stash를 삭제한다.

$ git stash branch testchanges
M index.html
M lib/simplegit.rb
Switched to a new branch 'testchanges'
On branch testchanges
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

  modified:   index.html

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

  modified:   lib/simplegit.rb

Dropped refs/stash@{0} (29d385a81d163dfd45a452a2ce816487a6b8b014)

이 명령은 브랜치를 새로 만들고 Stash를 복원해주는 매우 편리한 도구다.

워킹 디렉토리 청소하기

작업하고 있던 파일을 Stash 하지 않고 단순히 그 파일들을 치워버리고 싶을 때가 있다. git clean 명령이 그 일을 한다.

보통은 Merge나 외부 도구가 만들어낸 파일을 지우거나 이전 빌드 작업으로 생성된 각종 파일을 지우는 데 필요하다.

이 명령을 사용할 때는 신중해야 한다. 이 명령을 사용하면 워킹 디렉토리 안의 추적하고 있지 않은 모든 파일이 지워지기 때문이다. 명령을 실행하고 나서 후회해도 소용없다. 지워진 파일은 돌아오지 않는다.git stash –all 명령을 이용하면 지우는 건 똑같지만, 먼저 모든 파일을 Stash 하므로 좀 더 안전하다.

워킹 디렉토리의 불필요한 파일들을 전부 지우려면 git clean 을 사용한다. 추적 중이지 않은 모든 정보를 워킹 디렉토리에서 지우고 싶다면 git clean -f -d 명령을 사용하자. 이 명령은 하위 디렉토리까지 모두 지워버린다. -f 옵션은 강제(force)의 의미이며 "진짜로 그냥 해라"라는 뜻이다.

이 명령을 실행했을 때 어떤 일이 일어날지 미리 보고 싶다면 -n 옵션을 사용한다. -n 옵션은 “가상으로 실행해보고 어떤 파일들이 지워질지 알려달라” 라는 뜻이다.

$ git clean -d -n
Would remove test.o
Would remove tmp/

git clean 명령은 추적 중이지 않은 파일만 지우는 게 기본 동작이다. .gitignore 에 명시했거나 해서 무시되는 파일은 지우지 않는다. 무시된 파일까지 함께 지우려면 -x 옵션이 필요하다. 그래서 .o 파일 같은 빌드 파일까지도 지울 수 있다.

$ git status -s
 M lib/simplegit.rb
?? build.TMP
?? tmp/

$ git clean -n -d
Would remove build.TMP
Would remove tmp/

$ git clean -n -d -x
Would remove build.TMP
Would remove test.o
Would remove tmp/

git clean 이 무슨 짓을 할지 확신이 안들 때는 항상 -n 옵션을 붙여서 먼저 실행해보자. clean 명령을 대화형으로 실행하려면 -i 옵션을 붙이면 된다.

대화형으로 실행한 clean 명령의 모습은 아래와 같다.

$ git clean -x -i
Would remove the following items:
  build.TMP  test.o
*** Commands ***
    1: clean                2: filter by pattern    3: select by numbers    4: ask each             5: quit
    6: help
What now>

대화형으로 실행하면 파일마다 지우지 말지 결정하거나 특정 패턴으로 걸러서 지울 수도 있다.


gitでリモートブランチをローカルにcheckoutする

この記事は最終更新日から3年以上が経過しています。

新しい作業環境で開発リポジトリのmasterリポジトリをcloneしたあとにその他のブランチもcheckout/pullしたいことがある。というか、しないと作業にならない。

よく忘れるのでメモ。

git checkout -b local_branch_name origin/remote_branch_name

remote_branch_nameリモートブランチから派生するlocal_branch_nameローカルブランチを新たに作成する。

-bオプションをつけることで「新しいブランチを作り、チェックアウトする」という動作になる。


[初心者向け]こんなときどうする⁉︎ GitのTips31選!(https://qiita.com/Keisuke69/items/35d60e4e375fc525ccbd)

はじめに

半分自分用のメモですが、Gitを使って開発してる場合によくあることを簡単にまとめました。
よくあるネタではあるのですが、自分が困ったときに調べた結果をまとめています。
特に使い始めの頃とか初心者の人が困ったときの手助けになれば。
なお、自己責任でお願いします。
※この記事は元々自分のブログに投稿していたものを少し手直しして転載したものです
※間違いあったら指摘してください
※数が増えてたのにタイトルが26のままだったので修正しました

変更確認系

変更箇所を直前のコミットタイミングと比較したい

git diff HEAD~1

差分のサマリを見たい

git diff --stat <source> <target>

スペースの変更を無視してdiffしたい

これをしないと全体をインデントしたときとかに悲惨です。

git diff --ignore-space-change <source> <target>

自分のリポジトリをフォークして作られた他人のリポジトリを比較

git remote add <name> <フォーク元もしくは比較したいリポジトリ>
git fetch <name> #先ほど追加したリモートをfetch 
git diff FETCH_HEAD

フォーク元との比較にもどうぞ。

あれこれ修正したい

直前のコミットメッセージを変更したい

git commit --amend -m "new comment"

コミットをまとめたい

git rebase -i HEAD~5

エディタが開くのでpickなりrewordなりfixupなりを行う。
上記はHEADから5個前までのコミットを対象に作業している。

直前以前のコミットメッセージを変更したい

「コミットをまとめたい」とやり方は同じ。変更したい箇所までのHEADを指定してrebaseを実行する。
あとは変更したい箇所でpickなりをする。

コミッタ名やメールアドレスを変更したい

通常は以下の2コマンドで名前とメールアドレスを設定しておけば問題ない。

git config --global user.name "Your Name"
git config --global user.email you@example.com

が、既に異なる名前でコミットされているものを後から変更したい場合は以下のような処理を実行すればよい

git filter-branch --commit-filter '
    GIT_AUTHOR_NAME="New Name"
    GIT_AUTHOR_EMAIL="new@example.com"
    GIT_COMMITTER_NAME="New Name"
    GIT_COMMITTER_EMAIL="new@example.com"
    git commit-tree "$@"
' HEAD

commit-filterの後にシェルスクリプトを記述する。
上記の場合は、全てのコミットログに対して名前とアドレスを変更する処理を行っているが特定のコミッタだけ変更したい場合などはシェルのif文なりで引っ掛ければよい

取り消し系

githubにpushしたcommitの取り消し

githubにpushして後にcommitが間違っていたことに気づいた場合など。
ただし、以下の手順を実施するとcommitだけでなく変更も失われるので注意。ローカルのソースツリーは残された最後のcommitに戻されます。変更を保存したい場合は使わないように。

git rebase -i HEAD~2 #エディタが開くので二行目を削除して保存する
git push origin +master

github側だけcommitの取り消し

commitの取り消しをgithub側だけで行う場合。ローカルは同期されない。

git push -f origin HEAD^:master

ローカルだけcommitの取り消し

git reset HEAD^

git addの取り消し

git rm --cached <取り消したいファイル>

いろいろやり直したい(間違ってreset --hardした時とか)

git reflog

でHEADの変遷を表示して戻したい位置を指定してresetする。ちなみにHEAD@[0}が現在のHEAD位置。

git reset --hard HEAD@{1}

みたいな感じで。

間違って削除したファイルを元に戻したい

git checkout -f <対象ファイル>

ただし、変更も戻る。

ファイルを指定しない場合は全体が戻ります。

その他いろいろ

他人のリポジトリをローカルの別ブランチにチェックアウトしたい

git remote add <name> <フォーク元もしくは比較したいリポジトリ>
git fetch <name>
git checkout -b <branch_name> remotes/<remote_name>/<remote_branch_name>

github上でforkしたリポジトリの最新化

forkしたリポジトリをcloneした上でfork元のリポジトリをpullするだけ。
pullするにあたってはfork元をremoteに追加しておいてもいいし直接URL指定でもいい。

指定のタグをチェックアウトしてブランチ作成

git checkout -b <ブランチ名> refs/tags/<タグ名>
#ブランチ作らないなら-b不要

タグとタグの間のコミットログを表示

git log v1.0..v1.1 --pretty=format:"%ci [%h]%s"
#タグの代わりにハッシュ値を指定することもできる

タグの一覧表示

git tag -l

タグがリンクしているコミットのハッシュ値を確認

git rev-parse <タグ名>

特定のハッシュ値のコミットログを確認

git log ハッシュ値

リモートリポジトリのタグを削除

まずローカルでタグを削除してリモートを空のタグで上書きする

git tag -d <タグ名>
git push origin :refs/tags/<タグ名>

特定ファイルのブランチによる違いの比較

git diff branch1 branch2 filepath

リモートブランチをトラッキング先に設定

git branch --set-upstream work remotes/origin/work 

リモートブランチを削除したい

git push [remotename] :[branch] 

強制的にpushする

リモート側のツリーを強制的に上書きしてローカルの内容でpushしたい場合

git push <リモート名> <ローカルブランチ> --force

特定のコミットだけをマージしたい

git log等で対象コミットのハッシュ値を確認した上でcherry-pickを実行する。

git cherry-pick <ハッシュ値>

gitignoreで指定する前にaddしてしまった場合

インデックスから削除すると同時にファイルも削除する場合

$ git rm -f hogehoge~

インデックスからだけ削除する場合
※つまりファイルはそのまま

$ git rm --cached -f hogehoge~

gitの設定を確認したい

git config --list

ユーザ名とメールアドレスを設定したい

システム上の特定ユーザすべてのリポジトリで設定するには--globalオプションを指定する。

$ git config --global user.name "foo bar"
$ git config --global user.email foo@example.com

普通にrmしたファイルをまとめてgit rmしたい

OS上でrmで削除してしまったものをgit上でも削除したいがうっかりフォルダごと、しかも複数消してしまって大量にある場合など

$ git rm $(git ls-files --deleted)

最後に

今後も自分で躓いたりして新しいネタ見つけたら更新していきます。



1. rebase의 동작원리


・feature브랜치가 처음 파생된 아래 표시된 빨간점이 feature 브랜치의 base라고한다. rebase란 저 베이스를 옮기는 것을 의미한다.




base 이후부터 feature 가 만든 커밑까지의 플로우가  임시저장소에 격납. 격납된 부분을 fetch라고 부름





base 이후부터 feature 가 만든 커밑까지의 플로우가 삭제되고 feature는 master의 최신 커밑으로 checkout됨







・임시저장소의 fetch에서 커밑 하나하나를 master브랜치로 옮겨 master의 최신 커밑과 병합을 시킴





 





2. rebase 실행해보기


[지금까지의 플로우]

master 브랜치에서 1을 커밑

rb브랜치 생성

rb 브랜치에서 R1을 커밑

rb 브랜치에서 R2를 커밑

master 브렌치로 체크아웃

master 브렌치에서 M1을 커밑

master 브렌치에서 M2를 커밑

・$ git log --decorate --all --oneline --graph

rb의 base는 1인데, rebase해서 rb의 base를 M2로 바꾸어 줄 것임

* 1a65c2a (HEAD -> master) M2

* 338f6a1 M1

| * 8a1ca73 (rb) R2

| * a283221 R1

|/

* 8c33afd 1

git rebase master

git rebase master : branch가 rb에 존재할 때, rb의 베이스를 변경

git merge rb : branch가 master 에 존재할 때, rb를 master로 병합시킴


$ git log --decorate --all --oneline --graph


* f9c53a8 (HEAD -> rb) R2

* b0d3c67 R1

* 1a65c2a (master) M2

* 338f6a1 M1

* 8c33afd 1

git checkout master

git merge rb 

master 브랜치는 rb이상 가지고 있는 커밑이 없으므로 fast-forwarding


$ git log --decorate --all --oneline --graph

* f9c53a8 (HEAD -> master, rb) R2

* b0d3c67 R1

* 1a65c2a M2

* 338f6a1 M1

* 8c33afd 1


3. rebase의 충돌


[지금까지의 플로우]

master 브랜치에서 1을 커밑(f1.txt파일의 첫번째 줄에 A작성)

master 브렌치에서 M1을 커밑(f1.txt파일의 첫번째 줄에 A작성 + 2번째줄에 M1작성)

rb브랜치 생성

rb 브랜치에서 R1을 커밑(f1.txt파일의 첫번째 줄에 A작성 + 2번째줄에 R1작성)

rb 브랜치에서 R2를 커밑(f1.txt파일의 첫번째 줄에 A작성 + 2번째줄에 R2작성)

rb 브랜치에서 R2를 커밑(f1.txt파일의 첫번째 줄에 A작성 + 2번째줄에 R3작성)


$ git log --decorate --oneline --graph --all

* f5dc64d (HEAD -> rb) R3

* 20fd541 R2

* 6f0c444 R1

| * 4e9dd84 (master) M1

|/

* 3b42f60 1

git rebase master

-2번째 줄의 내용이 모두 상이하므로 rebase시 충돌 발생

First, rewinding head to replay your work on top of it...

Applying: R1

error: Failed to merge in the changes.

Using index info to reconstruct a base tree...

M       f1.txt

Falling back to patching base and 3-way merge...

Auto-merging f1.txt

CONFLICT (content): Merge conflict in f1.txt

Patch failed at 0001 R1

The copy of the patch that failed is found in: .git/rebase-apply/patch


Resolve all conflicts manually, mark them as resolved with

"git add/rm <conflicted_files>", then run "git rebase --continue".

You can instead skip this commit: run "git rebase --skip".

To abort and get back to the state before "git rebase", run "git rebase --abort".

충돌을 수동으로 해결 후 git rebase --continue 하라는 메시지가 뜸 
rebase in progress; onto 4e9dd84
You are currently rebasing branch 'rb' on '4e9dd84'.
  (all conflicts fixed: run "git rebase --continue")

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   f1.txt
・이때의 log를 확인해보니..

-git log --decorate --oneline --graph --all로 현재상황 확인

* 43a38df (HEAD) R1

* 4e9dd84 (master) M1

| * f5dc64d (rb) R3

| * 20fd541 R2

| * 6f0c444 R1

|/

* 3b42f60 1

-R1이 새로운 베이스 M1뒤에 잘 붙어있음.



git rebase --continue 

-R1의 둘째줄과 R2의 둘째줄이 겹치기 때문에 또 오류 메시지 뜸

-수동으로 수정 후 log 확인. R2가 R1 뒤에 잘 붙어있음.


* f75f8de (HEAD) R2

* 43a38df R1

* 4e9dd84 (master) M1

| * f5dc64d (rb) R3

| * 20fd541 R2

| * 6f0c444 R1

|/

* 3b42f60 1


git rebase --continue 

-R2의 둘째줄과 R3의 둘째줄이 겹치기 때문에 또 오류 메시지 뜸

-수동으로 수정 후 log 확인. R3가 R2 뒤에 잘 붙어있음.


* a0c8cb4 (HEAD -> rb) R3

* f75f8de R2

* 43a38df R1

* 4e9dd84 (master) M1

* 3b42f60 1


+ Recent posts