Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
李少辉-开发者
git
提交
89305da8
G
git
项目概览
李少辉-开发者
/
git
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
git
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
89305da8
编写于
8月 23, 2005
作者:
J
Junio C Hamano
浏览文件
操作
浏览文件
下载
差异文件
Merge refs/heads/master from .
上级
15ac5164
f5e375c9
变更
11
隐藏空白更改
内联
并排
Showing
11 changed file
with
587 addition
and
178 deletion
+587
-178
Documentation/git-show-branch.txt
Documentation/git-show-branch.txt
+107
-0
Documentation/git-show-branches-script.txt
Documentation/git-show-branches-script.txt
+0
-71
Documentation/git.txt
Documentation/git.txt
+1
-1
Makefile
Makefile
+1
-2
commit.c
commit.c
+15
-6
commit.h
commit.h
+2
-0
git-diff-script
git-diff-script
+8
-2
git-show-branches-script
git-show-branches-script
+0
-61
ls-files.c
ls-files.c
+73
-35
sha1_name.c
sha1_name.c
+41
-0
show-branch.c
show-branch.c
+339
-0
未找到文件。
Documentation/git-show-branch.txt
0 → 100644
浏览文件 @
89305da8
git-show-branch(1)
==================
v0.99.4, Aug 2005
NAME
----
git-show-branch - Show branches and their commits.
SYNOPSIS
--------
'git show-branch [--all] [--heads] [--tags] [--more=<n>] [--merge-base] <reference>...'
DESCRIPTION
-----------
Shows the head commits from the named <reference> (or all refs under
$GIT_DIR/refs/heads), and displays concise list of commit logs
to show their relationship semi-visually.
OPTIONS
-------
<reference>::
Name of the reference under $GIT_DIR/refs/.
--all --heads --tags::
Show all refs under $GIT_DIR/refs, $GIT_DIR/refs/heads,
and $GIT_DIR/refs/tags, respectively.
--more=<n>::
Usually the command stops output upon showing the commit
that is the common ancestor of all the branches. This
flag tells the command to go <n> commits beyond that.
--merge-base::
Instead of showing the commit list, just act like the
'git-merge-base' command except that it can accept more
than two heads.
OUTPUT
------
Given N <references>, the first N lines are the one-line
description from their commit message. The branch head that is
pointed at by $GIT_DIR/HEAD is prefixed with an asterisk '*'
character while other heads are prefixed with a '!' character.
Following these N lines, one-line log for each commit is
displayed, indented N places. If a commit is on the I-th
branch, the I-th indentation character shows a '+' sign;
otherwise it shows a space. Each commit shows a short name that
can be used as an exended SHA1 to name that commit.
The following example shows three branches, "master", "fixes"
and "mhf":
------------------------------------------------
$ git show-branch master fixes mhf
! [master] Add 'git show-branch'.
! [fixes] Introduce "reset type" flag to "git reset"
! [mhf] Allow "+remote:local" refspec to cause --force when fetching.
---
+ [mhf] Allow "+remote:local" refspec to cause --force when fetching.
+ [mhf~1] Use git-octopus when pulling more than one heads.
+ [fixes] Introduce "reset type" flag to "git reset"
+ [mhf~2] "git fetch --force".
+ [mhf~3] Use .git/remote/origin, not .git/branches/origin.
+ [mhf~4] Make "git pull" and "git fetch" default to origin
+ [mhf~5] Infamous 'octopus merge'
+ [mhf~6] Retire git-parse-remote.
+ [mhf~7] Multi-head fetch.
+ [mhf~8] Start adding the $GIT_DIR/remotes/ support.
+++ [master] Add 'git show-branch'.
------------------------------------------------
These three branches all forked from a common commit, [master],
whose commit message is "Add 'git show-branch'. "fixes" branch
adds one commit 'Introduce "reset type"'. "mhf" branch has many
other commits.
When only one head is given, the output format changes slightly
to conserve space. The '+' sign to show which commit is
reachable from which head and the first N lines to show the list
of heads being displayed are both meaningless so they are
omitted. Also the label given to each commit does not repeat
the name of the branch because it is obvious.
------------------------------------------------
$ git show-branch --more=4 master
[master] Add 'git show-branch'.
[~1] Add a new extended SHA1 syntax <name>~<num>
[~2] Fix "git-diff-script A B"
[~3] git-ls-files: generalized pathspecs
[~4] Make "git-ls-files" work in subdirectories
------------------------------------------------
Author
------
Written by Junio C Hamano <junkio@cox.net>
Documentation
--------------
Documentation by Junio C Hamano.
GIT
---
Part of the link:git.html[git] suite
Documentation/git-show-branches-script.txt
已删除
100644 → 0
浏览文件 @
15ac5164
git-show-branches-script(1)
===========================
v0.99.4, Aug 2005
NAME
----
git-show-branches-script - Show branches and their commits.
SYNOPSIS
--------
'git show-branches <reference>...'
DESCRIPTION
-----------
Shows the head commits from the named <reference> (or all refs under
$GIT_DIR/refs/heads), and displays concise list of commit logs
to show their relationship semi-visually.
OPTIONS
-------
<reference>::
Name of the reference under $GIT_DIR/refs/heads/.
OUTPUT
------
Given N <references>, the first N lines are the one-line
description from their commit message. The branch head that is
pointed at by $GIT_DIR/HEAD is prefixed with an asterisk '*'
character while other heads are prefixed with a '!' character.
Following these N lines, one-line log for each commit is
displayed, indented N places. If a commit is on the I-th
branch, the I-th indentation character shows a '+' sign;
otherwise it shows a space.
The following example shows three branches, "pu", "master" and
"rc":
------------------------------------------------
* [pu] Add cheap local clone '-s' flag to git-clone-script
! [master] Documentation updates.
! [rc] Merge master into rc
+ Add cheap local clone '-s' flag to git-clone-script
+ Alternate object pool mechanism updates.
+ Audit rev-parse users.
++ Documentation updates.
+ Merge master into rc
+++ [PATCH] plug memory leak in diff.c::diff_free_filepair()
------------------------------------------------
These three branches all forked from a common commit, "[PATCH]
plug memory leak...", and "rc" has one commit ahead of it. The
"master" branch has one different commit that is also shared by
"pu" branch, and "pu" branch has three more commits on top of
"master" branch.
Author
------
Written by Junio C Hamano <junkio@cox.net>
Documentation
--------------
Documentation by Junio C Hamano.
GIT
---
Part of the link:git.html[git] suite
Documentation/git.txt
浏览文件 @
89305da8
...
...
@@ -208,7 +208,7 @@ link:git-pull-script.html[git-pull-script]::
link:git-commit-script.html[git-commit-script]::
Record changes to the repository.
link:git-show-branch
es-script.html[git-show-branches-script
]::
link:git-show-branch
.html[git-show-branch
]::
Show branches and their commits.
link:git-repack-script.html[git-repack-script]::
...
...
Makefile
浏览文件 @
89305da8
...
...
@@ -71,7 +71,6 @@ SCRIPTS=git git-apply-patch-script git-merge-one-file-script git-prune-script \
SCRIPTS
+=
git-count-objects-script
# SCRIPTS += git-send-email-script
SCRIPTS
+=
git-revert-script
SCRIPTS
+=
git-show-branches-script
PROG
=
git-update-cache git-diff-files git-init-db git-write-tree
\
git-read-tree git-commit-tree git-cat-file git-fsck-cache
\
...
...
@@ -84,7 +83,7 @@ PROG= git-update-cache git-diff-files git-init-db git-write-tree \
git-diff-stages git-rev-parse git-patch-id git-pack-objects
\
git-unpack-objects git-verify-pack git-receive-pack git-send-pack
\
git-prune-packed git-fetch-pack git-upload-pack git-clone-pack
\
git-show-index git-daemon git-var git-peek-remote
\
git-show-index git-daemon git-var git-peek-remote
git-show-branch
\
git-update-server-info git-show-rev-cache git-build-rev-cache
ifndef
NO_CURL
...
...
commit.c
浏览文件 @
89305da8
...
...
@@ -38,23 +38,32 @@ enum cmit_fmt get_commit_format(const char *arg)
die
(
"invalid --pretty format"
);
}
static
struct
commit
*
check_commit
(
struct
object
*
obj
,
const
unsigned
char
*
sha1
)
static
struct
commit
*
check_commit
(
struct
object
*
obj
,
const
unsigned
char
*
sha1
,
int
quiet
)
{
if
(
obj
->
type
!=
commit_type
)
{
error
(
"Object %s is a %s, not a commit"
,
sha1_to_hex
(
sha1
),
obj
->
type
);
if
(
!
quiet
)
error
(
"Object %s is a %s, not a commit"
,
sha1_to_hex
(
sha1
),
obj
->
type
);
return
NULL
;
}
return
(
struct
commit
*
)
obj
;
}
struct
commit
*
lookup_commit_reference
(
const
unsigned
char
*
sha1
)
struct
commit
*
lookup_commit_reference_gently
(
const
unsigned
char
*
sha1
,
int
quiet
)
{
struct
object
*
obj
=
deref_tag
(
parse_object
(
sha1
));
if
(
!
obj
)
return
NULL
;
return
check_commit
(
obj
,
sha1
);
return
check_commit
(
obj
,
sha1
,
quiet
);
}
struct
commit
*
lookup_commit_reference
(
const
unsigned
char
*
sha1
)
{
return
lookup_commit_reference_gently
(
sha1
,
0
);
}
struct
commit
*
lookup_commit
(
const
unsigned
char
*
sha1
)
...
...
@@ -69,7 +78,7 @@ struct commit *lookup_commit(const unsigned char *sha1)
}
if
(
!
obj
->
type
)
obj
->
type
=
commit_type
;
return
check_commit
(
obj
,
sha1
);
return
check_commit
(
obj
,
sha1
,
0
);
}
static
unsigned
long
parse_commit_date
(
const
char
*
buf
)
...
...
commit.h
浏览文件 @
89305da8
...
...
@@ -21,6 +21,8 @@ extern const char *commit_type;
struct
commit
*
lookup_commit
(
const
unsigned
char
*
sha1
);
struct
commit
*
lookup_commit_reference
(
const
unsigned
char
*
sha1
);
struct
commit
*
lookup_commit_reference_gently
(
const
unsigned
char
*
sha1
,
int
quiet
);
int
parse_commit_buffer
(
struct
commit
*
item
,
void
*
buffer
,
unsigned
long
size
);
...
...
git-diff-script
浏览文件 @
89305da8
...
...
@@ -8,8 +8,14 @@ case "${#rev[*]}" in
1
)
git-diff-cache
-M
-p
"
$@
"
;;
2
)
begin
=
$(
echo
"
${
rev
[1]
}
"
|
tr
-d
'^'
)
end
=
"
${
rev
[0]
}
"
case
"
${
rev
[1]
}
"
in
^?
*
)
begin
=
$(
echo
"
${
rev
[1]
}
"
|
tr
-d
'^'
)
end
=
"
${
rev
[0]
}
"
;;
*
)
begin
=
"
${
rev
[0]
}
"
end
=
"
${
rev
[1]
}
"
;;
esac
git-diff-tree
-M
-p
$flags
$begin
$end
$files
;;
*
)
echo
"I don't understand"
...
...
git-show-branches-script
已删除
100755 → 0
浏览文件 @
15ac5164
#!/bin/sh
#
# Show refs and their recent commits.
#
.
git-sh-setup-script
||
die
"Not a git repository"
usage
()
{
die
"usage:
$0
<ref>..."
}
headref
=
`
readlink
$GIT_DIR
/HEAD
`
case
"
$(
git-rev-parse
--no-revs
)
"
in
''
)
;;
*
)
usage
;;
esac
revs
=
$(
git-rev-parse
--revs-only
--symbolic
--no-flags
"
$@
"
)
flags
=
$(
git-rev-parse
--revs-only
--flags
"
$@
"
)
case
"
$revs
"
in
''
)
revs
=
$(
git-rev-parse
--symbolic
--all
|
sed
-ne
's|^refs/heads/||p'
|
sort
)
shift
;;
esac
set
x
$revs
shift
hh
=
in
=
for
ref
do
case
"/
$headref
"
in
*
/
"
$ref
"
)
H
=
'*'
;;
*
)
H
=
'!'
;;
esac
h
=
`
git-rev-parse
--verify
"
$ref
^0"
2>/dev/null
`
||
continue
l
=
`
git-log-script
--max-count
=
1
--pretty
=
oneline
"
$h
"
|
sed
-e
's/^[^ ]* //'
`
hh
=
"
$hh
$h
"
echo
"
$in$H
[
$ref
]
$l
"
in
=
"
$in
"
done
set
x
$hh
shift
git-rev-list
--pretty
=
oneline
$flags
$@
|
while
read
v l
do
in
=
''
for
h
do
b
=
`
git-merge-base
$h
$v
`
case
"
$b
"
in
$v
)
in
=
"
$in
+"
;;
*
)
in
=
"
$in
"
;;
esac
done
echo
"
$in
$l
"
case
"
$in
"
in
*
' '
*
)
;;
*
)
break
;;
esac
done
ls-files.c
浏览文件 @
89305da8
...
...
@@ -21,7 +21,7 @@ static int line_terminator = '\n';
static
int
prefix_len
=
0
,
prefix_offset
=
0
;
static
const
char
*
prefix
=
NULL
;
static
const
char
*
glob
=
NULL
;
static
const
char
*
*
pathspec
=
NULL
;
static
const
char
*
tag_cached
=
""
;
static
const
char
*
tag_unmerged
=
""
;
...
...
@@ -302,6 +302,33 @@ static int cmp_name(const void *p1, const void *p2)
e2
->
name
,
e2
->
len
);
}
/*
* Match a pathspec against a filename. The first "len" characters
* are the common prefix
*/
static
int
match
(
const
char
**
spec
,
const
char
*
filename
,
int
len
)
{
const
char
*
m
;
while
((
m
=
*
spec
++
)
!=
NULL
)
{
int
matchlen
=
strlen
(
m
+
len
);
if
(
!
matchlen
)
return
1
;
if
(
!
strncmp
(
m
+
len
,
filename
+
len
,
matchlen
))
{
if
(
m
[
len
+
matchlen
-
1
]
==
'/'
)
return
1
;
switch
(
filename
[
len
+
matchlen
])
{
case
'/'
:
case
'\0'
:
return
1
;
}
}
if
(
!
fnmatch
(
m
+
len
,
filename
+
len
,
0
))
return
1
;
}
return
0
;
}
static
void
show_dir_entry
(
const
char
*
tag
,
struct
nond_on_fs
*
ent
)
{
int
len
=
prefix_len
;
...
...
@@ -310,7 +337,7 @@ static void show_dir_entry(const char *tag, struct nond_on_fs *ent)
if
(
len
>=
ent
->
len
)
die
(
"git-ls-files: internal error - directory entry not superset of prefix"
);
if
(
glob
&&
fnmatch
(
glob
,
ent
->
name
+
len
,
0
))
if
(
pathspec
&&
!
match
(
pathspec
,
ent
->
name
,
len
))
return
;
printf
(
"%s%s%c"
,
tag
,
ent
->
name
+
offset
,
line_terminator
);
...
...
@@ -373,7 +400,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
if
(
len
>=
ce_namelen
(
ce
))
die
(
"git-ls-files: internal error - cache entry not superset of prefix"
);
if
(
glob
&&
fnmatch
(
glob
,
ce
->
name
+
len
,
0
))
if
(
pathspec
&&
!
match
(
pathspec
,
ce
->
name
,
len
))
return
;
if
(
!
show_stage
)
...
...
@@ -455,36 +482,44 @@ static void prune_cache(void)
active_nr
=
last
;
}
/*
* If the glob starts with a subdirectory, append it to
* the prefix instead, for more efficient operation.
*
* But we do not update the "prefix_offset", which tells
* how much of the name to ignore at printout.
*/
static
void
extend_prefix
(
void
)
static
void
verify_pathspec
(
void
)
{
const
char
*
p
,
*
slash
;
char
c
;
p
=
glob
;
slash
=
NULL
;
while
((
c
=
*
p
++
)
!=
'\0'
)
{
if
(
c
==
'*'
)
break
;
if
(
c
==
'/'
)
slash
=
p
;
const
char
**
p
,
*
n
,
*
prev
;
char
*
real_prefix
;
unsigned
long
max
;
prev
=
NULL
;
max
=
PATH_MAX
;
for
(
p
=
pathspec
;
(
n
=
*
p
)
!=
NULL
;
p
++
)
{
int
i
,
len
=
0
;
for
(
i
=
0
;
i
<
max
;
i
++
)
{
char
c
=
n
[
i
];
if
(
prev
&&
prev
[
i
]
!=
c
)
break
;
if
(
c
==
'*'
||
c
==
'?'
)
break
;
if
(
c
==
'/'
)
len
=
i
+
1
;
}
prev
=
n
;
if
(
len
<
max
)
{
max
=
len
;
if
(
!
max
)
break
;
}
}
if
(
slash
)
{
int
len
=
slash
-
glob
;
char
*
newprefix
=
xmalloc
(
len
+
prefix_len
+
1
);
memcpy
(
newprefix
,
prefix
,
prefix_len
);
memcpy
(
newprefix
+
prefix_len
,
glob
,
len
);
prefix_len
+=
len
;
newprefix
[
prefix_len
]
=
0
;
prefix
=
newprefix
;
glob
=
*
slash
?
slash
:
NULL
;
if
(
prefix_offset
>
max
||
memcmp
(
prev
,
prefix
,
prefix_offset
))
die
(
"git-ls-files: cannot generate relative filenames containing '..'"
);
real_prefix
=
NULL
;
prefix_len
=
max
;
if
(
max
)
{
real_prefix
=
xmalloc
(
max
+
1
);
memcpy
(
real_prefix
,
prev
,
max
);
real_prefix
[
max
]
=
0
;
}
prefix
=
real_prefix
;
}
static
const
char
ls_files_usage
[]
=
...
...
@@ -499,7 +534,7 @@ int main(int argc, char **argv)
prefix
=
setup_git_directory
();
if
(
prefix
)
prefix_offset
=
prefix_len
=
strlen
(
prefix
);
prefix_offset
=
strlen
(
prefix
);
for
(
i
=
1
;
i
<
argc
;
i
++
)
{
char
*
arg
=
argv
[
i
];
...
...
@@ -577,13 +612,16 @@ int main(int argc, char **argv)
prefix_offset
=
0
;
continue
;
}
if
(
glob
||
*
arg
==
'-'
)
if
(
*
arg
==
'-'
)
usage
(
ls_files_usage
);
glob
=
arg
;
break
;
}
if
(
glob
)
extend_prefix
();
pathspec
=
get_pathspec
(
prefix
,
argv
+
i
);
/* Verify that the pathspec matches the prefix */
if
(
pathspec
)
verify_pathspec
();
if
(
show_ignored
&&
!
exc_given
)
{
fprintf
(
stderr
,
"%s: --ignored needs some exclude pattern
\n
"
,
...
...
sha1_name.c
浏览文件 @
89305da8
...
...
@@ -191,9 +191,29 @@ static int get_parent(const char *name, int len,
return
-
1
;
}
static
int
get_nth_ancestor
(
const
char
*
name
,
int
len
,
unsigned
char
*
result
,
int
generation
)
{
unsigned
char
sha1
[
20
];
int
ret
=
get_sha1_1
(
name
,
len
,
sha1
);
if
(
ret
)
return
ret
;
while
(
generation
--
)
{
struct
commit
*
commit
=
lookup_commit_reference
(
sha1
);
if
(
!
commit
||
parse_commit
(
commit
)
||
!
commit
->
parents
)
return
-
1
;
memcpy
(
sha1
,
commit
->
parents
->
item
->
object
.
sha1
,
20
);
}
memcpy
(
result
,
sha1
,
20
);
return
0
;
}
static
int
get_sha1_1
(
const
char
*
name
,
int
len
,
unsigned
char
*
sha1
)
{
int
parent
,
ret
;
const
char
*
cp
;
/* foo^[0-9] or foo^ (== foo^1); we do not do more than 9 parents. */
if
(
len
>
2
&&
name
[
len
-
2
]
==
'^'
&&
...
...
@@ -210,6 +230,27 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1)
if
(
parent
>=
0
)
return
get_parent
(
name
,
len
,
sha1
,
parent
);
/* "name~3" is "name^^^",
* "name~12" is "name^^^^^^^^^^^^", and
* "name~" and "name~0" are name -- not "name^0"!
*/
parent
=
0
;
for
(
cp
=
name
+
len
-
1
;
name
<=
cp
;
cp
--
)
{
int
ch
=
*
cp
;
if
(
'0'
<=
ch
&&
ch
<=
'9'
)
continue
;
if
(
ch
!=
'~'
)
parent
=
-
1
;
break
;
}
if
(
!
parent
&&
*
cp
==
'~'
)
{
int
len1
=
cp
-
name
;
cp
++
;
while
(
cp
<
name
+
len
)
parent
=
parent
*
10
+
*
cp
++
-
'0'
;
return
get_nth_ancestor
(
name
,
len1
,
sha1
,
parent
);
}
ret
=
get_sha1_basic
(
name
,
len
,
sha1
);
if
(
!
ret
)
return
0
;
...
...
show-branch.c
0 → 100644
浏览文件 @
89305da8
#include <stdlib.h>
#include "cache.h"
#include "commit.h"
#include "refs.h"
static
const
char
show_branch_usage
[]
=
"git-show-branch [--all] [--heads] [--tags] [--more=count] [<refs>...]"
;
#define UNINTERESTING 01
#define REV_SHIFT 2
#define MAX_REVS 29
/* should not exceed bits_per_int - REV_SHIFT */
static
struct
commit
*
interesting
(
struct
commit_list
*
list
)
{
while
(
list
)
{
struct
commit
*
commit
=
list
->
item
;
list
=
list
->
next
;
if
(
commit
->
object
.
flags
&
UNINTERESTING
)
continue
;
return
commit
;
}
return
NULL
;
}
static
struct
commit
*
pop_one_commit
(
struct
commit_list
**
list_p
)
{
struct
commit
*
commit
;
struct
commit_list
*
list
;
list
=
*
list_p
;
commit
=
list
->
item
;
*
list_p
=
list
->
next
;
free
(
list
);
return
commit
;
}
struct
commit_name
{
int
head_rev
;
/* which head's ancestor? */
int
generation
;
/* how many parents away from head_rev */
};
/* Name the commit as nth generation ancestor of head_rev;
* we count only the first-parent relationship for naming purposes.
*/
static
void
name_commit
(
struct
commit
*
commit
,
int
head_rev
,
int
nth
)
{
struct
commit_name
*
name
;
if
(
!
commit
->
object
.
util
)
commit
->
object
.
util
=
xmalloc
(
sizeof
(
struct
commit_name
));
name
=
commit
->
object
.
util
;
name
->
head_rev
=
head_rev
;
name
->
generation
=
nth
;
}
/* Parent is the first parent of the commit. We may name it
* as (n+1)th generation ancestor of the same head_rev as
* commit is nth generation ancestore of, if that generation
* number is better than the name it already has.
*/
static
void
name_parent
(
struct
commit
*
commit
,
struct
commit
*
parent
)
{
struct
commit_name
*
commit_name
=
commit
->
object
.
util
;
struct
commit_name
*
parent_name
=
parent
->
object
.
util
;
if
(
!
commit_name
)
return
;
if
(
!
parent_name
||
commit_name
->
generation
+
1
<
parent_name
->
generation
)
name_commit
(
parent
,
commit_name
->
head_rev
,
commit_name
->
generation
+
1
);
}
static
int
mark_seen
(
struct
commit
*
commit
,
struct
commit_list
**
seen_p
)
{
if
(
!
commit
->
object
.
flags
)
{
insert_by_date
(
commit
,
seen_p
);
return
1
;
}
return
0
;
}
static
void
join_revs
(
struct
commit_list
**
list_p
,
struct
commit_list
**
seen_p
,
int
num_rev
,
int
extra
)
{
int
all_mask
=
((
1u
<<
(
REV_SHIFT
+
num_rev
))
-
1
);
int
all_revs
=
all_mask
&
~
((
1u
<<
REV_SHIFT
)
-
1
);
while
(
*
list_p
)
{
struct
commit_list
*
parents
;
struct
commit
*
commit
=
pop_one_commit
(
list_p
);
int
flags
=
commit
->
object
.
flags
&
all_mask
;
int
nth_parent
=
0
;
int
still_interesting
=
!!
interesting
(
*
list_p
);
if
(
!
still_interesting
&&
extra
<
0
)
break
;
mark_seen
(
commit
,
seen_p
);
if
((
flags
&
all_revs
)
==
all_revs
)
flags
|=
UNINTERESTING
;
parents
=
commit
->
parents
;
while
(
parents
)
{
struct
commit
*
p
=
parents
->
item
;
int
this_flag
=
p
->
object
.
flags
;
parents
=
parents
->
next
;
nth_parent
++
;
if
(
nth_parent
==
1
)
name_parent
(
commit
,
p
);
if
((
this_flag
&
flags
)
==
flags
)
continue
;
parse_commit
(
p
);
if
(
mark_seen
(
p
,
seen_p
)
&&
!
still_interesting
)
extra
--
;
p
->
object
.
flags
|=
flags
;
insert_by_date
(
p
,
list_p
);
}
}
}
static
void
show_one_commit
(
struct
commit
*
commit
,
char
**
head_name
)
{
char
pretty
[
128
],
*
cp
;
struct
commit_name
*
name
=
commit
->
object
.
util
;
pretty_print_commit
(
CMIT_FMT_ONELINE
,
commit
->
buffer
,
~
0
,
pretty
,
sizeof
(
pretty
));
if
(
!
strncmp
(
pretty
,
"[PATCH] "
,
8
))
cp
=
pretty
+
8
;
else
cp
=
pretty
;
if
(
name
&&
head_name
)
{
printf
(
"[%s"
,
head_name
[
name
->
head_rev
]);
if
(
name
->
generation
)
printf
(
"~%d"
,
name
->
generation
);
printf
(
"] "
);
}
puts
(
cp
);
}
static
char
*
ref_name
[
MAX_REVS
+
1
];
static
int
ref_name_cnt
;
static
int
append_ref
(
const
char
*
refname
,
const
unsigned
char
*
sha1
)
{
struct
commit
*
commit
=
lookup_commit_reference_gently
(
sha1
,
1
);
if
(
!
commit
)
return
0
;
if
(
MAX_REVS
<
ref_name_cnt
)
{
fprintf
(
stderr
,
"warning: ignoring %s; "
"cannot handle more than %d refs"
,
refname
,
MAX_REVS
);
return
0
;
}
ref_name
[
ref_name_cnt
++
]
=
strdup
(
refname
);
ref_name
[
ref_name_cnt
]
=
NULL
;
return
0
;
}
static
int
append_head_ref
(
const
char
*
refname
,
const
unsigned
char
*
sha1
)
{
if
(
strncmp
(
refname
,
"refs/heads/"
,
11
))
return
0
;
return
append_ref
(
refname
+
5
,
sha1
);
}
static
int
append_tag_ref
(
const
char
*
refname
,
const
unsigned
char
*
sha1
)
{
if
(
strncmp
(
refname
,
"refs/tags/"
,
10
))
return
0
;
return
append_ref
(
refname
+
5
,
sha1
);
}
static
void
snarf_refs
(
int
head
,
int
tag
)
{
if
(
head
)
for_each_ref
(
append_head_ref
);
if
(
tag
)
for_each_ref
(
append_tag_ref
);
}
static
int
rev_is_head
(
char
*
head_path
,
int
headlen
,
char
*
name
,
unsigned
char
*
head_sha1
,
unsigned
char
*
sha1
)
{
int
namelen
;
if
((
!
head_path
[
0
])
||
memcmp
(
head_sha1
,
sha1
,
20
))
return
0
;
namelen
=
strlen
(
name
);
if
((
headlen
<
namelen
)
||
memcmp
(
head_path
+
headlen
-
namelen
,
name
,
namelen
))
return
0
;
if
(
headlen
==
namelen
||
head_path
[
headlen
-
namelen
-
1
]
==
'/'
)
return
1
;
return
0
;
}
static
int
show_merge_base
(
struct
commit_list
*
seen
,
int
num_rev
)
{
int
all_mask
=
((
1u
<<
(
REV_SHIFT
+
num_rev
))
-
1
);
int
all_revs
=
all_mask
&
~
((
1u
<<
REV_SHIFT
)
-
1
);
while
(
seen
)
{
struct
commit
*
commit
=
pop_one_commit
(
&
seen
);
int
flags
=
commit
->
object
.
flags
&
all_mask
;
if
(
!
(
flags
&
UNINTERESTING
)
&&
((
flags
&
all_revs
)
==
all_revs
))
{
puts
(
sha1_to_hex
(
commit
->
object
.
sha1
));
return
0
;
}
}
return
1
;
}
int
main
(
int
ac
,
char
**
av
)
{
struct
commit
*
rev
[
MAX_REVS
],
*
commit
;
struct
commit_list
*
list
=
NULL
,
*
seen
=
NULL
;
int
num_rev
,
i
,
extra
=
0
;
int
all_heads
=
0
,
all_tags
=
0
;
char
head_path
[
128
];
int
head_path_len
;
unsigned
char
head_sha1
[
20
];
int
merge_base
=
0
;
char
**
label
;
while
(
1
<
ac
&&
av
[
1
][
0
]
==
'-'
)
{
char
*
arg
=
av
[
1
];
if
(
!
strcmp
(
arg
,
"--all"
))
all_heads
=
all_tags
=
1
;
else
if
(
!
strcmp
(
arg
,
"--heads"
))
all_heads
=
1
;
else
if
(
!
strcmp
(
arg
,
"--tags"
))
all_tags
=
1
;
else
if
(
!
strcmp
(
arg
,
"--more"
))
extra
=
1
;
else
if
(
!
strncmp
(
arg
,
"--more="
,
7
))
{
extra
=
atoi
(
arg
+
7
);
if
(
extra
<
0
)
usage
(
show_branch_usage
);
}
else
if
(
!
strcmp
(
arg
,
"--merge-base"
))
merge_base
=
1
;
else
usage
(
show_branch_usage
);
ac
--
;
av
++
;
}
ac
--
;
av
++
;
if
(
all_heads
+
all_tags
)
snarf_refs
(
all_heads
,
all_tags
);
while
(
0
<
ac
)
{
unsigned
char
revkey
[
20
];
if
(
get_sha1
(
*
av
,
revkey
))
die
(
"bad sha1 reference %s"
,
*
av
);
append_ref
(
*
av
,
revkey
);
ac
--
;
av
++
;
}
/* If still no revs, then add heads */
if
(
!
ref_name_cnt
)
snarf_refs
(
1
,
0
);
for
(
num_rev
=
0
;
ref_name
[
num_rev
];
num_rev
++
)
{
unsigned
char
revkey
[
20
];
if
(
MAX_REVS
<=
num_rev
)
die
(
"cannot handle more than %d revs."
,
MAX_REVS
);
if
(
get_sha1
(
ref_name
[
num_rev
],
revkey
))
usage
(
show_branch_usage
);
commit
=
lookup_commit_reference
(
revkey
);
if
(
!
commit
)
die
(
"cannot find commit %s (%s)"
,
ref_name
[
num_rev
],
revkey
);
parse_commit
(
commit
);
if
(
!
commit
->
object
.
util
)
name_commit
(
commit
,
num_rev
,
0
);
mark_seen
(
commit
,
&
seen
);
/* rev#0 uses bit REV_SHIFT, rev#1 uses bit REV_SHIFT+1,
* and so on. REV_SHIFT bits from bit 0 are used for
* internal bookkeeping.
*/
commit
->
object
.
flags
|=
1u
<<
(
num_rev
+
REV_SHIFT
);
insert_by_date
(
commit
,
&
list
);
rev
[
num_rev
]
=
commit
;
}
join_revs
(
&
list
,
&
seen
,
num_rev
,
extra
);
head_path_len
=
readlink
(
".git/HEAD"
,
head_path
,
sizeof
(
head_path
)
-
1
);
if
((
head_path_len
<
0
)
||
get_sha1
(
"HEAD"
,
head_sha1
))
head_path
[
0
]
=
0
;
else
head_path
[
head_path_len
]
=
0
;
if
(
merge_base
)
return
show_merge_base
(
seen
,
num_rev
);
/* Show list */
if
(
1
<
num_rev
)
{
for
(
i
=
0
;
i
<
num_rev
;
i
++
)
{
int
j
;
int
is_head
=
rev_is_head
(
head_path
,
head_path_len
,
ref_name
[
i
],
head_sha1
,
rev
[
i
]
->
object
.
sha1
);
for
(
j
=
0
;
j
<
i
;
j
++
)
putchar
(
' '
);
printf
(
"%c [%s] "
,
is_head
?
'*'
:
'!'
,
ref_name
[
i
]);
show_one_commit
(
rev
[
i
],
NULL
);
}
for
(
i
=
0
;
i
<
num_rev
;
i
++
)
putchar
(
'-'
);
putchar
(
'\n'
);
}
label
=
ref_name
;
while
(
seen
)
{
struct
commit
*
commit
=
pop_one_commit
(
&
seen
);
int
this_flag
=
commit
->
object
.
flags
;
static
char
*
obvious
[]
=
{
""
};
if
((
this_flag
&
UNINTERESTING
)
&&
(
--
extra
<
0
))
break
;
if
(
1
<
num_rev
)
{
for
(
i
=
0
;
i
<
num_rev
;
i
++
)
putchar
((
this_flag
&
(
1u
<<
(
i
+
REV_SHIFT
)))
?
'+'
:
' '
);
putchar
(
' '
);
}
show_one_commit
(
commit
,
label
);
if
(
num_rev
==
1
)
label
=
obvious
;
}
return
0
;
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录